diff --git a/.gitignore b/.gitignore index f3a4caa..768e523 100644 --- a/.gitignore +++ b/.gitignore @@ -12,15 +12,10 @@ /config/version.c /docs/Makefile /etc/Makefile -/etc/mhn.defaults -/etc/mts.conf -/etc/sendfiles /h/Makefile /man/Makefile /man/man.sed -/mts/Makefile -/mts/libmts.a -/mts/smtp/Makefile +/man/mh-chart.man7 /sbr/Makefile /sbr/dtimep.c /sbr/libmh.a @@ -39,7 +34,6 @@ /uip/folder /uip/forw /uip/inc -/uip/install-mh /uip/mark /uip/mhbuild /uip/mhl @@ -49,14 +43,19 @@ /uip/mhparam /uip/mhpath /uip/mhshow +/uip/mhsign +/uip/mhpgp /uip/mhstore /uip/mhtest +/uip/mmh +/uip/mmhwrap /uip/msgchk /uip/msh /uip/new /uip/packf /uip/pick /uip/post +/uip/print-mimetype /uip/prompter /uip/rcvdist /uip/rcvpack @@ -68,14 +67,16 @@ /uip/rmm /uip/scan /uip/send +/uip/sendfiles /uip/show /uip/slocal /uip/sortm /uip/spost -/uip/viamail /uip/whatnow /uip/whom *.o *.1 *.5 +*.7 *.8 +/mmh-*.tar.gz diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 324dddc..0000000 --- a/ChangeLog +++ /dev/null @@ -1,3852 +0,0 @@ -2010-12-09 Ken Hornstein - - * h/nntp.h, configure.in, h/Makefile.in, h/mts.h, h/popsbr.h, - man/inc.man, man/mh-chart.man, man/mh-tailor.man, man/msgchk.man, - sbr/Makefile.in, sbr/mts.c, uip/Makefile.in, uip/inc.c, uip/msgchk.c, - uip/msh.c, uip/mshcmds.c, uip/popsbr.c: Massive garbage collection. - Remove functionality for APOP, RPOP, all NNTP support (including - bboards), and MPOP. - -2010-12-08 David Levine - - * uip/whatnowsbr.c: enforce requirement of at least one file - argument to attach command. - -2010-12-08 David Levine - - * man/send.man: added name= portion to Content-Type - headers to reflect 2006-10-24 change to uip/sendsbr.c. - That change allowed mhstore to use the (file)name when - extracting attachments. - -2010-12-03 Ken Hornstein - - * Everything: remove RCS keywords from files, since they no longer - work after git migration. - -2010-12-02 Ken Hornstein - - * .cvsignore, .gitignore, autogen.sh, */.cvsignore: Update files - for git conversion. - -2010-12-19 Ken Hornstein - - * aclocal.m4, config/Makefile.in, configure.in, man/mh-chart.man, - man/post.man, man/send.man, mts/smtp/Makefile.in, mts/smtp/smtp.c, - mts/smtp/smtp.h, sbr/Makefile.in, uip/Makefile.in, uip/post.c, - uip/send.c, uip/whatnowsbr.c, uip/whom.c: Clean up autoconf - code for handling of compiler flags for SASL, and add support - for TLS to the SMTP MTA. - -2010-11-12 Peter Maydell - - * man/slocal.man: fix formatting error that meant a - subsection heading wasn't displayed as such. - -2010-11-10 Peter Maydell - - * configure.in: add a level of expansion for mandir - when printing the end-of-configure install path - summary. - -2010-11-09 Peter Maydell - - * man/rmm.man: fix error in synopsis: the option is - [no]unlink, not [no]link. - -2010-08-31 David Levine - - * uip/.cvsignore: added "new". - -2010-02-03 Earl Hood - - * Bug #15213, #18635: The use of the insecure m_scratch() and - m_tmpfil() functions have been replaced by m_mktemp() - or m_mktemp2() functions (defined in sbr/m_mktemp.c). - The new functions use mkstemp() to securely create - temporary files to avoid the numerous race conditions - that exist with the old functions. This does assume - that mkstemp() is available. Unsure if we need to - create an alternative implementation if mkstemp() is - not available. More information about new temp file - functions in m_mktemp.c, including the support for - MHTMPDIR, TMPDIR, and TMP envvars. - -2010-02-02 Earl Hood - - * mts/smtp/smtp.c: added SASL support if mts configuration - setting is set to "sendmail". This is useful if sendmail - conf option is to a custom script that creates a proxy - connection to an smtp server. - - * sbr/mts.c: added support for MHMTSCONF and MHMTSUSERCONF - envvars. The former specifies an alternative system - mts.conf to use. The later specifies a user-specific - mts.conf to use. This one will be read after the system - conf, so the user's conf only needs to set options they - want to override. The MHMTSUSERCONF allows a user to set - personal alternative mail submission methods w/o affecting - other users on the system. - - * uip/whom.c: added SASL-based options so address checking - can work against a server that requires SASL. - -2009-12-29 David Levine - - * uip/mhlistsbr.c, uip/mhlsbr.c, uip/picksbr.c: cast - pointers to unsigned long before casting to unsigned int - to avoid warnings on 64-bit about casting from pointer - to int of different size. - - * uip/new.c: cast folder_len to int to avoid warning on - 64-bit about passing a size_t to an int conversion specifier. - -2009-12-25 David Levine - - * uip/inc.c: gcc 4.4.1 noticed that maildir could have been - used before initialization. In fact, if that code was ever - reached, maildir would never have been initialized. It's in - an adios call, so replaced with NULL. - -2009-12-21 David Levine - - * mts/smtp/smtp.c: In sm_auth_sasl (), removed zeroing of - sasl_inbuffer because it could be used in sm_fget (). Also, - removed allocation of sasl_inbuffer because that was done in - either smtp_init () or sendmail_init (). - -2009-01-17 Eric Gillespie - - * etc/mhn.defaults.sh: Never try to make mhshow start xterm. - -2009-01-16 Eric Gillespie - - * test/runtest, test/tests/inc/test-deb359167, - test/tests/inc/test-eom-align, test/tests/manpages/test-manpages: - Load common.sh via absolute path, otherwise some /bin/sh - (e.g. dash) can't load it. - - * uip/Makefile.in, uip/new.c, test/tests/new/test-basic: Add new - program, and fn/fp/unseen symlinks. - - * test/{runtest,setup-test}: Move MH profile under Mail directory - so each test script will have its own to muck with, if needed. - - * h/Makefile.in, h/crawl_folders.h, sbr/Makefile.in, - sbr/crawl_folders.c, uip/folder.c: Extract the folder crawling - code from folder.c into new crawl_folders function, using a - callback to assemble the folder info in folder.c. Drop compare - function and use strcmp instead. Rename addfold and addir to - add_folder and add_children (add dir vs. add folder? - confusing names). - -2008-12-26 Peter Maydell - - * sbr/m_getfld.c: fix two bugs which could cause us to walk off - the beginning of the stdio or prefix-string buffer when checking - for presence of the end-of-message delimiter in some situations. - This might cause inc to dump core if you were unlucky. (This was - Debian bug 359167.) - * test/tests/inc/{md5sums,msgheader.txt,test-deb359167, - test-eom-align,fromline.txt,filler.txt,deb359167.mbox}: new tests - both for the specific problem and to try to check various alignments - of the eom string with the stdio buffer ending. - * test/common.sh: new file for common utility functions for the - test scripts. Moved findprog out of manpage test script into this - new file. Added some functions for doing progress indicators. - -2008-12-25 Peter Maydell - - * test/runtest: automatically run setup-test if it hasn't already - been done. Improve error handling in test script with 'set -e'. - -2008-10-23 David Levine - - * h/mh.h: raised NAMESZ from 128 to 999. RFC 2822 limits line - lengths to 998 characters, so a header name can be at most that long. - m_getfld limits header names to 2 less than NAMESZ, which is fine, - because header names must be followed by a colon. Add one for - terminating NULL. - -2008-10-23 David Levine - - * sbr/m_getfld.c: in warning message, use NAMESZ-2 instead of - NAMESZ-1 bytes because the message says "exceeds", not - "is greater than or equal to". - -2008-10-23 David Levine - - * docs/MAIL.FILTERING: added note on removing procmail -f or - -r options to try to suppress generation of a "From " line on - incoming messages. - -2008-08-14 Eric Gillespie - - * test/setup-test: Don't run autogen.sh unless needed. Build in a - blddir under the temporary directory so as not to interfere with - whatever the developer may be doing in the source directory. - If the temporary directory already exists, rebuild and install it. - -2008-08-13 Eric Gillespie - - * sbr/ambigsw.c: Send print_sw output to stderr. This avoids - strange problems with scan `pick -bogus`, not to mention being - nicer anyway. - - * sbr/getans.c, sbr/print_help.c, uip/msh.c: Send print_sw output - to stdout. - - * h/prototypes.h, sbr/print_sw.c (print_sw): Add FILE * argument - and send output there rather than to stdout. - - * test/tests/pick/test-stderr: Add test that error messages don't - end up going to stdout. - -2008-08-13 Eric Gillespie - - * uip/pick.c: Print matching messages immediately, instead of - waiting until the very end to print anything. - Ensure valid sequence name as soon as we parse it from command, - instead of searching the messages first. - -2008-08-13 Eric Gillespie - - * uip/Makefile.in, uip/popi.c: Remove popi.c, which has been dead - since PatchSet 257 (2000/06/12 11:07:34 UTC). - -2008-08-13 Eric Gillespie - - * h/mhparse.h: Move interfaces also used by mhbuildsbr.c here - from mhparse.c. - - * uip/Makefile.in (mhbuild): Build with mhparse.o. - - * uip/mhbuildsbr.c: Drop the duplication of mhparse.c. - - * uip/mhbuild.c, uip/mhlist.c, uip/mhn.c, uip/mhshow.c, - uip/mhstore.c, uip/mhtest.c: Drop check swdeclaration, which is - now in mhparse.h. - - * uip/mhparse.c: Move some declarations to mhparse.h, and remove - 'static' from the definitions here. - (get_ctinfo): Take magic mhbuild support from mhbuildsbr.c's copy, - and adapt callers. - (incl_name_value, extract_name_value): Move from mhbuildsbr.c to - support get_ctinfo change). - (get_content, open7Bit): Add Content-Disposition support, added to - mhbuildsbr.c's copy in mhbuildsbr.c r1.12 (PatchSet 549). - (InitText): Default to CHARSET_UNSPECIFIED instead of "US-ASCII", - as mhbuildsbr.c's copy did. Explain termproc. - (openBase64, openQuoted, open7Bit): Fix comment from r1.5: - suffixes, not prefixes. - (openMail): Explain showproc. - - * test/tests/mhshow/test-cte-binary: Add test for - Content-Transfer-Encoding: binary (Debian #136976). - - * test/tests/mhbuild/test-forw: Add an mhbuild test, testing forw - with and without RFC-934 mode. More mhbuild tests would be nice. - -2008-08-13 Eric Gillespie - - * test/tests/bad-input/test-header: Add test for it. - - * sbr/m_getfld.c: If we reach the end of the line without finding - a ':' when parsing a header field, treat that line as the - beginning of the body rather than blowing up. These messages are - usually spam, but it's nice to be able to at least scan them. - -2008-08-12 Eric Gillespie - - * test/tests/mhshow/test-qp: Test various valid and invalid - escape sequences. - - * uip/mhparse.c (openQuoted): Simplify the decode-or-show for loop by - peeking ahead to the next byte(s) when encountering '=', and just let - invalid escape sequences through as literals (fixes bug #15245). - -2008-08-12 Peter Maydell - - * autogen.sh (new file): add script for running the GNU - autotools in the right order - * INSTALL: mention that you need to run autogen.sh if you - got nmh from CVS - * docs/README.developers: mention autogen.sh rather than - suggesting running autoheader and autoconf by hand. - * test/setup-test: run autotools via autogen.sh - -2008-08-08 Eric Gillespie - - * sbr/discard.c, sbr/m_getfld.c, uip/scansbr.c: Add support for - DragonFlyBSD stdio (from NetBSD pkgsrc). - -2008-08-05 Eric Gillespie - - * uip/folder.c: chdir(nmhdir) in main rather than in dodir, which - is called many times. Drop the chdir in get_folder_info, which - served no purpose at all. If struct stat has d_type (BSD), use - that to skip processing (strcmp, stat, and so on) of message - files, mostly undoing the slow-down from the last change. - - * configure.in: Call CHECK_TYPE_STRUCT_DIRENT_D_TYPE. - - * aclocal.m4: Add CHECK_TYPE_STRUCT_DIRENT_D_TYPE from - GNU coreutils. - -2008-08-04 Eric Gillespie - - * uip/folder.c: Simplify dodir/addir/addfold. Dump hacky - over-optimization in addir that tried to avoid readdir after all - child directories had been read; this was also trying to support - symlinks to directories, but would have been failing (because - nlink may have gone to 0 with symlinks to directories remaining) - had the lstat usage been correct (lstat doesn't fail for normal - directories; should have used S_ISLNK). - -2008-08-03 Peter Maydell - - * test/setup-test: use 'set -e' so we stop on compile failure. - Configure --enable-debug for convenience in debugging. - - * uip/whatnowsbr.c: bug #23319: rework the way we handle the working - directory when invoking the user's shell, so that we don't have - issues when the cwd contains a space or shell special character. - * test/tests/whatnow/test-attach-detach, test/tests/whatnow/test-cd, - test/tests/whatnow/test-ls: test cases for this. - - * sbr/fmt_compile.c: add 'do { ... } while (0)' wrappers - to various multi-statement macros to avoid nasty surprises - if the macros are used in if() clauses. - - * bug #23436: man/scan.man, man/forw.man, man/inc.man, - man/mh-chart.man, man/mhmail.man, man/mhshow.man, - man/mhstore.man, man/msgchk.man, man/packf.man, man/scan.man: - fix minor syntax errors groff warns about. - * test/runtest, test/README: allow test cases to report - that they have been SKIPped as well as PASS/FAIL - * test/tests/manpages/test-manpages - new test which runs groff - on the manpages and checks that there are no warnings. - * test/runalltests: ignore editor backup files - -2008-08-03 Eric Gillespie - - * etc/replcomps, etc/replgroupcomps: Trim trailing whitespace from - Subject field. - -2008-08-03 Peter Maydell - - * sbr/fmt_compile.c: when doing an if-test on the result - of a function which returns a string result, check whether - the string is non-empty (as the documentation says we do). - Previously we were always testing the integer 'value'. Bug - spotted by Eric Gillespie. - * test/tests/repl/test-if-str: test case for this bug - -2008-07-24 Eric Gillespie - - * test/setup-test: Run 'make clean' before building - -2008-07-24 Eric Gillespie - - * test/runtest: cat test-temp-dir only once. Destroy and create - test Mail hierarchy here, so each test has its own independent - test data. - - * test/setup-test: Drop needless pushd/popd, which don't exist in - sh anyway. Don't use aclocal, which is part of automake. - Don't create Mail hierarchy here (see test/runtest). - - * test/tests/folder/test-create, tests/folder/test-total: Drop - unused BINDIR. - - * tests/pick/test-pick: Remove failing no-op test. - - * test/tests/scan/test-scan: Write expected and actual output to - files and diff them. This way, if the output differs, diff - provides the FAILing exit code and shows the differences. - -2008-06-12 Josh Bressers - * man/repl.man, etc/mhl.reply: - Add an attribution line when replying to messages. - -2008-06-02 Peter Maydell - - * h/mh.h, h/prototypes.h, sbr/done.c, uip/inc.c, - uip/mhbuild.c, uip/mhlist.c, uip/mhn.c, uip/mhshow.c, - uip/mhstore.c, uip/mhtest.c, uip/packf.c, uip/pick.c, - uip/rcvdist.c, uip/rcvstore.c, uip/sendsbr.c: when - building on gcc, use the noreturn attribute on various - functions (should improve code and avoid some spurious - 'uninitialized variable' warnings). - -2008-06-01 Peter Maydell - - * docs/README.developers: update the bits about doing a - release announcement, now I've actually done one. - -2008-05-22 Peter Maydell - - * uip/scansbr.c: don't use MB_CUR_MAX if we aren't compiled - with multibyte support. - - * uip/whatnowsbr.c: factor out common code for writing ls - shell command, and make it do more sensible buffer length - checks. Also avoid relying on the return value of sprintf(), - as some old systems don't return number of characters written. - -2008-05-21 Peter Maydell - - * sbr/utils.c (mh_xrealloc): don't assume realloc() can - handle NULL pointers; some non-POSIX realloc()s can't. - - * sbr/dtimep.lex: add some table size declarations for the - benefit of elderly lexes with small defaults. - -2008-05-18 David Levine - - * sbr/addrsbr.c: removed "err" from conditional, because gcc - correctly warned that it would always evaluate as true. It's - the address of a static array. - -2008-05-16 Oliver Kiddle - - * sbr/Makefile.in, config/Makefile.in: Don't use $< in target rules - in makefiles, as POSIX says it's only defined in inference rules. - -2008-05-13 David Levine - - * configure.in, INSTALL: if --enable-masquerade is not - specified to configure, enable all supported masquerade forms. - This allows users to masquerade with the default - configuration. That seems to be more worthwhile now than - trying to prevent users from using it, especially with - single-user installations or those where a user can edit - etc/mts.conf. - -2008-05-04 Peter Maydell - - * bug #23167: sbr/ruserpass.c (ruserpass): make bad permissions - on .netrc be an instantly fatal error. Previously we returned - an error value; however, no caller was checking it. So now - ruserpass() has a void return type. - - * bug #23163: various minor fixes for the benefit of - older Unixes (specifically SunOS 4): - reintroduce strerror() substitute implementation - provide memmove() substitute implementation - - * bug #23163: fix accidentally broken 'build outside - source directory' feature - - * bug #23162: sbr/dtime.c: fix stray HAVE_TM_GMTOFF that - wasn't updated to the new macro name. - -2008-04-30 Peter Maydell - - * mts/smtp/smtp.c: provide a callback for SASL_CB_AUTHNAME - (fixes issue with SASL sending the wrong username in some - circumstances). Thanks to - for the patch. - -2008-04-29 Peter Maydell - - * Revert previous attempt at fix for SASL issue as it - is the wrong approach. - - * Fix in correct manner, by making sm_rrecord() and thus - sm_hear() set the length of the reply string correctly - (the SASL libraries now care if you pass in the wrong - length). - - * Correct various places in smtp.c where the reply string - might not have been correctly NUL-terminated. Includes a - fix for a particularly nasty and long standing screwup - where the buffer length counting in smhear() was totally - broken for continued lines from the server. - -2008-04-29 Peter Maydell - - * Cope with sasl_decode64() returning SASL_CONTINUE, as - happens with newer sasl libraries and LOGIN auth. - -2008-04-27 Peter Maydell - - * Updated some of the 'how to do a release' documentation. - - * Upped the VERSION string to '1.3-dev', since 1.3-RC1 has - been branched off. - -2008-04-27 Peter Maydell - - * Released nmh-1.3 RC1. - -2008-04-11 Oliver Kiddle - - * acconfig.h, configure.in, sbr/dtime.c, sbr/pidwait.c, - uip/mhshowsbr.c, uip/rcvtty.c, uip/slocal.c, uip/termsbr.c: - move most remaining macros out of acconfig.h which is an - obsolete feature of autoconf - -2008-04-05 Peter Maydell - - * bug #18655: fix use of admonish() for a fatal error (should - be adios(); only actual effect would be wrong exit code). - Thanks to Craig Leres for spotting this. - -2008-04-05 Peter Maydell - - * bug #20028 (Debian bug 399271): fix code assuming that pointer - differences were 32 bits -- thanks to Dean Gaudet for the patch. - -2008-01-25 Josh Bressers - - * uip/mhshowsbr.c (show_all_messages): Be more generous when parsing - multipart messages. - -2007-11-04 Joel Reicher - - * Changed done() link overriding to function pointer. Return type - is now void so that exit() can be used as done() callback. Dead - code return from all done()s removed, with return 1 in main() - following done() (should never be reached). - -2007-08-21 Josh Bressers - - * Red Hat Bug #253342: inc.c, utils.c, utils.h: When inc is run with - the -silent flag, don't exit(1) for no apparent reason. - -2007-03-12 Peter Maydell - - * bug #18630, #18631, #18632, #18634: various patches from - Craig Leres fixing error message argument problems. - -2007-03-12 Peter Maydell - - * bug #15212: configure.in, acconfig.h: remove configure test for - broken AT&T vi. This test was broken (it was always returning - failure even for non-broken vi implementations) and - unfixable. Nobody should be using AT&T vi any more so I have - simply moved it back to being a setting you can put manually into - acconfig.h if you must. - -2006-10-24 David Levine - - * uip/sendsbr.c: with attachformat values of 1 or 2, add - name= portion to Content-Type header. This makes them - consistent with attachformat value 0. And it allows mhstore - to use that (file)name when extracting attachments. - -2006-08-26 Josh Bressers - - * configure.in: If we're not using dotlocking, there is no need to set - inc sgid. - -2006-03-30 David Levine - - * uip/sendsbr.c: with attachformat values of 1 or 2, only - generate Content-Disposition headers for MIME attachments, not - for the message contents themselves. Microsoft Outlook Build - 10.0.6626, at least, doesn't show the message contents if they - have Content-Disposition. - -2006-03-09 Josh Bressers - - * sbr/fmt_rfc2047.c (decode_rfc2047): Don't close the iconv descriptor - if it isn't valid. - -2006-03-08 Josh Bressers - - * (mh_strcasecmp): Rename the private strcasecmp function to - mh_strcasecmp. This keeps the newer gnu linker happy. - -2006-03-05 Oliver Kiddle - - * sbr/fmt_rfc2047.c: don't try to malloc 0 bytes if an RFC2047 - encoded block is empty - -2006-03-04 Peter Maydell - - * etc/Makefile.in: use INSTALL_SCRIPT to install scripts; - this allows INSTALL_PROGRAM to be set to 'install -s' so - binaries are stripped on installation. Apparently the BSDs - do this. - -2006-02-25 David Levine - - * uip/sendsbr.c: replaced st_mtim with st_mtime, that's what - it should have been. Added #include of h/tws.h to pick up - dtime() prototype. - -2006-02-20 David Levine - - * h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c, - uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man: - added -attachformat switch to send, to support alternate MIME - header contents when using -attach. See send man page for - description. - - * man/mhbuild.man: wrapped one appearance of "Content-Disposition" - with quotes, to be consistent with others. - -2006-02-20 Josh Bressers - - * h/utils.h, sbr/utils.c, uip/flist.c, uip/folder.c: Move duplicate - function num_digits into utils.c - -2006-02-19 Josh Bressers - - * sbr/m_draft.c, sbr/utils.c, uip/folder.c, uip/inc.c, - uip/mhstoresbr.c, uip/popi.c, uip/refile.c: Add create_folder() - function, replacing duplicate code during folder creation. - -2006-02-18 David Levine - - * h/mime.h, h/mhparse.h, uip/mhbuildsbr.c, uip/mhfree.c, - man/mhbuild.man, docs/TODO: added support for an optional - Content-Disposition header in mhbuild (only). Its contents - are supplied between {}, positioned after the optional [], in - a mhbuild directive. If the contents do not contain a - "filename=" parameter, and the directive has a filename, or - something else that ends with "name=", then that will be used - to add a "filename=" parameter to the header. - -2006-02-12 David Levine - - * docs/TODO: added RFC2183 to reference of RFC1806 for - Content-Disposition header. - -2006-01-31 David Levine - - * uip/mhbuild.c, uip/mhbuildsbr.c, man/mhbuild.man: added - -nocontentid switch, to disable generation of Content-ID: - header in MIME messages. (Also added -contentid for - symmetry.) The default configuration of Microsoft Outlook, - Build 10.0.3416 in particular, doesn't see attachments in - incoming messages if there are Content-ID headers, see - http://home.cwru.edu/~wrv/eudoraoutlookfix.html. This allows - users to easily accomodate that by adding - mhbuild: -nocontentid to their .mh_profile. - -2006-01-29 Oliver Kiddle - - * bug 4360: uip/replsbr.c: remove trailing newlines from components - to fix bug with spaces at the end of Subject/References in replies - -2006-01-18 Oliver Kiddle - - * configure.in: use AS_HELP_STRING for formatting help messages - - * configure.in, sbr/fmt_scan.c: add autoconf magic to support - old systems that don't support multibyte character sets - - * sbr/fmt_scan.c: fix bug with insertion of newline being wrong if - the num function was used at the end of the format buffer - -2006-01-17 David Levine - - * uip/post.c, uip/spost.c: in make_bcc_file (), use same - logic as in finish_headers () to detect whether there is an - existing From: line in the draft. If draft_from masquerade - flag is enabled, this allows the From: to be obeyed in the - Bcc, instead of the old behavior of always replacing it with - the signature. - -2006-01-17 Oliver Kiddle - - * sbr/fmt_scan.c: more robust multi-byte/column support for field - widths, restoring right justification feature - -2006-01-16 Oliver Kiddle - - * h/aliasbr.h, h/rcvmail.h, man/Makefile.in, man/slocal.man, - sbr/lock_file.c, uip/aliasbr.c, uip/dropsbr.c, uip/post.c, - uip/slocal.c, man/mh-mts.man: remove remnants of code for MMDF - - * uip/scansbr.c: multiply buffer size by MB_CUR_MAX so multi-byte - chars fit - -2006-01-14 Josh Bressers - - * sbr/fmt_scan.c: Turn the PUTSF macro into a function capable of - handling multi column characters. - -2006-01-07 Josh Bressers - - * Remove sbr/strerror.c -- strerror(3) is defined in C89. - -2006-01-06 Josh Bressers - - * patch #3968: Move the add() function from its own file (add.c) and - into utils.c. There was also a duplicate add() function in mf.c which - has been removed. - -2006-01-02 Josh Bressers - - * Remove sbr/pwd.c file, moving the pwd() function into sbr/utils.c. - -2006-01-01 Josh Bressers - - * patch #3967: Create a mh_xrealloc function to prevent mistakes when - calling realloc. - -2006-01-01 Josh Bressers - - * patch #3966: Create a mh_xmalloc function to prevent mistakes when - calling malloc. - -2005-12-24 Peter Maydell - - * Bug #15285: Don't use $< in target rules in makefiles, as POSIX - says it's only defined in inference rules. (BSD make was expanding - $< to the empty string in the rule for building sbr/dtimep.c, which - causes lex to apparently hang because it's reading from stdin.) - -2005-12-24 Peter Maydell - - * Completely redo db library checking -- we now check for working - (include file, library) pairs rather than checking for headers and - libraries separately. We also now provide --with-ndbm=lib and - --with-ndbmheader=header options to configure to handle situations - where configure's autodetection fails. - -2005-12-21 Peter Maydell - - * Fix stupid accidental dependence on a bash quirk in previous - configure script change. - -2005-12-15 Peter Maydell - - * Improve checking for Berkeley db libraries: configure should now - find a suitable library on systems with new gdbm where - compatibility functions are in the gdbm_compat library, and on - systems with libdb4. - -2005-12-13 Michael Forrest - - * Fedora Bug #163760: sbr/context_read.c (context_read): Ensure that - the context is only read once. - -2005-12-12 Josh Bressers - - * uip/sendsbr.c (annoaux): Fix the call to annotate() fixing a bug - which prevented repl from properly annotating messages. - -2005-12-07 Jon Steinhart - - * Fixed a bug where anno -append put the headers in the wrong place - if applied to a message that didn't contain any headers. - - * Added a special value of "all" to the -number option that causes - anno -delete to delete all matching components instead of just - the first one. - - * Added new -preserve and -nopreserve options. Using -preserve - retains the original last accessed and last modified times on - annotated messages. - -2005-12-05 Josh Bressers - - * Fedora Bug #174983: configure.in: Fix the AC_PATH_PROG default when - vi isn't found during build. - -2005-11-19 Peter Maydell - - * bug #14977: sbr/context_read.c: special case an MHCONTEXT of - "/dev/null" and don't try to lock it. - - * bug #9228, debian bug #146449: man/mh-profile.man: make it clearer - that lower case environment variables (and in particular mheditor) - are internal to nmh and not intended to be set by the user. - -2005-11-09 Peter Maydell - - * sbr/mf.c: fix buffer overrun with absurdly long addresses - (only causes crashes if scan is run with '-width 16536' or similar) - - * bug #7917: sbr/context_foil.c, sbr/context_read.c, - sbr/context_save.c: mark 'no context' with NULL rather than - "/dev/null" so we don't inadvertently try to lock /dev/null (which - takes up to a minute in some locking configurations and makes post - very slow). - - * patch #3913: uip/post.c: pass some globals into sm_init() so that - it uses SASL if necessary. (This bug was preventing Bcc'd emails - from being sent via SASL authenticated SMTP.) - - * bug #9813: uip/rmf.c: don't crash if there's no Current-Folder - entry in the context file. - -2005-11-13 Oliver Kiddle - - * bug #7833: uip/Makefile.in: remove link to install-mh that caused - problems on some systems - - * bug #739: Makefile.in: install target now depends on all to avoid - problem on case-insensitive file systems with the INSTALL file - -2005-11-10 Josh Bressers - - * Fedora Bug #172838: configure.in: Fix the AC_PATH_PROG default when - sendmail isn't found during build. - -2005-11-09 Peter Maydell - - * h/aliasbr.h: fix a non-ANSI prototype. - -2005-11-08 Oliver Kiddle - - * Simon Burge: acconfig.h, configure.in, uip/rcvtty.c, uip/slocal.c: - fix to handle getutent() on NetBSD - - * INSTALL, README, docs/README.about, man/nmh.man: update most - references to the web page and mailing list locations - - * bug #10230: etc/Makefile.in, man/Makefile.in, uip/Makefile.in: - Michael De La Rue: prepend DESTDIR to install locations - - * configure.in, */Makefile.in, mts/smtp/smtp.c: replace obsolete - autoconf macros - -2005-11-06 Peter Maydell - - * sbr/fmt_rfc2047.c, sbr/fmt_scan.c, h/prototypes.h: fix various - possible overruns of the buffers in fmt_scan() which would cause - crashes if scan was run with '-width 16536' or similar. - - * uip/popsbr.c: fix compile error which only showed up if nmh - was configured with --enable-apop. - - * Debian Bug# 245932, RedHat Bug# 172388: uip/mhparse.c: don't - crash when handling a multipart MIME message with an invalid - Content-Type header (file handle was being fclose()d twice). - - * sbr/Makefile.in: adjust lex command to work on both old and - new versions of flex. - - * configure.in: add an AC_PREREQ() so autoconf 2.13 gives a helpful - error message and the Debian autoconf-version-guessing wrapper - doesn't guess wrongly. - -2005-11-02 Oliver Kiddle - - * Debian Bug# 320069: Nick Rusnov: uip/popsbr.c: fail when - kpop connection attempted without KPOP support compiled in - - * Debian Bug# 320090: Nick Rusnov: sbr/Makefile.in: fix for newer - version of flex and remove autogenerated file from cvs - - * patch #1155: uip/flist.c: speed up flist by skipping stat on - files with numbers as names - - * docs/Makefile.in: include new files in distribution - -2005-10-11 Bill Wohler - - * docs/FAQ: fold questions into MH FAQ and distribute that instead - -2005-10-05 Oliver Kiddle - - * Harald Geyer: h/mh.h, uip/replsbr.c: back out previous change - (fork/vfork) and replace with code that handles the issue directly - -2005-05-18 Oliver Kiddle - - * Debian Bug# 143485: Nick Rusnov: h/mh.h: use fork instead of - vfork on Linux - - * Debian Bug# 261592: Harald Geyer: uip/mhlsbr.c, uip/replsbr.c: - test/report error writing to stdout - - * mts/smtp/smtp.c, uip/popsbr.c: correct SASL include file locations - - * docs/COMPLETION-BASH: bash completion definitions from Debian - - * patch #2863: savannah@brisammon.fastmail.fm: sbr/folder_read.c: - fix a bug affecting AFS where nmh was setting the READONLY flag - for a folder even when you do have write access to the folder - - * Carl Mummert: h/fmt_compile.h, man/mh-format.man, - sbr/fmt_compile.c, sbr/fmt_scan.c: add unquote() function for - removing quotes from RFC-2822 encoded headers - -2005-02-23 Oliver Kiddle - - * use iconv to convert RFC-2047 encoded headers to the - character set used by the current locale - - * sbr/folder_read.c fix Debian bug #202667: crash when a - message's filename overflows an int when converted - - * Updated config.guess and config.sub to the most recent - versions (from automake 1.9.5) - -2005-02-21 Oliver Kiddle - - * sbr/getpass.c fix bug where inc crashed on failing to reopen - the terminal - -2005-01-27 Oliver Kiddle - - * Added -proxy option to inc and msgchk. Based on old patch - from Michael Richardson. - - * On systems where it is available, use nl_langinfo to get the - character set if MM_CHARSET is unset - -2005-01-21 Oliver Kiddle - - * sbr/check_charset.c US-ASCII is a subset of UTF-8 so can be - handled directly when UTF-8 is being used - -2004-12-17 Oliver Kiddle - - * uip/mhmisc.c Fix -part option to mhshow/mhlist/mhstore to - find sub-parts of the specified part - -2004-11-19 Jon Steinhart - - * h/prototypes.h, sbr/folder_addmsg.c, uip/mhstoresbr.c, - uip/rcvstore.c, uip/refile.c: Added mail directory argument to - folder_addmsg in order to make it possible to provide a path to - the ext_hook call that is mailpath-based. A problem existed when - a folder was a symbolic link and the pwd call would return the - path relative to the filesystem, not to mailpath. A new argument - was needed because there was otherwise no reasonable way to get - that path. - -2004-11-16 Jon Steinhart - - * sbr/folder_pack.c: Fixed problem where the refile hook was being - called after a message was renamed so that it wasn't around for - the hook. The hook is now called before the message file is - renamed. - - * sbr/folder_addmsg.c: Fixed wrong directory for hook when - refiling with -src option. - -2004-10-15 Jon Steinhart - - * uip/sortm.c: Fixed calling of external hooks. - -2004-10-12 Jon Steinhart - - * uip/inc.c: Fixed another weird bug caused by the static - mailpath being overwritten. - - * uip/sendsbr.c: Fixed bug that caused anno to mangle headers. - - * sbr/lock_file.c: Fixed strange bug that prevented a lock from - ever being obtained if getting it failed the first time. The - problem was that the string of XXXXXX that is required by - mkstemp() was overwritten the first time through, and so all - subsequent times failed because mkstemp() failed. The fix - reinitializes the tmp file string. - - * uip/inc.c: Fixed bug in which the static maildir was overwritted - if a format string was read from the profile. - - * sbr/folder_delmsgs.c: Fixed bug that was producing an incorrect - path for the external hook. - -2003-10-06 Glenn Burkhardt - - * uip/slocal.c, configure.in: db configuration fix for Debian; yet - another location for ndbm. - -2003-09-30 Glenn Burkhardt - - * Fix 'pick' so handling of options "-list" and "-seq" are - independent. - * Fix 'inc' realloc error when bringing in more than 100 msgs - to empty folder. - * Patches submitted by Nick Rusnov from Debian archive applied: - - Debian Bug# - 136976 - Handle binary content messages - 143427 - mh-format.man typo - 144098 - 'spost; should have same behavior as 'post' - w.r.t. mts.conf masquerade line - 149745 - slocal ignores 'N' result of previous command - 152728 - increase SMTP timeouts to conform to RFC 1123 - The timeouts suggested by the RFC seem long - to me - but the RFC is still listed as active. - 181867 - typo for nmh.man - -2003-08-10 Jeffrey C Honig - - * Fix problem where parsing of address/date fields in fmt_compile - is optimized to the first instance. The first instance may be in - contitional code which will result in cached data to - be used. Instead, convert c_flags to a flags field from a boolean - and parse on the first use. - * Remove some unused flag bits. - -Fri Jul 01 22:02:00 2003 Glenn Burkhardt - - * Applied fixes for configuration problems with Solaris and - systems with gdbm instead of db1 (includes bug #2024) - * Fixes for bugs - #578 - repl leaks umask - #1393 - sortm core dumps - #1650 - msh leaks file descriptors - #1730 - Double free() in mhfree.c:free_encoding() - #3356 - In-Reply-To header in default replcomps should be - RFC2822 compliant - * Revised man page for mh-format (bug #2031) - * New replcomps, etc, with Fcc: +outbox in default versions - -Sat Mar 17 03:18:15 2001 Dan Harkless - - * Ken Hornstein's configure.in Cyrus SASL checks were doing - `x"$with_cyrus_sasl" != "no"' instead of `... != x"no"'. - -Tue Mar 06 21:04:27 2001 Dan Harkless - - * Found some historical information about MH in RFC 808. - Supplemented it with info from Jerry Peek's MH book and added it - to docs/README.about. - -Tue Feb 6 20:35:40 2001 Shantonu Sen - - * sbr/dtime.c Use the same Y2K correction code as dtimep.lex - - * sbr/dtimep.lex Restrict the parser to accept either - a numerical timezone offset, or a symbolic one (e.g. EST), - but not both (Since "2000 -400 EDT" might cause a double - subtraction of 60 minutes if both are parsed. One should be - enough). - -Mon Feb 05 20:22:54 2001 Dan Harkless - - * -L isn't sufficient for specifying the path of the Cyrus SASL - shared library. That'll allow us to link successfully, but on - many/most OSes that won't allow us to find libsasl at runtime. On - Solaris, we need to specify the library path with -R as well (or - else the user will have to use the $LD_LIBRARY_PATH kludge, which - is considered harmful). This fix should be extended to other OSes - as well. - - * Print whether we have SASL support in the "nmh configuration" - summary configure prints out. - - * Say in README.developers to use `\date' in case anyone is like - me and has `date' aliased in their shell to use a nonstandard (but - subjectively more readable) format. - -Thu Jan 25 21:15:52 2001 Shantonu Sen - - * man/mh-chart.man has updated synposes of - all nmh commands. - -Tue Jan 23 20:26:15 2001 Shantonu Sen - - * etc/digestcomps tried to force dates into a - 19xx when it's not necessary. - -Fri Jan 19 21:22:08 2001 Shantonu Sen - - * First round of manpage updates finished. They - are standardized on -man macros, with minimal - roff mark-up. - - * man/tmac.h.in is no longer needed, since the - manpages do not depend on them anymore. Note: - strict "man" programs that didn't allow ".so" - sourcing outside the man tree will now format - the man pages correctly. - - * man/vmh.1 is no longer built, since uip/vmh isn't - -Tue Jan 9 6:01:22 2001 Shantonu Sen - - * Finished manpages ali-prev - - * Removed deprecated files from the repository. - Specifically, those rooted in zotnet/ and mts/sendmail - mts/mmdf. "cvs update -dP" will give a pruned directory - structure. - - * Updated docs/Makefile.in to include README.manpages, and - uip/Makefile.in to include popi.c (which isn't being built, - though). This allows "make nmhdist" to create an archive that - is file-for-file identical to the current cvs repository. - -Sun Dec 31 20:48:50 2000 Shantonu Sen - - * Create docs/README.manpages, which details - the formatting rules I've been using. - - * Finished ali-inc. - -Sat Dec 30 9:50:13 2000 Shantonu Sen - - * Created a new file "DATE" to hold the date - of the most recent nmh release. This date will be - used in the manpages. - - * Updated docs/README.developers to add the step - of updating DATE. Also, updated configure to - read in the contents of the file as the variable - $DATE. - - * Started work on updating man pages, with only - ali finished so far. Changes: 1) no dependence - on an external macro file, 2) uses only - -man macros (although I may be mistaken in this), - 3) syntax in the SYNOPSIS is a little more - in line with standard UNIX documentation, such as - bold flags and italicized parameters. - -Sun Dec 24 10:06:30 2000 Shantonu Sen - - * Updated INSTALL with information about the - --with-locking option. - - * Fixed the Hesiod tests in configure.in. In - systems where res_send was in -lresolv, this - information was not being communicated to the - HESIOD_LIBS var. Now, if res_send is not found - in the default libraries, it's assumed to be - in -lresolv, and thus -lresolv is appended to - HESIOD_LIBS, which will need that to avoid - undefined symbols problems. - - * Fixed the Kerberos tests in configure.in. New - versions of Kerberos 5 have renamed -lcrypto - to -lk5crypto (circa krb5 1.1 or thereabouts). The - new test tries to determine if -lk5crypto exists. If so, - this is a new krb5 system. If not, test for -lcrypto - and the rest of old krb5. If that fails, look - for a genuine krb4 installation. - -Fri Dec 22 22:08:51 2000 Dan Harkless - - * -apop and -noapop were not documented in msgchk.man. - -snoop was documented but didn't appear in the usage SYNOPSIS. - -Fri Dec 22 23:42:16 2000 Shantonu Sen - - * Made a new ./configure option called - "--with-locking" that allows the file - locking mechanism to be chosen there instead of - requiring a manual edit of config.h. - - * If the option is not explicitly set, or an - invalid option is specified, "dot" locking is - chosen. Valid options are "dot", "fcntl", - "flock", and "lockf". We need a way to tell - the user that these are the valid options, and - change the flag "--with-locking" if it's not - descriptive enough. - -Fri Dec 22 19:21:29 2000 Shantonu Sen - - * Remove the lex-specific memory hints at the - beginning of sbr/dtimep.lex. We've already - committed to supporting flex only, since - lex does not easily allow us to parse a single - string, as well as other problems documented - below and on nmh-workers. - - * Added a switch statement to configure.in to - test for Mac OS X. If this is the case, LDFLAGS - should not contain "-s" since the linker rejects - the flag. - - * Updated MACHINES to include Mac OS X Public Beta, - as well as Linux 2.4 running glibc 2.2. - -Wed Dec 20 16:00:46 2000 Shantonu Sen - - * Marked deprecated directories in docs/README.developers - as deprecated, with pointers to the new code location. - Eventually these deprecated directories should go away. - -Tue Dec 19 19:16:37 2000 Dan Harkless - - * -apop and -noapop were not documented in inc.man. -snoop was - documented but didn't appear in the usage SYNOPSIS. - -Thu Dec 14 14:32:09 2000 Shantonu Sen - - * Updated config.guess and config.sub to the most recent - versions on ftp://ftp.gnu.org/pub/gnu/config, dated - 12-07-00. This should prevent configure from failing - on newer operating systems because config.{guess,sub} - couldn't correctly identify them. - -Thu Dec 14 1:30:44 2000 Shantonu Sen - - * Fixed the circular dependency created when I moved - zotnet/mts to mts/generic and merged them into libmts. - mts/generic/client.c and mts/generic/mts.c are now in sbr/ - (and thus in libmh), which makes libmh self-contained and - not depending on an external archive. - - * All include statements now look for mts.h in h/. The - Makefiles and configure script have been modified so that - mts/generic is no longer built. - -Mon Dec 11 22:08:07 2000 Dan Harkless - - * When Shantonu made the new libmts.a, he swapped $(MTSLIB) and - libmh.a in sbr/Makefile.in so that libmh.a comes first, but this - causes the build to fail on Solaris, because libmts.a has to get - ruserpass() out of libmh.a. Swapping them back to the way Ken - Hornstein's patch (which I applied on Jul 20) put them, with - libmh.a correctly coming second. If there are times when libmts.a - needs to come second, then it would appear there's a circular - dependency and someone (Shantonu?) did an mts merge incorrectly. - -Fri Sep 8 01:36:23 2000 Shantonu Sen - - * Took out bad time textual time zones like BST and JST. - I found them online somewhere, but am not sure if they're - correct. - -Fri Sep 8 00:36:48 2000 Shantonu Sen - - * Moved zotnet/mts to mts/generic. This code reorganization - makes the entire zotnet tree deprecated -- bboards is unneeded, - mf was was moved to sbr, tws was rewritten and moved to sbr, and - now finally mts. - - * Created a new static library called libmts.a used during - compilation which includes the generic mts code and the - smtp/sendmail code. This supercedes the functionality of the - old libsmtp.a and the remains of libzot.a. - - * Updated header includes to reference the new location of mts.h - in mts/generic/mts.h. Also, update the configure and top-level - Makefile not to descend into zotnet. Also, they don't descend - into mts/mmdf and mts/sendmail (the sendmail code has been - merged into the smtp code). - - * Added #include to h/md5.h, since my compile was - complaining about implicitly-declared memcpy and memset, which - appear to be in strings.h. In any event, nmh.h should take care - of it for us. - - * When doing a "make nmhdist", notice that the generated - snapshot does not include zotnet of the mts directories as noted - above. Since they are no longer compiled, and I don't see any - obvious code path to get to them, end-users should probably - not need them. If you think otherwise, turn Makefile generation - back on in configure.in and turn on recursion into those dirs - in the appropriate Makefile.in - -Wed Sep 6 22:40:03 2000 Shantonu Sen - - * Tracked down the problem in the new dtimep where time - zones were being radically misreported. It was because the - parser knew about military time zones (such as M or E) but in - some cases did not know about the textual representation of - some zones (like MET). When it encountered one of these, the - date parser misread MET as the military time zone T (well, first - zone M, then E, and finally T). I took military zones out, and - things seem much better. Also, the default behavior of parsing - time zones appears to default to GMT in the absence of better - info, which is less bogus than assuming the mail came from the - current time zone, which was the behavior in 1.04. - -Thu Aug 10 13:22:13 2000 Dan Harkless - - * Decided that limiting the message number columns to 3 on my - scan.MMDDYY and scan.YYYYMMDD (to try to regain space taken by - extra date info) was ill-conceived. It's not that tough to get - past 999 messages, though I imagine it's rather rare to exceed - 9999. Changed these to 4. Also put the "replied / encrypted" - column back in YYYYMMDD -- I've never seen it show anything but a - space, but that space is useful if you use scan, grep, and awk - (with the default field separator) to grab message numbers (I know - -- pick should really be used for these purposes...). - -Mon Aug 7 20:11:09 CEST 2000 Ruud de Rooij - - * Modify umask set by mhshow to enable user execute bit, so that - viewers that create temporary directories (e.g., lynx) will be - able to access them. - -Thu Aug 03 17:14:08 2000 Dan Harkless - - * TODO: Allow multiple simultaneous differing contexts, probably - each tied to a parent (terminal) process. - -Tue Aug 1 10:48:05 EDT 2000 Kimmo Suominen - - * Makefile install rules should not look for generated files in - the source tree -- this will happen to work when configuring and - building inside the source tree but will fail when using an - external build tree. Fixed etc/Makefile.in. - -Mon Jul 24 16:20:45 2000 Dan Harkless - - * When Shantonu wrote the new, more portable dtimep.lex, he left - out the #ifdef DSTXXX stuff for some reason. Not a good idea, as - that code is required for proper printing of numeric-offset - timezones that have daylight saving time. Without that code, - -0700 during DST gets printed as MST instead of PDT. - - * Renamed DSTXXX as ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST and - added an explanatory comment by its #definition. - - * Updated README.developers with the fact that zotnet/tws is going away. - -Thu Jul 20 20:30:52 2000 Dan Harkless - - * Moved Kimmo's new "--with-hash-backup" to be output with the - rest of the --with options in the configure --help output. Also, - people did not preserve my alphabetization of the --with options - when they added new ones. Re-alphabetized. - - * One more pass at README.developers now that it's clear that my - previously-suggested one-line autoconf-file commit can cause - unnecessary local makes and an out-of-sync stamp-h.in file, but - would not cause problems for other people using the CVS files. - - * Ken Hornstein's SASL patch was not integrated properly with - Ruud's new merged mts/sendmail code. Kimmo has since fixed nmh so - it compiles, but according to Ken, the SASL stuff still does not - work. Integrating a patch from him for this. - - * Last pass at README.developers -- Kimmo's 5-step commit was - overkill. You only need 3 steps, since configure.in is the only - autoconf file with the RCS $Id keyword. - - * Applied Kurt J. Lidl 's $MAILHOST patch: - - I have a small patch that would be nice to be included -- - basically, it allows the usage of the "MAILHOST" environment - variable, without having to have HESIOD turned on. I need - this functionality for my environment, where we have identical - /usr/local on all my machines (so I cannot just hardcode into - the mts.conf file), and I have multiple POP mail servers for - my users. - - Modified inc.man to reflect that along with "pophost:" and -host, - $MAILHOST can now activate POP mail inclusion as well. - - * Fixed warnings from diff on first-time install of nmh. Also - added 'echo's clarifying the etc file installation activities. - -Tue Jul 18 19:36:59 EDT 2000 Kimmo Suominen - - * Added the answer to Dan's question in README.developers. - -Mon Jul 17 19:10:36 2000 Dan Harkless - - * Clarified and made some corrections to Kimmo's README.developers - changes (BTW, if anyone can explain why the RCS Ids are able to cause - problems with the dependencies, please fill in the explanation -- - I never encountered a problem with the old single-commit method). - -Sat Jul 15 23:13:49 EDT 2000 Kimmo Suominen - - * Add configure option --with-hash-backup so the backup prefix can - be easily changed from "," to "#". - - * Simplified sbr/Makefile.in so that it works with any make. - - * Use mkstemp in sbr/lock_file.c. - - * Commits of autoconf-related files apparently can't all be done - in one shot due to RCS Ids changing when committing -- updated - README.developers. - -Tue Jul 11 14:18:01 2000 Dan Harkless - - * Clarified post.man and send.man for those not completely up on - SASL terminology. "SASL encryption layers are not supported for - SMTP" means that encryption is supported for the authentication - but not for the subsequent data stream. - -Sat Jul 8 01:36:19 EDT 2000 Kimmo Suominen - - * Applied Ken Hornstein 's patches - implementing SASL support for POP3 and SMTP. If nmh is compiled - with SASL support, using the -sasl switch on the inc, msgchk, - post, and send commands will enable authentication encryption for - SMTP, and both authentication and data stream encryption for POP3. - -Sat Jun 10 18:37:59 CEST 2000 Ruud de Rooij - - * Merged mts/sendmail functionality into mts/smtp; switching between - smtp and sendmail delivery method is now controlled by mts.conf. - - * If tsort cannot deal with loops, in addition to defining tsort as - cat, also define lorder as echo. - - * Removed uip/popi.c from list of sources. - -Thu Jun 08 19:36:57 2000 Dan Harkless - - * New dtimep.lex didn't parse day names properly. Fixed. Also - clarified ambiguous comments preceding day_map[] array (from old - dtimep.lex) that probably led to the erroneous cp++ being added. - -Wed Jun 7 20:52:33 CEST 2000 Ruud de Rooij - - * Added one more mkstemp invocation to uip/spost.c (which was in a - #if 0 block). - - * Applied patch from Peter Maydell to clean up permissions handling - and error handling in uip/inc.c. - -Mon Jun 5 22:10:07 CEST 2000 Ruud de Rooij - - * Use cat instead of tsort if tsort cannot deal with loops in its - input (which is the case for tsort from GNU textutils). - -Mon Jun 5 21:14:36 CEST 2000 Ruud de Rooij - - * If lockfile is present, and its dotlockfile program is setgid, - inc does not need to be setgid. - -Sun Jun 4 21:35:40 CEST 2000 Ruud de Rooij - - * Added autoconf test for Miquel van Smoorenburg's liblockfile - library, as found on Debian systems. - - * Added liblockfile support to sbr/lock_file.c. - -Wed May 31 7:19:30 2000 Shantonu Sen - - * Fixed up dtimep.lex a bit. Added back memory options for AIX to - increase available memory. Took out %option noyywrap, which - wasn't understood by AT&T lex, as well as the -i - case-insensitivity flag. - -Wed May 31 07:40:45 2000 Doug Morris - - * Added a lint target to the Makefiles and a check in autoconf - to determine whether lint or lclint exists on the system. - -Fri May 30 19:21:48 2000 Dan Harkless - - * etc/Makefile.in was incorrectly installing mts.conf.in and - sendfiles.in -- fixed. Generated sendfiles script was not a - dependency of the `all' target, and was incorrectly included in - the distribution. Changed the suffix for the backed-up previous - versions of the etc files from the ambiguous .old to .prev. Added - call to diff -- only keep the .prev files around if different from - the newly-installed versions (intentionally didn't redirect output - to /dev/null so you'll notice when your changed versions are - getting moved aside). - - * INSTALL never documented the etc/*.old thing. Documented the - new etc/*.prev thing (including a note to watch for diff output). - - * Applied Alec Wolman 's dropsbr.c patch: - - In the map_write routine, a call is made to map_open and this - call is supposed to set the "clear" variable to 0 or 1, - depending on whether the map file is empty or not. In - mh6.8.3, this worked because map_open would set "clear" by - calling the mbx_Xopen routine. In nmh, the code for mbx_Xopen - was merged into mbx_open, but the interface for mbx_open - doesn't support the clear variable, so that functionality was - lost. The map_open interface still contains "int *clear" in - the prototype, but never sets it. - - My patch eliminates "clear" from the map_open interface (I - checked to make sure that map_write is the only client of - map_open). Furthermore, my patch also sets the "clear" - variable properly at the beginning of map_write by calling - fstat(). This eliminates the bug in that the value of "clear" - being used later in the routine was just stack garbage. - - Having a bad value of clear causes this next bug to be - triggered: The fp file pointer was being opened with fdopen, - but in two of the three switch cases it wasn't being closed. - In certain cases, this was causing packf to run out of file - descriptors if you attempted to pack a large folder. - -Mon May 29 7:48:15 2000 Shantonu Sen - - * Moved the date parsing routines from zotnet/tws to sbr/ (and - tws.h to h/). Updated all source files to reflect to new location - of tws.h. - - * Rewrote dparsetime (in dtimep.lex -> dtimep.c) to replace the - old zotnet/tws/dtimep.c, dtimep.lex, lexstring.c, lexedit.c, and - dtimep.c-lexed. It should now work with flex (although untested - with lex), and requires no sed-ing. For now, I have the lexed - version in the distribution, so that end-users don't need to worry - about running it through flex/lex. I have not added back support - for guessing the time zone when it's not specified. - -Sun May 28 17:44:15 CEST 2000 Ruud de Rooij - - * Added autoconf check for getutent(). - - * Changed uip/rcvtty.c and uip/slocal.c to use getutent() and - friends. Since I can only check on Linux, please check if - this works on other systems. - -Sun May 28 14:58:49 CEST 2000 Ruud de Rooij - - * Applied patch from Peter Maydell to uip/scansbr.c for more - checks for write failures. - - * Unlink temporary file properly in uip/rcvtty.c. - - * Moved viamail from bindir to libdir. - - * Changed sendfiles into sendfiles.in, so that path to viamail - is patched in. - - * Added gzip support to sendfiles. - - * Added References header to replcomps and replgroupcomps. - -Sun May 28 14:39:31 CEST 2000 Ruud de Rooij - - * Fixed m_getfld bug which caused segmentation faults when - incorporating messages which ended in multiple linefeeds crossing - a buffer boundary. - -Fri May 26 13:21:59 2000 Dan Harkless - - * msh has been unable to show MIME messages ever since 1.0. Alec - Wolman tracked down the problem to the - -show flag being passed to mhshow. mhshow is equivalent to the - old mhn -show, so we don't need the -show anymore. Removed it. - -Fri May 12 02:51:21 2000 Shantonu Sen - - * zotnet/bboards is not longer built by default. Goal is to move - the assorted functions in zotnet into sbr or some more logical - place. - - * Moved zotnet/mf to sbr, and changed mf.h references accordingly, - as well as Makefiles. - -Thu May 11 02:21:34 2000 Shantonu Sen - - * Simplified sbr/Makefile.in so that both SRCS and OBJS aren't - seperately and redundantly defined, but so that OBJS is a - pattern-substituted version of SRCS with suffix .c -> .o. This - should make maintainability easier. - - * Added section to MACHINES indicating what platforms nmh is known - to compile and work on, just to give users peace of mind, or - something. This is by no means complete or exhaustive, so add - whatever you know works. - -Tue May 09 20:38:04 2000 Dan Harkless - - * Alphabetized Shantonu's $pop_kinds output on configure's "pop is - enabled" line. If POP3 is the only kind of POP enabled, say so, - rather than just saying "yes" (which is ambiguous). - - * Fixed four warnings in Shantonu's new getpass.c. Needed to - #include for calloc(), for ttyname(), and - "h/mh.h" for adios(). Also changed ch from char to int to get rid - of "comparison is always 1 due to limited range of data type" on EOF. - - * Added steps to README.developers saying to change the version - number to X.Y.Z+dev. Did a little rearranging and changed the FTP - dir from /home/ftp to /var/ftp to reflect Doug's new machine. - - * Changed configure.in to use gcc -Wall even without - --enable-debug, to prevent developers compiling optimized from - introducing warnings, and to give end-users a warm, fuzzy feeling - as they (hopefully) see no warnings come out (except perhaps on - the lex output file) even with -Wall. - - * Renamed getpass() to nmh_getpass() since the prototype for - getpass() varies from OS to OS, and we want to _always_ use our - version of the function. Fixed all the callers to use - nmh_getpass() and added it to prototypes.h. Semi-arbitrarily - upped MAX_PASSWORD_LEN from 128 to 256. buf was being calloc()'d - and the memory leaked -- should have just been declared as static - char array. Prepended "Portions of this code are" to the - copyright message, as this version has been changed significantly - from the BSD version. - - * Added "nmh-local functions to use in preference to OS versions" - section to README.developers (currently just says to use - nmh_getpass() instead of system getpass()). - - * Prepended "Portions of this code are" to the copyright message - in ruserpass.c also. - - * Added mts.conf.5 page per Neil W Rickert 's - report: - - This happens on solaris: - - % man mts.conf - windex entry incorrect: mts.conf(5) not found. - No manual entry for mts.conf. - - It is fixed by - - % echo ".so man5/mh-tailor.5" > mts.conf.5 - - done in the man5 directory. We need to add 'mts.conf.5' as a - reference sourcing mh-tailor.5. - -Mon May 08 23:51:55 2000 Dan Harkless - - * Doug informed me that the way I had restored the "lost" version - histories was wrong, because `cvs checkout's of old versions of - nmh wouldn't work properly. It occurs to me that this could be - fixed by simply deleting those tags in the new-location *,v files, - but oh well. I'm putting everything back to the way Doug - originally had it. To get the old version history for a file that - used to be in the top directory, you'll need to "blindly" do a - `cvs log' there (even though you won't have a local copy of the - file in that directory). `cvs diff' will no longer be able to - diff pre-move versions vs. post-move versions -- you'll have to do - a lot of manual gyrations with `cvs checkout' and then use `diff'. - - * I had alphabetized the --configure options in the --help output - awhile back, but Shantonu added --enable-apop just under - --enable-pop. Put it in alphabetical order and clarified what - --enable-apop does vs. --enable-pop and --with-krb4. Also changed - --with-mts help line from "mail transport agent" to "mail - transport agent/service" so the 's' in "mts" doesn't seem to come - out of nowhere. - - * Added two steps to "releasing nmh" in README.developers. After - making the tarball, it's a good idea to diff the tree vs. the CVS - tree to make sure no files got left out, and then to chown the - files so that they're owned by root, preventing a Trojaning attack - by a malicious remote user with a UID matching yours. - - * Changed DIFFERENCES to say that RPOP is not currently supported - rather than implying it by saying that APOP, KPOP, and POP[3] are. - -Sun May 07 18:16:43 2000 Shantonu Sen - - * Imported NetBSD version of getpass() and made extensive - revisions for compatibility with programs that pipe the password - to stdin, such as exmh. - - * Removed tests for system ruserpass() which sometimes gave - phantom positive results. Also, bext to use internal functions if - we ever want to change .netrc format to something else, or access - other files. - -Sat May 06 08:28:09 2000 Dan Harkless - - * Restored lost version histories for those moved files by doing a - manual `mv' in the CVSROOT on mhost. CVS badly needs a `cvs mv' - command so that you can move files (without having physical access - to the CVSROOT) without losing versioning. Put MACHINES back at - the top level as it needs to be read before building. Fixed DIST - variable in {.,docs}/Makefile.in to reflect that and to add - missing entry for "INSTALL" file. - -Sat May 06 13:13:07 2000 Doug Morris - - * Re-cleaned up nmh documentation (by moving things to docs - subdir) and modified Makefile & configure.in to handle the change. - -Mon Apr 17 21:28:40 2000 Dan Harkless - - * Scott Blachowicz pointed out that the configure --help output - for --enable-masquerade was misleading. Clarified. - -Mon Apr 17 19:01:00 2000 Shantonu Sen - - * APOP support can be compiled in to inc and msgchk using - --enable-apop. - - * To access an APOP host, specify -apop on the command line - along with any -host or -user option. - -Fri Apr 14 23:10:44 2000 Dan Harkless - - * Upped the version number to 1.0.4+dev until the next nmh release. - - * Added a "releasing nmh" section to README.developers, while the - process was fresh in my mind. - -Fri Apr 14 18:21:34 2000 Dan Harkless - - * Added new files README.developers, ChangeLog_MH-3_to_MH-6.6, and - ChangeLog_MH-6.7.0_to_MH-6.8.4.html to DIST target in Makefile.in. - - * Released nmh-1.0.4. - -Tue Apr 11 21:37:03 2000 Dan Harkless - - * Applied Brian Campbell 's mhn.defaults.sh - patch: - - It appears that there shouldn't be quotes around the %s in the - iso-8859-1 charset entry; xterm passes the remaining arguments - to the program, quoting them means that xterm thinks they're - part of the program's name. - - This %s isn't the same as the "Insert content subtype" one from - mhshow-show-* -- it doesn't come from MIME headers and is safe not - to quote. - -Sun Apr 09 13:03:59 2000 Doug Morris - - * added check in fmt_compile() to handle a single-character - format string. fmt_compile() depends on having an array of - format characters with an empty item at the end. A - single-character format would cause programs using this - function to segfault because the algorithm used to decide on - the length of the array mistakenly created a single-item array - when the format string was one character. This eventually - caused problems when the program attempted to test item+1 - in the array. - -Thu Apr 06 21:53:50 2000 Dan Harkless - - * Richard Coleman threw out a lot of old MH-specific files in nmh. - Much of the stuff, indeed, is not worth saving, but there are - nuggets that are very worthwhile, and should probably be added - back in. Most important, IMHO, are the MH change logs, as they - can help answer questions like "Why is this code like this?" or - "How long has this been broken?" or "What was this ever used for?" - - I've added a new file to the nmh tree called - ChangeLog_MH-3_to_MH-6.6. It's cobbled together from the - mh-6.8.4/papers/mh*/MHCHANGES files. I've re-ordered the entries - to go from newest at the top to oldest at the bottom to match the - ChangeLog convention. Unfortunately there are no change logs for - versions of MH prior to 3 in the MH tar files available at - . Also, it appears to me that there - are MH-6.6 changes that aren't documented in the logs. - - I've also added ChangeLog_MH-6.7.0_to_MH-6.8.4.html. This is - based on mh-6.8.4/papers/changes/mh-changes.ms. The nroff format - and its "catman"-type output are a pain to deal with, but I was - loath to throw away the formatting, so I converted the file to - HTML. The only actual markup in the body are the "" and "" - tags, and "<" and ">" instead of '<' and '>', so it's quite - doable to view the file in plain ASCII mode as well. Note that - some of the changes this file documents as having been made in - MH-6.8.4 may not be present in nmh -- Richard started with 6.8.3 - and later put in certain 6.8.4 stuff. - -Wed Apr 05 21:09:28 2000 Dan Harkless - - * Applied Eric Schnoebelen 's mhshowsbr.c patch - fixing apparent bugs in Dan Winship's new security quoting code: - - Since upgrading, I've been getting the following errors - while attempting to process some MIME messages: - - (1) Syntax error: Unterminated quoted string - exit 2 - - and: - - (2) line 1/10 (END)Segmentation fault (core dumped) - - (2) appears to be due to the testing of an unset pointer in - mhshowsbr.c:show_multi_aux(). (1) appears to be caused by - mis-quoting a filename being handed to the shell in - mhshowsbr.c:show_content_aux(). - - Resolving the pointer reference issue in - mhshowsbr.c:show_multi_aux() turned up a similar mis-quoting - problem in the routine. - -Tue Mar 28 16:17:39 2000 Doug Morris - - * Applied Todd.Miller@courtesan.com's patch to dropsbr.c to - prevent core dumping on packf. Here's the note from his message: - - Since sizeof(buffer) == sizeof(tmpbuffer) packf will dump - core on a file w/o a From line with a line >= BUFSIZ. - I noticed this because I had a junk file in my mail - spool somehow. - -Fri Mar 17 11:59:33 2000 Dan Harkless - - * wesley.craig@umich.edu did not document his previous KPOP patch, - so I did so, and asked him to check what I wrote. Unfortunately - he didn't notice my misunderstanding of his patch. I wrote that - if you #define POPSERVICE "kpop", inc and msgchk will use KPOP - exclusively, but if you leave it as "pop3", you can use Wesley's - new -kpop switch on a given invocation. Instead, however, -kpop - turned out to be necessary on every invocation, and a KPOP user - complained. Applied Wesley's new patch, which makes things work - like I thought his original patch did. After that, did one more - clarifying pass to the documentation in inc.man and msgchk.man. - -Wed Mar 15 18:45:45 2000 Dan Harkless - - * When I fixed the long-standing makedir() bugs in January, I had - the code call strtoul(..., 0), which I believed to be safe as all - modes specified as ASCII constants in the nmh code started with a - leading zero (signifying octal), which I did as it would work if - internal constants were ever changed to hex. Unfortunately I was - unaware of the "Folder-Protect:" .mh_profile entry, which - mh-profile.man documents as an octal-only constant, with no - leading zero required. I've changed the strtoul() call to an - atooi() call and removed the misleading leading zeroes on the - ASCII octal constants in the code and man pages. Also changed the - "Folder-Protect:" example in the man page to something more - interesting than a duplication of the default. - - * When I added my --enable-masquerade option, you'll note that I - didn't make it --enable-nmh-masquerade. I find the --enable-nmh-* - options too wordy and I'm not sure why Richard went that route. - I've renamed them to just --enable-*, but the old versions will - still work as well (they just aren't advertised). - - * Added a line to the "nmh configuration" output saying whether - POP is enabled. - - * Added a new README.developers file. From the file: - - This file is intended to provide a few tips for anyone doing - development on nmh. Developers who learn things "the hard - way" about the nmh codebase (as opposed to local info best - encoded in a comment) are encouraged to share their wisdom - here. - - Currently the topics are "autoconf files" and "directory structure". - -Tue Mar 14 12:41:48 2000 Dan Harkless - - * Applied, after some finessing, - Simon Burge 's --with-smtpservers patch: - - Here's a patch that allows you to add - - --with-smtpservers= - - to the ./configure command line to set the "servers: " line in - etc/mts.conf. Around here, we use "mailhost" so that all - machines in the current domain just talk to a central machine - and nothing else runs an MTA. Now, I can use - - --with-smtpservers=mailhost - - instead of having to remember to fix this by hand (and often - forgetting to do so!). - - * Inspired by Simon's patch, added an --enable-masquerade option - to configure. It will set the "masquerade:" line of mts.conf. - You may specify a subset of the three types of masquerading, like - --enable-masquerade="draft_from mmailid", or leave off explicit - arguments to enable all three types. - - * Alphabetized the --enable and --with options in configure.in and - INSTALL and added documentation of the two new options to the latter. - - * Added new dependency for mts.conf: Makefile. If this isn't - done, then when you reconfigure nmh with new values for - --enable-masquerade or --with-smtpservers, you'll fail to get an - updated copy of mts.conf. - - * Applied Simon Burge 's dtimep.lex patch: - - It seems that some MUA's didn't handle y2k very well - ELM - seems to be one of them, and Ultrix's DXmail (based on MH!). - I've got a few emails this month that look like: - - 575 Jan 00 Xxxxxx Xxxx 3603 ... - and - 22+ Jan 00 Xxx Xxxxx 1771 ... - - The first has "15 Jan 100" as the date and the second has - "19 Jan 00" as the date. The following works around this so - that scan, show, sortm, etc work ok. - - I put Simon's patch under the control of a new #define called - FIX_NON_Y2K_COMPLIANT_MUA_DATES. There's some commentary in - acconfig.h about when you might not want to #define it. - - * Created new dtimep.c-lexed with Simon's change using dtimep.lex - lexed on Solaris 2.6. Added missing dependency in - zotnet/tws/Makefile.in for dtimep.c: dtimep.c-lexed. - - * Added scan.MMDDYY and scan.YYYYMMDD format files. - -Mon Mar 13 21:32:00 2000 Dan Harkless - - * Applied Sullivan N. Beck 's mhshow-suffix patch: - - With the patch below, you can add lines like: - - mhshow-suffix-application/msword: .doc - mhshow-suffix-application/PostScript: .ps - - to the mhn.defaults file to append the given suffix to a - scratch file. This allows applications which require a - certain suffix to run properly. - - * Removed -force_html from lynx entry in mhn.defaults.sh (I - believe older versions of lynx lack that option) and added - "mhshow-suffix-text/html: .html". - - * Modified username_extension masquerading to only use the - extended address on generated [Resent-]From: lines and SMTP - envelope From:. With Neil's original implementation, nmh's global - idea of the username was changed, which would result in inc lying - and saying you had no new mail because it was looking for a - mailbox called, for instance, "dan-nmh" (where username was "dan" - and $USERNAME_EXTENSION was "-nmh"). - - * Applied Simon Burge 's dtime.c patch: - - There's a wrap-around problem that affects the implementation - of Zeller's congruence in dtime.c. This causes the day-of-week - calculations to fail for dates after Feb 29, 2000 (probably up - until some year far in the future). - -Mon Mar 06 12:20:20 2000 Dan Harkless - - * Applied Neil W Rickert 's msh.c patch: - - I finally tracked down the problem in msh that was causing - errors whenever I tried to examine a 'mmdf' style mailbox. - - It turns out that not enough memory was being allocated with - calloc(), causing memory pointers to be overwritten and - corrupted. - -Fri Mar 03 16:07:33 2000 Dan Harkless - - * Changed the new "plussed_user" option to mts.conf's - "masquerade:" to "username_extension" after getting feedback from - qmail users, who use '-' as a separator rather than '+'. Removed - checking of $USERPLUS variable. Now check $USERNAME_EXTENSION, - which needs to include the appropriate separator for your MTA - ('-', '+', or whatever) as its first character. - -Thu Mar 02 23:04:30 2000 Dan Harkless - - * Added a new "boolean" type to mh.h and TRUE and FALSE constants. - - * Added a note to DIFFERENCES stating that it's out-of-date - (Richard was the last one to update it) and that we should - consider only documenting incompatibilities with MH there. - - * Implemented (and documented) a third kind of username - masquerading: "plussed user" masquerading. This one was suggested - by Neil Rickert . It's based on sendmail's - "plussed user" feature, where mail sent to + will be - delivered to . When it's enabled, it's controlled by the - $USERPLUS environment variable. How is it enabled? Well, that - leads me to: - - * Renamed the "mmailid:" setting in mts.conf to "masquerade:", and - changed it so that rather than being a boolean, it can be set to - any combination of the three values "draft_from", "mmailid", and - "plussed_user". Thus it is now possible to enable the three types - of masquerading individually. - - * Fixed a bug with "mmailid" masquerading (dating back to MH?) - where if it was turned on, ','s would no longer be considered - GECOS field delimiters. - -Wed Mar 01 23:30:50 2000 Dan Harkless - - * Changed the GECOS-field '&' translation behavior to be - controlled by the BSD42 #define rather than GCOS_HACK, since it's - apparently always appropriate on OSes where BSD42 is #defined, and - never appropriate on any other OSes. Thanks to Kimmo Suominen for - responding to my "What is this code here for?" comment in mts.c - and explaining the feature. - -Mon Feb 28 21:50:29 2000 Dan Harkless - - * Upped the version number to 1.0.3+dev (ideally this should be - done by whoever makes a release tar file, immediately after doing - so). - - * Applied Paul Fox 's scansbr.c - patch, posted to comp.mail.mh, which he says prevents loss of mail - when inc'ing into a full filesystem. - - * Changed "echo > stamp-h.in" in Makefile.in to "date > stamp-h.in" - so that stamp-h.in will be different each time configure.in and - related files are changed, making it easier to check it in (which - is necessary to prevent unnecessary autoconf calls). - - * My declaration of initgroups() in slocal.c to eliminate the "no - prototype" warning wasn't portable (FreeBSD 3.[23] choked). Now - use AC_EGREP_HEADER to see where initgroups() is declared, if - anywhere. - -Sun Feb 20 12:17:15 2000 Ruud de Rooij - - * Fix security hole in mhshowsbr.c which allowed untrusted shell - code to be executed. - - * Released nmh 1.0.3. - -Thu Feb 10 10:54:36 2000 Dan Harkless - - * Oops. %-escapes on mhstore lines in mhn.defaults.sh should not - be surrounded by single quotes, as a shell is not spawned when - just saving files, and the filenames will end up with literal - quotes embedded in them. - -Fri Feb 04 12:29:12 2000 Dan Harkless - - * Whoever originally added the -help switch to all the commands - got too cute and had the option itself print out as "-(help)" in - the -help output. One theory is that they were making reference - to the fact that clearly you know about the -help option since - you're currently looking at its output. I think it's a bad idea - to overload the meaning of the parentheses, however -- they're - supposed to indicate what abbreviated prefix of the switch you're - allowed to specify. - - The other theory is that because you can say something like - "mhstore -" and get "mhstore: - ambiguous. It matches" followed - by the same list of switches you get with -help, they were saying - you can "sorta" abbreviate "-help" as "-". You don't get the - "Usage:" string, though, so it's not really the same thing. - -Thu Feb 03 17:52:01 2000 Dan Harkless - - * Applied wesley.craig@umich.edu's KPOP patches. According to him: - - The following patch fixes a problem with requesting a - service key for a machine that has multiple 'A' records. It - also makes "-kpop" a command line option, for users who - would like to use both "kpop" and "pop". - - Did no testing of the new features, as I don't have access to a - KPOP server. - - * Modified inc.man and msgchk.man to document Wesley's new -kpop. - - * Modified INSTALL and config.h.in to reflect the new -kpop feature. - -Fri Jan 28 17:39:24 2000 Dan Harkless - - * All %-escapes in mhn.defaults that actually expand to something - should be surrounded by single quotes. Added quotes to the ones - in mhn.defaults.sh that were missing them. - - * Added check for lynx to write mhshow-show-text/html line in - mhn.defaults.sh. - -Thu Jan 27 12:22:25 2000 Dan Harkless - - * makedir() had multiple bugs dating back to MH. An octal - constant was apparently being interpreted as decimal, resulting in - directories with no user read or execute permissions, making - nested directory creation fail. And there wasn't even an - _attempt_ to set desired permissions (e.g. from "Folder-Protect:" - in .mh_profile) on the outer directories of a nested directory. - - * A second `make install' would always fail because the check for - whether mh_profile.5 existed was written incorrectly. - -Wed Jan 26 02:22:00 2000 Dan Harkless - - * Added documentation on both types of masquerading to post's man - page. - -Tue Jan 25 22:58:12 2000 Dan Harkless - - * Doug's portability fix of my setgid inc autodetection had a - caching bug -- if you re-ran configure, uip/Makefile would be - corrupted, and installation would bomb out on OSes where inc needs - to be setgid. - - * Implemented a new kind of email address masquerading. Usually, - when a user writes a custom "From:" header in a draft, nmh uses it - rather than generating one. However, the user's true address is - used in the SMTP envelope "From:" and is revealed in the "Sender:" - header. Now, when mmailid is set to non-zero, the envelope - "From:" uses the address specified in the draft "From:" header, - and there is no "Sender:" header. This is useful when sending on - behalf of a remote POP3 account or when remote mail robots - incorrectly use the envelope "From:" in preference to the body - "From:". This processing has only been implemented for post, not - for the undocumented spost (which was already missing some "From:" - processing that post has). - -Mon Jan 24 22:26:06 2000 Dan Harkless - - * Got rid of the rest of the gcc -Wall warnings that I didn't have - time for on 1999-07-15 (and, it would seem, some new ones people - introduced since then). The primary ones were the warnings that - default prototypes were being used for [v]snprintf() and - str[n]casecmp(). As of right now, there are _no_ compilation - warnings except on dtimep.c-lexed (at least under AIX 4.1.5 and - Solaris 2.6). - -Sun Jan 2 23:42:18 2000 Ruud de Rooij - - * Move mhtest from bindir to libdir. - - * Move sendfiles from libdir to bindir. - - * Updated sendfiles manpage to reflect this change. - - * Added documentation for -build and -file switches to repl and - forw manpages (patch from Peter Maydell). - - * Fixed interaction between specifying -cc in profile and -group on - command-line. - -Tue Nov 1 13:48:10 1999 Dan Harkless - - * Changed the version number from 1.0.3 to 1.0.2+dev. There was - not unanimous support for my proposed even/odd release/developer - version number dichotomy. 1.0.2+dev implies release 1.0.2 plus - some development. - -Fri Oct 29 13:42:51 1999 Dan Harkless - - * Upped the version number to 1.0.3. If we don't do this, then - when people report bugs against 1.0.2, we won't know "which" 1.0.2 - they're talking about (since the development source is publically - available via CVS). I think the Linux kernel version numbers are - a good model, so the next time we roll a tarball, it should be - version 1.0.4 (or higher -- anyhow, an even-numbered version). - -Fri Oct 29 06:41:08 1999 Doug Morris - - * Released nmh-1.0.2. - -Tue Oct 26 22:57:00 1999 Doug Morris - - * Added check for whether "libtool" is in fact gnu libtool. If - it is, it is not used. This is the wrong behavior. If vendor - XYZ later on decides to create yet another libtool, we'll be - caught again. This works for now. - - * Minor updates to MACHINES refering to Mac OS X. - -Thu Oct 21 20:45:37 1999 Doug Morris - - * Added check for "libtool" (a ranlib type tool for Mac OS X) - and modified Makefiles so that nmh will build under Mac OS X. - -Sun Oct 17 08:28:56 1999 Ruud de Rooij - - * Changed repl defaults to partly revert to MH behaviour, - "-cc all" is now only implied with -group. - - * The replcomps template includes cc: header again (as in MH). - - * Updated repl man page to reflect these changes. - -Sat Oct 16 02:57:47 1999 Doug Morris - - * Tweaked configure to handle Solaris and SunOS after the BIND - changes. Both need more cleanup. - -Sat Oct 16 00:17:36 1999 Doug Morris - - * Removed BIND define and replaced it with a check for - gethostbyname (to determine if the host is DNS aware) and a - check for sethostent. This appears to be the right thing to - do, but there is no explanation of the reasoning behind the - BIND define in the code and it appears to have been used for - multiple purposes. - -Wed Oct 13 15:53:53 1999 Doug Morris - - * Updated manpages Makefile to link mh-profile.5 to - mh_profile.5 after installation. Suggestion from Richard Cohen - . - - * Modified configure.in to check for _IO_write_ptr and libio.h - to determine whether to define LINUX_STDIO instead of using - config.guess. - -Mon Oct 4 15:22:46 1999 Dan Harkless - - * Added '-L' to the calls of 'ls' in configure.in -- I have seen - multiple machines in the past where the mail spool was a symlink - to a directory on another device with more free space. - -Fri Oct 1 22:36:56 1999 Dan Harkless - - * Fixed a portability problem in Doug's fix of a portability - problem in my MAILGROUP autoconf support ('ls -l' vs. 'ls -lg'). - -Sat Sep 25 18:40:43 1999 Ruud de Rooij - - * Added config.sub and config.guess to the list of files to be - distributed. - - * Fixed bug in sbr/fmt_scan.c where an extra newline would be - added if a list of addresses was split over several header lines. - - * In mts/smtp/smtp.c, undefine strlen and strcpy if they are - macros, regardless of platform. - - * Allow q to quit mhshow, and n to skip to next part. Patch from - Kimmo Suominen . - - * Modified mhstore to recognize attachments created by sendfiles - with x-conversions=gzip. - -Mon Sep 13 21:20:10 1999 Doug Morris - - * added explicit cast to long from time_t for tclock in - post.c. - - * Commented out #ifdefs for in termsbr.c since - it's needed for ioctl() anyway. This prevents a warning about - implicit definition of ioctl(). - - * Moved guesses performed by AC_CANONICAL_SYSTEM back into the - "User Configuration" section of config.h (moved @TOP@ in - acconfig.h) so they're easier to find, should someone actually - want to mess with them. - -Sun Sep 12 15:50:34 1999 Doug Morris - - * updated Makefile.in so it recognized COMPLETION-TCSH and - COMPLETION-ZSH (only used in make nmhdist). - - * added prototype for ruserpas to . Fixes - warnings in mhparse.c and mhbuildsbr.c. - - * added include checks for and to - prevent warnings in fmt_compile.c, fmt_scan.c, lock_file.c, - sendsbr.c, mhbuildsbr.c, mhcachesbr.c, picksbr.c, and post.c. - - * added include for to ali.c, scan.c, ap.c, - rcvdist.c, rcvstore.c, rcvtty.c, and spost.c to remove - warnings about implicit definition of mts_init(). - - * added to slocal.c to prevent warnings about - function initgroups. - - * added to prevent warning about missing SIGNAL - function. - - * added function prototypes to smtp.c, whatnowproc.c, - mhbuildsbr.c, mhparse.c, mshcmds.c, show.c, whatnow.c, mhl.c - to fix warnings. - - * explicitly declared mbx_style in mshcmds.c and lused in - fmtdump.c as type static int instead of just static to - prevent warnings. - - * various code cleanups to prevent ambiguous statements - (brackets for if/thens and parens for complicated if - statements). - - -Sun Sep 12 09:19:27 1999 Doug Morris - - * commented out _cleanup() in mf.c because it's the only - location in all of the source code where it exists. It was - preventing compilation on at least linux. - - * Added check for which is the new location where - linux systems appear to be stuffing this header file. - -Thu Sep 09 23:15:49 1999 Doug Morris - - * fixed varous mkstmep bugs introduced in 1.0.1 by me. Whups! - - * added mh_profile SEGV patch from Richard Cohen - that prevents crashing when - mh_profile doesn't end in a newline. A similar patch was - previously sent in by Andrew Bettison . - - * fixed bug in associated with MAILGROUP #define (group "mail" - is not universal) -- hard to believe, but true. - -Tue Sep 7 16:47:03 1999 Dan Harkless - - * Renamed ZSH.COMPLETION to COMPLETION-ZSH and added COMPLETION-TCSH. - -Tue Aug 17 16:06:29 1999 Dan Harkless - - * Automated #define of MAILGROUP and installation of inc as setgid mail - when the mail spool directory isn't world-writable. - -Thu Jul 15 18:37:07 1999 Dan Harkless - - * slocal -debug used to leave a file in /tmp for each message - processed. Very bad for folks with slocal -debug in their .forward! - - * Got rid of a ton of compilation warnings. Most were "junk" - warnings due to the use of gcc -Wall (without -Wno-parentheses), - but a few represented real bugs. There remain many warnings to be - tackled that are due to missing function prototypes (e.g. snprintf()). - - * Default rcvdistcomps no longer puts a copy of all outgoing - messages in outbox. Added an rcvdistcomps.outbox that does. - -Sat Jun 09 12:22:47 1999 Doug Morris - - * Updated configure to check for mkstemp (available on OpenBSD) and - substitute it for mktemp if available. - -Thu May 13 16:40:19 1999 Doug Morris - - * Added config.sub and config.guess and updated acconfig.h and - configure.in to automatically detect system type and set the - proper #defines. - -Wed May 12 23:41:33 1999 Dan Winship - - * Released nmh-1.0.1. - -Fri May 7 17:18:28 1999 Dan Winship - - * Fixed flist to properly deal with relative folder names. - Problem noted by Jerry Peek . - - * Fixed --with-krb4 to work with original Kerberos 4 libraries as - well as the Kerberos 5 compat libraries. Based on a patch from - Assar Westerlund . - - * Added a check in configure.in to test if modf is in libc and - link with libm if not. This is needed by at least Digital UNIX. - Problem pointed out by Kevin Oberman . - - * Fix a bug from the "mhn -show" to "mhshow" renaming that - made the "list" command in whatnow not work for some users. - From Ruud de Rooij . - - * Replaced "extern int errno" with "#include " in a - number of files. Suggested by Stephen Wilson Bailey - . - - * Fixed a problem in how "packf -mbox" translated "Return-Path:" - lines. From Kimmo Suominen . - - * Fixed a segmentation fault in inc. Patch originally from Ruud de - Rooij . - - * Allow display of 8bit encoded messages. From Kimmo Suominen - . - - * Fixed repl to not add line breaks in the middle of long - addresses when building a reply. From Ruud de Rooij - . - - * Added -library switch to spost so it can parse user aliases like - post does. From Ruud de Rooij . - - * Changed configure.in's check for sigsetjmp to properly deal - with systems like Linux where it is a macro. From - . - - * Fixed a bug in whatnow that could cause it to sometimes exit - without prompting the user. Based on a patch by Richard Geiger - . - - * Added code to deal with SIGPIPE in mhl so it doesn't print - "Broken pipe" if you quit out of the moreproc. - - * Documentation: Added a note to MACHINES about Irix make. Added a - pointer to the online copy of the MH book in INSTALL. Added - some additional information to the whatnow and packf man pages, - suggested by Jerry Peek . - - * Updated INSTALL, FAQ, etc to not refer to Richard as the - maintainer or math.gatech.edu as the home any more. - -1999-02-06 Richard Coleman - - * Released nmh-1.0. - - * Merged mbx_open and mbx_Xopen in dropsbr.c. Fixed - mbx_open so that the mode of zero length maildrops - would not be changed. - - * Replaced the substitute version of snprintf() with the - one from the Apache web server. - - * Changed to default mode for creating new messages to 0600 - (this should have been done a long time ago). - - * Changed "flist" to handle searching for multiple sequences - for each folder. Also flist will now correctly split - Unseen-Sequence if it consists of multiple sequences. - - * Added new switches `-unlink' and `-nounlink' to "refile". - - * Added new switches `-unlink' and `-nounlink' to "rmm". - - * More cleanups of slocal output. Changed adorn() to - send to stdout, instead of stderr (to match rest of - verbose printing). - - * Merged mbx_create() into mbx_open, so that creating and - opening a nonexistent maildrop is done atomically. This - removes a bad race condition. - - * Fixed bug that caused slocal to be unable to save to MMDF - style drop file. - - * Added new wrapper function usr_folder() to slocal.c to - handle adding message to folder (currently, it still uses - usr_pipe() to call rcvstore). - - * seq_list() checks for empty folder before scanning for - sequence information. - - * num_digits() in flist.c and folder.c now returns correct - value for 0. Also added sanity check. - - * folder_delmsgs() now correctly decrements internal message - count. - - * Don't attempt to read sequence information if folder - is empty. - - * Split seq_read into seq_public and seq_private. - - * Small change to sigmsg.awk, since newer versions of gawk - interpret 034 as octal. - - * In flist, don't scan for sequence information in empty folder. - - * Updated mhn.defaults.sh to output profile entries for mhshow, - mhstore, and mhbuild. - - * Changed configuration parameter "mhn-access-ftp" to - "nmh-access-ftp". Updated man pages - - * Moved the code in InitMultipart to reverse the order of the - parts in a multipart, into its own function "reverse_parts()". - - * Changed code in mhbuildsbr.c to store unencoded content - in the c_cefile structure when building. - - * Changed code in mhoutsbr.c to look for unencoded content - in the c_cefile structure when outputing message. - - * Changed configuration parameter "mhn-cache" and - "mhn-private-cache", to "nmh-cache" and "nmh-private-cache", - since it is used in mhstore, mhlist, and mhshow. Updated man pages - - * Change configuration parameter "mhn-storage" to - "nmh-storage", since it is now used in mhstore, mhlist, - and mhshow. Updated man pages - - * Add autoconf support for KPOP (kerberized pop). - - * Add autoconf support for Hesiod. - - * Split routines to output a message given a Content structure - (output_message, output_content, write7Bit, etc..) to a new - file "mhoutsbr.c". - - * Split output_content(), into output_content() and build_headers(). - - * Changed copy_some_headers() in mhstoresbr.c, to use the linked - list of header fields, rather than reopening the message. - - * Added free_header() to mhfree.c to free structures containing - header field information. - - * Changed get_content() to use the linked list of header fields - when parsing the various MIME headers (Content-XXX). - - * Changed get_content() to store linked list of header field - values when parsing a content. - - * Changed mhbuild, mhn, mhlist, mhshow, mhstore, to use the - routines in mhcachesbr.c to handle the content cache. - - * Split various funtions (find_cache, find_cache_aux, find_cache_aux2, - cache_content) into new file mhcachesbr.c. - - * More calls to sprintf/strcpy (primarily in mhparse.c - and mhbuildsbr.c) converted to snprintf/strncpy. - - * When a message is displayed with `mhshow', it is now - removed from the "unseen" sequence. - - * Change the default "showmimeproc" to "mhshow". - - * Split "mhn -show" off into separate command "mhshow". - - * Split "mhn -store" off into separate command "mhstore". - - * Split "mhn -list" off into separate command "mhlist". - - * Add sanity checks to context_find(), context_replace(), - and context_del(), to abort if context file hasn't been - read. - - * Add calls to context_read(), to the beginning of all nmh - commands (instead of being called indirectly by context_find). - - * Changes the "substitute" version of vsnprintf/snprintf for - operating systems without native versions, to just call the - native vsprintf(), and ignore the buffer length. This is - faster, but less secure than the previous version that used - temporary files. This should only be a problem for systems - which do not have a native snprintf(), and require `inc' to - be setuid/setgid. - - * Lots more calls to sprintf/strcpy converted to snprintf/strncpy. - - * Changes client() routine to take additional parameter, which is - the buffer length of the parameter "response". Then added - buffer length checks for this parameter. - - * Changed getws() to get_fields(), since that is apparently the - name of a wide character version of gets() on some archetitures. - - * Lots of sprintf/strcpy calls converted to snprintf/strncpy. - - * Change the code in most of the commands that take multiple - message names/sequences/ranges on the command, such that - the msgs array is expanded dynamically. This removes most - of the limits on the length of command lines. - - * Add additional parameter to copyip(), to specify the - maximum number of strings that can be copied (security - fix). - - * Create new function getarguments(), to massage the argument - vector before parsing it (add any arguments from your - profile to the beginning of the argument vector). This - also removed the general limit on the number of command line - arguments. - -1998-07-04 Richard Coleman - - * Released nmh-0.27. - - * Added a new command "delete", that is available during - a "whatnow" session. It is equivalent to "quit -delete". - - * Added another parameter to editfile (in whatnowsbr.c), - that controls whether editfile should remember the last - program that was exec'ed. This way the whatnow command - "mime", will not be re-executed if "edit" is later given - with no arguments. - - * Changed whatnowsbr.c, so that whatnow doesn't abort if - mhbuild returns an error. - - * Added parameter to sendsbr(), so you may specify whether to - rename the draft file. - - * Pass delay time to splitmsg() as a parameter, rather than - use a global variable. - - * Moved code to rename draft file after sending message from - splitmsg and sendaux, to sendsbr. - - * Removed all the code in viamail to split messages and then - mail them. Replaced this with the standard sendsbr.c routines. - - * Changed sendsbr(), so that when splitting messages into - messages of type "message/partial", the header fields that - are copied are more compliant with RFC-2046. - - * Fixed mhbuild to track temporary files better. They are - now correctly removed when mhbuild aborts. - - * Created a new man page for "sendfiles". The information - about "mhn -viamail" in the "mhn" man page was moved to - this new page. - - * Changed the name of the "viamail" shell script to - "sendfiles". Modified "sendfiles" to use the new - viamail program. - - * Moved the functionality for "mhn -viamail" out of mhn, - and into a separate executable called "viamail". - - * When storing MIME contents to a folder using mhn -store, - they are now accumulated in a temporary file, and then added - to the folder using folder_addmsg(). - - * Moved code to save content to a folder from store_content - to new function output_content_folder. - - * Moved code to save content to file from store_content to - new function output_content_file. - - * Moved code to parse storage format string from store_content - to new function parse_format_string. - - * Fix copy_some_headers() in mhstoresbr.c, so that the - correct header fields in the first enclosing message/partial - will be copied (according to RFC2046), when using mhn -store - to reassemble messages of type message/partial. - - * Fixed bug to openFTP() in mhparse.c, that caused the - tmp file to not be removed, when transferring a - message/external file from ftp. - - * Moved the code in mhparse.c to process -auto switch (scan - contents for the attribute "name"), to a new function - "get_storeproc" in mhstoresbr.c. - - * Moved routines to free data structures related to MIME - content from mhparse.c and mhbuildsbr.c, to new file - mhfree.c. - - * Moved code to show/display MIME content into new - file mhshowsbr.c. - - * Moved code to store MIME content from into - new file mhstoresbr.c - - * Moved code to parse MIME content into new - file mhparse.c. - - * Moved code to list information about MIME content - into new file mhlistsbr.c. - - * Move part_ok(), type_ok(), content_error(), flush_errors(), - and set_endian() to new file mhmisc.c. - - * Start to isolate the code to show, list, and store MIME - messages. One side effect is that only one flag (-show, - -list, or -store) can be used at a time now. - - * mhn -store -auto wasn't storing file in correct directory. - - * Removed a few dead variables from sbr/ruserpass.c - - * move code for creating tmp files, and renaming the - the composition draft in mhbuild, from build_mime() - to main(). - - * remove left-over code in mhbuild.c, mhbuildsbr.c, for - the -[no]auto switch (which isn't used in mhbuild). - - * split mhn.c into mhn.c and mhnsbr.c (name later changed - to mhparse.c). - - * split mhbuild.c into mhbuild.c and mhbuildsbr.c. - -1998-05-25 Richard Coleman - - * Released nmh-0.26. - - * Added (unlisted) options [no]dashstuffing to send, post, - and whatnow to determine whether to do RFC934 quoting - (dashstuffing) for encapsulated BCC messages. The default - is still the same (dashstuffing). - - * Changed the undocumented feature "nodashmunging" in forw - and mhl, into the documented feature "nodashstuffing". The - default for forw, is still "dashstuffing" for backward - compatibility, although I don't believe that bursting - RFC934 digests is very common anymore. - - * Added an option to define REALLYDUMB in the default config.h. - But it is not on by default. - - * moved creation of config file mts.conf from zotnet/mts - to etc. This simplified the Makefile in zotnet/mts. - - * simplified directory support/general to etc. - - * removed unneeded directory support/bboards. - - * split getusername() into getusername() and getuserinfo(). - - * Changed getusr() routine to getusername(). - - * Slight cleanup in folder_pack.c on code that records the new - number of the "cur" message when packing. - -1998-05-08 Richard Coleman - - * Released nmh-0.25. - - * Change install process, so that hard linking the correct mts - library to libmts.a, is not necessary. The final link process - uses the original name of the library. - - * Fixed bug in flist.c and folder.c, so that symbolic links which - point to directories, will not decrement the number of directory - links remaining. - - * Split the function list_content (in mhn.c and mhbuild.c) into - list_content and list_debug. - - * Don't pack (folder -pack) an empty folder. - - * Exit gracefully in flist.c, if no sequence is specified, - and no "Unseen-Sequence" is given in nmh profile. - -1998-02-27 Richard Coleman - - * Released nmh-0.24. - - * Small clarification to the man page for `ali'. - - * Fix bug in inc.c so that if both flags `-file' and `-truncate' - are given, that order doesn't matter. - - * Fix bug in seq_list.c when realloc'ing for - large sequence line. - -1998-02-23 Richard Coleman - - * Released nmh-0.23. - - * Add new section on "Transfer Encodings" to man page for mhbuild. - - * In mhbuild.c, split compose_content into compose_content - (parse and execute composition string), and scan_content (scan - content, decided transfer encoding, check for clash with boundary - string). I did a good amount of rearranging of this code. - - * Moved definitions for data structures for parsing MIME - messages from mhn.c and mhbuild.c to a new include - file h/mhnsbr.h. - - * Small amount of rearranging in sendsbr.c - - * Small changes to MAIL.FILTERING file. - - * Add the file MAIL.FILTERING to nmh distribution. - - * Add line to packf so that if message begins with - "X-Envelope-From:" field, it is converted to "From ". - - * Fix packf to add "From " line to beginning of message, - even if Return-Path doesn't exist. - - * Add note to MACHINES file that on Linux, configure - doesn't find the functions sigsetjmp/siglongjmp. - - * Fix configuration for machines that don't have (or find) - sigsetjmp/siglongjmp. - -1998-02-11 Richard Coleman - - * Released nmh-0.22. - - * Add a configure check for sigsetjmp. Add some conditional - #define's in h/signals.h in case it's not found. - - * Added additional notes about -auto switch in mhn man page. - - * Added note about MM_CHARSET environment variable to - mh-profile(5) man page. - - * Fix signal problem in mhn.c (change setjmp/longjmp to - sigsetjmp/siglongjmp). - -1998-02-09 Richard Coleman - - * Released nmh-0.22-pre1. - - * Changed the first line in mhl.format from - " -- using template mhl.format -- " to a blank line. - - * Added note about automimeproc to mh-profile man page. - - * Reorganize the main entry point for parsing a MIME message - or file in mhn. Add new function parse_file() as new main - entry point for parsing MIME files. - - * Add note to mhn man page, that "mhn -file -" will accept the - source message on the standard input. - - * Changed a sanity check in folder_realloc that was too strict. - - * -norfc934mode is now the default for mhbuild, - rather than -rfc934mode. - - * Fix mhbuild, so that Content-Description and RFC-822 comments - from #forw directive will be correctly included if there is - only one message. - - * Change mhn to correctly default parts of multipart/digest to - message/rfc822 (leftover code from rfc934mode was removed). - - * Restore HP specific code to zotnet/tws/lexstring.c. Apparently - it is still needed. - -1998-02-06 Richard Coleman - - * Released nmh-0.21. - - * If the file given to mhbuild is "-", then accept the draft on - standard input, and output the MIME message to standard output. - - * Cleaned up code in mhbuild.c that decides what transfer - encoding to use. - - * Cleaned up code in mhbuild.c that decides what character set - to use for text contents. - - * Removed old hpux specific code from zotnet/tws/lexstring.c - -1998-02-02 Richard Coleman - - * Released nmh-0.21-pre2. - - * Added the "decode" variable to mhl.format and mhl.header. - - * Added new variable "decode" to mhlsbr.c to decode text in - header fields as per RFC-2047. - - * Make sure that when decoding RFC-2047 header fields, that any - spaces at the ends of the encoded text are not ignored, but the - spaces between encoded word are. - - * Removed #ifdef's for MIME. MIME support is always compiled in. - - * scan/inc will now decode both Subject and From lines as - RFC-2047 encoded header fields. - - * Added new function write_charset_8bit() to sbr. It returns - the character set to use for 8bit text in composition draft. - Changed mhbuild to use this function. - - * Split mhn man page into man pages for mhn and mhbuild. - - * mhn -show will only now only use default method for content - of type plain, if it is NOT a part of a multipart/alternative. - - * Split mhn -build into mhbuild. Did some code cleanup. - - * Added support for %(decode) to fmtdump.c. - - * check_charset() now accepts US-ASCII as a subset of any - ISO-8859-X character set. - - * Changed the default "showproc" to mhl, instead of the - pager more. - - * When reading file into mhn composition file, only need read - permissions, not write permissions. - - * Added own version of strcasecmp to distribution, since - nmh calls it frequently with NULL pointers (ughh). - - * Replaced uleq.c with strcasecmp. Removed uleq.c from - distribution. - -1998-01-22 Richard Coleman - - * Released nmh-0.21-pre1. - - * If a message is missing charset parameter to text/plain, show - will assume US-ASCII, rather than just calling showmimeproc. - - * Change show.c and mshcmds.c to use check_charset to see if text - message contains valid character set. - - * Added new scan format file "scan.nomime" to support/general - that doesn't do any RFC-2047 decoding. - - * Modified all the scan format files in support/general to do - RFC-2047 decoding of Subject field. - - * Did more work on sbr/fmt_rfc2047.c, so that it will correctly - ignore whitespace between two valid encoded words, but not - between an encoded word and normal text. - - * Created new file sbr/check_charset.c. Moved code from - fmt_rfc2047.c to check for valid character set to this file. - - * Added format escape %(decode) to decode contents of "str" register - as a RFC-2047 header field. - - * The command install-mh now recognizes the switches -version - and -help. - - * Added a new argument to print_help.c to decide whether to - print profile entries (needed for install-mh to prevent weird - loops). - - * Changed folder_read.c and folder_realloc.c so that mp->lowoff - is initialize to max (mp->lowmsg, 1) rather than always 1. - - * Changed macros for sequence/attribute manipulation so that - message status array doesn't need to always start at 1. - - * Small cleanups in folder_realloc(). - -1998-01-09 Richard Coleman - - * Released nmh-0.20. - - * Added configure option --with-pager=PAGER. - - * Added configure option --with-editor=EDITOR. - - * Changed the default format file for mhl (mhl.format) to - also ignore (not display) the header fields Content-Type, - Content-Transfer-Encoding, and Content-ID - - * Fixed core dump in addrsbr.c when using %(proper) format function - and the To: line was missing. - - * Added the file ZSH.COMPLETION to the distribution. - -1998-01-04 Richard Coleman - - * Released nmh-0.20-pre2. - - * Added new switch -snoop to both `msgchk' and `inc', so you can - watch the POP transaction. - - * Changed "replgroupcomps" to check for Mail-Followup-To header - first, and use it if available. - - * Changed "replcomps" to check for Mail-Reply-To header - first, and use it if available. - -1998-01-03 Richard Coleman - - * Released nmh-0.20-pre1. - - * Changed seq_list.c to dynamically enlarge the buffer for - collecting the message ranges in a long sequence line. - This should remove the last hard limit on the size of a - sequence line. - - * Changed seq_read.c so that can read long sequence lines. - It will use multiple calls to m_getfld() when m_getfld() - returns the state FLDPLUS. - - * Changed brkstring.c to dynamically add more space for pointers - if necessary. This is needed when splitting up large sequence - lines. - - * Did some small cleanups in seq_save.c. - - * Added new switches `-[no]unseen' to rcvstore, to control - whether new messages are added to Unseen-Sequence. - - * Moved locking routines (zotnet/mts/lock.c) to sbr/lock_file.c - - * Changed the internal UNSEEN flag to SELECT_UNSEEN which is - more appropriate. Changed the MHPATH flag to ALLOW_NEW. - - * Changed "replcomps" to not include CC and TO lines so that - that reply message is only directed at the author of the - message to which you are replying. - - * Added new switch `-group' to command repl, which causes repl - to use new forms file "replgroupcomps". This is intended for - making group replies. - - * Removed #ifdef for ATHENA. - -1997-12-28 Richard Coleman - - * Released nmh-0.19. - - * Fix repl,forw so that switch `-form file' will not abort - as ambiguious (silly mistake on my part). - - * Cleaned up the mhn man page. Added info about a few escapes - for the formatting/display strings that were not documented - (%%, %t). Moved the BNF grammar for the mime composition file, - to the end of the man page. - - * Added the options -[no]format to the command repl. The - switch `-format' will filter the message to which you are - replying with the standard message filter "mhl.reply", which - is now included in the distribution. The `-noformat' option - will negate the use of -format or -filter and not include - the message to which you are replying in the draft. - - * Did some cleaning and reorganization on many of the man - pages. - - * Added debugging switch `-debug' to mhparam, which displays - the values of all `procs' (and some other misc configuration - info) that nmh keeps in global variables. - - * When using `refile -preserve', if a conflict occurs, then use - the next available number above the message number you wish - to preserve. - - * In forw.c, split the code for creating MIME style forwarding - out of copy_draft, and into copy_mime_draft. - - * Move routines in mark.c to print sequences, into new - file sbr/seq_print.c - - * flist will now update the current folder. - - * Added the switches -[no]fast to flist, to replace - -[no]total. The previous switches are still accepted - but now undocumented. - - * More reorganization in flist of the code for - traversing folders. - - * The command "flist +foo -all" will now scan the folder - "foo" and all its 1st level children. - - * Add missing include file to sbr/snprintf.c - - * Fix alarm bug in rcvtty, so that when it calls external - process, the alarm is never longer than 30 minutes. - -1997-12-17 Richard Coleman - - * Released nmh-0.18. - - * Fixed bug in mark, so that "mark -list -seq foo" will - correctly indicate if "foo" is a private sequence. I found - this bug mentioned in Jerry Peek's book. - - * Simplified the code in seq_setcur(), since seq_addmsg() now - retains the public/private status of sequences. - - * Changed sequence handling so that if the switches -public - or -nopublic, are not specified for the commands mark, pick, - or rcvstore, then existing sequences will retain their - previous public/private status. - - * mhparam now handles the mh-sequences profile entry - correctly. - - * flist -all will now also check readonly folders (for - private sequences). - - * Improve the leaf optimization for folder command. - It will now track the number of directories in a folder, - and stop stat'ing files once it has hit all the subfolders. - - * Renamed m_getfolder to getfolder. Changed getfolder to - take option to determine whether it should get current - folder, or just default folder (Inbox). Changed rcvstore, - inc, and rmf to use the new getfolder. - - * flist now indicates if a sequence is private. - - * Change WUNTRACED to 0, in pidwait.c, so that commands will - wait for stopped processes. - - * conflict will dynamically allocate space for group names, - so it can now handle system with more than 100 groups. - -1997-12-09 Richard Coleman - - * Released nmh-0.18-pre4. - - * Check if we have enough message status space, before we - call folder_realloc() in burst, mhpath, and m_draft(). - - * mhn will now correctly identify a formatting string of "-" - for the option -store, and send content to stdout. - - * Change the way that memory for message status is - allocated. It is dynamcially allocated separately from - the folder/message structure. This required changing - folder_read.c, folder_realloc.c, folder_free.c. - - * Removed all the MTR code (experimental code for message - status allocation). - - * Renamed m_readfolder.c to folder_read.c and simplified - the code. - - * Renamed m_freefolder.c to folder_free.c. - - * Add function trim() to slocal.c to pretty print - the debugging output. - - * Changed the name of m_packfolder() to folder_pack(). - Changed the name of m_remsg() to folder_realloc(). - -Wed Dec 3 23:33:38 1997 Richard Coleman - - * Released nmh-0.18-pre3. - - * Changed installation to add `flists' which is hard linked - to `flist'. This is a equivalent to `flist -all'. - - * For flist, -showzero is on by default. - - * Major changes to flist. Default is now for flist to search - current folder. The switch `-all' is now used to specify - searching all top level folders. The new switch `-showzero' - is used to print out folders that don't contain any messages - in the given sequence. - - * Split BuildFolderList in flist.c into 2 functions - (BuildFolderList, BuildFolderListR). Changed these functions - so that flist now does better leaf optimization, and will stop - stat'ing directory entries when it knows it has hit all the - subdirectories of a given directory. - - * Reorganized code in folder.c, so that all relevant folders - are scanned first and information recorded. Then all the - folder summaries at printed out at one time. - - * Made the options of folder(s) more orthogonal. Now - "folder -all -noheader -nototal" will do the right thing. - - * Added `-noall' switch to folder, for completeness. - - * Changed the default mode for creation of new folders - to 0700 (was 0711). - - * Slightly changed the format for flist. It now indicates - if a folder is current. Also the width of the various - fields are now calculated at runtime. - - * Changed the format for folder(s). Folder names - are now left justified. The width of the various fields - are calculated at runtime. - -Sun Nov 30 19:14:53 1997 Richard Coleman - - * Released nmh-0.18-pre2. - - * Add paragraph to man page for install-mh and to INSTALL file - about checking for global mh.profile. - - * Renamed m_find() to context_find(). - Renamed m_replace() to context_replace(). - Renamed m_delete() to context_del(). - Renamed m_update() to context_save(). - Renamed m_getdefs() to context_read(). - Renamed m_foil() to context_foil(). - - * Change rcvstore to use routine folder_addmsg(), instead of - adding message to folder itself. - - * Changed refile, so that if the switch -preserve is used, - and a conflict occurs for a particular folder, then folder_addmsg() - will just use next highest available number for that folder, - instead of exiting. - - * Make folder_addmsg() more robust. It will make repeated - attempts to link file into folder if link returns with - the error EEXIST. - - * Fix bug, so that that if forking sendmail, HELO will be sent - unless clientname: option is defined but empty (so now it - is the same as the direct smtp code). - - * Changed sprintb to snprintb (now we pass the buffer length - to new routine). Changed code to use new function. - - * Added snprintf to sbr. Added configure check to build it - if you don't have a native version (but haven't changed much - code to use it yet). - -Thu Nov 13 18:42:18 1997 Richard Coleman - - * Released nmh-0.18-pre1. - - * Fixed alarm bug in slocal, so that alarm is never - called with a value larger than 30 mintues. - - * Fixed race condition in rmm and refile, so that - context is updated before external rmmproc is called. - - * Removed all the OVERHEAD code. - - * Move code to add message to folder from refile.c - to folder_addmsg.c - -Fri Jul 25 19:39:29 1997 Richard Coleman - - * Did some rearranging of the internals of inc.c. - - * Make -inplace the default for anno, forw, dist, and repl. - - * Changed --enable-smtp to --with-mts={smtp,sendmail} - - * Created new directory mts/sendmail for direct sendmail - interface (although it currently still uses SMTP). - - * Removed all the TMA (trusted mail agent) code - - * Removed all the TTYD (terminal access daemon) code - - * Removed all the MF (uucp filtering) code. - - * Removed all the code for BERK. - - * Removed all the code for stand-alone delivery (MHMTS). - - * Split the file mts/sendmail/smail.c into sendmail.c and - smtp.c. Changed the name of the directory to mts/smtp. - - * Changed autoconf to use @sysconfdir@ for location of - configuration files. - - * Changed #define in mhn.c from FTP to BUILTIN_FTP. - -Mon Jul 21 03:22:34 1997 Richard Coleman - - * Released nmh-0.17. - - * MAKEDEFS weren't passed down to recursive makes correctly. - - * slocal.c now checks for UTMP_FILE and _PATH_UTMP instead - of hard-coding "/etc/utmp". - - * rcvtty.c check for _PATH_UTMP if UTMP_FILE is not - defined. - - * Remove configure checks for ulong and ushort. Changed - code to just use unsigned {short, long}. - - * Change addmsg function in refile.c to return new - number of refiled message. - - * Added check in get_returnpath for empty unixbuf. - - * Cleanup of sbr/pidstatus to use more POSIX macros - for return value of wait(). - - * Change configure to also check /bin for "more". - -Sat Jul 12 00:02:23 1997 Richard Coleman - - * Released nmh-0.16. - -Mon Jun 23 20:13:24 1997 Richard Coleman - - * Added automimeproc, which should replace automhnproc. - - * multipart messages will no longer abort for messages - of type 8bit or binary (although we still can't really - deal with binary messages, yet). - - * Fix double free of c_storage. From John MacMillan. - - * mhn now treats unknown subtypes of "text" as text/plain. - - * mhn changed so that specifying mhn-show-multipart, or - mhn-show-multipart/{mixed, alternate, etc...) will override - the use of the internal method for displaying these types. - Previously mhn would always use the internal method for subtypes - mixed, alternate, digest, and parallel (even if an alternate - method was specified in mhn.defaults). - - * mhn show treats unknown subtypes of multipart, as type - multipart/mixed (as specified RFC2046). - - * mhn checks for the parameter "name" rather than "x-name". - From MH-6.8.4 patch. - - * Fix double free of ctinfo in user_content when using - #forw with single message. From John MacMillan (and - MH-6.8.4 patch). - - * Changed -mhnproc switch for show, to -showmimeproc. - - * Changed profile entry "mhnproc" to "showmimeproc". - - * Added "mime" option to "whatnow", which calls the program - "buildmimeproc" (default is mhn -build) to process MIME - composition files. - - * Added -build switch to mhn, to process MIME composition - files. - - * Did some reorganizing of mhn.c. - - * Changed casting in mts/sendmail/smail.c from (char) to - (signed char) so SMTP reply codes work correctly for machines - which used unsigned chars by default. - -Sat Jun 21 01:21:47 1997 Richard Coleman - - * Released nmh-0.15. - - * Added new form "scan.unseen" to distribution. It marks messages - which are in any sequence in Unseen-Sequence. - - * Do some rearranging of date/time code in zotnet/tws/dtime.c - - * Fix sign extension bugs in fmt_scan.c. - - * Fix m_atoi.c so that strings ending in non-digit characters - return 0. - - * Split code in burst.c so that finding delimiters of digested - messages and bursting a message into multiple messages are - two separate functions (find_delim and burst). - - * Add workaround fo AC_PATH_PROG in configure.in, so - that BSD4.4 machines can find sendmail, vi, more. - - * Added "-width" option to rcvtty. - - * Change a few variable names in zotnet/mts/client.c since - they conflict with defines on AIX. - - * Makefile in zotnet/tws assumes lexing of dtimep.lex was - unsuccessful if resulting file is less than 500 lines long - (rather than 10, which was previous value), since AIX - sed gives mangled file of about 200 lines. - - * Extract code in rcvstore.c to link message into folder, - and put in own subroutine. - - * Extract code in refile.c to link message into folder, - and put in own subroutine. - - * Moved code to remove messages from folder into own - routine "folder_delmsgs" in sbr. Changed rmm.c and - refile.c to use new routine. - -Fri May 16 06:09:31 1997 Richard Coleman - - * Renamed m_seqok to seq_nameok. - - * Changed m_setunseen, msh, mshcmds, flist, and scan to use - seq_getnum. - - * Changed m_seqflag to return the number of a sequence rather - than its bit flag. Changed its name to seq_getnum and renamed - file to sbr/seq_getnum.c. - - * Removed function m_seqnew and file sbr/m_seqnew.c since it is - no longer used. - - * Added zero switch to m_seqadd function to zero out bits before - adding message to sequence. - - * Renamed function m_setvis to m_setunseen, and renamed - corresponding file in sbr. - - * Renamed function m_setseq to m_setprev, and renamed corresponding - file in sbr. - - * Changed mark.c and pick.c to use m_seqaddsel and m_seqdelsel. - - * Added new function m_seqdelsel to m_seqdel.c, which deletes - all selected messages from a sequence. - - * Added new function m_seqaddsel to m_seqadd.c, which adds all - selected messages to a sequence. - - * Split sbr/m_seqnew.c into m_seqadd.c, m_seqdel.c, m_seqnew.c, - and m_seqok.c. - -Thu May 15 00:53:17 1997 Richard Coleman - - * Renamed function pack_folder to m_packfolder, and moved it - from uip/folder.c into its own file sbr/m_packfolder.c - -Wed May 14 23:38:00 1997 Richard Coleman - - * Changed function m_gmsg to m_readfolder. Renamed file - sbr/m_gmsg.c to sbr/m_readfolder.c. - -Mon May 5 19:57:11 1997 Richard Coleman - - * Expanded rcvtty man page, and added small patch from - MH-6.8.4 distribution. - -Fri May 2 15:24:34 1997 Richard Coleman - - * Released nmh-0.14. - - * Comment out configure test and code for tgetent to allocate its - own termcap buffer when passed a NULL argument. - -Sat Apr 26 03:46:38 1997 Richard Coleman - - * Added new options `-checkmime', `-nocheckmime', and `-mhnproc' - to show. Restructured code to handle options to various - `procs' better. Deprecated `-noshowproc' option and NOMHNPROC - environment variable. - - * Added new man page `mh-draft' which documents the - draft folder facility in nmh. - - * Renamed fmtsbr.h to fmt_scan.h. Renamed fmtcompile.h - to fmt_compile.h. - - * split fmtsbr.c into fmt_scan.c and fmt_new.c. Renamed - fmtcompile.c to fmt_compile.c, and formataddr.c to - fmt_addr.c. - - * `send -help' wasn't showing the -(no)mime and -split - options. - -Fri Apr 25 02:50:36 1997 Richard Coleman - - * Released nmh-0.13. - - * Changed mhpath so it doesn't abort if a message sequence - such as "mhpath all" expands to more than 1000 messages. - Also mhpath now dynamically reallocated space for message - names (The number of command line arguments is still limited - to MAXARGS). - - * Did some general restructuring of the code in folder.c - that checks for folder information, and prints it. - -Thu Apr 24 01:04:37 1997 Richard Coleman - - * Changed `folder' to reallocate space for folder names if - necessary. So `folders' can now handle more than 300 folders. - -Tue Apr 22 14:01:26 1997 Richard Coleman - - * Change configure to use a compile check to see if the tm struct - has tm_gmtoff, rather than using egrep. - -Mon Apr 21 02:19:17 1997 Richard Coleman - - * Released nmh-0.12. - - * Had set_exists and unset_exists macros backwards. - - * Released nmh-0.11. - -Thu Apr 10 02:39:53 1997 Richard Coleman - - * Added documentation to mh-profile.man about the various - `procs' (mhlproc, showproc, lproc, etc...). - - * Replace the bit twiddling for SELECTED, UNSEEN, and - mp->attrstats with macros. - - * If system doesn't have SIGEMT (like Linux), then use SIGTERM - in msh.c instead. - - * Change fstat to stat in m_gmsg.c since Linux wants - to hide dd->dd_fd. - - * Merge Linux patch sent in by Michel Oosterhof (original - patch from bsa@kf8nh.wariat.org). - - * Document an undocumented MH feature. mhn -form mhl.null - will suppress the display of the message header. - - * mhparam will now return "mhparam etcdir". - - * Add catproc to /config/config.c and use that in show.c - and mshcmds.c, rather than hard coding in /bin/cat. - - * Add mhnproc to the list of `procs' in mh-profile.man. - - * Add configure test for lorder and tsort commands. - - * Commented out the padding in the `msgs` struct in h/mh.h - - * Change m_gmsg.c to allocate elements to the `info' array by - 500 elements at a time (rather than MAXFOLDERS / 5). - - * Add note to man page for mhmail that zero length messages are - not sent. Need to use -body "" to send empty messages. - - * zotnet/mts/mts.c : compare character with '\0', not NULL. - - * sbr/getcpy.c : assign '\0' to character, not NULL. - - * add m_fmsg to most programs in uip so that they explicitly free - folder/message structure when done with folder. - - * uip/slocal.c : cleanup processing of sender. Make sure it is - defined even if message is missing "From " line. - -Mon Mar 31 03:37:35 1997 Richard Coleman - - * Released nmh-0.10. - -Sun Mar 30 21:46:17 1997 Richard Coleman - - * Add configure check for . Turn on LOCALE support - by default. - -Thu Mar 20 03:21:24 1997 Richard Coleman - - * Reversed previous decision to retain "From " lines in slocal. - The "From " line is now removed from all messages. - - * inc now saves the date from the "From " envelope in the - Delivery-Date header for all messages. - - * sbr/m_getfld.c: Clean up processing of Return-Path and - Delivery-Date from the "From " envelope. - -Mon Mar 17 19:03:36 1997 Richard Coleman - - * client.c: cast iaddr to int before comparing return value - of inet_addr with NOTOK. - -Tue Mar 11 04:38:10 1997 Richard Coleman - - * Grep test for signal names was failing on some OS'es because - of missing tabs in regex. - -Sat Mar 8 01:58:22 1997 Richard Coleman - - * Released nmh-0.09. - - * Move config files and format files to *.old before installing. - - * Add configure check for killpg. - - * msh.c: include instead of and - . - - * prompter.c: don't include anymore. - -Thu Mar 6 04:03:24 1997 Richard Coleman - - * Added `-mime' and `-nomime' options to `repl'. - From MH-6.8.4 diff. - -Tue Mar 4 03:10:37 1997 Richard Coleman - - * ruserpass.c : removed conflicting prototypes. - - * rcvtty.c : Fixed rcvtty to obey terminal permissions granted - by `mesg' command. Previously only worked on BSD machines. - -Mon Mar 3 00:18:59 1997 Richard Coleman - - * rcvtty.c : Changed to use #define UTMP_FILE (if exists) rather - than hard coded "/etc/utmp". - - * Released nmh-0.08. - - * Changed slocal to lock .maildelivery (or file given by -maildelivery) - when accessing ndbm/db file for duplicate suppression, instead of - locking database itself. - -Thu Feb 27 05:28:09 1997 Richard Coleman - - * Added slocal action `mmdf' to deliver to a file in mmdf format. - - * Changed the slocal actions `file' and `>' to always deliver in - mbox (uucp) format rather than be determined by RPATHS config - option. - - * Changed the slocal action `mbox' to deliver in mbox (uucp) format - rather than mmdf format. - - * slocal now adds Delivery-Date field to all messages (previously it - only added it to messages when delivering them to a file). The - "From " line is now retained on all messages if compiling with - RPATHS, rather than being discarded. - - * rcvpack no longer adds the Delivery-Date field to messages. - -Sun Feb 23 22:03:54 1997 Richard Coleman - - * Removed the script packmbox, since it's functionality has been - added to packf. - - * Changed packf so that it uses mbox (uucp) format by default - rather than mmdf format. Added options -mbox and -mmdf to - packf so you can choose the preferred format. - - * Changed rcvpack so that it uses mbox (uucp) format by default - rather than mmdf format. Added options -mbox and -mmdf to - rcvpack so you can choose the preferred format. - -Tue Feb 18 00:01:05 1997 Richard Coleman - - * Changed nmh to use dot locking by default (although you - can still easily change this in config.h). - - * Simplified locking code. Removed code allowing setting of - locking type in mts.conf. Now the locking type and locking - directory (if any) can only be set at compile time. - -Fri Feb 14 02:49:18 1997 Richard Coleman - - * Prefer getting timezone information from tm->gmtoff rather - than tzset and external timezone variable. - -Thu Feb 13 00:35:45 1997 Richard Coleman - - * Fixed typo in ruserpass.c in the variable toktabs. - - * When ruserpass was added to LIBOBJS, it was missing - the suffix. - - * Released nmh-0.07. - -Tue Feb 11 01:29:47 1997 Richard Coleman - - * Add check to configure, so that if ruserpass, or _ruserpass - is not found, build version of ruserpass in sbr. - - * Added define's to discard.c, m_getfld.c, and scansbr.c so - the code that manipulates internals of stdio, will build - on SCO 5.x. - - * Added #define to control whether to compile the simple - built-in FTP client in mhn. - - * Added configure check for ushort and ulong. Change code - to use ushort/ulong rather than u_short/u_long. - - * A couple of small cleanups in locking code. - - * Added configure check for gmtoff element in struct tm. - - * Added configure check for tzset. - -Fri Feb 7 03:01:57 1997 Richard Coleman - - * Released nmh-0.06. - - * Removed code for machines that don't have socket - interface (how could they get mail anyway?). - - * Removed code for BSD41 machines. I don't think there are - many such machines around anymore. - - * Add configure check for function uname, and prefer it - over gethostname. General cleanup of zotnet/mts/mts.c. - - * Change all `lseek' calls to use POSIX symbolic constants - SEEK_SET, SEEK_CUR, SEEK_END. - -Thu Feb 6 01:16:30 1997 Richard Coleman - - * Check lex generated file in zotnet/tws and use - pre-generated version if necessary. - - * Released nmh-0.05. - - * Change to use reliable signals on all platforms that have - sigaction. Change so that interrupted system calls are - restarted for all signals except SIGALRM. This fixes alarm - handling code in smail.c for BSD based systems. - - * Added lorder and tsort commands so that created libs can - be linked in one pass. - -Tue Feb 4 01:33:00 1997 Richard Coleman - - * Changed pidwait so that while it is waiting for a child, - it should block signals rather than ignore them. - -Mon Feb 3 21:05:30 1997 Richard Coleman - - * Add checks to configure for dbm_open and -lndbm. - -Thu Jan 30 05:15:42 1997 Richard Coleman - - * folder -pop and folder -push were freeing some memory too - quickly, which caused the entry popped from the stack to not - become the current folder. - -Wed Jan 29 01:28:02 1997 Richard Coleman - - * Released nmh-0.04. - - * Define ospeed and PC in termsbr.c is OS doesn't have - it. - -Sun Jan 26 20:25:10 1997 Richard Coleman - - * editfile will create a symbolic link to the altmsg if it - can't make a link, on any machine supporting lstat. Formerly - this would happen only on BSD42 based machines. - -Sat Jan 25 22:54:26 1997 Richard Coleman - - * traverse (in popsbr.c) wasn't calling va_start before using - variable argument list. Fixes core dump in inc when using POP. - -Fri Jan 24 03:27:59 1997 Richard Coleman - - * The variable pass in remotemail needed to be set to - NULL. (From MH-6.8.4 diff). Fixes core dump of msgchk when - using POP. - - * inc and msgchk were using -rpop by default when configured - with POP support. Default is now -norpop. - -Thu Jan 23 02:01:17 1997 Richard Coleman - - * By default, post will now give the SMTP HELO command with - the local hostname. If you specify a hostname with the - clientname: option in mts.conf file, post will give the - HELO command with that name instead. If the argument to the - clientname: option is empty, no HELO command is given. - (From the MH-6.8.4 diff) - -Wed Jan 22 01:55:45 1997 Richard Coleman - - * When using `-help' for a command, it will also print its - profile compents from .mh_profile. (From MH-6.8.4 diff) - - * "slocal -file" will now correctly takes its input from - a file (currently need to specify full path). - -Sun Jan 19 20:37:21 1997 Richard Coleman - - * "slocal -debug" will now issue a warning if a non-blank - line in the .maildelivery file has less than 5 fields. - -Sat Jan 18 02:26:41 1997 Richard Coleman - - * Changed slocal so that code for duplicate suppression - (MH config was MSGID) is always built. Added the options - -[no]suppressdup to slocal to turn this on/off. - -Thu Jan 16 00:26:34 1997 Richard Coleman - - * Released nmh-0.03. - - * Fixed problem where mark would core dump if no - .mh_sequence file existed. - - * Fixed problem where slocal would core dump if -debug - option was given, and certain headers were missing. - - * Added patch to slocal to add `folder' (+) action, which - is shorthand for piping message to rcvstore. Updated - man page. - -Wed Jan 15 21:30:17 1997 Richard Coleman - - * Changed flist option -unseen to -[no]all. Cleaned up - flist man page. - -Fri Jan 10 20:36:33 1997 Richard Coleman - - * Fixed flist. Changed the profile component `Folder-Order' - to `Flist-Order. Added option `-sequence' to flist, so - you can specify the name of the sequence to search for. - -Thu Jan 9 00:20:48 1997 Richard Coleman - - * A few minor portability cleanups. Changed to use PATH_MAX - rather than MAXPATHLEN. Don't assume ospeed variable exists - in termsbr.c. Removed some conflicting prototypes. - -Wed Jan 8 11:05:02 1997 Richard Coleman - - * Add configure test to check if tgetent will accept NULL - and allocate its own buffer. Borrowed from zsh. - - * Changed libpath to etcpath. - -Mon Jan 6 04:15:35 1997 Richard Coleman - - * Cleaned up source code and Makefiles, so that if your `make' - supports the VPATH option, you can build nmh in a different - directory from where the source code is located. - -Fri Jan 3 05:05:18 1997 Richard Coleman - - * Released nmh-0.02. - -Wed Jan 1 17:41:52 1997 Richard Coleman - - * Split mhook man page into man pages for rcvdist, rcvpack, - and rcvtty. - -Tue Dec 31 03:07:48 1996 Richard Coleman - - * Changed code to use strerror, rather than using sys_errlist - and sys_nerr directly. - -Mon Dec 30 02:15:25 1996 Richard Coleman - - * -compat switch from install-mh removed. - - * Changed the default POP port from "pop" to "pop3". - -Sat Dec 28 13:25:05 1996 Richard Coleman - - * Changed mhn_defaults to mhn.defaults. Changed create_mhn_defaults - (again) to mhn.defaults.sh. Changed find_program (again) to - mhn.find.sh. mhn.defaults.sh now takes the search path - as an argument. Default search path is now specified in Makefile - rather than in script. - -Fri Dec 27 16:34:01 1996 Richard Coleman - - * Changed mtstailor file to mts.conf. Updated man pages. - - * Changed si_value to si_val in mhn.c, since it conflicts with - macro defined on Solaris. - -Thu Dec 26 02:50:15 1996 Richard Coleman - - * Added --enable-nmh-mhe (and --disable-nmh-mhe) to enable/disable - support for Emacs front-end mhe. It is on by default. - - * Added the following configure options: --enable-nmh-pop to - enable client side pop support, --enable-nmh-smtp to enable - SMTP support. Client-side pop support now compiles. Man - pages for inc, msgchk, mh-chart now correctly added pop - options if enabled. - -Tue Dec 24 14:33:20 1996 Richard Coleman - - * Added configure test for bug in C libraries where linker - can't find ruserpass, but can find _ruserpass. - - * Fixed configure test so that termcap variable ospeed is - correctly found. - -Mon Dec 23 19:40:17 1996 Richard Coleman - - * Source files converted to ANSI C. - - * md5 now compiled separately rather than being included - in mhn.c. Changed md5 to use memset and memcpy. - -Fri Dec 20 02:29:37 1996 Richard Coleman - - * Collected the error routines adios, advise, admonish, and advertise - into one file (error.c), and did some rearranging of the code. - -Thu Dec 19 19:05:29 1996 Richard Coleman - - * Added awk script sigmsg.awk (originally written by - Geoff Wing for zsh) to - automatically generate signal messages for pidstatus.c. - Added files sbr/signals.c, h/signals.h. Code now uses - sigprocmask to block signals (if available). Code now uses - signal blocking on non-BSD machines. - -Wed Dec 18 01:55:17 1996 Richard Coleman - - * Add configure check for ATTVIBUG. From Soren's mh autoconf work. - - * Released nmh-0.01. - - * Added configure code to check for type of signals functions - you have (POSIX or BSD style signals). Added function - SIGPROCMASK to simulate sigprocmask on machines that don't - have POSIX signals. - -Fri Dec 13 19:40:48 1996 Richard Coleman - - * Added -version switch to all commands. Also added to - their man pages. - -Mon Dec 9 16:36:54 1996 Richard Coleman - - * Renamed uip/trmsbr.c to termsbr.c and changed it to use - POSIX termios.h style functions if present. - -Tue Dec 3 16:18:39 1996 Richard Coleman - - * Changed support/general/bootmhn.sh to output new mhn_defaults - file to standard output by default (makes it easier for testing). - Changed name of script to create_mhn_defaults. Changed bootmhn.findit - script to find_program. - -Sun Dec 1 10:00:00 1996 Richard Coleman - - * Added patch to uip/folder.c from exmh distribution to - speed up -recurse option. - - * Added flist command from exmh distribution. It doesn't work - yet, but it compiles :-) - - * Changed default location for install to - /usr/local/nmh/{bin,etc,lib,man}. Split files so that format - and configuration files go in nmh/etc, and support binaries go - in nmh/lib. Of course, all this can now be changed in the top - level Makefile. - - * Started with mh-6.8.3 as based and converted to autoconf. - Rewrote all the Makefiles. Currently only works with sendmail/smtp. - Pop support and plenty of other things, are now broken. diff --git a/DATE b/DATE index 4a3bde8..233c554 100644 --- a/DATE +++ b/DATE @@ -1 +1 @@ -27 April 2008 +2012-07-16 diff --git a/INSTALL b/INSTALL index 3c48294..8f3b7d3 100644 --- a/INSTALL +++ b/INSTALL @@ -3,16 +3,16 @@ # -------------- -Installing nmh +Installing mmh -------------- Please read all of the following instructions before you begin -building nmh. +building mmh. You should check the MACHINES file to see if there are any specific -build instructions for your operating system. To build nmh, you will +build instructions for your operating system. To build mmh, you will need an ANSI C compiler such as gcc. -0) If you have obtained nmh by checking it out of CVS, you will +0) If you have obtained mmh by checking it out of git, you will need to run the GNU autotools to regenerate some files. (If your directory already contains a file 'config.h.in' then this has already been done and you do not need to do it.) @@ -20,102 +20,49 @@ need an ANSI C compiler such as gcc. ./autogen.sh - (Note that if you're doing nmh development, you should look at + (Note that if you're doing mmh development, you should look at docs/README.developers, since there is other developer-friendly advice there as well.) -1) From the top-level source directory, run the command +1) From the top-level source directory, run the command: - ./configure [options] + ./configure [options] - This will check the configuration of your OS, and create the - include file config.h, as well as the various Makefiles. + This will check the configuration of your OS, as well as the various + Makefiles. - The configure script accepts various options. The options of - most interest are listed in a section below. To see the list - of all available options, you can run + The configure script accepts various options. The options of + most interest are listed in a section below. To see the list + of all available options, you can run: - ./configure --help + ./configure --help -2) Look through the user configuration section at the beginning - of the generated include file `config.h'. You may - want to customize some #defines for your environment. +2) make -3) make +3) make install -4) make install - - Note that if you have [n]mh files in your install directories with + Note that if you have mmh files in your install directories with the same names as the files being installed, the old ones will get - overwritten without any warning. The only directory that isn't - true for is the `etc' directory -- in that directory, the previous - copy of each will be backed up as .prev if it differs - from the newly-installed copy. Watch for any diff output while - make is processing that directory to see if you need to merge - changes from *.prev files into the new versions. - -5) Edit the file `mts.conf' (installed in the nmh `etc' directory) - and make any necessary changes for the mail transport interface - you are using. - - The default `mts.conf' file assumes you retrieve new mail from - a local (or NFS mounted) maildrop, and send outgoing mail by - injecting the message to a mail transfer agent (such as sendmail) - on the local machine via SMTP. - - If, instead, all your mail sending and receiving occurs on a - remote POP/SMTP server, you will need to look at the values of the - variables "localname", "pophost", and "servers": - - a) "localname" defines the hostname that nmh considers local. - If not set, then nmh queries your OS for this value. You will - want to change this if you wish your e-mail to appear as if it - originated on the POP server. - - b) "pophost" defines the server that runs the POP daemon, and to - which `inc' and `msgchk' will always query for new mail. - - c) "servers" defines the server to which you send outgoing SMTP - traffic. - - If you compile with POP support, but don't want to use it exclusively, - you can use the `-host' and `-user' options to `inc' and `msgchk' - rather than hardcoding pophost in `mts.conf'. - - Check the `mh-tailor' man page for a list of all the available options - for this file ("masquerade" may be of particular interest). - -6) If you have enabled POP support, make sure that `pop3' (or more - precisely the value of the define POPSERVICE in config.h) is defined - in the /etc/services file (or its NIS/NIS+ equivalent) on the client - machine. It should be something equivalent to "110/tcp". This might - have already been done when the POP daemon was installed. - -7) Edit the file `mhn.defaults' (installed in the nmh `etc' directory). - This file contains the default profile entries for the nmh command - `mhn' and is created by the script `mhn.defaults.sh'. This script - will search a generic path (essentially your $PATH) for programs to - handle various content types (for example, xv to display images). - You can re-run this script and give it a more tailored path. You may - want to re-run this script later if you install new programs to - display content. An example of this is: - - % cd support/general - % ./mhn.defaults.sh /usr/local/bin:/usr/X11/bin:/usr/ucb > mhn.defaults - - and then move `mhn.defaults' into the nmh `etc' directory. - - The `mhn.defaults.sh' script only searches for a simple set of programs. - If you have specialized programs to handle various types, you will need - to edit the `mhn.defaults' file manually. The syntax of this file is - described in the man page for `mhn', and in section 9.4 of the book - "MH & xmh: Email for Users and Programmers", 3rd edition, by Jerry Peek, - on the Internet at . - -9) Add an optional global mh.profile, if desired. This profile should be - placed in the nmh `etc' directory with the name `mh.profile'. This - file will be used to construct the initial .mh_profile of a new nmh - user, but will not be consulted after that. + overwritten without any warning. The only directory this isn't + true for, is the `etc' directory -- in that directory, the distributed + files are installed with a `.dist' suffix if they differ from the + existing file. Watch for information messages while make is processing + that directory to see if you need to merge changes. + +4) Edit the file `mhn.defaults' (installed in the mmh `etc' directory). + + This file contains the default profile entries for the mmh commands + mhlist/mhstore/show. The syntax of this file is described in section + 9.4 of the book "MH & xmh: Email for Users and Programmers", 3rd edition, + by Jerry Peek, on the Internet at + . + +5) Add the bindir to your PATH variable. + + If you haven't change any paths, then the bindir is `/usr/local/mmh/bin'. + Likely, your PATH is set in ~/.profile, ~/.kshrc, ~/.bashrc, or a similar + file. + ----------------------------------------------- Compiler options, or using a different compiler @@ -124,109 +71,72 @@ By default, configure will use the "gcc" compiler if found. You can use a different compiler, or add unusual options for compiling or linking that the "configure" script does not know about, by either editing the user configuration section of the top level Makefile (after running configure) -or giving "configure" initial values for these variables by setting them -in the environment. Using a Bourne-compatible shell (such as sh,ksh,zsh), - -you can do that on the command line like this: - CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure - +or giving "configure" initial values for these in its command line or in +its environment. For example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + Or on systems that have the "env" program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure +If you want to add to, not replace, compile flags, you can use OURDEFS: + ./configure OURDEFS='-Wextra -Wno-sign-compare' + ---------------------------------------- -Building nmh on additional architectures +Building mmh on additional architectures ---------------------------------------- -To build nmh on additional architectures, you can do a "make distclean". -This should restore the nmh source distribution back to its original -state. You can then configure nmh as above on other architectures in -which you wish to build nmh. Or alternatively, you can use a different +To build mmh on additional architectures, you can do a "make distclean". +This should restore the mmh source distribution back to its original +state. You can then configure mmh as above on other architectures in +which you wish to build mmh. Or alternatively, you can use a different build directory for each architecture. - + --------------------------------- Using a different build directory --------------------------------- -You can compile the nmh in a different directory from the one containing +You can compile the mmh in a different directory from the one containing the source code. Doing so allows you to compile it on more than one architecture at the same time. To do this, you must use a version of "make" that supports the "VPATH" variable, such as GNU "make". "cd" to the directory where you want the object files and executables to go and run the "configure" script. "configure" automatically checks for the source code in the directory that "configure" is in. For example, - - cd /usr/local/solaris/nmh - /usr/local/src/nmh-1.0/configure + + cd /usr/local/solaris/mmh + /usr/local/src/mmh-1.0/configure make --------------------- Options for configure --------------------- ---prefix=DIR (DEFAULT is /usr/local/nmh) +--prefix=DIR (DEFAULT is /usr/local/mmh) This will change the base prefix for the installation location - for the various parts of nmh. Unless overridden, nmh is installed + for the various parts of mmh. Unless overridden, mmh is installed in ${prefix}/bin, ${prefix}/etc, ${prefix}/lib, ${prefix}/man. --bindir=DIR (DEFAULT is ${prefix}/bin) - nmh's binaries (show, inc, comp, ...) are installed here. + mmh's binaries (show, inc, comp, ...) are installed here. + You need to have this directory in your PATH variable. --libdir=DIR (DEFAULT is ${prefix}/lib) - nmh's support binaries (post, slocal, mhl, ...) are installed here. + mmh's test tools (ap, dp, mhtest, ...) are installed here. + They are seldom useful to normal users. --sysconfdir=DIR (DEFAULT is ${prefix}/etc) - nmh's config files (mts.conf, mhn.defaults, ...) are installed here. + mmh's config files (mhn.defaults, ...) are installed here. --mandir=DIR (DEFAULT is ${prefix}/man) - nmh's man pages are installed here. + mmh's man pages are installed here. --enable-debug Enable debugging support. ---enable-masquerade[='draft_from mmailid username_extension'] - If this option is disabled, the mts.conf file will contain the - line "masquerade: " (with no value), which may be manually edited - later. You may find it convenient to specify a value at - configure-time, however, so that each time nmh is reinstalled, - the right value will be there. By default, it is enabled. - - The above usage shows the default, with all three masquerade - options being specified. Any subset of the three may be - specified. - - See the mh-tailor(5) man page for full documentation of "masquerade:". - ---enable-mhe (DEFAULT) - Add support for the Emacs front-end `mhe'. - ---enable-pop - Enable client-side support for pop. - ---enable-apop - Enable client-side support for apop (Authenticated POP). - ---with-editor=EDITOR (DEFAULT is vi) - specify the full path of the default editor to use. If this - option is not given, then the configuration process will search - for the `vi' command and use it as the default. If you wish to - specify an interface which is compatible with MH, then use the - nmh command `prompter'. If you specify `prompter', then you don't - need to give the full pathname. - ---with-hesiod=PREFIX - Specify the location of Hesiod. - ---with-krb4=PREFIX - Specify the location of Kerberos V4 for KPOP support. After - running configure, you will need to change the POPSERVICE #define in - config.h if you want to use KPOP exclusively (rather than being able - to switch between KPOP and normal POP3). See the comments inside - config.h for details. - --with-locking=LOCKTYPE (DEFAULT is dot) - Specify the locking mechanism when attempting to "inc" or - "msgchk" a local mail spool. Valid options are "dot", - "fcntl", "flock", and "lockf". Of the four, dot-locking - requires no special kernel or filesystem support, and simply - creates a file called "FILE.lock" to indicate that "FILE" is - locked. + Specify the locking mechanism when attempting to "inc" + a local mail spool. Valid options are "dot", "fcntl", "flock", + and "lockf". Of the four, dot-locking requires no special kernel + or filesystem support, and simply creates a file called + "FILE.lock" to indicate that "FILE" is locked. In order to be effective, you should contact the site administrator to find out what locking mechanisms other @@ -235,53 +145,7 @@ Options for configure is not world- or user-writeable, and thus a lock file cannot be created. ---with-mts=MTS (DEFAULT is smtp) - Specify the default mail transport system you want to use. The two - acceptable options are "smtp" (which is the default), and - "sendmail". This value will be put into the mts.conf file. You - may find it convenient to specify a value at configure-time, - however, so that each time nmh is reinstalled, the right value will - be there. - - If you use "smtp", this will enable a direct SMTP (simple mail - transport protocol) interface in nmh. When sending mail, instead - of passing the message to the mail transport agent, `post' will - open a socket connection to the mail port on the machine specified - in the `mts.conf' file (default is localhost), and speak SMTP - directly. - - If you use "sendmail", then `post' will send messages by forking a - local copy of sendmail. Currently it will still speak SMTP with - this local copy of sendmail. - - If you wish to use a transport agent other than sendmail, you will - need to use a `sendmail wrapper'. - ---with-ndbm=LIB (DEFAULT is to autodetect) ---with-ndbmheader=HEADER (DEFAULT is to autodetect) - Specify the header file (eg ndbm.h) and library (eg ndbm) to use - to compile against the ndbm database library. By default, configure - will try various possibilities until it finds one that works; this - option only needs to be specified if the autodetection fails or - makes the wrong choice. - - If either of these options is given then the other must also be - specified. - ---with-pager=PAGER (DEFAULT is more) - Specify the default pager (file lister) to use. If this option - is not given, then the configuration process will search for the - command `more' and use it as the default. - ---with-smtpservers='SMTPSERVER1[ SMTPSERVER2...]' (DEFAULT is localhost) - If this option is not specified, the mts.conf file will contain - the line "servers: localhost", which may be manually edited later. - You may find it convenient to specify a value at configure-time, - however, so that each time nmh is reinstalled, the right value will be - there. - - See the mh-tailor(5) man page for full documentation of "servers:". -- -The nmh team -nmh-workers@nongnu.org +markus schnalke +and the nmh team diff --git a/MACHINES b/MACHINES deleted file mode 100644 index ddd30fa..0000000 --- a/MACHINES +++ /dev/null @@ -1,97 +0,0 @@ -# -# MACHINE -- operating system specific information -# - -nmh is known to compile on the following platforms (save the -exceptions noted below), using an ANSI C compiler, such as gcc. - -AIX 4.1.5.0.01 -FreeBSD -IRIX 6.5 -Linux 2.2, 2.3, 2.4 (glibc 2.1, glibc 2.2) -Mac OS X Public Beta -NetBSD 1.4.2 -OpenBSD -Solaris 7 and 8 (sparc,x86) -SunOS 4.1 - -Known Compilation problems: --------------------------------------- -FreeBSD: -OpenBSD: -NetBSD: - -Some BSD4.4 machines have problems when running nmh's configure script. -They will be unable to find the location of vi and sendmail. This is -due to POSIX features (breakage?) in the shell sh. The solution is to -run the configure script under the shell `bash': - - % bash configure - --------------------------------------- -Mac OS X/Rhapsody 5: - -Version 5.3 at least has the same sh/bash bug as the *BSD systems -above. This appears to be fixed in 5.5. - -Will not compile correctly unless you configure with the --enable-debug -option. It appears to find conflicts in the headers only when debugging -is disabled. With debugging enabled, it compiles and runs happily. - --------------------------------------- -HPUX: - -Lots of problems have been reported with using HPUX `cc'. In particular, -problems with `scan' giving incorrect dates (everything is 01/00). -It is highly recommended that you use `gcc' instead. - -Also, new versions of HPUX (10.20?) will core dump in `scan' because -of some workaround code in zotnet/tws/lexstring.c. This workaround is -needed for older versions of HPUX, but causes problems on newer versions. -The solution is the added line (minus our indentation): - - #undef hpux - -after line 15 of the file zotnet/tws/lexstring.c. - --------------------------------------- -Irix (SGI): - -Irix make is notoriously buggy. If you're using it, you should "touch -config.h.in" before configuring to prevent a problem where it tries to -rebuild targets that shouldn't be rebuilt. (Alternately, you can just -use GNU make instead of Irix make.) - --------------------------------------- -Linux: - -The configuration script does a test to discover if your vi is broken -(if it reports non-zero exit codes on certain pseudo-errors). This test -will hang if the program `ex' on your system is a link to the vi clone -`vile'. The workaround is to replace the command ex as a link to another -vi clone such as nvi or elvis. - --------------------------------------- -Solaris: - -With --enable-debug you'll see a lot of warnings. This is even worse -when compiling using the Sun Workshop compiler since it issues a -warning for every instance of a problem instead of summarizing them. -The main one concerns arrays with an index of type char. This is ok. -The array itself is a hash of chars, so the array size and the type -match. There isn't another safe and portable way to do this at the -moment. An explicit cast would get rid of the warnings, but I think -it's better to leave it complaining for now until we come up with -a better solution. The whole thing is probablly going to be chucked -with UTC-8 support anyway. - -Other than the warnings, it builds ok. --------------------------------------- -SunOS 4.1.1/4.1.3/4.1.4: - -You can't use the C compiler that comes with SunOS 4 since -it isn't ANSI C. But nmh builds just fine with gcc. With ---enable-debug you will see a lot of warnings. --------------------------------------- - - diff --git a/Makefile.in b/Makefile.in index 1fe2d38..79746ab 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,8 +1,8 @@ # -# Makefile for top level of nmh distribution +# Makefile for top level of mmh distribution # -# nmh version +# mmh version VERSION = @VERSION@ SHELL = /bin/sh @@ -26,9 +26,12 @@ bindir = @bindir@ # location of support binaries and scripts libdir = @libdir@ -# location of nmh configuration and formats files +# location of mmh configuration and formats files etcdir = @sysconfdir@ +# location of ... +datarootdir = @datarootdir@ + # location of man pages mandir = @mandir@ @@ -38,12 +41,6 @@ mailspool = @mailspool@ # location of mail transport agent sendmailpath = @sendmailpath@ -# default editor -default_editor = @editorpath@ - -# default pager -default_pager = @pagerpath@ - CC = @CC@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ @OURDEFS@ @@ -58,8 +55,7 @@ MAKEDEFS = CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' DEFS='$(DEFS)' \ CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \ prefix='$(prefix)' exec_prefix='$(exec_prefix)' bindir='$(bindir)' \ etcdir='$(etcdir)' libdir='$(libdir)' mandir='$(mandir)' \ -mailspool='$(mailspool)' sendmailpath='$(sendmailpath)' \ -default_editor='$(default_editor)' default_pager='$(default_pager)' +mailspool='$(mailspool)' sendmailpath='$(sendmailpath)' INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -68,13 +64,13 @@ INSTALL_DATA = @INSTALL_DATA@ .SUFFIXES: # all files in this directory included in the distribution -DIST = ChangeLog COPYRIGHT DATE INSTALL MACHINES README VERSION \ - ChangeLog install-sh mkinstalldirs Makefile.in aclocal.m4 \ - acconfig.h config.h.in configure.in configure stamp-h.in \ +DIST = COPYRIGHT DATE INSTALL README VERSION \ + autogen.sh install-sh Makefile.in aclocal.m4 \ + acconfig.h config.h.in configure.ac configure stamp-h.in \ config.sub config.guess # subdirectories in distribution -SUBDIRS = h config sbr mts uip etc man docs +SUBDIRS = h config sbr uip etc man docs # ========== DEPENDENCIES FOR BUILDING AND INSTALLING ========== @@ -106,6 +102,7 @@ superclean: superclean-recursive superclean-local mostlyclean-local: rm -f *~ + rm -rf autom4te.cache clean-local: mostlyclean-local @@ -138,7 +135,7 @@ Makefile: Makefile.in config.status config.status: configure VERSION ./config.status --recheck -configure: configure.in aclocal.m4 +configure: configure.ac aclocal.m4 cd $(srcdir) && autoconf config.h: stamp-h @@ -146,7 +143,7 @@ stamp-h: config.h.in config.status ./config.status config.h stamp config.h.in: stamp-h.in -stamp-h.in: configure.in acconfig.h aclocal.m4 +stamp-h.in: configure.ac acconfig.h aclocal.m4 cd $(srcdir) && autoheader date > $@ @@ -156,20 +153,20 @@ reset: cd $(srcdir) && autoconf cd $(srcdir) && date > stamp-h.in -# name of new nmh distribution tar file -tarfile = nmh-$(VERSION).tar.gz +# name of new mmh distribution tar file +tarfile = mmh-$(VERSION).tar.gz # ftp directory location -ftpdir = /ftp/nmh +ftpdir = /ftp/mmh -# file containing name of new nmh distribution +# file containing name of new mmh distribution distname: - @echo nmh-$(VERSION) > distname + @echo mmh-$(VERSION) > distname -# build nmh distribution +# build mmh distribution distdir = `cat distname` -nmhdist: $(DIST) distname - @echo "Begin building nmh-$(VERSION) distribution" +mmhdist: $(DIST) distname + @echo "Begin building mmh-$(VERSION) distribution" rm -rf $(distdir) mkdir $(distdir) @chmod 755 $(distdir) @@ -185,13 +182,13 @@ nmhdist: $(DIST) distname chmod -R a+r $(distdir) tar chf - $(distdir) | gzip -c > $(tarfile) rm -rf $(distdir) distname - @echo "Done building nmh-$(VERSION) distribution" + @echo "Done building mmh-$(VERSION) distribution" -# release a new nmh distribution into ftp directory -nmhrelease: +# release a new mmh distribution into ftp directory +mmhrelease: $(tarfile) rm -f $(ftpdir)/$(tarfile) - rm -f $(ftpdir)/nmh.tar.gz + rm -f $(ftpdir)/mmh.tar.gz mv $(tarfile) $(ftpdir)/$(tarfile) - cd $(ftpdir) && ln -s $(tarfile) nmh.tar.gz + cd $(ftpdir) && ln -s $(tarfile) mmh.tar.gz cd $(ftpdir) && md5sum *.gz > MD5SUM diff --git a/README b/README index 328f383..b61ba4c 100644 --- a/README +++ b/README @@ -10,11 +10,10 @@ distribution in a file named COPYRIGHT. Developers ---------- Information of interest to nmh developers can be found in the -README.developers file in the docs subdirectory of this distribution. +README.developers file in the docs subdirectory of this distribution. If you're hacking on the code, you should also definitely subscribe to the nmh-workers mailing list. To do so, please visit the nmh-workers -info page at -http://lists.nongnu.org/mailman/listinfo/nmh-workers +info page at . If you're interested in working on nmh, but aren't sure what to do, see the TODO file in the docs subdirectory. There's plenty of work there. @@ -24,11 +23,10 @@ The files COMPLETION-BASH, COMPLETION-TCSH and COMPLETION-ZSH in the docs subdirectory give cookbook examples of how to use the enhanced features of these shells with nmh. There is also a section in Jerry Peek's book covering nmh/MH and working with the shell. The section is -available online here: http://www.ics.uci.edu/~mh/book/mh/mhanthsh.htm +available online at . For More information -------------------- There is more information, including a FAQ and a bit of historical information in the docs subdirectory. There are also links to further -documentation on the nmh website located at http://nmh.nongnu.org/ . - +documentation on the nmh website located at . diff --git a/VERSION b/VERSION index cd438c9..f1f9143 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3-dev +0.1-dev diff --git a/acconfig.h b/acconfig.h index 3649bf3..7352240 100644 --- a/acconfig.h +++ b/acconfig.h @@ -20,95 +20,6 @@ */ /* #define LOCKDIR "/usr/spool/locks" */ -/* - * Define this if your passwords are stored in some type of - * distributed name service, such as NIS, or NIS+. - */ -#define DBMPWD 1 - -/* - * Directs nmh not to try and rewrite addresses - * to their official form. You probably don't - * want to change this without good reason. - */ -#define DUMB 1 - -/* - * Define this if you do not want nmh to attach the local hostname - * to local addresses. You must also define DUMB. You probably - * don't need this unless you are behind a firewall. - */ -/* #define REALLYDUMB 1 */ - -/* - * Starting on January 1, 2000, some MUAs like ELM and Ultrix's DXmail started - * generated bad dates ("00" or "100" for the year). If this #define is active, - * we use windowing to correct those dates to what we presume to be the intended - * values. About the only time this could get us into trouble would be if a MUA - * was generating a year of "00" in 2001 or later, due to an unrelated bug. In - * this case we would "correct" the year to 2000, which could result in - * inaccurate bug reports against the offending MUA. A much more esoteric case - * in which you might not want to #define this would be if you were OCR'ing in - * old written correspondence and saving it in email format, and you had dates - * of 1899 or earlier. - */ -#define FIX_NON_Y2K_COMPLIANT_MUA_DATES 1 - -/* - * Directs inc/slocal to extract the envelope sender from "From " - * line. If inc/slocal is saving message to folder, then this - * sender information is then used to create a Return-Path - * header which is then added to the message. - */ -#define RPATHS 1 - -/* - * If defined, slocal will use `mbox' format when saving to - * your standard mail spool. If not defined, it will use - * mmdf format. - */ -#define SLOCAL_MBOX 1 - -/* - * If this is defined, nmh will recognize the ~ construct. - */ -#define MHRC 1 - -/* - * Compile simple ftp client into mhn. This will be used by mhn - * for ftp access unless you have specified another access method - * in your .mh_profile or mhn.defaults. Use the "mhn-access-ftp" - * profile entry to override this. Check mhn(1) man page for - * details. - */ -#define BUILTIN_FTP 1 - -/* - * If you enable POP support, this is the the port name that nmh will use. Make - * sure this is defined in your /etc/services file (or its NIS/NIS+ equivalent). - * If you are using KPOP, you will need to change this to "kpop" unless you want - * to be able to use both POP3 _and_ Kerberized POP and plan to use inc and - * msgchk's -kpop switch every time in the latter case. - */ -#define POPSERVICE "pop3" - -/* - * Define the default creation modes for folders and messages. - */ -#define DEFAULT_FOLDER_MODE "700" -#define DEFAULT_MESSAGE_MODE "600" - -/* - * Name of link to file to which you are replying. - */ -#define LINK "@" - -/* - * Define to 1 if your vi has ATT bug, such that it returns - * non-zero exit codes on `pseudo-errors'. - */ -#undef ATTVIBUG - /***** END USER CONFIGURATION SECTION *****/ @TOP@ diff --git a/aclocal.m4 b/aclocal.m4 index 20d123f..872f5f9 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -4,125 +4,8 @@ # optional libraries for networking functions. # -AC_DEFUN([AC_CHECK_NETLIBS], +AC_DEFUN([NMH_CHECK_NETLIBS], [AC_SEARCH_LIBS([gethostbyname], [nsl], , [AC_MSG_ERROR([gethostbyname not found])]) AC_SEARCH_LIBS([connect], [socket], , [AC_MSG_ERROR([connect not found])]) ])dnl - -dnl -------------- -dnl CHECK FOR NDBM -dnl -------------- -dnl -dnl NMH_CHECK_DBM(include,library,action-if-found,action-if-not) - -dnl Check for presence of dbm_open() in the specified library -dnl and with the specified include file (if libname is the empty -dnl string then don't try to link against any particular library). - -dnl We set nmh_ndbm_found to 'yes' or 'no'; if found we set -dnl nmh_ndbmheader to the first arg and nmh_ndbm to the second. - -dnl If this macro accepted a list of include,library tuples -dnl to test in order that would be cleaner than the current -dnl nest of calls in configure.in. - -dnl We try to link our own code fragment (which includes the -dnl headers in the same way slocal.c does) rather than -dnl using AC_CHECK_LIB because on later versions of libdb -dnl the dbm_open() function is provided via a #define and -dnl we don't want to hardcode searching for the internal -dnl function that lies behind it. (AC_CHECK_LIB works by -dnl defining its own bogus prototype rather than pulling in -dnl the right header files.) - -dnl An oddity (bug) of this macro is that if you haven't -dnl done AC_PROG_CC or something that implies it before -dnl using this macro autoconf complains about a recursive -dnl expansion. - -AC_DEFUN(NMH_CHECK_NDBM, -[ -if test "x$2" = "x"; then - nmh_libs= - AC_MSG_CHECKING([for dbm in $1]) -else - nmh_libs="-l$2 " - AC_MSG_CHECKING([for dbm in $1 and $2]) -fi - -dnl We don't try to cache the result, because that exceeds -dnl my autoconf skills -- feel free to put it in :-> -- PMM - -nmh_saved_libs="$LIBS" -LIBS="$nmh_libs $5 $LIBS" -AC_LINK_IFELSE(AC_LANG_PROGRAM([[ -#define DB_DBM_HSEARCH 1 -#include <$1> -]], -[[dbm_open("",0,0);]]),[nmh_ndbm_found=yes],[nmh_ndbm_found=no]) -LIBS="$nmh_saved_libs" - -if test "$nmh_ndbm_found" = "yes"; then - AC_MSG_RESULT(yes) - nmh_ndbmheader="$1" - nmh_ndbm="$2" - $3 -else - AC_MSG_RESULT(no) - $4 - : -fi -])dnl - -dnl ---------------- -dnl CHECK FOR d_type -dnl ---------------- -dnl -dnl From Jim Meyering. -dnl -dnl Check whether struct dirent has a member named d_type. -dnl - -# Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004 Free Software -# Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -AC_DEFUN([CHECK_TYPE_STRUCT_DIRENT_D_TYPE], - [AC_REQUIRE([AC_HEADER_DIRENT])dnl - AC_CACHE_CHECK([for d_type member in directory struct], - jm_cv_struct_dirent_d_type, - [AC_TRY_LINK(dnl - [ -#include -#ifdef HAVE_DIRENT_H -# include -#else /* not HAVE_DIRENT_H */ -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* HAVE_SYS_NDIR_H */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* HAVE_SYS_DIR_H */ -# ifdef HAVE_NDIR_H -# include -# endif /* HAVE_NDIR_H */ -#endif /* HAVE_DIRENT_H */ - ], - [struct dirent dp; dp.d_type = 0;], - - jm_cv_struct_dirent_d_type=yes, - jm_cv_struct_dirent_d_type=no) - ] - ) - if test $jm_cv_struct_dirent_d_type = yes; then - AC_DEFINE(HAVE_STRUCT_DIRENT_D_TYPE, 1, - [Define if there is a member named d_type in the struct describing - directory headers.]) - fi - ] -) diff --git a/config/Makefile.in b/config/Makefile.in index 23ded2a..80eb409 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -17,15 +17,16 @@ bindir = @bindir@ libdir = @libdir@ etcdir = @sysconfdir@ -default_editor = @editorpath@ -default_pager = @pagerpath@ +sendmailpath = @sendmailpath@ +mailspool = @mailspool@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -INCLUDES = -I.. -I$(top_srcdir) @CPPFLAGS@ -CONFIGDEFS = -DNMHBINDIR='"$(bindir)"' -DNMHETCDIR='"$(etcdir)"' -DNMHLIBDIR='"$(libdir)"' \ - -DDEFAULT_EDITOR='"$(default_editor)"' -DDEFAULT_PAGER='"$(default_pager)"' +INCLUDES = -I$(top_srcdir) @CPPFLAGS@ +CONFIGDEFS = -DNMHETCDIR='"$(etcdir)"' \ + -DSENDMAILPATH='"$(sendmailpath)"' \ + -DMAILSPOOL='"$(mailspool)"' COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) COMPILE2 = $(CC) -c $(DEFS) $(CONFIGDEFS) $(INCLUDES) $(CFLAGS) @@ -85,9 +86,9 @@ subdir = config Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ diff --git a/config/config.c b/config/config.c index c2d307e..52ef436 100644 --- a/config/config.c +++ b/config/config.c @@ -1,366 +1,175 @@ - /* - * config.c -- master nmh configuration file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** config.c -- master nmh configuration file +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#ifdef MHRC -# include -#endif - -#define nmhbindir(file) NMHBINDIR#file -#define nmhetcdir(file) NMHETCDIR#file -#define nmhlibdir(file) NMHLIBDIR#file /* - * Find the location of a format or configuration - * file, and return its absolute pathname. - * - * 1) If already absolute pathname, then leave unchanged. - * 2) Next, if it begins with ~user, then expand it. - * 3) Next, check in nmh Mail directory. - * 4) Next, check in nmh `etc' directory. - * - */ - -char * -etcpath (char *file) -{ - static char epath[PATH_MAX]; - char *cp; -#ifdef MHRC - char *pp; - struct passwd *pw; -#endif - -#ifdef MHRC - context_read(); -#endif - - switch (*file) { - case '/': - /* If already absolute pathname, return it */ - return file; - -#ifdef MHRC - case '~': - /* Expand ~username */ - if ((cp = strchr(pp = file + 1, '/'))) - *cp++ = '\0'; - if (*pp == '\0') { - pp = mypath; - } else { - if ((pw = getpwnam (pp))) - pp = pw->pw_dir; - else { - if (cp) - *--cp = '/'; - goto try_it; - } - } - - snprintf (epath, sizeof(epath), "%s/%s", pp, cp ? cp : ""); - if (cp) - *--cp = '/'; - - if (access (epath, R_OK) != NOTOK) - return epath; /* else fall */ -try_it: -#endif /* MHRC */ - - default: - /* Check nmh Mail directory */ - if (access ((cp = m_mailpath (file)), R_OK) != NOTOK) - return cp; - } - - /* Check nmh `etc' directory */ - snprintf (epath, sizeof(epath), nmhetcdir(/%s), file); - return (access (epath, R_OK) != NOTOK ? epath : file); -} - - -/* - * Standard yes/no switches structure - */ - -struct swit anoyes[] = { - { "no", 0 }, - { "yes", 0 }, - { NULL, 0 } -}; - -/* - * nmh constants - */ - -/* initial profile for new users */ -char *mh_defaults = nmhetcdir (/mh.profile); - -/* default name of user profile */ -char *mh_profile = ".mh_profile"; +** nmh globals +*/ -/* name of current message "sequence" */ -char *current = "cur"; - -/* standard component files */ -char *components = "components"; /* comp */ -char *replcomps = "replcomps"; /* repl */ -char *replgroupcomps = "replgroupcomps"; /* repl -group */ -char *forwcomps = "forwcomps"; /* forw */ -char *distcomps = "distcomps"; /* dist */ -char *rcvdistcomps = "rcvdistcomps"; /* rcvdist */ -char *digestcomps = "digestcomps"; /* forw -digest */ - -/* standard format (filter) files */ -char *mhlformat = "mhl.format"; /* show */ -char *mhlreply = "mhl.reply"; /* repl -filter */ -char *mhlforward = "mhl.forward"; /* forw -filter */ +char *mhetcdir = NMHETCDIR; -char *draft = "draft"; +char *invo_name; /* command invocation name */ +char *mypath; /* user's $HOME */ +char *mmhpath; /* pathname of user's mmh dir */ +char *defpath; /* pathname of user's profile */ +char *ctxpath; /* pathname of user's context */ +char ctxflags; /* status of user's context */ +struct node *m_defs; /* profile/context structure */ -char *inbox = "Inbox"; -char *defaultfolder = "inbox"; -char *pfolder = "Current-Folder"; -char *usequence = "Unseen-Sequence"; -char *psequence = "Previous-Sequence"; -char *nsequence = "Sequence-Negation"; - -/* profile entries for storage locations */ -char *nmhstorage = "nmh-storage"; -char *nmhcache = "nmh-cache"; -char *nmhprivcache = "nmh-private-cache"; +/* +** nmh constants: standard file names +** +** Important: Adjust uip/mmh.sh if you make changes here! +*/ -/* profile entry for external ftp access command */ -char *nmhaccessftp = "nmh-access-ftp"; +/* default name of the mail storage */ +char *mailstore = "Mail"; -char *mhlibdir = NMHLIBDIR; -char *mhetcdir = NMHETCDIR; +/* default name of user profile */ +char *mmhdir = ".mmh"; -/* - * nmh not-so constants - */ +/* default name of user profile */ +char *profile = "profile"; -/* - * Default name for the nmh context file. - */ +/* default name for the nmh context file */ char *context = "context"; /* - * Default name of file for public sequences. If NULL, - * then nmh will use private sequences by default, unless the - * user defines a value using the "mh-sequences" profile entry. - */ -#ifdef NOPUBLICSEQ -char *mh_seq = NULL; -#else +** Default name of file for public sequences. Gets overridden +** by a `Mh-Sequences' entry in the user's profile. Set to NULL +** or the empty string to use private sequences by default. +*/ char *mh_seq = ".mh_sequences"; -#endif - -/* - * nmh globals - */ -char ctxflags; /* status of user's context */ -char *invo_name; /* command invocation name */ -char *mypath; /* user's $HOME */ -char *defpath; /* pathname of user's profile */ -char *ctxpath; /* pathname of user's context */ -struct node *m_defs; /* profile/context structure */ +/* standard component files */ +char *components = "components"; /* comp */ +char *replcomps = "replcomps"; /* repl */ +char *replgroupcomps = "replgroupcomps"; /* repl -group */ +char *forwcomps = "forwcomps"; /* forw */ +char *distcomps = "distcomps"; /* dist */ +char *rcvdistcomps = "rcvdistcomps"; /* rcvdist */ +char *digestcomps = "digestcomps"; /* forw -digest */ -/* - * nmh processes - */ +/* standard format (filter) files */ +char *mhlformat = "mhl.format"; /* show */ +char *mhlreply = "mhl.reply"; /* repl */ -/* - * This is the program to process MIME composition files - */ -char *buildmimeproc = nmhbindir (/mhbuild); -/* - * This is the program to `cat' a file. - */ -char *catproc = "/bin/cat"; /* - * mhl runs this program as a visual-end. - */ +** standard names for: mail folders, sequences, and profile entries +*/ -char *faceproc = NULL; +/* some default folder names */ +char *defaultfolder = "+inbox"; +char *draftfolder = "+drafts"; +char *trashfolder = "+trash"; -/* - * This program is usually called directly by users, but it is - * also invoked by the post program to process an "Fcc", or by - * comp/repl/forw/dist to refile a draft message. - */ +char *inbox = "Inbox"; /* profile entry name to specify the default folder */ +char *curfolder = "Current-Folder"; -char *fileproc = nmhbindir (/refile); +/* predefined sequences */ +char *seq_all = "a"; +char *seq_beyond = "b"; /* the previous `new' sequence */ +char *seq_cur = "c"; +char *seq_first = "f"; +char *seq_last = "l"; +char *seq_next = "n"; +char *seq_prev = "p"; +char *seq_unseen = "u"; +char *seq_neg = "!"; -/* - * This program is called to incorporate messages into a folder. - */ +char *usequence = "Unseen-Sequence"; +char *psequence = "Previous-Sequence"; +char *nsequence = "Sequence-Negation"; -char *incproc = nmhbindir (/inc); +/* profile entries for storage locations */ +char *nmhstorage = "nmh-storage"; -/* - * When a user runs an nmh program for the first time, this program - * is called to create his nmh profile, and mail directory. - */ +/* Default header field names */ +char *attach_hdr = "Attach"; +char *sign_hdr = "Sign"; +char *enc_hdr = "Enc"; -char *installproc = nmhlibdir (/install-mh); +/* the tool to query the mime type of a file */ +char *mimetypequery = "Mime-Type-Query"; +char *mimetypequeryproc = "file -b --mime"; -/* - * This is the default program invoked by a "list" response - * at the "What now?" prompt. It is also used by the draft - * folder facility in comp/dist/forw/repl to display the - * draft message. - */ -char *lproc = DEFAULT_PAGER; /* - * This is the path for the Bell equivalent mail program. - */ - -char *mailproc = nmhbindir (/mhmail); +** nmh default programs +*/ /* - * This is used by mhl as a front-end. It is also used - * by mhn as the default method of displaying message bodies - * or message parts of type text/plain. - */ - -char *moreproc = DEFAULT_PAGER; - -/* - * This is the program (mhl) used to filter messages. It is - * used by mhn to filter and display the message headers of - * MIME messages. It is used by repl/forw (with -filter) - * to filter the message to which you are replying/forwarding. - * It is used by send/post (with -filter) to filter the message - * for "Bcc:" recipients. - */ - -char *mhlproc = nmhlibdir (/mhl); - -/* - * This is the super handy BBoard reading program, which is - * really just the nmh shell program. - */ - -char *mshproc = nmhbindir (/msh); - -/* - * This program is called to pack a folder. - */ - -char *packproc = nmhbindir (/packf); +** This is the default program invoked by a "list" or "display" response +** at the "What now?" prompt. It will be given the absolute pathname of +** the message to show. The string ``show -file'' is most likely what you +** want to be you listproc. +*/ +char *listproc = "show -file"; /* - * This is the delivery program called by send to actually - * deliver mail to users. This is the interface to the MTS. - */ - -char *postproc = nmhlibdir (/post); +** This is used by mhl as a front-end. It is also used +** by show(1) as the default method of displaying message bodies +** or message parts of type text/plain. +*/ +char *defaultpager = "more"; /* - * This is program is called by slocal to handle - * the action `folder' or `+'. - */ - -char *rcvstoreproc = nmhlibdir (/rcvstore); - -/* - * This program is called to remove a folder. - */ - -char *rmfproc = nmhbindir (/rmf); - -/* - * This program is called to remove a message by rmm or refile -nolink. - * It's usually empty, which means to rename the file to a backup name. - */ - -char *rmmproc = NULL; +** This is the editor invoked by the various message +** composition programs. It SHOULD be a full screen +** editor, such as vi or emacs, but any editor will work. +*/ +char *defaulteditor = "vi"; /* - * This program is usually called by the user's whatnowproc, but it - * may also be called directly to send a message previously composed. - */ - -char *sendproc = nmhbindir (/send); +** This program is called after comp, et. al., have built a draft +*/ +char *whatnowproc = "whatnow"; /* - * This is the path to the program used by "show" - * to display non-text (MIME) messages. - */ - -char *showmimeproc = nmhbindir (/mhshow); +** This is the sendmail interface to use for sending mail. +*/ +char *sendmail = SENDMAILPATH; /* - * This is the default program called by "show" to filter - * and display standard text (non-MIME) messages. It can be - * changed to a pager (such as "more" or "less") if you prefer - * that such message not be filtered in any way. - */ - -char *showproc = nmhlibdir (/mhl); - -/* - * This program is called by vmh as the back-end to the window management - * protocol - */ - -char *vmhproc = nmhbindir (/msh); - -/* - * This program is called after comp, et. al., have built a draft - */ - -char *whatnowproc = nmhbindir (/whatnow); - -/* - * This program is called to list/validate the addresses in a message. - */ +** This is the path to the system mail spool directory (e.g. `/var/mail'). +*/ +char *mailspool = MAILSPOOL; -char *whomproc = nmhbindir (/whom); /* - * This is the editor invoked by the various message - * composition programs. It SHOULD be a full screen - * editor, such as vi or emacs, but any editor will work. - */ +** file stuff +*/ -char *defaulteditor = DEFAULT_EDITOR; - -/* - * This is the global nmh alias file. It is somewhat obsolete, since - * global aliases should be handled by the Mail Transport Agent (MTA). - */ - -char *AliasFile = nmhetcdir (/MailAliases); - -/* - * File protections - */ +/* +** Folders (directories) are created with this protection (mode) +*/ +char *foldprot = "0700"; /* - * Folders (directories) are created with this protection (mode) - */ +** Every NEW message will be created with this protection. When a +** message is filed it retains its protection. +*/ +char *msgprot = "0600"; -char *foldprot = DEFAULT_FOLDER_MODE; -/* - * Every NEW message will be created with this protection. When a - * message is filed it retains its protection, so this only applies - * to messages coming in through inc. - */ -char *msgprot = DEFAULT_MESSAGE_MODE; +/* +** Standard yes/no switches structure +*/ +struct swit anoyes[] = { + { "no", 0 }, + { "yes", 0 }, + { NULL, 0 } +}; diff --git a/config/version.sh b/config/version.sh index 1ff7eed..5a9628c 100755 --- a/config/version.sh +++ b/config/version.sh @@ -1,13 +1,13 @@ #!/bin/sh # -# version.sh -- script to create version string(s) for nmh. +# version.sh -- script to create version string(s) for mmh. # # You need to pass the script the version number to use. # if [ -z "$1" ]; then - echo "usage: version.sh VERSION" 1>&2 - exit 1 + echo "usage: version.sh VERSION" 1>&2 + exit 1 fi VERSION=$1 @@ -18,25 +18,27 @@ HOSTNAME=unknown # Find out the name of the host we are compiling on for prog in uname hostname do - for dir in $PATH - do - if [ ! -f $dir/$prog ]; then - continue + for dir in $PATH + do + if [ ! -f $dir/$prog ]; then + continue + fi + case $prog in + uname) + HOSTNAME=`$prog -n` + ;; + hostname) + HOSTNAME=`$prog` + ;; + esac + break + done + if [ X"$HOSTNAME" != X -a X"$HOSTNAME" != Xunknown ]; then + break fi - case $prog in - uname) HOSTNAME=`$prog -n` - ;; - hostname) HOSTNAME=`$prog` - ;; - esac - break - done - if [ X"$HOSTNAME" != X -a X"$HOSTNAME" != Xunknown ]; then - break - fi done IFS=" " -echo "char *version_str = \"nmh-$VERSION [compiled on $HOSTNAME at `date`]\";" -echo "char *version_num = \"nmh-$VERSION\";" +echo "char *version_str = \"mmh-$VERSION [compiled on $HOSTNAME at `date`]\";" +echo "char *version_num = \"mmh-$VERSION\";" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..2633228 --- /dev/null +++ b/configure.ac @@ -0,0 +1,586 @@ +dnl +dnl configure.ac -- autoconf template for mmh +dnl + +dnl Move this up a bit +AC_PREREQ(2.61) +dnl (I was able to configure with autoconf-2.59 --meillo 2012-03-22) + +AC_INIT(mmh, m4_normalize(m4_include([VERSION]))) +AC_CONFIG_SRCDIR(h/nmh.h) +AC_CONFIG_HEADER(config.h) + +AC_CANONICAL_TARGET + +dnl --------------------- +dnl define a macro or two +dnl --------------------- + +AC_DEFUN(NMH_PROG_GNU_LIBTOOL, [ +if test -n "$LIBTOOL" ; then + tmptest=`$LIBTOOL --version 2>&1 | grep GNU` + if test x"$tmptest" != x ; then + GNU_LIBTOOL=1 + AC_SUBST(GNU_LIBTOOL)dnl + fi +fi +] ) + +echo "configuring for AC_PACKAGE_NAME-AC_PACKAGE_VERSION" +AC_SUBST(VERSION,AC_PACKAGE_VERSION)dnl + +dnl What date of mmh are we building? +DATE=`cat ${srcdir}/DATE` +echo "configuring for mmh dated $DATE" +AC_SUBST(DATE)dnl + +dnl -------------------------- +dnl CHECK COMMAND LINE OPTIONS +dnl -------------------------- + +dnl Do you want to debug mmh? +AC_ARG_ENABLE(debug, + AS_HELP_STRING([--enable-debug],[enable nmh code debugging])) +dnl The old redundant --enable-nmh-debug is deprecated and undocumented. +if test x"$enable_nmh_debug" = x"yes"; then + enable_debug=yes +fi + +dnl What method of locking to use? +AC_ARG_WITH(locking, + AS_HELP_STRING([--with-locking=@<:@dot|fcntl|flock|lockf@:>@], + [specify the file locking method])) + +if test x"$with_locking" = x"dot"; then + LOCKTYPE="dot" + AC_DEFINE(DOT_LOCKING, 1, [Define to use dot based file locking.])dnl +elif test x"$with_locking" = x"flock"; then + LOCKTYPE="flock" + AC_DEFINE(FLOCK_LOCKING, 1, [Define to use flock() based locking.])dnl +elif test x"$with_locking" = x"lockf"; then + LOCKTYPE="lockf" + AC_DEFINE(LOCKF_LOCKING, 1, [Define to use lockf() based locking.])dnl +elif test x"$with_locking" = x"fcntl"; then + LOCKTYPE="fcntl" + AC_DEFINE(FCNTL_LOCKING, 1, [Define to use fnctl() based locking.])dnl +else + LOCKTYPE="dot" + AC_DEFINE(DOT_LOCKING)dnl +fi + + +dnl ---------------------------------------------------- +dnl Default location is /usr/local/mmh/{bin,etc,lib,share/man} +dnl ---------------------------------------------------- +AC_PREFIX_DEFAULT(/usr/local/mmh) + + +dnl ------------------ +dnl CHECK THE COMPILER +dnl ------------------ +dnl We want these before the checks, +dnl so the checks can modify their values. +test -z "$CFLAGS" && CFLAGS= auto_cflags=1 +if test x"$enable_debug" = x"yes"; then + test -z "$LDFLAGS" && LDFLAGS=-g +fi + +AC_PROG_CC + +AC_CACHE_CHECK(whether compiler supports -Wno-pointer-sign, nmh_cv_has_noptrsign, +[nmh_saved_cflags="$CFLAGS" + CFLAGS="$CFLAGS -Wno-pointer-sign" + AC_TRY_COMPILE([],[],nmh_cv_has_noptrsign=yes,nmh_cv_has_noptrsign=no) + CFLAGS="$nmh_saved_cflags"]) + +dnl if the user hasn't specified CFLAGS, then +dnl if compiler is gcc, then +dnl use -O2 and some warning flags +dnl else use -O +dnl We use -Wall; if the compiler supports it we also use -Wno-pointer-sign, +dnl because gcc 4 now produces a lot of new warnings which are probably mostly +dnl spurious and which in any case we don't want to deal with now. +if test "$nmh_cv_has_noptrsign" = "yes"; then + nmh_gcc_warnflags="-Wall -Wno-pointer-sign" +else + nmh_gcc_warnflags="-Wall" +fi + +if test -n "$auto_cflags"; then + if test x"$enable_debug" = x"yes"; then + if test -n "$GCC"; then + test -z "$CFLAGS" && CFLAGS="$nmh_gcc_warnflags -g" || CFLAGS="$CFLAGS $nmh_gcc_warnflags -g" + else + test -z "$CFLAGS" && CFLAGS=-g || CFLAGS="$CFLAGS -g" + fi + else + if test -z "$LDFLAGS"; then + case "$build_os" in + darwin*) + LDFLAGS= + ;; + *) + LDFLAGS=-s + ;; + esac + fi + if test -n "$GCC"; then + test -z "$CFLAGS" && CFLAGS="$nmh_gcc_warnflags -O2" || CFLAGS="$CFLAGS $nmh_gcc_warnflags -O2" + else + test -z "$CFLAGS" && CFLAGS=-O || CFLAGS="$CFLAGS -O" + fi + fi +fi + +AC_C_CONST dnl Does compiler support `const'. + +dnl ------------------ +dnl CHECK FOR PROGRAMS +dnl ------------------ +AC_PROG_MAKE_SET dnl Does make define $MAKE +AC_PROG_INSTALL dnl Check for BSD compatible `install' +AC_PROG_RANLIB dnl Check for `ranlib' +AC_PROG_AWK dnl Check for mawk,gawk,nawk, then awk +AC_PROG_LEX dnl Check for lex/flex + +dnl Look for `cut' +pathtmp=/usr/bin:/bin:/usr/local/bin:/usr/xpg4/bin:/usr/ucb +AC_PATH_PROG(cutpath, cut, no, [$pathtmp]) + +dnl ---------------------------------------------- +dnl check for lclint, and lint if it doesn't exist +dnl ---------------------------------------------- +AC_CHECK_PROG(linttmp1, lclint, lclint, no)dnl +if test x$ac_cv_prog_linttmp1 != xno ; then + LINT=$ac_cv_prog_linttmp1 + LINTFLAGS="-weak +posixlib -macrovarprefixexclude" +else + AC_CHECK_PROG(linttmp2, lint, lint, no)dnl + if test x$ac_cv_prog_linttmp2 != xno ; then + LINT=$ac_cv_prog_linttmp2 + LINTFLAGS="" + else + LINT="echo 'No lint program found'" + LINTFLAGS="" + fi +fi +AC_SUBST(LINT)dnl +AC_SUBST(LINTFLAGS)dnl + +dnl try to figure out which one we've got +AC_CHECK_PROG(LIBTOOL, libtool, libtool, , [$pathtmp]) +NMH_PROG_GNU_LIBTOOL + +dnl Check for lorder and tsort commands +AC_CHECK_PROG(LORDER, lorder, lorder, no)dnl +AC_CHECK_PROG(TSORT, tsort, tsort, no)dnl + +dnl If either doesn't exist, replace them with echo and cat +if test x$ac_cv_prog_LORDER != xlorder -o x$ac_cv_prog_TSORT != xtsort; then + LORDER=echo + TSORT=cat + AC_SUBST(LORDER)dnl + AC_SUBST(TSORT)dnl +dnl Mac OS X has lorder, but sh is too broken for it to work +dnl elif test -z "`lorder config/config.c 2>&1 | grep config/config.c`" ; then +dnl LORDER=echo +dnl TSORT=cat +dnl AC_SUBST(LORDER)dnl +dnl AC_SUBST(TSORT)dnl +fi + +dnl Check whether tsort can deal with loops +AC_CACHE_CHECK(whether tsort can deal with loops, nmh_cv_tsort_loop, + [if test -z "`echo a b b a | tsort 2>/dev/null | grep a`" ; then + nmh_cv_tsort_loop=no + else + nmh_cv_tsort_loop=yes + fi]) +if test x$nmh_cv_tsort_loop = xno ; then + LORDER=echo + TSORT=cat + AC_SUBST(LORDER)dnl + AC_SUBST(TSORT)dnl +fi + +dnl Look for `ls' +pathtmp=/usr/bin:/bin:/usr/local/bin:/usr/xpg4/bin:/usr/ucb +AC_PATH_PROG(lspath, ls, no, [$pathtmp]) + +dnl See how we get ls to display the owner and the group +if test "$lspath" != "no"; then + AC_CACHE_CHECK(how to get ls to show us the group ownership of a file, + nmh_cv_ls_grpopt, + [if test x"`$lspath -dl / | $AWK '{print $9}'`" = x"/"; then + dnl There were 9 parameters, so unless this is a really bizarre, nonstandard + dnl ls, it would seem -l gave us both the user and group. On this type of + dnl ls, -g makes _only_ the group be displayed (and not the user). + nmh_cv_ls_grpopt="-l" + else + dnl Looks like -l only gave us the user, so we need -g to get the group too. + nmh_cv_ls_grpopt="-lg" + fi]) +fi + +dnl Look for `sendmail' +pathtmp=/usr/lib:/usr/sbin:/usr/etc:/usr/ucblib:/usr/bin:/bin +AC_PATH_PROG(sendmailpath, sendmail, /usr/sbin/sendmail, [$pathtmp]) + +dnl Look for `vi' +pathtmp=/usr/bin:/bin:/usr/ucb:/usr/local/bin +AC_PATH_PROG(vipath, vi, /bin/vi, [$pathtmp]) + +dnl ---------------------------------------------------------- +dnl FIND MAIL SPOOL AND SEE IF WE NEED TO MAKE inc SETGID MAIL +dnl ---------------------------------------------------------- +AC_CACHE_CHECK(where mail spool is located, nmh_cv_mailspool, +[for mailspool in /var/mail dnl + /var/spool/mail dnl + /usr/spool/mail dnl + /dev/null; dnl Just in case we fall through +do + test -d $mailspool && break +done +nmh_cv_mailspool=$mailspool +]) +mailspool=$nmh_cv_mailspool +AC_SUBST(mailspool)dnl + +dnl See whether the mail spool directory is world-writable. +if test "$lspath" != "no" -a "$cutpath" != "no"; then + AC_CACHE_CHECK(whether the mail spool is world-writable, + nmh_cv_mailspool_world_writable, + [if test "`$lspath -dlL $mailspool | $cutpath -c9`" = "-"; then + nmh_cv_mailspool_world_writable=no + else + nmh_cv_mailspool_world_writable=yes + fi]) +fi + +dnl Also, check for liblockfile (as found on Debian systems) +AC_CHECK_HEADER(lockfile.h, AC_CHECK_LIB(lockfile, lockfile_create) ) + +dnl and whether its companion program dotlockfile is setgid +AC_PATH_PROG(dotlockfilepath, dotlockfile, no) +if test "$ac_cv_lib_lockfile_lockfile_create" != "no" ; then + if test "$ac_cv_path_dotlockfilepath" != "no" ; then + AC_CACHE_CHECK(whether dotlockfile is setgid, nmh_cv_dotlockfile_setgid, + [ if test -g "$ac_cv_path_dotlockfilepath" ; then + nmh_cv_dotlockfile_setgid=yes + else + nmh_cv_dotlockfile_setgid=no + fi]) + fi +fi + +dnl If mailspool is not world-writable and dotlockfile is not setgid, +dnl we need to #define MAILGROUP to 1 and make inc setgid. +if test x"$LOCKTYPE" = x"dot" -a x"$nmh_cv_mailspool_world_writable" = x"no" -a x"$nmh_cv_dotlockfile_setgid" != x"yes" ; then + dnl do we really need both of these? + AC_DEFINE(MAILGROUP,1, + [Define to 1 if you need to make `inc' set-group-id because your mail spool is not world writable. There are no guarantees as to the safety of doing this, but this #define will add some extra security checks.])dnl + SETGID_MAIL=1 +fi +AC_SUBST(SETGID_MAIL)dnl + +dnl Use ls to see which group owns the mail spool directory. +AC_CACHE_CHECK(what group owns the mail spool, nmh_cv_ls_mail_grp, +[nmh_cv_ls_mail_grp=`$lspath -dL $nmh_cv_ls_grpopt $mailspool|$AWK '{print $4}'` +]) +MAIL_SPOOL_GRP=$nmh_cv_ls_mail_grp +AC_SUBST(MAIL_SPOOL_GRP)dnl + +dnl ------------------ +dnl CHECK HEADER FILES +dnl ------------------ + +dnl On glibc we need to define at least the '_XOPEN_SOURCE' level of features, +dnl or wchar.h doesn't declare a prototype for wcwidth(). But if we only define +dnl that level then db.h won't compile. So we define _GNU_SOURCE which turns +dnl on everything. Perhaps other OSes need some feature switch set to get wcwidth() +dnl declared; if so they should have an entry added to this case statement. +dnl NB that we must define this on the compiler command line, not in config.h, +dnl because it must be set before any system header is included and there's no +dnl portable way to make sure that files generated by lex include config.h +dnl before system header files. + +case "$target_os" in + linux*) + # Like DEFS, but doesn't get stomped on by configure when using config.h: + OURDEFS="$OURDEFS -D_GNU_SOURCE" + ;; +esac +AC_SUBST(OURDEFS) + +AC_HEADER_STDC +AC_HEADER_TIOCGWINSZ +AC_CHECK_HEADERS(fcntl.h crypt.h termcap.h \ + langinfo.h wchar.h wctype.h iconv.h \ + sys/param.h sys/time.h sys/stream.h ) + +dnl +dnl Checks for _IO_write_ptr. A Linuxism used by nmh on linux. We +dnl really use a whole set of them, but this check should be +dnl sufficient. +dnl +AC_CHECK_HEADER(libio.h, [ + AC_EGREP_HEADER(_IO_write_ptr, libio.h, [ + AC_DEFINE(LINUX_STDIO,1,[Use the Linux _IO_*_ptr defines from .]) ]) ]) + +AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1, + [Define to 1 if `struct winsize' requires .]),, +[[#if HAVE_SYS_STREAM_H +# include +#endif +]]) + +dnl --------------- +dnl CHECK FUNCTIONS +dnl --------------- +AC_CHECK_FUNCS(nl_langinfo mbtowc wcwidth) + +dnl Look for the initgroups() declaration. On AIX 4.[13], Solaris 4.1.3, and +dnl ULTRIX 4.2A the function is defined in libc but there's no declaration in +dnl any system header. +dnl +dnl On Solaris 2.[456], the declaration is in . On HP-UX 9-11 and +dnl (reportedly) FreeBSD 3.[23], it's in . Any other locations we +dnl need to check? +AH_TEMPLATE(INITGROUPS_HEADER, [Define to the header containing the declaration of `initgroups'.]) +AC_EGREP_HEADER(initgroups, grp.h, AC_DEFINE(INITGROUPS_HEADER, ), + AC_EGREP_HEADER(initgroups, unistd.h, + AC_DEFINE(INITGROUPS_HEADER, ))) + +dnl Check for multibyte character set support +if test "x$ac_cv_header_wchar_h" = "xyes" -a "x$ac_cv_header_wctype_h" = "xyes" \ + -a "x$ac_cv_func_wcwidth" = "xyes" -a "x$ac_cv_func_mbtowc" = "xyes"; then + AC_DEFINE(MULTIBYTE_SUPPORT, 1, + [Define to enable support for multibyte character sets.]) +fi + +dnl ------------------- +dnl CHECK FOR LIBRARIES +dnl ------------------- +dnl Check location of modf +AC_CHECK_FUNC(modf, , AC_CHECK_LIB(m, modf)) + +dnl Checks for network libraries (nsl, socket) +NMH_CHECK_NETLIBS + +termcap_curses_order="termcap curses ncurses" +for lib in $termcap_curses_order; do + AC_CHECK_LIB(${lib}, tgetent, [TERMLIB="-l$lib"; break]) +done +AC_SUBST(TERMLIB)dnl +if test "x$TERMLIB" = "x"; then + echo 'Could not find tgetent() in any library.' + echo 'Is there a ncurses-devel package that you can install?' + exit 1 +fi + + +dnl --------------- +dnl CHECK FOR ICONV +dnl --------------- + +dnl Find iconv. It may be in libiconv and may be iconv() or libiconv() +if test "x$ac_cv_header_iconv_h" = "xyes"; then + AC_CHECK_FUNC(iconv, ac_found_iconv=yes, ac_found_iconv=no) + if test "x$ac_found_iconv" = "xno"; then + AC_CHECK_LIB(iconv, iconv, ac_found_iconv=yes) + if test "x$ac_found_iconv" = "xno"; then + AC_CHECK_LIB(iconv, libiconv, ac_found_iconv=yes) + fi + if test "x$ac_found_iconv" != "xno"; then + LIBS="-liconv $LIBS" + fi + else + dnl Handle case where there is a native iconv but iconv.h is from libiconv + AC_CHECK_DECL(_libiconv_version, + [ AC_CHECK_LIB(iconv, libiconv, LIBS="-liconv $LIBS") ],, + [ #include ]) + fi +fi +if test "x$ac_found_iconv" = xyes; then + AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) +fi + +dnl Check if iconv uses const in prototype declaration +if test "x$ac_found_iconv" = "xyes"; then + AC_CACHE_CHECK(for iconv declaration, ac_cv_iconv_const, + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[#ifdef __cplusplus + "C" + #endif + #if defined(__STDC__) || defined(__cplusplus) + size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); + #else + size_t iconv(); + #endif]])], + [ac_cv_iconv_const=], + [ac_cv_iconv_const=const])]) + AC_DEFINE_UNQUOTED([ICONV_CONST], $ac_cv_iconv_const, + [Define as const if the declaration of iconv() needs const.]) +fi + + +dnl --------------------- +dnl CHECK TERMCAP LIBRARY +dnl --------------------- + +dnl Add the termcap library, so that the following configure +dnl tests will find it when it tries to link test programs. +nmh_save_LIBS="$LIBS" +LIBS="$TERMLIB $LIBS" + +dnl Check if tgetent accepts NULL (and will allocate its own termcap buffer) +dnl Some termcaps reportedly accept a zero buffer, but then dump core +dnl in tgetstr(). +dnl Under Cygwin test program crashes but exit code is still 0. So, +dnl we test for a file that porgram should create +AH_TEMPLATE([TGETENT_ACCEPTS_NULL], +[Define to 1 if tgetent() accepts NULL as a buffer.]) +AC_CACHE_CHECK(if tgetent accepts NULL, +nmh_cv_func_tgetent_accepts_null, +[AC_TRY_RUN([ +main() +{ + char buf[4096]; + int r1 = tgetent(buf, "vt100"); + int r2 = tgetent(NULL,"vt100"); + if (r1 >= 0 && r1 == r2) { + char tbuf[1024], *u; + u = tbuf; + tgetstr("cl", &u); + creat("conftest.tgetent", 0640); + } + exit((r1 != r2) || r2 == -1); +} +], + if test -f conftest.tgetent; then + nmh_cv_func_tgetent_accepts_null=yes + else + nmh_cv_func_tgetent_accepts_null=no + fi, + nmh_cv_func_tgetent_accepts_null=no, + nmh_cv_func_tgetent_accepts_null=no)]) +if test x$nmh_cv_func_tgetent_accepts_null = xyes; then + AC_DEFINE(TGETENT_ACCEPTS_NULL) +fi +AC_CACHE_CHECK(if tgetent returns 0 on success, +nmh_cv_func_tgetent_zero_success, +[AC_TRY_RUN([ +main() +{ + char buf[4096]; + int r1 = tgetent(buf, "!@#$%^&*"); + int r2 = tgetent(buf, "vt100"); + if (r1 < 0 && r2 == 0) { + char tbuf[1024], *u; + u = tbuf; + tgetstr("cl", &u); + creat("conftest.tgetent0", 0640); + } + exit(r1 == r2); +} +], + if test -f conftest.tgetent0; then + nmh_cv_func_tgetent_zero_success=yes + else + nmh_cv_func_tgetent_zero_success=no + fi, + nmh_cv_func_tgetent_zero_success=no, + nmh_cv_func_tgetent_zero_success=no)]) +AH_TEMPLATE([TGETENT_SUCCESS], +[Define to what tgetent() returns on success (0 on HP-UX X/Open curses).]) +if test x$nmh_cv_func_tgetent_zero_success = xyes; then + AC_DEFINE(TGETENT_SUCCESS, 0) +else + AC_DEFINE(TGETENT_SUCCESS, 1) +fi + +dnl Now put the libraries back to what it was before we +dnl starting checking the termcap library. +LIBS="$nmh_save_LIBS" + +dnl -------------- +dnl CHECK TYPEDEFS +dnl -------------- +AC_TYPE_PID_T +AC_TYPE_OFF_T +AC_TYPE_UID_T +AC_TYPE_MODE_T +AC_TYPE_SIZE_T + +dnl ---------------- +dnl CHECK STRUCTURES +dnl ---------------- + +dnl For platforms such as FreeBSD that have tm_gmtoff in struct tm. +dnl (FreeBSD has a timezone() function but not a timezone global +dnl variable that is visible). +AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[#include ]) + +AC_STRUCT_DIRENT_D_TYPE + +dnl Where is located? Needed as input for signames.awk +AC_CACHE_CHECK(where signal.h is located, nmh_cv_path_signal_h, +[for SIGNAL_H in /usr/include/bsd/sys/signal.h dnl Next + /usr/include/asm/signal.h dnl Linux 1.3.0 and above + /usr/include/asm/signum.h dnl some versions of Linux/Alpha + /usr/include/linux/signal.h dnl Linux up to 1.2.11 + /usr/include/sys/signal.h dnl Almost everybody else + /dev/null; dnl Just in case we fall through +do + test -f $SIGNAL_H && \ + grep '#[ ]*define[ ][ ]*SIG[0-9A-Z]*[ ]*[0-9][0-9]*' $SIGNAL_H > /dev/null && \ + break +done +nmh_cv_path_signal_h=$SIGNAL_H +]) +SIGNAL_H=$nmh_cv_path_signal_h +AC_SUBST(SIGNAL_H)dnl + + +dnl ---------------- +dnl OUTPUT MAKEFILES +dnl ---------------- +AC_CONFIG_FILES(Makefile config/Makefile h/Makefile sbr/Makefile uip/Makefile \ + etc/Makefile docs/Makefile man/Makefile) +AC_CONFIG_COMMANDS([stamp],[test -z "$CONFIG_HEADERS" || echo > stamp-h]) +AC_OUTPUT + +dnl These odd looking assignments are done to expand out unexpanded +dnl variables in bindir et al (for instance mandir is '${datarootdir}/man', +dnl but expanding that gives '${prefix}/share/man', so we need to expand +dnl again to get the final answer. +dnl We only use the expanded versions to print the install paths in +dnl the final summary and should use them nowhere else (see the autoconf +dnl docs for the rationale for bindir etc being unexpanded). +eval "nmhbin=${bindir}"; eval "nmhbin=${nmhbin}" +eval "nmhsysconf=${sysconfdir}"; eval "nmhsysconf=${nmhsysconf}" +eval "nmhlib=${libdir}"; eval "nmhlib=${nmhlib}" +eval "nmhman=${mandir}"; eval "nmhman=${nmhman}" + +echo " +mmh configuration +----------------- +mmh version : AC_PACKAGE_VERSION +target os : ${target} +compiler : ${CC} +compiler flags : ${CFLAGS} +linker flags : ${LDFLAGS} +definitions : ${OURDEFS} +source code location : ${srcdir} + +binary install path : ${nmhbin} +library install path : ${nmhlib} +config install path : ${nmhsysconf} +man page install path : ${nmhman} + +sendmail path : ${sendmailpath} +mail spool : ${mailspool} + +file locking type : ${LOCKTYPE} +" diff --git a/configure.in b/configure.in deleted file mode 100644 index e93e173..0000000 --- a/configure.in +++ /dev/null @@ -1,1017 +0,0 @@ -dnl -dnl configure.in -- autoconf template for nmh -dnl - -dnl Move this up a bit -AC_PREREQ(2.61) - -AC_INIT(nmh, m4_normalize(m4_include([VERSION]))) -AC_CONFIG_SRCDIR(h/nmh.h) -AC_CONFIG_HEADER(config.h) - -AC_CANONICAL_TARGET - -dnl --------------------- -dnl define a macro or two -dnl --------------------- - -AC_DEFUN(NMH_PROG_GNU_LIBTOOL, [ -if test -n "$LIBTOOL" ; then - tmptest=`$LIBTOOL --version 2>&1 | grep GNU` - if test x"$tmptest" != x ; then - GNU_LIBTOOL=1 - AC_SUBST(GNU_LIBTOOL)dnl - fi -fi -] ) - -echo "configuring for AC_PACKAGE_NAME-AC_PACKAGE_VERSION" -AC_SUBST(VERSION,AC_PACKAGE_VERSION)dnl - -dnl What date of nmh are we building? -DATE=`cat ${srcdir}/DATE` -echo "configuring for nmh dated $DATE" -AC_SUBST(DATE)dnl - -dnl -------------------------- -dnl CHECK COMMAND LINE OPTIONS -dnl -------------------------- - -dnl Do you want to debug nmh? -AC_ARG_ENABLE(debug, - AS_HELP_STRING([--enable-debug],[enable nmh code debugging])) -dnl The old redundant --enable-nmh-debug is deprecated and undocumented. -if test x"$enable_nmh_debug" = x"yes"; then - enable_debug=yes -fi - -dnl Allow users to send email from addresses other than their default? -AC_ARG_ENABLE(masquerade, - AS_HELP_STRING([--enable-masquerade='draft_from mmailid username_extension'], - [enable up to 3 types of address masquerading]), - [if test x"$enable_masquerade" = x"yes"; then - masquerade="draft_from mmailid username_extension" - else - masquerade="$enable_masquerade" - fi], [masquerade="draft_from mmailid username_extension"]) -AC_SUBST(masquerade)dnl - -dnl Do you want mhe support? -AC_ARG_ENABLE(mhe, - AS_HELP_STRING([--disable-mhe],[disable mhe support])) - -dnl mhe support is on by default, so define it unless --disable-mhe or the -dnl deprecated, undocumented --disable-nmh-mhe are specified. -if test x"$enable_mhe" != x"no" -a x"$enable_nmh_mhe" != x"no"; then - AC_DEFINE(MHE, 1, - [Define to compile in support for the Emacs front-end mh-e.])dnl -fi - -dnl Do you want client-side support for pop? -AC_ARG_ENABLE(pop, - AS_HELP_STRING([--enable-pop], [enable client-side support for plain POP3])) -dnl The old redundant --enable-nmh-pop is deprecated and undocumented. -if test x"$enable_nmh_pop" = x"yes"; then - enable_pop=yes -fi - -dnl Do you want to disable use of locale functions -AH_TEMPLATE([LOCALE], -[Undefine if you don't want locale features. By default this is defined.]) -AC_ARG_ENABLE([locale], -AC_HELP_STRING([--disable-locale], [turn off locale features]), -[if test x$enableval = xyes; then - AC_DEFINE(LOCALE) -fi], -AC_DEFINE(LOCALE) -) - -dnl Do you want client-side support for using SASL for authentication? -dnl Note that this code will be enabled for both POP and SMTP -AC_ARG_WITH(cyrus-sasl, AS_HELP_STRING([--with-cyrus-sasl], - [Enable SASL support via the Cyrus SASL library])) -if test x"$with_cyrus_sasl" != x -a x"$with_cyrus_sasl" != x"no"; then - AC_DEFINE(CYRUS_SASL, 1, - [Define to use the Cyrus SASL library for authentication of POP and SMTP.])dnl - if test x"$with_cyrus_sasl" != xyes; then - AC_MSG_WARN([Arguments to --with-cyrus-sasl now ignored]) - AC_MSG_WARN([Please pass the appropriate arguments to CPPFLAGS/LDFLAGS]) - fi - sasl_support=yes -else - sasl_support=no -fi - -dnl Do you want client-side support for encryption with TLS? -AC_ARG_WITH(tls, AS_HELP_STRING([--with-tls], [Enable TLS support])) -if test x"$with_tls" != x -a x"$with_tls" != x"no"; then - AC_DEFINE(TLS_SUPPORT, 1, [Support TLS for session encryption.])dnl - tls_support=yes -else - tls_support=no -fi - -dnl What should be the default editor? -AC_ARG_WITH(editor, - AS_HELP_STRING([--with-editor=EDITOR],[specify the default editor])) - -if test -n "$with_editor"; then - editorpath="$with_editor" -fi - -dnl Set the backup prefix -AC_ARG_WITH([hash-backup], - AS_HELP_STRING([--with-hash-backup],[use # as the backup prefix (default: ,)])) -if test x"$with_hash_backup" != x -a x"$with_hash_backup" != x"no"; then - backup_prefix="#" -else - backup_prefix="," -fi -AC_DEFINE_UNQUOTED(BACKUP_PREFIX, "$backup_prefix", - [The prefix that is prepended to the name of message files when they are "removed" by rmm. This should typically be `,' or `#'.])dnl - -dnl After we know if we're including apop and kpop support, do pop stuff -if test x"$enable_pop" = x"yes"; then - AC_DEFINE(POP, 1, - [Define this to compile client-side support for pop into inc and msgchk.])dnl - POPLIB=popsbr.o - POPSED='/^%nmhbeginpop%/d;/^%nmhendpop%/d' -else - POPSED='/^%nmhbeginpop%/,/^%nmhendpop%/d' -fi -AC_SUBST(POPLIB)dnl -AC_SUBST(POPSED)dnl - -dnl What method of locking to use? -AC_ARG_WITH(locking, - AS_HELP_STRING([--with-locking=@<:@dot|fcntl|flock|lockf@:>@], - [specify the file locking method])) - -if test x"$with_locking" = x"dot"; then - LOCKTYPE="dot" - AC_DEFINE(DOT_LOCKING, 1, [Define to use dot based file locking.])dnl -elif test x"$with_locking" = x"flock"; then - LOCKTYPE="flock" - AC_DEFINE(FLOCK_LOCKING, 1, [Define to use flock() based locking.])dnl -elif test x"$with_locking" = x"lockf"; then - LOCKTYPE="lockf" - AC_DEFINE(LOCKF_LOCKING, 1, [Define to use lockf() based locking.])dnl -elif test x"$with_locking" = x"fcntl"; then - LOCKTYPE="fcntl" - AC_DEFINE(FCNTL_LOCKING, 1, [Define to use fnctl() based locking.])dnl -else - LOCKTYPE="dot" - AC_DEFINE(DOT_LOCKING)dnl -fi - -dnl What method of posting should post use? -AC_ARG_WITH(mts, - AS_HELP_STRING([--with-mts=@<:@smtp|sendmail@:>@], - [specify the default mail transport agent/service])) - -if test x"$with_mts" = x"smtp"; then - MTS="smtp" -elif test x"$with_mts" = x"sendmail"; then - MTS="sendmail" -else - MTS="smtp" -fi -AC_SUBST(MTS)dnl - -dnl Both the smtp and sendmail mail transport services use the smtp code -AC_DEFINE(SMTPMTS, 1, - [Define if you want SMTP (simple mail transport protocol) support.])dnl - -dnl What should be the default pager? -AC_ARG_WITH(pager, - AS_HELP_STRING([--with-pager=PAGER],[specify the default pager])) - -if test -n "$with_pager"; then - pagerpath="$with_pager" -fi - -dnl What should be the default mail server(s)? -AC_ARG_WITH(smtpservers, - AS_HELP_STRING([--with-smtpservers='SMTPSERVER1@<:@ SMTPSERVER2...@:>@'], - [specify the default SMTP server(s) @<:@localhost@:>@])) -if test -n "$with_smtpservers"; then - smtpservers="$with_smtpservers" -else - smtpservers="localhost" -fi -AC_SUBST(smtpservers)dnl - -dnl ---------------------------------------------------- -dnl Default location is /usr/local/nmh/{bin,etc,lib,man} -dnl ---------------------------------------------------- -AC_PREFIX_DEFAULT(/usr/local/nmh) - -dnl ------------------ -dnl CHECK THE COMPILER -dnl ------------------ -dnl We want these before the checks, -dnl so the checks can modify their values. -test -z "$CFLAGS" && CFLAGS= auto_cflags=1 -if test x"$enable_debug" = x"yes"; then - test -z "$LDFLAGS" && LDFLAGS=-g -fi - -AC_PROG_CC - -AC_CACHE_CHECK(whether compiler supports -Wno-pointer-sign, nmh_cv_has_noptrsign, -[nmh_saved_cflags="$CFLAGS" - CFLAGS="$CFLAGS -Wno-pointer-sign" - AC_TRY_COMPILE([],[],nmh_cv_has_noptrsign=yes,nmh_cv_has_noptrsign=no) - CFLAGS="$nmh_saved_cflags"]) - -dnl if the user hasn't specified CFLAGS, then -dnl if compiler is gcc, then -dnl use -O2 and some warning flags -dnl else use -O -dnl We use -Wall; if the compiler supports it we also use -Wno-pointer-sign, -dnl because gcc 4 now produces a lot of new warnings which are probably mostly -dnl spurious and which in any case we don't want to deal with now. -if test "$nmh_cv_has_noptrsign" = "yes"; then - nmh_gcc_warnflags="-Wall -Wno-pointer-sign" -else - nmh_gcc_warnflags="-Wall" -fi - -if test -n "$auto_cflags"; then - if test x"$enable_debug" = x"yes"; then - if test -n "$GCC"; then - test -z "$CFLAGS" && CFLAGS="$nmh_gcc_warnflags -g" || CFLAGS="$CFLAGS $nmh_gcc_warnflags -g" - else - test -z "$CFLAGS" && CFLAGS=-g || CFLAGS="$CFLAGS -g" - fi - else - if test -z "$LDFLAGS"; then - case "$build_os" in - darwin*) - LDFLAGS= - ;; - *) - LDFLAGS=-s - ;; - esac - fi - if test -n "$GCC"; then - test -z "$CFLAGS" && CFLAGS="$nmh_gcc_warnflags -O2" || CFLAGS="$CFLAGS $nmh_gcc_warnflags -O2" - else - test -z "$CFLAGS" && CFLAGS=-O || CFLAGS="$CFLAGS -O" - fi - fi -fi - -AC_C_CONST dnl Does compiler support `const'. - -dnl ------------------ -dnl CHECK FOR PROGRAMS -dnl ------------------ -AC_PROG_MAKE_SET dnl Does make define $MAKE -AC_PROG_INSTALL dnl Check for BSD compatible `install' -AC_PROG_RANLIB dnl Check for `ranlib' -AC_PROG_AWK dnl Check for mawk,gawk,nawk, then awk -AC_PROG_LEX dnl Check for lex/flex - -dnl Look for `cut' -pathtmp=/usr/bin:/bin:/usr/local/bin:/usr/xpg4/bin:/usr/ucb -AC_PATH_PROG(cutpath, cut, no, [$pathtmp]) - -dnl ---------------------------------------------- -dnl check for lclint, and lint if it doesn't exist -dnl ---------------------------------------------- -AC_CHECK_PROG(linttmp1, lclint, lclint, no)dnl -if test x$ac_cv_prog_linttmp1 != xno ; then - LINT=$ac_cv_prog_linttmp1 - LINTFLAGS="-weak +posixlib -macrovarprefixexclude" -else - AC_CHECK_PROG(linttmp2, lint, lint, no)dnl - if test x$ac_cv_prog_linttmp2 != xno ; then - LINT=$ac_cv_prog_linttmp2 - LINTFLAGS="" - else - LINT="echo 'No lint program found'" - LINTFLAGS="" - fi -fi -AC_SUBST(LINT)dnl -AC_SUBST(LINTFLAGS)dnl - -dnl try to figure out which one we've got -AC_CHECK_PROG(LIBTOOL, libtool, libtool, , [$pathtmp]) -NMH_PROG_GNU_LIBTOOL - -dnl Check for lorder and tsort commands -AC_CHECK_PROG(LORDER, lorder, lorder, no)dnl -AC_CHECK_PROG(TSORT, tsort, tsort, no)dnl - -dnl If either doesn't exist, replace them with echo and cat -if test x$ac_cv_prog_LORDER != xlorder -o x$ac_cv_prog_TSORT != xtsort; then - LORDER=echo - TSORT=cat - AC_SUBST(LORDER)dnl - AC_SUBST(TSORT)dnl -dnl Mac OS X has lorder, but sh is too broken for it to work -dnl elif test -z "`lorder config/config.c 2>&1 | grep config/config.c`" ; then -dnl LORDER=echo -dnl TSORT=cat -dnl AC_SUBST(LORDER)dnl -dnl AC_SUBST(TSORT)dnl -fi - -dnl Check whether tsort can deal with loops -AC_CACHE_CHECK(whether tsort can deal with loops, nmh_cv_tsort_loop, - [if test -z "`echo a b b a | tsort 2>/dev/null | grep a`" ; then - nmh_cv_tsort_loop=no - else - nmh_cv_tsort_loop=yes - fi]) -if test x$nmh_cv_tsort_loop = xno ; then - LORDER=echo - TSORT=cat - AC_SUBST(LORDER)dnl - AC_SUBST(TSORT)dnl -fi - -dnl Look for `ls' -pathtmp=/usr/bin:/bin:/usr/local/bin:/usr/xpg4/bin:/usr/ucb -AC_PATH_PROG(lspath, ls, no, [$pathtmp]) - -dnl See how we get ls to display the owner and the group -if test "$lspath" != "no"; then - AC_CACHE_CHECK(how to get ls to show us the group ownership of a file, - nmh_cv_ls_grpopt, - [if test x"`$lspath -dl / | $AWK '{print $9}'`" = x"/"; then - dnl There were 9 parameters, so unless this is a really bizarre, nonstandard - dnl ls, it would seem -l gave us both the user and group. On this type of - dnl ls, -g makes _only_ the group be displayed (and not the user). - nmh_cv_ls_grpopt="-l" - else - dnl Looks like -l only gave us the user, so we need -g to get the group too. - nmh_cv_ls_grpopt="-lg" - fi]) -fi - -dnl Look for `more' -pathtmp=/usr/bin:/bin:/usr/ucb:/usr/local/bin -AC_PATH_PROG(morepath, more, no, [$pathtmp]) - -dnl If pager is not specified yet, -dnl then use `more' as the default. -if test -z "$pagerpath"; then - pagerpath="$morepath" -fi -AC_SUBST(pagerpath)dnl - -dnl Look for `sendmail' -pathtmp=/usr/lib:/usr/sbin:/usr/etc:/usr/ucblib:/usr/bin:/bin -AC_PATH_PROG(sendmailpath, sendmail, /usr/sbin/sendmail, [$pathtmp]) - -dnl Look for `vi' -pathtmp=/usr/bin:/bin:/usr/ucb:/usr/local/bin -AC_PATH_PROG(vipath, vi, /bin/vi, [$pathtmp]) - -dnl If editor is not specified yet, -dnl then use `vi' as the default. -if test -z "$editorpath"; then - editorpath="$vipath" -fi -AC_SUBST(editorpath)dnl - -dnl ---------------------------------------------------------- -dnl FIND MAIL SPOOL AND SEE IF WE NEED TO MAKE inc SETGID MAIL -dnl ---------------------------------------------------------- -AC_CACHE_CHECK(where mail spool is located, nmh_cv_mailspool, -[for mailspool in /var/mail dnl - /var/spool/mail dnl - /usr/spool/mail dnl - /dev/null; dnl Just in case we fall through -do - test -d $mailspool && break -done -nmh_cv_mailspool=$mailspool -]) -mailspool=$nmh_cv_mailspool -AC_SUBST(mailspool)dnl - -dnl See whether the mail spool directory is world-writable. -if test "$lspath" != "no" -a "$cutpath" != "no"; then - AC_CACHE_CHECK(whether the mail spool is world-writable, - nmh_cv_mailspool_world_writable, - [if test "`$lspath -dlL $mailspool | $cutpath -c9`" = "-"; then - nmh_cv_mailspool_world_writable=no - else - nmh_cv_mailspool_world_writable=yes - fi]) -fi - -dnl Also, check for liblockfile (as found on Debian systems) -AC_CHECK_HEADER(lockfile.h, AC_CHECK_LIB(lockfile, lockfile_create) ) - -dnl and whether its companion program dotlockfile is setgid -AC_PATH_PROG(dotlockfilepath, dotlockfile, no) -if test "$ac_cv_lib_lockfile_lockfile_create" != "no" ; then - if test "$ac_cv_path_dotlockfilepath" != "no" ; then - AC_CACHE_CHECK(whether dotlockfile is setgid, nmh_cv_dotlockfile_setgid, - [ if test -g "$ac_cv_path_dotlockfilepath" ; then - nmh_cv_dotlockfile_setgid=yes - else - nmh_cv_dotlockfile_setgid=no - fi]) - fi -fi - -dnl If mailspool is not world-writable and dotlockfile is not setgid, -dnl we need to #define MAILGROUP to 1 and make inc setgid. -if test x"$LOCKTYPE" = x"dot" -a x"$nmh_cv_mailspool_world_writable" = x"no" -a x"$nmh_cv_dotlockfile_setgid" != x"yes" ; then - dnl do we really need both of these? - AC_DEFINE(MAILGROUP,1, - [Define to 1 if you need to make `inc' set-group-id because your mail spool is not world writable. There are no guarantees as to the safety of doing this, but this #define will add some extra security checks.])dnl - SETGID_MAIL=1 -fi -AC_SUBST(SETGID_MAIL)dnl - -dnl Use ls to see which group owns the mail spool directory. -AC_CACHE_CHECK(what group owns the mail spool, nmh_cv_ls_mail_grp, -[nmh_cv_ls_mail_grp=`$lspath -dL $nmh_cv_ls_grpopt $mailspool|$AWK '{print $4}'` -]) -MAIL_SPOOL_GRP=$nmh_cv_ls_mail_grp -AC_SUBST(MAIL_SPOOL_GRP)dnl - -dnl ------------------ -dnl CHECK HEADER FILES -dnl ------------------ - -dnl On glibc we need to define at least the '_XOPEN_SOURCE' level of features, -dnl or wchar.h doesn't declare a prototype for wcwidth(). But if we only define -dnl that level then db.h won't compile. So we define _GNU_SOURCE which turns -dnl on everything. Perhaps other OSes need some feature switch set to get wcwidth() -dnl declared; if so they should have an entry added to this case statement. -dnl NB that we must define this on the compiler command line, not in config.h, -dnl because it must be set before any system header is included and there's no -dnl portable way to make sure that files generated by lex include config.h -dnl before system header files. - -case "$target_os" in - linux*) - # Like DEFS, but doesn't get stomped on by configure when using config.h: - OURDEFS="$OURDEFS -D_GNU_SOURCE" - ;; -esac -AC_SUBST(OURDEFS) - -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_HEADER_TIME -AC_HEADER_SYS_WAIT -AC_HEADER_STAT -AC_HEADER_TIOCGWINSZ -AC_CHECK_HEADERS(string.h memory.h stdlib.h unistd.h errno.h fcntl.h \ - limits.h crypt.h termcap.h termio.h termios.h locale.h \ - langinfo.h wchar.h wctype.h iconv.h netdb.h \ - sys/param.h sys/time.h sys/utsname.h sys/stream.h \ - arpa/inet.h arpa/ftp.h) - -dnl -dnl Checks for _IO_write_ptr. A Linuxism used by nmh on linux. We -dnl really use a whole set of them, but this check should be -dnl sufficient. -dnl -AC_CHECK_HEADER(libio.h, [ - AC_EGREP_HEADER(_IO_write_ptr, libio.h, [ - AC_DEFINE(LINUX_STDIO,1,[Use the Linux _IO_*_ptr defines from .]) ]) ]) - -AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1, - [Define to 1 if `struct winsize' requires .]),, -[[#if HAVE_SYS_STREAM_H -# include -#endif -]]) - -dnl --------------- -dnl CHECK FUNCTIONS -dnl --------------- -AC_FUNC_VFORK -AC_CHECK_LIB(mkstemp,mkstemp) -AC_CHECK_FUNCS(waitpid wait3 sigaction sigprocmask sigblock sigsetmask \ - sighold sigrelse writev lstat uname tzset killpg mkstemp \ - getutent nl_langinfo mbtowc wcwidth) - -dnl sigsetjmp may be a macro -AC_MSG_CHECKING(for sigsetjmp) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[sigsetjmp((void *)0, 0);]])],[AC_DEFINE(HAVE_SIGSETJMP, 1, - [Define to 1 if you have the `sigsetjmp'.]) AC_MSG_RESULT(yes)], - [AC_MSG_RESULT(no)]) - -AC_REPLACE_FUNCS(memmove snprintf strerror strdup) - -dnl Look for the initgroups() declaration. On AIX 4.[13], Solaris 4.1.3, and -dnl ULTRIX 4.2A the function is defined in libc but there's no declaration in -dnl any system header. -dnl -dnl On Solaris 2.[456], the declaration is in . On HP-UX 9-11 and -dnl (reportedly) FreeBSD 3.[23], it's in . Any other locations we -dnl need to check? -AH_TEMPLATE(INITGROUPS_HEADER, [Define to the header containing the declaration of `initgroups'.]) -AC_EGREP_HEADER(initgroups, grp.h, AC_DEFINE(INITGROUPS_HEADER, ), - AC_EGREP_HEADER(initgroups, unistd.h, - AC_DEFINE(INITGROUPS_HEADER, ))) - -dnl On AIX 4.1, snprintf() is defined in libc.a but there's no prototype in -dnl or elsewhere. Apparently it's not officially supported (though it -dnl seems to work perfectly and IBM apparently uses it in internal code). -dnl Anyhow, if we omit our own snprintf() and vsnprintf() prototypes when we -dnl HAVE_SNPRINTF, we get a billion warnings at compile time. Use the C -dnl preprocessor to preprocess stdio.h and make sure that there's actually a -dnl prototype. -AC_EGREP_HEADER(snprintf, stdio.h, AC_DEFINE(HAVE_SNPRINTF_PROTOTYPE,1, - [Define to 1 if has a prototype for snprintf().])) - -dnl Check for multibyte character set support -if test "x$ac_cv_header_wchar_h" = "xyes" -a "x$ac_cv_header_wctype_h" = "xyes" \ - -a "x$ac_cv_func_wcwidth" = "xyes" -a "x$ac_cv_func_mbtowc" = "xyes"; then - AC_DEFINE(MULTIBYTE_SUPPORT, 1, - [Define to enable support for multibyte character sets.]) -fi - -dnl ------------------- -dnl CHECK FOR LIBRARIES -dnl ------------------- -dnl Check location of modf -AC_CHECK_FUNC(modf, , AC_CHECK_LIB(m, modf)) - -dnl Checks for network libraries (nsl, socket) -AC_CHECK_NETLIBS - -termcap_curses_order="termcap curses ncurses" -for lib in $termcap_curses_order; do - AC_CHECK_LIB(${lib}, tgetent, [TERMLIB="-l$lib"; break]) -done -AC_SUBST(TERMLIB)dnl - -dnl --------------- -dnl CHECK FOR ICONV -dnl --------------- - -dnl Find iconv. It may be in libiconv and may be iconv() or libiconv() -if test "x$ac_cv_header_iconv_h" = "xyes"; then - AC_CHECK_FUNC(iconv, ac_found_iconv=yes, ac_found_iconv=no) - if test "x$ac_found_iconv" = "xno"; then - AC_CHECK_LIB(iconv, iconv, ac_found_iconv=yes) - if test "x$ac_found_iconv" = "xno"; then - AC_CHECK_LIB(iconv, libiconv, ac_found_iconv=yes) - fi - if test "x$ac_found_iconv" != "xno"; then - LIBS="-liconv $LIBS" - fi - else - dnl Handle case where there is a native iconv but iconv.h is from libiconv - AC_CHECK_DECL(_libiconv_version, - [ AC_CHECK_LIB(iconv, libiconv, LIBS="-liconv $LIBS") ],, - [ #include ]) - fi -fi -if test "x$ac_found_iconv" = xyes; then - AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) -fi - -dnl Check if iconv uses const in prototype declaration -if test "x$ac_found_iconv" = "xyes"; then - AC_CACHE_CHECK(for iconv declaration, ac_cv_iconv_const, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include - #include ]], - [[#ifdef __cplusplus - "C" - #endif - #if defined(__STDC__) || defined(__cplusplus) - size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); - #else - size_t iconv(); - #endif]])], - [ac_cv_iconv_const=], - [ac_cv_iconv_const=const])]) - AC_DEFINE_UNQUOTED([ICONV_CONST], $ac_cv_iconv_const, - [Define as const if the declaration of iconv() needs const.]) -fi - -dnl -------------- -dnl CHECK FOR NDBM -dnl -------------- - -AC_ARG_WITH([ndbm],AS_HELP_STRING([--with-ndbm=ARG],[use -lARG to link with ndbm]), - [nmh_ndbm=$withval],[nmh_ndbm=autodetect]) -AC_ARG_WITH([ndbmheader],AS_HELP_STRING([--with-ndbmheader=ARG],[#include to use ndbm]), - [nmh_ndbmheader=$withval],[nmh_ndbmheader=autodetect]) - -if test "$nmh_ndbm" = "autodetect"; then - if test "$nmh_ndbmheader" != "autodetect"; then - AC_MSG_ERROR([must specify both --with-ndbm and --with-ndbmheader or neither]) - else - - dnl There are at least four implementations of ndbm, and - dnl several of those can be in different places at the whim - dnl of the system integrator. A good summary of this mess - dnl can be found at http://www.unixpapa.com/incnote/dbm.html - - dnl Classic ndbm with no library required (eg NetBSD): try this - dnl first so we don't accidentally link in a pointless but harmless - dnl library in one of the later ndbm.h+libfoo tests: - NMH_CHECK_NDBM(ndbm.h,,, - dnl Berkeley DBv2 emulating ndbm: header in db.h: - NMH_CHECK_NDBM(db.h,db,, - dnl Berkeley DBv1 emulating ndbm: - NMH_CHECK_NDBM(ndbm.h,db,, - NMH_CHECK_NDBM(ndbm.h,db1,, - dnl Classic ndbm: - NMH_CHECK_NDBM(ndbm.h,ndbm,, - dnl glibc2.1 systems put db1 in a subdir: - NMH_CHECK_NDBM(db1/ndbm.h,db1,, - dnl GNU gdbm emulating ndbm, with header possibly in gdbm/ - dnl and possibly needing gbdm_compat library: - NMH_CHECK_NDBM(gdbm/ndbm.h,gdbm,, - NMH_CHECK_NDBM(gdbm/ndbm.h,gdbm_compat -lgdbm,, - NMH_CHECK_NDBM(ndbm.h,gdbm,, - NMH_CHECK_NDBM(ndbm.h,gdbm_compat -lgdbm)))))))))) - - fi -else - dnl We don't really need to check that the user-specified values work, - dnl but it is a convenience to the user to bomb out early rather than - dnl after configure and half the compile process. - NMH_CHECK_NDBM([$nmh_ndbmheader],[$nmh_ndbm]) -fi - -if test "$nmh_ndbm_found" = "no"; then - AC_MSG_ERROR([could not find a working ndbm library/header combination]) -else - dnl Now export the lib/header to our makefile/config.h: - if test x"$nmh_ndbmheader" != x; then - AC_DEFINE_UNQUOTED(NDBM_HEADER, <$nmh_ndbmheader>, - [Define to the header containing the ndbm API prototypes.]) - fi - if test x"$nmh_ndbm" != x; then - NDBM_LIBS="-l$nmh_ndbm" - else - NDBM_LIBS= - fi - AC_SUBST(NDBM_LIBS) -fi - - -dnl -------------------- -dnl CHECK FOR CYRUS-SASL -dnl -------------------- - -AS_IF([test x"$sasl_support" = x"yes"],[ - AC_CHECK_HEADER([sasl/sasl.h], , [AC_MSG_ERROR([sasl.h not found])]) - AC_CHECK_LIB([sasl2], [sasl_client_new], , - [AC_MSG_ERROR([Cyrus SASL library not found])])]) - -dnl ----------------- -dnl CHECK FOR OPENSSL -dnl ----------------- - -AS_IF([test x"$tls_support" = x"yes"],[ - AC_CHECK_HEADER([openssl/ssl.h], , [AC_MSG_ERROR([openssl/ssl.h not found])]) - AC_CHECK_LIB([crypto], [BIO_write], , - [AC_MSG_ERROR([OpenSSL crypto library not found])]) - AC_CHECK_LIB([ssl], [SSL_library_init], , - [AC_MSG_ERROR([OpenSSL library not found])])]) - -dnl --------------------- -dnl CHECK TERMCAP LIBRARY -dnl --------------------- - -dnl Add the termcap library, so that the following configure -dnl tests will find it when it tries to link test programs. -nmh_save_LIBS="$LIBS" -LIBS="$TERMLIB $LIBS" - -dnl Checks for external variable ospeed in the termcap library. -AC_CACHE_CHECK(if an include file defines ospeed, -nmh_cv_decl_ospeed_include_defines, -[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -#if HAVE_TERMIOS_H -#include -#endif -#if HAVE_TERMCAP_H -#include -#endif]], [[ospeed = 0;]])], -nmh_cv_decl_ospeed_include_defines=yes,nmh_cv_decl_ospeed_include_defines=no)]) - -if test $nmh_cv_decl_ospeed_include_defines = no; then - AC_CACHE_CHECK(if you must define ospeed, - nmh_cv_decl_ospeed_must_define, - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], - [[extern short ospeed; ospeed = 0;]])], - nmh_cv_decl_ospeed_must_define=yes,nmh_cv_decl_ospeed_must_define=no)]) -fi - -AH_TEMPLATE(HAVE_OSPEED, [Define to 1 if your termcap library has the ospeed variable.]) -if test $nmh_cv_decl_ospeed_include_defines = yes; then - AC_DEFINE(HAVE_OSPEED)dnl -elif test $nmh_cv_decl_ospeed_must_define = yes; then - AC_DEFINE(HAVE_OSPEED) - AC_DEFINE(MUST_DEFINE_OSPEED, 1, - [Define to 1 if you have ospeed, but it is not defined in termcap.h.]) -fi - -dnl Check if tgetent accepts NULL (and will allocate its own termcap buffer) -dnl Some termcaps reportedly accept a zero buffer, but then dump core -dnl in tgetstr(). -dnl Under Cygwin test program crashes but exit code is still 0. So, -dnl we test for a file that porgram should create -AH_TEMPLATE([TGETENT_ACCEPTS_NULL], -[Define to 1 if tgetent() accepts NULL as a buffer.]) -AC_CACHE_CHECK(if tgetent accepts NULL, -nmh_cv_func_tgetent_accepts_null, -[AC_TRY_RUN([ -main() -{ - char buf[4096]; - int r1 = tgetent(buf, "vt100"); - int r2 = tgetent((char*)0,"vt100"); - if (r1 >= 0 && r1 == r2) { - char tbuf[1024], *u; - u = tbuf; - tgetstr("cl", &u); - creat("conftest.tgetent", 0640); - } - exit((r1 != r2) || r2 == -1); -} -], - if test -f conftest.tgetent; then - nmh_cv_func_tgetent_accepts_null=yes - else - nmh_cv_func_tgetent_accepts_null=no - fi, - nmh_cv_func_tgetent_accepts_null=no, - nmh_cv_func_tgetent_accepts_null=no)]) -if test x$nmh_cv_func_tgetent_accepts_null = xyes; then - AC_DEFINE(TGETENT_ACCEPTS_NULL) -fi -AC_CACHE_CHECK(if tgetent returns 0 on success, -nmh_cv_func_tgetent_zero_success, -[AC_TRY_RUN([ -main() -{ - char buf[4096]; - int r1 = tgetent(buf, "!@#$%^&*"); - int r2 = tgetent(buf, "vt100"); - if (r1 < 0 && r2 == 0) { - char tbuf[1024], *u; - u = tbuf; - tgetstr("cl", &u); - creat("conftest.tgetent0", 0640); - } - exit(r1 == r2); -} -], - if test -f conftest.tgetent0; then - nmh_cv_func_tgetent_zero_success=yes - else - nmh_cv_func_tgetent_zero_success=no - fi, - nmh_cv_func_tgetent_zero_success=no, - nmh_cv_func_tgetent_zero_success=no)]) -AH_TEMPLATE([TGETENT_SUCCESS], -[Define to what tgetent() returns on success (0 on HP-UX X/Open curses).]) -if test x$nmh_cv_func_tgetent_zero_success = xyes; then - AC_DEFINE(TGETENT_SUCCESS, 0) -else - AC_DEFINE(TGETENT_SUCCESS, 1) -fi - -dnl Now put the libraries back to what it was before we -dnl starting checking the termcap library. -LIBS="$nmh_save_LIBS" - -dnl -------------- -dnl CHECK TYPEDEFS -dnl -------------- -AC_TYPE_SIGNAL -AC_TYPE_PID_T -AC_TYPE_OFF_T -AC_TYPE_UID_T -AC_TYPE_MODE_T -AC_TYPE_SIZE_T - -dnl Check for sigset_t. Currently I'm looking in -dnl and . Others might need -dnl to be added. -AC_CACHE_CHECK(for sigset_t, nmh_cv_type_sigset_t, -[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], [[sigset_t tempsigset;]])], -nmh_cv_type_sigset_t=yes,nmh_cv_type_sigset_t=no)]) -if test $nmh_cv_type_sigset_t = no; then - AC_DEFINE(sigset_t, unsigned int, - [Define to `unsigned int' if or doesn't define.]) -fi - -dnl ---------------- -dnl CHECK STRUCTURES -dnl ---------------- -AC_CHECK_MEMBERS(struct stat.st_blksize) - -AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, - [#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif]) - -AC_CHECK_MEMBERS(struct utmp.ut_type,,,[#include ]) - -AC_MSG_CHECKING(for union wait) -AC_CACHE_VAL(nmh_cv_union_wait, [dnl - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], - [[union wait status; int pid; pid = wait (&status); -#ifdef WEXITSTATUS -/* Some POSIXoid systems have both the new-style macros and the old - union wait type, and they do not work together. If union wait - conflicts with WEXITSTATUS et al, we don't want to use it at all. */ - if (WEXITSTATUS (status) != 0) pid = -1; -#ifdef WTERMSIG - /* If we have WEXITSTATUS and WTERMSIG, just use them on ints. */ - -- blow chunks here -- -#endif -#endif -#ifdef HAVE_WAITPID - /* Make sure union wait works with waitpid. */ - pid = waitpid (-1, &status, 0); -#endif - ]])], - [nmh_cv_union_wait=yes], - [nmh_cv_union_wait=no])]) -if test "$nmh_cv_union_wait" = yes; then - AC_DEFINE(HAVE_UNION_WAIT, 1, - [Define to 1 if you have the \`union wait' type in .]) -fi -AC_MSG_RESULT($nmh_cv_union_wait) - -CHECK_TYPE_STRUCT_DIRENT_D_TYPE() - -dnl ------------- -dnl CHECK SIGNALS -dnl ------------- -dnl What style of signal do you have (POSIX, BSD, or SYSV)? -AH_TEMPLATE(RELIABLE_SIGNALS, [Define to 1 if you have reliable signals.]) -AC_MSG_CHECKING(what style of signals to use) -if test $ac_cv_func_sigaction = yes -a $ac_cv_func_sigprocmask = yes; then - signals_style=POSIX_SIGNALS - AC_DEFINE(POSIX_SIGNALS, 1, - [Define to 1 if you use POSIX style signal handling.]) - AC_DEFINE(RELIABLE_SIGNALS) -elif test $ac_cv_func_sigblock = yes -a $ac_cv_func_sigsetmask = yes; then - signals_style=BSD_SIGNALS - AC_DEFINE(BSD_SIGNALS,1, - [Define to 1 if you use BSD style signal handling (and can block signals).]) - AC_DEFINE(RELIABLE_SIGNALS) -elif test $ac_cv_func_sighold = yes -a $ac_cv_func_sigrelse = yes; then - signals_style=SYSV_SIGNALS - AC_DEFINE(SYSV_SIGNALS,1, - [Define to 1 if you use SYSV style signal handling (and can block signals).]) -else - signals_style=NO_SIGNAL_BLOCKING - AC_DEFINE(NO_SIGNAL_BLOCKING,1, - [Define to 1 if you have no signal blocking at all (bummer).]) -fi - -AC_MSG_RESULT($signals_style) - -dnl Where is located? Needed as input for signames.awk -AC_CACHE_CHECK(where signal.h is located, nmh_cv_path_signal_h, -[for SIGNAL_H in /usr/include/bsd/sys/signal.h dnl Next - /usr/include/asm/signal.h dnl Linux 1.3.0 and above - /usr/include/asm/signum.h dnl some versions of Linux/Alpha - /usr/include/linux/signal.h dnl Linux up to 1.2.11 - /usr/include/sys/signal.h dnl Almost everybody else - /dev/null; dnl Just in case we fall through -do - test -f $SIGNAL_H && \ - grep '#[ ]*define[ ][ ]*SIG[0-9A-Z]*[ ]*[0-9][0-9]*' $SIGNAL_H > /dev/null && \ - break -done -nmh_cv_path_signal_h=$SIGNAL_H -]) -SIGNAL_H=$nmh_cv_path_signal_h -AC_SUBST(SIGNAL_H)dnl - -dnl ---------------- -dnl OS SPECIFIC DEFINES -dnl ---------------- -AH_TEMPLATE(SYS5, [Defined for Solaris 2.x, Irix, OSF/1, HP-UX, AIX, SCO5; only used in vmh.c which is not built.]) -AH_TEMPLATE(SVR4, [Defined for Solaris 2.x, Irix, OSF/1, HP-UX, AIX; only used in vmh.c which is not built.]) -AH_TEMPLATE(BSD44, [Defined for SunOS 4, FreeBSD, NetBSD, OpenBSD, BSD/OS, Mac OS X/Rhapsody; only used in vmh.c which is not built.]) -AH_TEMPLATE(BSD42, [Defined for SunOS 4, FreeBSD, NetBSD, OpenBSD, BSD/OS, Mac OS X/Rhapsody -- does PicoBSD have uname?]) -AH_TEMPLATE(SCO_5_STDIO, [Defined for SCO5.]) - -case "$target_os" in - - solaris2*) - AC_DEFINE(SYS5) - AC_DEFINE(SVR4) - ;; - irix*) - AC_DEFINE(SYS5) - AC_DEFINE(SVR4) - ;; - osf*) - AC_DEFINE(SYS5) - AC_DEFINE(SVR4) - ;; - aix*) - AC_DEFINE(SYS5) - AC_DEFINE(SVR4) - ;; - sunos4*) - AC_DEFINE(BSD42) - ;; - freebsd*) - AC_DEFINE(BSD42) - AC_DEFINE(BSD44) - ;; - netbsd*) - AC_DEFINE(BSD42) - AC_DEFINE(BSD44) - ;; - openbsd*) - AC_DEFINE(BSD42) - AC_DEFINE(BSD44) - ;; - bsd/os*) - AC_DEFINE(BSD42) - AC_DEFINE(BSD44) - ;; - sco5*) - AC_DEFINE(SYS5) - AC_DEFINE(SCO_5_STDIO) - ;; -esac - - -dnl ---------------- -dnl OUTPUT MAKEFILES -dnl ---------------- -AC_CONFIG_FILES(Makefile config/Makefile h/Makefile sbr/Makefile uip/Makefile \ - mts/Makefile mts/smtp/Makefile \ - etc/Makefile docs/Makefile man/Makefile) -AC_CONFIG_COMMANDS([stamp],[test -z "$CONFIG_HEADERS" || echo > stamp-h]) -AC_OUTPUT - -dnl These odd looking assignments are done to expand out unexpanded -dnl variables in bindir et al (for instance mandir is '${datarootdir}/man', -dnl but expanding that gives '${prefix}/share/man', so we need to expand -dnl again to get the final answer. -dnl We only use the expanded versions to print the install paths in -dnl the final summary and should use them nowhere else (see the autoconf -dnl docs for the rationale for bindir etc being unexpanded). -eval "nmhbin=${bindir}"; eval "nmhbin=${nmhbin}" -eval "nmhsysconf=${sysconfdir}"; eval "nmhsysconf=${nmhsysconf}" -eval "nmhlib=${libdir}"; eval "nmhlib=${nmhlib}" -eval "nmhman=${mandir}"; eval "nmhman=${nmhman}" - -pop_kinds=no -if test x"$enable_pop" = x"yes"; then - pop_kinds="yes (" - - if test x"$enable_apop" = x"yes"; then - pop_kinds="${pop_kinds}APOP " - fi - - pop_kinds="${pop_kinds}POP3)" -fi - -echo " -nmh configuration ------------------ -nmh version : AC_PACKAGE_VERSION -target os : ${target} -compiler : ${CC} -compiler flags : ${CFLAGS} -linker flags : ${LDFLAGS} -definitions : ${OURDEFS} -source code location : ${srcdir} -binary install path : ${nmhbin} -library install path : ${nmhlib} -config files install path : ${nmhsysconf} -man page install path : ${nmhman} -backup prefix : ${backup_prefix} -transport system : ${MTS} -file locking type : ${LOCKTYPE} -default smtp servers : ${smtpservers} -default editor : ${editorpath} -default pager : ${pagerpath} -email address masquerading : ${masquerade} -pop is enabled : ${pop_kinds} -SASL support : ${sasl_support} -TLS support : ${tls_support}" -echo "" diff --git a/docs/COMPLETION-BASH b/docs/COMPLETION-BASH index b5bdfbc..35cdf9f 100644 --- a/docs/COMPLETION-BASH +++ b/docs/COMPLETION-BASH @@ -2,6 +2,9 @@ # Copyright 2003 "Wade Richards" # Permission granted to redistribute under the BSD license +[ "$BASH_COMPLETION" ] || echo "ERROR: COMPLETION-BASH is not intended to be \ +sourced directly, but rather added to a bash-completion package installation." + have show && _nmh() { @@ -13,7 +16,7 @@ _nmh() prev=${COMP_WORDS[COMP_CWORD-1]} command=$1 - orig_opts=$(shopt -p extglob) + orig_opts=$(shopt -p extglob) shopt -s extglob # Get the folder, if specified @@ -21,110 +24,94 @@ _nmh() do case "${COMP_WORDS[i]}" in \++([a-zA-Z_]) ) - folder=${COMP_WORDS[i]} + folder=${COMP_WORDS[i]} origfolder=$( folder -f ) ;; esac done - case $current in - -* ) + case $current in + -* ) # Command-line switches for the most common commands. case $command in - ali ) + ali ) # no sequences or messages options=(-alias -list -nolist -normalize -nonormalize -user - -nouser -version -help) + -nouser -Version -help) ;; - burst ) + burst ) options=(-inplace -noinplace -quiet -noquiet -verbose - -noverbose -version -help) + -noverbose -Version -help) ;; comp ) - options=(-form -use -nouse -file -draftfolder -draftmessage - -nodraftfolder -editor -noedit -whatnowproc -nowhatnowproc - -version -help ) - ;; + options=(-form -use -nouse + -editor -noedit -whatnowproc + -Version -help ) + ;; flist* ) options=(-sequence -all -noall -showzero -noshowzero - -recurse -norecurse -fast -nofast -alpha -noalpha -version + -recurse -norecurse -fast -nofast -alpha -noalpha -Version -help) ;; folder* ) options=(-all -noall -create -nocreate -fast -nofast -header -noheader -recurse -norecurse -total -nototal -list -nolist - -push -pop -pack -nopack -print -verbose -noverbose -version - -help) + -push -pop -pack -nopack -print -verbose -noverbose + -Version -help) ;; forw ) - options=(-annotate -noannotate -form -format -noformat - -filter -inplace -noinplace -mime -nomime -draftfolder - -draftmessage -nodraftfolder -editor -noedit -whatnowproc - -nowhatnowproc -dashstuffing -nodashstuffing -build -file - -version -help) + options=(-annotate -noannotate -form + -editor -noedit -whatnowproc -build + -Version -help) ;; inc ) - options=(-audit -noaudit -changecur -nochangecur -form -format - -file -silent -nosilent -truncate -notruncate -width -host - -user -pack -nopack -apop -noapop -kpop -sasl -saslmech -snoop - -version -help) + options=(-audit -noaudit -changecur -nochangecur -form + -file -silent -nosilent -truncate -notruncate -width + -Version -help) ;; mark ) options=(-sequence -add -delete -list -public -nopublic - -zero -nozero -version -help) - ;; - next ) - options=(-showmimeproc -header -noheader -checkmime - -nocheckmime -version -help) + -zero -nozero -Version -help) ;; packf ) - options=(-file -mbox -mmdf -version -help) + options=(-file -Version -help) ;; pick ) options=(-and -or -not -lbrace -rbrace --component -cc -date -from -search -subject -to -after -before -datefield -sequence -public -nopublic -zero -nozero -list -nolist - -version -help) - ;; - prev ) - options=(-showproc -showmimeproc -header -noheader -checkmime - -nocheckmime -version -help) + -Version -help) ;; refile ) - options=(-draft -link -nolink -preserve -nopreserve -unlink - -nounlink -src -file -rmmproc -normmproc -version -help) + options=(-link -nolink -src -file -Version -help) ;; repl ) options=(-annotate -noannotate -group -nogroup -cc - -nocc -query -noquery -form -format -noformat -filter - -inplace -noinplace -mime -nomime -fcc -width -draftfolder - -draftmessage -nodraftfolder -editor -noedit -whatnowproc - -nowhatnowproc -build -file -version -help) + -nocc -query -noquery -form -filter -nofilter + -mime -nomime -editor -noedit -whatnowproc + -build -file -Version -help) ;; rmf ) - options=(-interactive -nointeractive -version -help) + options=(-interactive -nointeractive -Version -help) ;; rmm ) - options=(-link -nolink -version -help) + options=(-link -nolink -Version -help) ;; scan ) - options=(-clear -noclear -form -format -header -noheader - -width -reverse -noreverse -file -version -help ) + options=(-form -header -noheader + -width -file -Version -help ) ;; show ) - options=(-draft -showproc -showmimeproc -header -noheader - -checkmime -nocheckmime -version -help) + next ) + prev ) + options=(-file -part -type -form -Version -help) ;; sortm ) options=(-datefield -textfield -notextfield -limit -nolimit - -verbose -noverbose -version -help) - ;; - whom ) - options=(-alias -check -nocheck -draft -draftfolder - -draftmessage -nodraftfolder -version -help) + -verbose -noverbose -Version -help) ;; * ) - options=(-help -version -seq) + options=(-help -Version -seq) ;; esac ;; @@ -137,13 +124,13 @@ _nmh() +([0-9a-z])-* ) # Partial range start=${current/%-*/} - options=( $( scan $folder -format "%(msg)" "${start}-last" ) first prev cur next last ) + options=( $( scan $folder -form "=%(msg)" "${start}-last" ) first prev cur next last ) options=( ${options[@]//#/${start}-} ) ;; +([0-9]) ) # Message number, or start of range - options=( $( scan $folder -format "%(msg)" ) first prev cur next last ) + options=( $( scan $folder -form "=%(msg)" ) first prev cur next last ) options=( ${options[@]} ${options[@]//%/-} ) ;; @@ -162,4 +149,4 @@ _nmh() COMPREPLY=( $( compgen -W "${options[*]}" -- $current ) ) return 0 } -[ "$have" ] && complete -F _nmh ali anno burst comp dist flist flists folder folders forw inc mark mhbuild mhl mhlist mhmail mhn mhparam mhpath mhshow mhstore msgchk msh next packf pick prev prompter rcvdist rcvpack rcvstore rcvtty refile repl rmf rmm scan send sendfiles show slocal sortm whatnow whom +[ "$have" ] && complete -F _nmh ali anno burst comp dist flist flists folder folders forw inc mark mhbuild mhl mhlist mhmail mhparam mhpath mhstore next packf pick prev prompter rcvdist rcvpack rcvstore refile repl rmf rmm scan send sendfiles show slocal sortm whatnow diff --git a/docs/COMPLETION-TCSH b/docs/COMPLETION-TCSH index f75933e..644bcaf 100644 --- a/docs/COMPLETION-TCSH +++ b/docs/COMPLETION-TCSH @@ -29,7 +29,6 @@ complete forw c%+%D:$nmh_mail_dir% complete inc c%+%D:$nmh_mail_dir% complete mark c%+%D:$nmh_mail_dir% complete mhl c%+%D:$nmh_mail_dir% -complete mhn c%+%D:$nmh_mail_dir% complete mhpath c%+%D:$nmh_mail_dir% complete next c%+%D:$nmh_mail_dir% complete packf c%+%D:$nmh_mail_dir% @@ -45,4 +44,3 @@ complete send c%+%D:$nmh_mail_dir% complete show c%+%D:$nmh_mail_dir% complete sortm c%+%D:$nmh_mail_dir% complete whatnow c%+%D:$nmh_mail_dir% -complete whom c%+%D:$nmh_mail_dir% diff --git a/docs/COMPLETION-ZSH b/docs/COMPLETION-ZSH index 5c10cc8..4d67d92 100644 --- a/docs/COMPLETION-ZSH +++ b/docs/COMPLETION-ZSH @@ -43,8 +43,7 @@ function mhcomp { # # Extract nmh message names and numbers for completion. Use of the # correct folder, if it is not the current one, requires that it -# should be the previous command line argument. If the previous -# argument is `-draftmessage', a hard wired draft folder name is used. +# should be the previous command line argument. # mhfseq() { local folder foldpath words pos nums @@ -55,11 +54,6 @@ mhfseq() { # First try the previous word. if [[ $words[$pos-1] = [@+]* ]]; then folder=$words[$pos-1] - # Next look and see if we're looking for a draftmessage - elif [[ $words[$pos-1] = -draftmessage ]]; then - # EDIT ME: shortcut -- hard-wire draftfolder here - # Should really look for a +draftfolder argument. - folder=+drafts fi # Else use the current folder ($folder empty) @@ -125,23 +119,23 @@ compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ 's[-]' -k "(sequence all noall recurse norecurse showzero noshowzero \ alpha noalpha fast nofast help)" -- flist flists -compctl -K mhfseq -x 's[+][@],c[-1,-draftfolder] s[+][@]' \ - -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq - \ +compctl -K mhfseq -x 's[+][@],c[-1] s[+][@]' \ + -K mhcomp -S / -q - 'c[-1]' -K mhfseq - \ 'C[-1,-(editor|whatnowproc)]' -c - \ - 's[-]' -k "(draftfolder draftmessage nodraftfolder editor noedit \ - file form use nouse whatnowproc nowhatnowproc help)" - \ + 's[-]' -k "(editor noedit \ + form use nouse whatnowproc help)" - \ 'c[-1,-form]' -K mhfile -- comp compctl -K mhfseq -x 's[+][@]' \ - -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq -\ - 's[-]' -k "(annotate noannotate cc nocc draftfolder nodraftfolder \ - draftmessage editor noedit fcc filter form group nogroup inplace noinplace - query noquery width whatnowproc nowhatnowproc help)" - 'c[-1,(cc|nocc)]' \ + -K mhcomp -S / -q - 'c[-1]' -K mhfseq -\ + 's[-]' -k "(annotate noannotate cc nocc \ + editor noedit filter nofilter form group nogroup \ + query noquery width whatnowproc help)" - 'c[-1,(cc|nocc)]' \ -k "(all to cc me)" - 'C[-1,-(filter|form)]' -K mhfile - \ 'C[-1,-(editor|whatnowproc)]' -c -- repl compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ - 's[-]' -k "(audit noaudit changecur nochangecur form format \ + 's[-]' -k "(audit noaudit changecur nochangecur form \ file silent nosilent truncate notruncate width help)" - \ 'C[-1,-(audit|form)]' -K mhfile - 'c[-1,-file]' -f + -- inc @@ -150,19 +144,16 @@ compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ mark compctl -K mhfseq -x 's[+][@]' \ - -K mhcomp -S / -q - 'c[-1,-file]' -f - 'c[-1,-rmmprov]' -c - \ - 's[-]' -k "(draft link nolink preserve nopreserve src file \ - rmmproc normmproc help)" -- refile + -K mhcomp -S / -q - 'c[-1,-file]' -f - \ + 's[-]' -k "(link nolink src file help)" -- refile compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ - 's[-]' -k "(clear noclear form format header noheader reverse noreverse \ + 's[-]' -k "(form \ file help width)" - 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile -- scan compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ - 's[-]' -k "(draft form moreproc nomoreproc header noheader \ - showproc noshowproc length width help)" - 'C[-1,-(show|more)proc]' -c - \ - 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \ - 'c[-1,-length]' -s '$LINES' - 'c[-1,-width]' -s '$COLUMNS' -- show next prev + 's[-]' -k "(file form part type help)" - \ + 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - -- show next prev compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ -k "(help)" -- rmm @@ -172,17 +163,4 @@ compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ public nopublic search sequence subject to zero nozero not or and \ lbrace rbrace)" -- pick -compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ - -k "(alias check draft draftfolder draftmessage help nocheck \ - nodraftfolder)" -- whom - -compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ - -k "(file part type list headers noheaders realsize norealsize nolist \ - show serialonly noserialonly form pause nopause noshow store auto noauto \ - nostore cache nocache rcache wcache check nocheck ebcdicsafe noebcdicsafe \ - rfc934mode norfc934mode verbose noverbose help)" - \ - 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \ - 'C[-1,-[rw]cache]' -k '(public private never ask)' -- mhn - compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' -k '(help)' -- mhpath - diff --git a/docs/ChangeLog_MH-3_to_MH-6.6 b/docs/ChangeLog_MH-3_to_MH-6.6 index ea7cd58..4b7ecf8 100644 --- a/docs/ChangeLog_MH-3_to_MH-6.6 +++ b/docs/ChangeLog_MH-3_to_MH-6.6 @@ -936,7 +936,7 @@ Sun Feb 23 13:59:46 1986 /mtr Thu Feb 20 22:57:33 1986 /mtr - + MH 6.4 #1[UCI] (nrtc-gremlin) made available to Van Jacobson for inclusion in 4.3BSD UNIX @@ -1092,7 +1092,7 @@ Wed Feb 5 14:42:55 1986 /mtr Wed Feb 5 11:25:05 1986 /mtr - + MH 6.3 #1[UCI] (nrtc-gremlin) is official, still awaiting Berkeley enhancements @@ -1845,7 +1845,7 @@ Sun Oct 13 14:17:10 1985 /mtr Wed Oct 9 19:49:04 1985 /mtr - uip/send.c: fix bogus annotation handling, e.g., + uip/send.c: fix bogus annotation handling, e.g., send -push; rmm; folder -pack uip/{forw,mhlsbr}.c: add extra blank line after final EB so user can add suffix text with an editor (e.g., prompter) @@ -3030,7 +3030,7 @@ Wed Apr 3 23:52:13 1985 /mtr (agent: Marshall Rose) Tue Mar 26 18:32:49 1985 /mtr (agent: Marshall Rose) - conf/{config/mts.c,tailor/READ-ME}, config/aliasbr.h, mts/mts.h, + conf/{config/mts.c,tailor/READ-ME}, config/aliasbr.h, mts/mts.h, uip/aliasbr.c: make "*" logic mts-tailorable (ugh), you get to choose highest non-user uid and non-user shell @@ -3430,7 +3430,7 @@ Wed Apr 3 23:52:13 1985 /mtr (agent: Marshall Rose) Tue Mar 26 18:32:49 1985 /mtr (agent: Marshall Rose) - conf/{config/mts.c,tailor/READ-ME}, config/aliasbr.h, mts/mts.h, + conf/{config/mts.c,tailor/READ-ME}, config/aliasbr.h, mts/mts.h, uip/aliasbr.c: make "*" logic mts-tailorable (ugh), you get to choose highest non-user uid and non-user shell @@ -3944,7 +3944,7 @@ Wed Nov 28 22:59:34 1984 /mtr (agent: Marshall Rose) sbr/m_draft.c: call path() on value of Draft-Folder: so relative folders work (!!) uip/repl.c: expand fcc: @folder arguments - + Wed Nov 28 20:42:21 1984 /mtr (agent: Marshall Rose) @@ -4171,7 +4171,7 @@ Fri Nov 16 19:01:32 1984 /mtr (agent: Marshall Rose) uip/msh.c: remove -[no]burst switches. Add "rmm" command, but don't document it yet. Still have to resolve a few problems. - + Fri Nov 16 08:21:08 1984 /mtr (agent: Marshall Rose) @@ -4958,7 +4958,7 @@ Sun Jul 15 17:10:38 1984 Rand MH mail system (agent: Marshall Rose) diff --git a/docs/ChangeLog_nmh b/docs/ChangeLog_nmh new file mode 100644 index 0000000..324dddc --- /dev/null +++ b/docs/ChangeLog_nmh @@ -0,0 +1,3852 @@ +2010-12-09 Ken Hornstein + + * h/nntp.h, configure.in, h/Makefile.in, h/mts.h, h/popsbr.h, + man/inc.man, man/mh-chart.man, man/mh-tailor.man, man/msgchk.man, + sbr/Makefile.in, sbr/mts.c, uip/Makefile.in, uip/inc.c, uip/msgchk.c, + uip/msh.c, uip/mshcmds.c, uip/popsbr.c: Massive garbage collection. + Remove functionality for APOP, RPOP, all NNTP support (including + bboards), and MPOP. + +2010-12-08 David Levine + + * uip/whatnowsbr.c: enforce requirement of at least one file + argument to attach command. + +2010-12-08 David Levine + + * man/send.man: added name= portion to Content-Type + headers to reflect 2006-10-24 change to uip/sendsbr.c. + That change allowed mhstore to use the (file)name when + extracting attachments. + +2010-12-03 Ken Hornstein + + * Everything: remove RCS keywords from files, since they no longer + work after git migration. + +2010-12-02 Ken Hornstein + + * .cvsignore, .gitignore, autogen.sh, */.cvsignore: Update files + for git conversion. + +2010-12-19 Ken Hornstein + + * aclocal.m4, config/Makefile.in, configure.in, man/mh-chart.man, + man/post.man, man/send.man, mts/smtp/Makefile.in, mts/smtp/smtp.c, + mts/smtp/smtp.h, sbr/Makefile.in, uip/Makefile.in, uip/post.c, + uip/send.c, uip/whatnowsbr.c, uip/whom.c: Clean up autoconf + code for handling of compiler flags for SASL, and add support + for TLS to the SMTP MTA. + +2010-11-12 Peter Maydell + + * man/slocal.man: fix formatting error that meant a + subsection heading wasn't displayed as such. + +2010-11-10 Peter Maydell + + * configure.in: add a level of expansion for mandir + when printing the end-of-configure install path + summary. + +2010-11-09 Peter Maydell + + * man/rmm.man: fix error in synopsis: the option is + [no]unlink, not [no]link. + +2010-08-31 David Levine + + * uip/.cvsignore: added "new". + +2010-02-03 Earl Hood + + * Bug #15213, #18635: The use of the insecure m_scratch() and + m_tmpfil() functions have been replaced by m_mktemp() + or m_mktemp2() functions (defined in sbr/m_mktemp.c). + The new functions use mkstemp() to securely create + temporary files to avoid the numerous race conditions + that exist with the old functions. This does assume + that mkstemp() is available. Unsure if we need to + create an alternative implementation if mkstemp() is + not available. More information about new temp file + functions in m_mktemp.c, including the support for + MHTMPDIR, TMPDIR, and TMP envvars. + +2010-02-02 Earl Hood + + * mts/smtp/smtp.c: added SASL support if mts configuration + setting is set to "sendmail". This is useful if sendmail + conf option is to a custom script that creates a proxy + connection to an smtp server. + + * sbr/mts.c: added support for MHMTSCONF and MHMTSUSERCONF + envvars. The former specifies an alternative system + mts.conf to use. The later specifies a user-specific + mts.conf to use. This one will be read after the system + conf, so the user's conf only needs to set options they + want to override. The MHMTSUSERCONF allows a user to set + personal alternative mail submission methods w/o affecting + other users on the system. + + * uip/whom.c: added SASL-based options so address checking + can work against a server that requires SASL. + +2009-12-29 David Levine + + * uip/mhlistsbr.c, uip/mhlsbr.c, uip/picksbr.c: cast + pointers to unsigned long before casting to unsigned int + to avoid warnings on 64-bit about casting from pointer + to int of different size. + + * uip/new.c: cast folder_len to int to avoid warning on + 64-bit about passing a size_t to an int conversion specifier. + +2009-12-25 David Levine + + * uip/inc.c: gcc 4.4.1 noticed that maildir could have been + used before initialization. In fact, if that code was ever + reached, maildir would never have been initialized. It's in + an adios call, so replaced with NULL. + +2009-12-21 David Levine + + * mts/smtp/smtp.c: In sm_auth_sasl (), removed zeroing of + sasl_inbuffer because it could be used in sm_fget (). Also, + removed allocation of sasl_inbuffer because that was done in + either smtp_init () or sendmail_init (). + +2009-01-17 Eric Gillespie + + * etc/mhn.defaults.sh: Never try to make mhshow start xterm. + +2009-01-16 Eric Gillespie + + * test/runtest, test/tests/inc/test-deb359167, + test/tests/inc/test-eom-align, test/tests/manpages/test-manpages: + Load common.sh via absolute path, otherwise some /bin/sh + (e.g. dash) can't load it. + + * uip/Makefile.in, uip/new.c, test/tests/new/test-basic: Add new + program, and fn/fp/unseen symlinks. + + * test/{runtest,setup-test}: Move MH profile under Mail directory + so each test script will have its own to muck with, if needed. + + * h/Makefile.in, h/crawl_folders.h, sbr/Makefile.in, + sbr/crawl_folders.c, uip/folder.c: Extract the folder crawling + code from folder.c into new crawl_folders function, using a + callback to assemble the folder info in folder.c. Drop compare + function and use strcmp instead. Rename addfold and addir to + add_folder and add_children (add dir vs. add folder? + confusing names). + +2008-12-26 Peter Maydell + + * sbr/m_getfld.c: fix two bugs which could cause us to walk off + the beginning of the stdio or prefix-string buffer when checking + for presence of the end-of-message delimiter in some situations. + This might cause inc to dump core if you were unlucky. (This was + Debian bug 359167.) + * test/tests/inc/{md5sums,msgheader.txt,test-deb359167, + test-eom-align,fromline.txt,filler.txt,deb359167.mbox}: new tests + both for the specific problem and to try to check various alignments + of the eom string with the stdio buffer ending. + * test/common.sh: new file for common utility functions for the + test scripts. Moved findprog out of manpage test script into this + new file. Added some functions for doing progress indicators. + +2008-12-25 Peter Maydell + + * test/runtest: automatically run setup-test if it hasn't already + been done. Improve error handling in test script with 'set -e'. + +2008-10-23 David Levine + + * h/mh.h: raised NAMESZ from 128 to 999. RFC 2822 limits line + lengths to 998 characters, so a header name can be at most that long. + m_getfld limits header names to 2 less than NAMESZ, which is fine, + because header names must be followed by a colon. Add one for + terminating NULL. + +2008-10-23 David Levine + + * sbr/m_getfld.c: in warning message, use NAMESZ-2 instead of + NAMESZ-1 bytes because the message says "exceeds", not + "is greater than or equal to". + +2008-10-23 David Levine + + * docs/MAIL.FILTERING: added note on removing procmail -f or + -r options to try to suppress generation of a "From " line on + incoming messages. + +2008-08-14 Eric Gillespie + + * test/setup-test: Don't run autogen.sh unless needed. Build in a + blddir under the temporary directory so as not to interfere with + whatever the developer may be doing in the source directory. + If the temporary directory already exists, rebuild and install it. + +2008-08-13 Eric Gillespie + + * sbr/ambigsw.c: Send print_sw output to stderr. This avoids + strange problems with scan `pick -bogus`, not to mention being + nicer anyway. + + * sbr/getans.c, sbr/print_help.c, uip/msh.c: Send print_sw output + to stdout. + + * h/prototypes.h, sbr/print_sw.c (print_sw): Add FILE * argument + and send output there rather than to stdout. + + * test/tests/pick/test-stderr: Add test that error messages don't + end up going to stdout. + +2008-08-13 Eric Gillespie + + * uip/pick.c: Print matching messages immediately, instead of + waiting until the very end to print anything. + Ensure valid sequence name as soon as we parse it from command, + instead of searching the messages first. + +2008-08-13 Eric Gillespie + + * uip/Makefile.in, uip/popi.c: Remove popi.c, which has been dead + since PatchSet 257 (2000/06/12 11:07:34 UTC). + +2008-08-13 Eric Gillespie + + * h/mhparse.h: Move interfaces also used by mhbuildsbr.c here + from mhparse.c. + + * uip/Makefile.in (mhbuild): Build with mhparse.o. + + * uip/mhbuildsbr.c: Drop the duplication of mhparse.c. + + * uip/mhbuild.c, uip/mhlist.c, uip/mhn.c, uip/mhshow.c, + uip/mhstore.c, uip/mhtest.c: Drop check swdeclaration, which is + now in mhparse.h. + + * uip/mhparse.c: Move some declarations to mhparse.h, and remove + 'static' from the definitions here. + (get_ctinfo): Take magic mhbuild support from mhbuildsbr.c's copy, + and adapt callers. + (incl_name_value, extract_name_value): Move from mhbuildsbr.c to + support get_ctinfo change). + (get_content, open7Bit): Add Content-Disposition support, added to + mhbuildsbr.c's copy in mhbuildsbr.c r1.12 (PatchSet 549). + (InitText): Default to CHARSET_UNSPECIFIED instead of "US-ASCII", + as mhbuildsbr.c's copy did. Explain termproc. + (openBase64, openQuoted, open7Bit): Fix comment from r1.5: + suffixes, not prefixes. + (openMail): Explain showproc. + + * test/tests/mhshow/test-cte-binary: Add test for + Content-Transfer-Encoding: binary (Debian #136976). + + * test/tests/mhbuild/test-forw: Add an mhbuild test, testing forw + with and without RFC-934 mode. More mhbuild tests would be nice. + +2008-08-13 Eric Gillespie + + * test/tests/bad-input/test-header: Add test for it. + + * sbr/m_getfld.c: If we reach the end of the line without finding + a ':' when parsing a header field, treat that line as the + beginning of the body rather than blowing up. These messages are + usually spam, but it's nice to be able to at least scan them. + +2008-08-12 Eric Gillespie + + * test/tests/mhshow/test-qp: Test various valid and invalid + escape sequences. + + * uip/mhparse.c (openQuoted): Simplify the decode-or-show for loop by + peeking ahead to the next byte(s) when encountering '=', and just let + invalid escape sequences through as literals (fixes bug #15245). + +2008-08-12 Peter Maydell + + * autogen.sh (new file): add script for running the GNU + autotools in the right order + * INSTALL: mention that you need to run autogen.sh if you + got nmh from CVS + * docs/README.developers: mention autogen.sh rather than + suggesting running autoheader and autoconf by hand. + * test/setup-test: run autotools via autogen.sh + +2008-08-08 Eric Gillespie + + * sbr/discard.c, sbr/m_getfld.c, uip/scansbr.c: Add support for + DragonFlyBSD stdio (from NetBSD pkgsrc). + +2008-08-05 Eric Gillespie + + * uip/folder.c: chdir(nmhdir) in main rather than in dodir, which + is called many times. Drop the chdir in get_folder_info, which + served no purpose at all. If struct stat has d_type (BSD), use + that to skip processing (strcmp, stat, and so on) of message + files, mostly undoing the slow-down from the last change. + + * configure.in: Call CHECK_TYPE_STRUCT_DIRENT_D_TYPE. + + * aclocal.m4: Add CHECK_TYPE_STRUCT_DIRENT_D_TYPE from + GNU coreutils. + +2008-08-04 Eric Gillespie + + * uip/folder.c: Simplify dodir/addir/addfold. Dump hacky + over-optimization in addir that tried to avoid readdir after all + child directories had been read; this was also trying to support + symlinks to directories, but would have been failing (because + nlink may have gone to 0 with symlinks to directories remaining) + had the lstat usage been correct (lstat doesn't fail for normal + directories; should have used S_ISLNK). + +2008-08-03 Peter Maydell + + * test/setup-test: use 'set -e' so we stop on compile failure. + Configure --enable-debug for convenience in debugging. + + * uip/whatnowsbr.c: bug #23319: rework the way we handle the working + directory when invoking the user's shell, so that we don't have + issues when the cwd contains a space or shell special character. + * test/tests/whatnow/test-attach-detach, test/tests/whatnow/test-cd, + test/tests/whatnow/test-ls: test cases for this. + + * sbr/fmt_compile.c: add 'do { ... } while (0)' wrappers + to various multi-statement macros to avoid nasty surprises + if the macros are used in if() clauses. + + * bug #23436: man/scan.man, man/forw.man, man/inc.man, + man/mh-chart.man, man/mhmail.man, man/mhshow.man, + man/mhstore.man, man/msgchk.man, man/packf.man, man/scan.man: + fix minor syntax errors groff warns about. + * test/runtest, test/README: allow test cases to report + that they have been SKIPped as well as PASS/FAIL + * test/tests/manpages/test-manpages - new test which runs groff + on the manpages and checks that there are no warnings. + * test/runalltests: ignore editor backup files + +2008-08-03 Eric Gillespie + + * etc/replcomps, etc/replgroupcomps: Trim trailing whitespace from + Subject field. + +2008-08-03 Peter Maydell + + * sbr/fmt_compile.c: when doing an if-test on the result + of a function which returns a string result, check whether + the string is non-empty (as the documentation says we do). + Previously we were always testing the integer 'value'. Bug + spotted by Eric Gillespie. + * test/tests/repl/test-if-str: test case for this bug + +2008-07-24 Eric Gillespie + + * test/setup-test: Run 'make clean' before building + +2008-07-24 Eric Gillespie + + * test/runtest: cat test-temp-dir only once. Destroy and create + test Mail hierarchy here, so each test has its own independent + test data. + + * test/setup-test: Drop needless pushd/popd, which don't exist in + sh anyway. Don't use aclocal, which is part of automake. + Don't create Mail hierarchy here (see test/runtest). + + * test/tests/folder/test-create, tests/folder/test-total: Drop + unused BINDIR. + + * tests/pick/test-pick: Remove failing no-op test. + + * test/tests/scan/test-scan: Write expected and actual output to + files and diff them. This way, if the output differs, diff + provides the FAILing exit code and shows the differences. + +2008-06-12 Josh Bressers + * man/repl.man, etc/mhl.reply: + Add an attribution line when replying to messages. + +2008-06-02 Peter Maydell + + * h/mh.h, h/prototypes.h, sbr/done.c, uip/inc.c, + uip/mhbuild.c, uip/mhlist.c, uip/mhn.c, uip/mhshow.c, + uip/mhstore.c, uip/mhtest.c, uip/packf.c, uip/pick.c, + uip/rcvdist.c, uip/rcvstore.c, uip/sendsbr.c: when + building on gcc, use the noreturn attribute on various + functions (should improve code and avoid some spurious + 'uninitialized variable' warnings). + +2008-06-01 Peter Maydell + + * docs/README.developers: update the bits about doing a + release announcement, now I've actually done one. + +2008-05-22 Peter Maydell + + * uip/scansbr.c: don't use MB_CUR_MAX if we aren't compiled + with multibyte support. + + * uip/whatnowsbr.c: factor out common code for writing ls + shell command, and make it do more sensible buffer length + checks. Also avoid relying on the return value of sprintf(), + as some old systems don't return number of characters written. + +2008-05-21 Peter Maydell + + * sbr/utils.c (mh_xrealloc): don't assume realloc() can + handle NULL pointers; some non-POSIX realloc()s can't. + + * sbr/dtimep.lex: add some table size declarations for the + benefit of elderly lexes with small defaults. + +2008-05-18 David Levine + + * sbr/addrsbr.c: removed "err" from conditional, because gcc + correctly warned that it would always evaluate as true. It's + the address of a static array. + +2008-05-16 Oliver Kiddle + + * sbr/Makefile.in, config/Makefile.in: Don't use $< in target rules + in makefiles, as POSIX says it's only defined in inference rules. + +2008-05-13 David Levine + + * configure.in, INSTALL: if --enable-masquerade is not + specified to configure, enable all supported masquerade forms. + This allows users to masquerade with the default + configuration. That seems to be more worthwhile now than + trying to prevent users from using it, especially with + single-user installations or those where a user can edit + etc/mts.conf. + +2008-05-04 Peter Maydell + + * bug #23167: sbr/ruserpass.c (ruserpass): make bad permissions + on .netrc be an instantly fatal error. Previously we returned + an error value; however, no caller was checking it. So now + ruserpass() has a void return type. + + * bug #23163: various minor fixes for the benefit of + older Unixes (specifically SunOS 4): + reintroduce strerror() substitute implementation + provide memmove() substitute implementation + + * bug #23163: fix accidentally broken 'build outside + source directory' feature + + * bug #23162: sbr/dtime.c: fix stray HAVE_TM_GMTOFF that + wasn't updated to the new macro name. + +2008-04-30 Peter Maydell + + * mts/smtp/smtp.c: provide a callback for SASL_CB_AUTHNAME + (fixes issue with SASL sending the wrong username in some + circumstances). Thanks to + for the patch. + +2008-04-29 Peter Maydell + + * Revert previous attempt at fix for SASL issue as it + is the wrong approach. + + * Fix in correct manner, by making sm_rrecord() and thus + sm_hear() set the length of the reply string correctly + (the SASL libraries now care if you pass in the wrong + length). + + * Correct various places in smtp.c where the reply string + might not have been correctly NUL-terminated. Includes a + fix for a particularly nasty and long standing screwup + where the buffer length counting in smhear() was totally + broken for continued lines from the server. + +2008-04-29 Peter Maydell + + * Cope with sasl_decode64() returning SASL_CONTINUE, as + happens with newer sasl libraries and LOGIN auth. + +2008-04-27 Peter Maydell + + * Updated some of the 'how to do a release' documentation. + + * Upped the VERSION string to '1.3-dev', since 1.3-RC1 has + been branched off. + +2008-04-27 Peter Maydell + + * Released nmh-1.3 RC1. + +2008-04-11 Oliver Kiddle + + * acconfig.h, configure.in, sbr/dtime.c, sbr/pidwait.c, + uip/mhshowsbr.c, uip/rcvtty.c, uip/slocal.c, uip/termsbr.c: + move most remaining macros out of acconfig.h which is an + obsolete feature of autoconf + +2008-04-05 Peter Maydell + + * bug #18655: fix use of admonish() for a fatal error (should + be adios(); only actual effect would be wrong exit code). + Thanks to Craig Leres for spotting this. + +2008-04-05 Peter Maydell + + * bug #20028 (Debian bug 399271): fix code assuming that pointer + differences were 32 bits -- thanks to Dean Gaudet for the patch. + +2008-01-25 Josh Bressers + + * uip/mhshowsbr.c (show_all_messages): Be more generous when parsing + multipart messages. + +2007-11-04 Joel Reicher + + * Changed done() link overriding to function pointer. Return type + is now void so that exit() can be used as done() callback. Dead + code return from all done()s removed, with return 1 in main() + following done() (should never be reached). + +2007-08-21 Josh Bressers + + * Red Hat Bug #253342: inc.c, utils.c, utils.h: When inc is run with + the -silent flag, don't exit(1) for no apparent reason. + +2007-03-12 Peter Maydell + + * bug #18630, #18631, #18632, #18634: various patches from + Craig Leres fixing error message argument problems. + +2007-03-12 Peter Maydell + + * bug #15212: configure.in, acconfig.h: remove configure test for + broken AT&T vi. This test was broken (it was always returning + failure even for non-broken vi implementations) and + unfixable. Nobody should be using AT&T vi any more so I have + simply moved it back to being a setting you can put manually into + acconfig.h if you must. + +2006-10-24 David Levine + + * uip/sendsbr.c: with attachformat values of 1 or 2, add + name= portion to Content-Type header. This makes them + consistent with attachformat value 0. And it allows mhstore + to use that (file)name when extracting attachments. + +2006-08-26 Josh Bressers + + * configure.in: If we're not using dotlocking, there is no need to set + inc sgid. + +2006-03-30 David Levine + + * uip/sendsbr.c: with attachformat values of 1 or 2, only + generate Content-Disposition headers for MIME attachments, not + for the message contents themselves. Microsoft Outlook Build + 10.0.6626, at least, doesn't show the message contents if they + have Content-Disposition. + +2006-03-09 Josh Bressers + + * sbr/fmt_rfc2047.c (decode_rfc2047): Don't close the iconv descriptor + if it isn't valid. + +2006-03-08 Josh Bressers + + * (mh_strcasecmp): Rename the private strcasecmp function to + mh_strcasecmp. This keeps the newer gnu linker happy. + +2006-03-05 Oliver Kiddle + + * sbr/fmt_rfc2047.c: don't try to malloc 0 bytes if an RFC2047 + encoded block is empty + +2006-03-04 Peter Maydell + + * etc/Makefile.in: use INSTALL_SCRIPT to install scripts; + this allows INSTALL_PROGRAM to be set to 'install -s' so + binaries are stripped on installation. Apparently the BSDs + do this. + +2006-02-25 David Levine + + * uip/sendsbr.c: replaced st_mtim with st_mtime, that's what + it should have been. Added #include of h/tws.h to pick up + dtime() prototype. + +2006-02-20 David Levine + + * h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c, + uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man: + added -attachformat switch to send, to support alternate MIME + header contents when using -attach. See send man page for + description. + + * man/mhbuild.man: wrapped one appearance of "Content-Disposition" + with quotes, to be consistent with others. + +2006-02-20 Josh Bressers + + * h/utils.h, sbr/utils.c, uip/flist.c, uip/folder.c: Move duplicate + function num_digits into utils.c + +2006-02-19 Josh Bressers + + * sbr/m_draft.c, sbr/utils.c, uip/folder.c, uip/inc.c, + uip/mhstoresbr.c, uip/popi.c, uip/refile.c: Add create_folder() + function, replacing duplicate code during folder creation. + +2006-02-18 David Levine + + * h/mime.h, h/mhparse.h, uip/mhbuildsbr.c, uip/mhfree.c, + man/mhbuild.man, docs/TODO: added support for an optional + Content-Disposition header in mhbuild (only). Its contents + are supplied between {}, positioned after the optional [], in + a mhbuild directive. If the contents do not contain a + "filename=" parameter, and the directive has a filename, or + something else that ends with "name=", then that will be used + to add a "filename=" parameter to the header. + +2006-02-12 David Levine + + * docs/TODO: added RFC2183 to reference of RFC1806 for + Content-Disposition header. + +2006-01-31 David Levine + + * uip/mhbuild.c, uip/mhbuildsbr.c, man/mhbuild.man: added + -nocontentid switch, to disable generation of Content-ID: + header in MIME messages. (Also added -contentid for + symmetry.) The default configuration of Microsoft Outlook, + Build 10.0.3416 in particular, doesn't see attachments in + incoming messages if there are Content-ID headers, see + http://home.cwru.edu/~wrv/eudoraoutlookfix.html. This allows + users to easily accomodate that by adding + mhbuild: -nocontentid to their .mh_profile. + +2006-01-29 Oliver Kiddle + + * bug 4360: uip/replsbr.c: remove trailing newlines from components + to fix bug with spaces at the end of Subject/References in replies + +2006-01-18 Oliver Kiddle + + * configure.in: use AS_HELP_STRING for formatting help messages + + * configure.in, sbr/fmt_scan.c: add autoconf magic to support + old systems that don't support multibyte character sets + + * sbr/fmt_scan.c: fix bug with insertion of newline being wrong if + the num function was used at the end of the format buffer + +2006-01-17 David Levine + + * uip/post.c, uip/spost.c: in make_bcc_file (), use same + logic as in finish_headers () to detect whether there is an + existing From: line in the draft. If draft_from masquerade + flag is enabled, this allows the From: to be obeyed in the + Bcc, instead of the old behavior of always replacing it with + the signature. + +2006-01-17 Oliver Kiddle + + * sbr/fmt_scan.c: more robust multi-byte/column support for field + widths, restoring right justification feature + +2006-01-16 Oliver Kiddle + + * h/aliasbr.h, h/rcvmail.h, man/Makefile.in, man/slocal.man, + sbr/lock_file.c, uip/aliasbr.c, uip/dropsbr.c, uip/post.c, + uip/slocal.c, man/mh-mts.man: remove remnants of code for MMDF + + * uip/scansbr.c: multiply buffer size by MB_CUR_MAX so multi-byte + chars fit + +2006-01-14 Josh Bressers + + * sbr/fmt_scan.c: Turn the PUTSF macro into a function capable of + handling multi column characters. + +2006-01-07 Josh Bressers + + * Remove sbr/strerror.c -- strerror(3) is defined in C89. + +2006-01-06 Josh Bressers + + * patch #3968: Move the add() function from its own file (add.c) and + into utils.c. There was also a duplicate add() function in mf.c which + has been removed. + +2006-01-02 Josh Bressers + + * Remove sbr/pwd.c file, moving the pwd() function into sbr/utils.c. + +2006-01-01 Josh Bressers + + * patch #3967: Create a mh_xrealloc function to prevent mistakes when + calling realloc. + +2006-01-01 Josh Bressers + + * patch #3966: Create a mh_xmalloc function to prevent mistakes when + calling malloc. + +2005-12-24 Peter Maydell + + * Bug #15285: Don't use $< in target rules in makefiles, as POSIX + says it's only defined in inference rules. (BSD make was expanding + $< to the empty string in the rule for building sbr/dtimep.c, which + causes lex to apparently hang because it's reading from stdin.) + +2005-12-24 Peter Maydell + + * Completely redo db library checking -- we now check for working + (include file, library) pairs rather than checking for headers and + libraries separately. We also now provide --with-ndbm=lib and + --with-ndbmheader=header options to configure to handle situations + where configure's autodetection fails. + +2005-12-21 Peter Maydell + + * Fix stupid accidental dependence on a bash quirk in previous + configure script change. + +2005-12-15 Peter Maydell + + * Improve checking for Berkeley db libraries: configure should now + find a suitable library on systems with new gdbm where + compatibility functions are in the gdbm_compat library, and on + systems with libdb4. + +2005-12-13 Michael Forrest + + * Fedora Bug #163760: sbr/context_read.c (context_read): Ensure that + the context is only read once. + +2005-12-12 Josh Bressers + + * uip/sendsbr.c (annoaux): Fix the call to annotate() fixing a bug + which prevented repl from properly annotating messages. + +2005-12-07 Jon Steinhart + + * Fixed a bug where anno -append put the headers in the wrong place + if applied to a message that didn't contain any headers. + + * Added a special value of "all" to the -number option that causes + anno -delete to delete all matching components instead of just + the first one. + + * Added new -preserve and -nopreserve options. Using -preserve + retains the original last accessed and last modified times on + annotated messages. + +2005-12-05 Josh Bressers + + * Fedora Bug #174983: configure.in: Fix the AC_PATH_PROG default when + vi isn't found during build. + +2005-11-19 Peter Maydell + + * bug #14977: sbr/context_read.c: special case an MHCONTEXT of + "/dev/null" and don't try to lock it. + + * bug #9228, debian bug #146449: man/mh-profile.man: make it clearer + that lower case environment variables (and in particular mheditor) + are internal to nmh and not intended to be set by the user. + +2005-11-09 Peter Maydell + + * sbr/mf.c: fix buffer overrun with absurdly long addresses + (only causes crashes if scan is run with '-width 16536' or similar) + + * bug #7917: sbr/context_foil.c, sbr/context_read.c, + sbr/context_save.c: mark 'no context' with NULL rather than + "/dev/null" so we don't inadvertently try to lock /dev/null (which + takes up to a minute in some locking configurations and makes post + very slow). + + * patch #3913: uip/post.c: pass some globals into sm_init() so that + it uses SASL if necessary. (This bug was preventing Bcc'd emails + from being sent via SASL authenticated SMTP.) + + * bug #9813: uip/rmf.c: don't crash if there's no Current-Folder + entry in the context file. + +2005-11-13 Oliver Kiddle + + * bug #7833: uip/Makefile.in: remove link to install-mh that caused + problems on some systems + + * bug #739: Makefile.in: install target now depends on all to avoid + problem on case-insensitive file systems with the INSTALL file + +2005-11-10 Josh Bressers + + * Fedora Bug #172838: configure.in: Fix the AC_PATH_PROG default when + sendmail isn't found during build. + +2005-11-09 Peter Maydell + + * h/aliasbr.h: fix a non-ANSI prototype. + +2005-11-08 Oliver Kiddle + + * Simon Burge: acconfig.h, configure.in, uip/rcvtty.c, uip/slocal.c: + fix to handle getutent() on NetBSD + + * INSTALL, README, docs/README.about, man/nmh.man: update most + references to the web page and mailing list locations + + * bug #10230: etc/Makefile.in, man/Makefile.in, uip/Makefile.in: + Michael De La Rue: prepend DESTDIR to install locations + + * configure.in, */Makefile.in, mts/smtp/smtp.c: replace obsolete + autoconf macros + +2005-11-06 Peter Maydell + + * sbr/fmt_rfc2047.c, sbr/fmt_scan.c, h/prototypes.h: fix various + possible overruns of the buffers in fmt_scan() which would cause + crashes if scan was run with '-width 16536' or similar. + + * uip/popsbr.c: fix compile error which only showed up if nmh + was configured with --enable-apop. + + * Debian Bug# 245932, RedHat Bug# 172388: uip/mhparse.c: don't + crash when handling a multipart MIME message with an invalid + Content-Type header (file handle was being fclose()d twice). + + * sbr/Makefile.in: adjust lex command to work on both old and + new versions of flex. + + * configure.in: add an AC_PREREQ() so autoconf 2.13 gives a helpful + error message and the Debian autoconf-version-guessing wrapper + doesn't guess wrongly. + +2005-11-02 Oliver Kiddle + + * Debian Bug# 320069: Nick Rusnov: uip/popsbr.c: fail when + kpop connection attempted without KPOP support compiled in + + * Debian Bug# 320090: Nick Rusnov: sbr/Makefile.in: fix for newer + version of flex and remove autogenerated file from cvs + + * patch #1155: uip/flist.c: speed up flist by skipping stat on + files with numbers as names + + * docs/Makefile.in: include new files in distribution + +2005-10-11 Bill Wohler + + * docs/FAQ: fold questions into MH FAQ and distribute that instead + +2005-10-05 Oliver Kiddle + + * Harald Geyer: h/mh.h, uip/replsbr.c: back out previous change + (fork/vfork) and replace with code that handles the issue directly + +2005-05-18 Oliver Kiddle + + * Debian Bug# 143485: Nick Rusnov: h/mh.h: use fork instead of + vfork on Linux + + * Debian Bug# 261592: Harald Geyer: uip/mhlsbr.c, uip/replsbr.c: + test/report error writing to stdout + + * mts/smtp/smtp.c, uip/popsbr.c: correct SASL include file locations + + * docs/COMPLETION-BASH: bash completion definitions from Debian + + * patch #2863: savannah@brisammon.fastmail.fm: sbr/folder_read.c: + fix a bug affecting AFS where nmh was setting the READONLY flag + for a folder even when you do have write access to the folder + + * Carl Mummert: h/fmt_compile.h, man/mh-format.man, + sbr/fmt_compile.c, sbr/fmt_scan.c: add unquote() function for + removing quotes from RFC-2822 encoded headers + +2005-02-23 Oliver Kiddle + + * use iconv to convert RFC-2047 encoded headers to the + character set used by the current locale + + * sbr/folder_read.c fix Debian bug #202667: crash when a + message's filename overflows an int when converted + + * Updated config.guess and config.sub to the most recent + versions (from automake 1.9.5) + +2005-02-21 Oliver Kiddle + + * sbr/getpass.c fix bug where inc crashed on failing to reopen + the terminal + +2005-01-27 Oliver Kiddle + + * Added -proxy option to inc and msgchk. Based on old patch + from Michael Richardson. + + * On systems where it is available, use nl_langinfo to get the + character set if MM_CHARSET is unset + +2005-01-21 Oliver Kiddle + + * sbr/check_charset.c US-ASCII is a subset of UTF-8 so can be + handled directly when UTF-8 is being used + +2004-12-17 Oliver Kiddle + + * uip/mhmisc.c Fix -part option to mhshow/mhlist/mhstore to + find sub-parts of the specified part + +2004-11-19 Jon Steinhart + + * h/prototypes.h, sbr/folder_addmsg.c, uip/mhstoresbr.c, + uip/rcvstore.c, uip/refile.c: Added mail directory argument to + folder_addmsg in order to make it possible to provide a path to + the ext_hook call that is mailpath-based. A problem existed when + a folder was a symbolic link and the pwd call would return the + path relative to the filesystem, not to mailpath. A new argument + was needed because there was otherwise no reasonable way to get + that path. + +2004-11-16 Jon Steinhart + + * sbr/folder_pack.c: Fixed problem where the refile hook was being + called after a message was renamed so that it wasn't around for + the hook. The hook is now called before the message file is + renamed. + + * sbr/folder_addmsg.c: Fixed wrong directory for hook when + refiling with -src option. + +2004-10-15 Jon Steinhart + + * uip/sortm.c: Fixed calling of external hooks. + +2004-10-12 Jon Steinhart + + * uip/inc.c: Fixed another weird bug caused by the static + mailpath being overwritten. + + * uip/sendsbr.c: Fixed bug that caused anno to mangle headers. + + * sbr/lock_file.c: Fixed strange bug that prevented a lock from + ever being obtained if getting it failed the first time. The + problem was that the string of XXXXXX that is required by + mkstemp() was overwritten the first time through, and so all + subsequent times failed because mkstemp() failed. The fix + reinitializes the tmp file string. + + * uip/inc.c: Fixed bug in which the static maildir was overwritted + if a format string was read from the profile. + + * sbr/folder_delmsgs.c: Fixed bug that was producing an incorrect + path for the external hook. + +2003-10-06 Glenn Burkhardt + + * uip/slocal.c, configure.in: db configuration fix for Debian; yet + another location for ndbm. + +2003-09-30 Glenn Burkhardt + + * Fix 'pick' so handling of options "-list" and "-seq" are + independent. + * Fix 'inc' realloc error when bringing in more than 100 msgs + to empty folder. + * Patches submitted by Nick Rusnov from Debian archive applied: + + Debian Bug# + 136976 - Handle binary content messages + 143427 - mh-format.man typo + 144098 - 'spost; should have same behavior as 'post' + w.r.t. mts.conf masquerade line + 149745 - slocal ignores 'N' result of previous command + 152728 - increase SMTP timeouts to conform to RFC 1123 + The timeouts suggested by the RFC seem long + to me - but the RFC is still listed as active. + 181867 - typo for nmh.man + +2003-08-10 Jeffrey C Honig + + * Fix problem where parsing of address/date fields in fmt_compile + is optimized to the first instance. The first instance may be in + contitional code which will result in cached data to + be used. Instead, convert c_flags to a flags field from a boolean + and parse on the first use. + * Remove some unused flag bits. + +Fri Jul 01 22:02:00 2003 Glenn Burkhardt + + * Applied fixes for configuration problems with Solaris and + systems with gdbm instead of db1 (includes bug #2024) + * Fixes for bugs + #578 - repl leaks umask + #1393 - sortm core dumps + #1650 - msh leaks file descriptors + #1730 - Double free() in mhfree.c:free_encoding() + #3356 - In-Reply-To header in default replcomps should be + RFC2822 compliant + * Revised man page for mh-format (bug #2031) + * New replcomps, etc, with Fcc: +outbox in default versions + +Sat Mar 17 03:18:15 2001 Dan Harkless + + * Ken Hornstein's configure.in Cyrus SASL checks were doing + `x"$with_cyrus_sasl" != "no"' instead of `... != x"no"'. + +Tue Mar 06 21:04:27 2001 Dan Harkless + + * Found some historical information about MH in RFC 808. + Supplemented it with info from Jerry Peek's MH book and added it + to docs/README.about. + +Tue Feb 6 20:35:40 2001 Shantonu Sen + + * sbr/dtime.c Use the same Y2K correction code as dtimep.lex + + * sbr/dtimep.lex Restrict the parser to accept either + a numerical timezone offset, or a symbolic one (e.g. EST), + but not both (Since "2000 -400 EDT" might cause a double + subtraction of 60 minutes if both are parsed. One should be + enough). + +Mon Feb 05 20:22:54 2001 Dan Harkless + + * -L isn't sufficient for specifying the path of the Cyrus SASL + shared library. That'll allow us to link successfully, but on + many/most OSes that won't allow us to find libsasl at runtime. On + Solaris, we need to specify the library path with -R as well (or + else the user will have to use the $LD_LIBRARY_PATH kludge, which + is considered harmful). This fix should be extended to other OSes + as well. + + * Print whether we have SASL support in the "nmh configuration" + summary configure prints out. + + * Say in README.developers to use `\date' in case anyone is like + me and has `date' aliased in their shell to use a nonstandard (but + subjectively more readable) format. + +Thu Jan 25 21:15:52 2001 Shantonu Sen + + * man/mh-chart.man has updated synposes of + all nmh commands. + +Tue Jan 23 20:26:15 2001 Shantonu Sen + + * etc/digestcomps tried to force dates into a + 19xx when it's not necessary. + +Fri Jan 19 21:22:08 2001 Shantonu Sen + + * First round of manpage updates finished. They + are standardized on -man macros, with minimal + roff mark-up. + + * man/tmac.h.in is no longer needed, since the + manpages do not depend on them anymore. Note: + strict "man" programs that didn't allow ".so" + sourcing outside the man tree will now format + the man pages correctly. + + * man/vmh.1 is no longer built, since uip/vmh isn't + +Tue Jan 9 6:01:22 2001 Shantonu Sen + + * Finished manpages ali-prev + + * Removed deprecated files from the repository. + Specifically, those rooted in zotnet/ and mts/sendmail + mts/mmdf. "cvs update -dP" will give a pruned directory + structure. + + * Updated docs/Makefile.in to include README.manpages, and + uip/Makefile.in to include popi.c (which isn't being built, + though). This allows "make nmhdist" to create an archive that + is file-for-file identical to the current cvs repository. + +Sun Dec 31 20:48:50 2000 Shantonu Sen + + * Create docs/README.manpages, which details + the formatting rules I've been using. + + * Finished ali-inc. + +Sat Dec 30 9:50:13 2000 Shantonu Sen + + * Created a new file "DATE" to hold the date + of the most recent nmh release. This date will be + used in the manpages. + + * Updated docs/README.developers to add the step + of updating DATE. Also, updated configure to + read in the contents of the file as the variable + $DATE. + + * Started work on updating man pages, with only + ali finished so far. Changes: 1) no dependence + on an external macro file, 2) uses only + -man macros (although I may be mistaken in this), + 3) syntax in the SYNOPSIS is a little more + in line with standard UNIX documentation, such as + bold flags and italicized parameters. + +Sun Dec 24 10:06:30 2000 Shantonu Sen + + * Updated INSTALL with information about the + --with-locking option. + + * Fixed the Hesiod tests in configure.in. In + systems where res_send was in -lresolv, this + information was not being communicated to the + HESIOD_LIBS var. Now, if res_send is not found + in the default libraries, it's assumed to be + in -lresolv, and thus -lresolv is appended to + HESIOD_LIBS, which will need that to avoid + undefined symbols problems. + + * Fixed the Kerberos tests in configure.in. New + versions of Kerberos 5 have renamed -lcrypto + to -lk5crypto (circa krb5 1.1 or thereabouts). The + new test tries to determine if -lk5crypto exists. If so, + this is a new krb5 system. If not, test for -lcrypto + and the rest of old krb5. If that fails, look + for a genuine krb4 installation. + +Fri Dec 22 22:08:51 2000 Dan Harkless + + * -apop and -noapop were not documented in msgchk.man. + -snoop was documented but didn't appear in the usage SYNOPSIS. + +Fri Dec 22 23:42:16 2000 Shantonu Sen + + * Made a new ./configure option called + "--with-locking" that allows the file + locking mechanism to be chosen there instead of + requiring a manual edit of config.h. + + * If the option is not explicitly set, or an + invalid option is specified, "dot" locking is + chosen. Valid options are "dot", "fcntl", + "flock", and "lockf". We need a way to tell + the user that these are the valid options, and + change the flag "--with-locking" if it's not + descriptive enough. + +Fri Dec 22 19:21:29 2000 Shantonu Sen + + * Remove the lex-specific memory hints at the + beginning of sbr/dtimep.lex. We've already + committed to supporting flex only, since + lex does not easily allow us to parse a single + string, as well as other problems documented + below and on nmh-workers. + + * Added a switch statement to configure.in to + test for Mac OS X. If this is the case, LDFLAGS + should not contain "-s" since the linker rejects + the flag. + + * Updated MACHINES to include Mac OS X Public Beta, + as well as Linux 2.4 running glibc 2.2. + +Wed Dec 20 16:00:46 2000 Shantonu Sen + + * Marked deprecated directories in docs/README.developers + as deprecated, with pointers to the new code location. + Eventually these deprecated directories should go away. + +Tue Dec 19 19:16:37 2000 Dan Harkless + + * -apop and -noapop were not documented in inc.man. -snoop was + documented but didn't appear in the usage SYNOPSIS. + +Thu Dec 14 14:32:09 2000 Shantonu Sen + + * Updated config.guess and config.sub to the most recent + versions on ftp://ftp.gnu.org/pub/gnu/config, dated + 12-07-00. This should prevent configure from failing + on newer operating systems because config.{guess,sub} + couldn't correctly identify them. + +Thu Dec 14 1:30:44 2000 Shantonu Sen + + * Fixed the circular dependency created when I moved + zotnet/mts to mts/generic and merged them into libmts. + mts/generic/client.c and mts/generic/mts.c are now in sbr/ + (and thus in libmh), which makes libmh self-contained and + not depending on an external archive. + + * All include statements now look for mts.h in h/. The + Makefiles and configure script have been modified so that + mts/generic is no longer built. + +Mon Dec 11 22:08:07 2000 Dan Harkless + + * When Shantonu made the new libmts.a, he swapped $(MTSLIB) and + libmh.a in sbr/Makefile.in so that libmh.a comes first, but this + causes the build to fail on Solaris, because libmts.a has to get + ruserpass() out of libmh.a. Swapping them back to the way Ken + Hornstein's patch (which I applied on Jul 20) put them, with + libmh.a correctly coming second. If there are times when libmts.a + needs to come second, then it would appear there's a circular + dependency and someone (Shantonu?) did an mts merge incorrectly. + +Fri Sep 8 01:36:23 2000 Shantonu Sen + + * Took out bad time textual time zones like BST and JST. + I found them online somewhere, but am not sure if they're + correct. + +Fri Sep 8 00:36:48 2000 Shantonu Sen + + * Moved zotnet/mts to mts/generic. This code reorganization + makes the entire zotnet tree deprecated -- bboards is unneeded, + mf was was moved to sbr, tws was rewritten and moved to sbr, and + now finally mts. + + * Created a new static library called libmts.a used during + compilation which includes the generic mts code and the + smtp/sendmail code. This supercedes the functionality of the + old libsmtp.a and the remains of libzot.a. + + * Updated header includes to reference the new location of mts.h + in mts/generic/mts.h. Also, update the configure and top-level + Makefile not to descend into zotnet. Also, they don't descend + into mts/mmdf and mts/sendmail (the sendmail code has been + merged into the smtp code). + + * Added #include to h/md5.h, since my compile was + complaining about implicitly-declared memcpy and memset, which + appear to be in strings.h. In any event, nmh.h should take care + of it for us. + + * When doing a "make nmhdist", notice that the generated + snapshot does not include zotnet of the mts directories as noted + above. Since they are no longer compiled, and I don't see any + obvious code path to get to them, end-users should probably + not need them. If you think otherwise, turn Makefile generation + back on in configure.in and turn on recursion into those dirs + in the appropriate Makefile.in + +Wed Sep 6 22:40:03 2000 Shantonu Sen + + * Tracked down the problem in the new dtimep where time + zones were being radically misreported. It was because the + parser knew about military time zones (such as M or E) but in + some cases did not know about the textual representation of + some zones (like MET). When it encountered one of these, the + date parser misread MET as the military time zone T (well, first + zone M, then E, and finally T). I took military zones out, and + things seem much better. Also, the default behavior of parsing + time zones appears to default to GMT in the absence of better + info, which is less bogus than assuming the mail came from the + current time zone, which was the behavior in 1.04. + +Thu Aug 10 13:22:13 2000 Dan Harkless + + * Decided that limiting the message number columns to 3 on my + scan.MMDDYY and scan.YYYYMMDD (to try to regain space taken by + extra date info) was ill-conceived. It's not that tough to get + past 999 messages, though I imagine it's rather rare to exceed + 9999. Changed these to 4. Also put the "replied / encrypted" + column back in YYYYMMDD -- I've never seen it show anything but a + space, but that space is useful if you use scan, grep, and awk + (with the default field separator) to grab message numbers (I know + -- pick should really be used for these purposes...). + +Mon Aug 7 20:11:09 CEST 2000 Ruud de Rooij + + * Modify umask set by mhshow to enable user execute bit, so that + viewers that create temporary directories (e.g., lynx) will be + able to access them. + +Thu Aug 03 17:14:08 2000 Dan Harkless + + * TODO: Allow multiple simultaneous differing contexts, probably + each tied to a parent (terminal) process. + +Tue Aug 1 10:48:05 EDT 2000 Kimmo Suominen + + * Makefile install rules should not look for generated files in + the source tree -- this will happen to work when configuring and + building inside the source tree but will fail when using an + external build tree. Fixed etc/Makefile.in. + +Mon Jul 24 16:20:45 2000 Dan Harkless + + * When Shantonu wrote the new, more portable dtimep.lex, he left + out the #ifdef DSTXXX stuff for some reason. Not a good idea, as + that code is required for proper printing of numeric-offset + timezones that have daylight saving time. Without that code, + -0700 during DST gets printed as MST instead of PDT. + + * Renamed DSTXXX as ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST and + added an explanatory comment by its #definition. + + * Updated README.developers with the fact that zotnet/tws is going away. + +Thu Jul 20 20:30:52 2000 Dan Harkless + + * Moved Kimmo's new "--with-hash-backup" to be output with the + rest of the --with options in the configure --help output. Also, + people did not preserve my alphabetization of the --with options + when they added new ones. Re-alphabetized. + + * One more pass at README.developers now that it's clear that my + previously-suggested one-line autoconf-file commit can cause + unnecessary local makes and an out-of-sync stamp-h.in file, but + would not cause problems for other people using the CVS files. + + * Ken Hornstein's SASL patch was not integrated properly with + Ruud's new merged mts/sendmail code. Kimmo has since fixed nmh so + it compiles, but according to Ken, the SASL stuff still does not + work. Integrating a patch from him for this. + + * Last pass at README.developers -- Kimmo's 5-step commit was + overkill. You only need 3 steps, since configure.in is the only + autoconf file with the RCS $Id keyword. + + * Applied Kurt J. Lidl 's $MAILHOST patch: + + I have a small patch that would be nice to be included -- + basically, it allows the usage of the "MAILHOST" environment + variable, without having to have HESIOD turned on. I need + this functionality for my environment, where we have identical + /usr/local on all my machines (so I cannot just hardcode into + the mts.conf file), and I have multiple POP mail servers for + my users. + + Modified inc.man to reflect that along with "pophost:" and -host, + $MAILHOST can now activate POP mail inclusion as well. + + * Fixed warnings from diff on first-time install of nmh. Also + added 'echo's clarifying the etc file installation activities. + +Tue Jul 18 19:36:59 EDT 2000 Kimmo Suominen + + * Added the answer to Dan's question in README.developers. + +Mon Jul 17 19:10:36 2000 Dan Harkless + + * Clarified and made some corrections to Kimmo's README.developers + changes (BTW, if anyone can explain why the RCS Ids are able to cause + problems with the dependencies, please fill in the explanation -- + I never encountered a problem with the old single-commit method). + +Sat Jul 15 23:13:49 EDT 2000 Kimmo Suominen + + * Add configure option --with-hash-backup so the backup prefix can + be easily changed from "," to "#". + + * Simplified sbr/Makefile.in so that it works with any make. + + * Use mkstemp in sbr/lock_file.c. + + * Commits of autoconf-related files apparently can't all be done + in one shot due to RCS Ids changing when committing -- updated + README.developers. + +Tue Jul 11 14:18:01 2000 Dan Harkless + + * Clarified post.man and send.man for those not completely up on + SASL terminology. "SASL encryption layers are not supported for + SMTP" means that encryption is supported for the authentication + but not for the subsequent data stream. + +Sat Jul 8 01:36:19 EDT 2000 Kimmo Suominen + + * Applied Ken Hornstein 's patches + implementing SASL support for POP3 and SMTP. If nmh is compiled + with SASL support, using the -sasl switch on the inc, msgchk, + post, and send commands will enable authentication encryption for + SMTP, and both authentication and data stream encryption for POP3. + +Sat Jun 10 18:37:59 CEST 2000 Ruud de Rooij + + * Merged mts/sendmail functionality into mts/smtp; switching between + smtp and sendmail delivery method is now controlled by mts.conf. + + * If tsort cannot deal with loops, in addition to defining tsort as + cat, also define lorder as echo. + + * Removed uip/popi.c from list of sources. + +Thu Jun 08 19:36:57 2000 Dan Harkless + + * New dtimep.lex didn't parse day names properly. Fixed. Also + clarified ambiguous comments preceding day_map[] array (from old + dtimep.lex) that probably led to the erroneous cp++ being added. + +Wed Jun 7 20:52:33 CEST 2000 Ruud de Rooij + + * Added one more mkstemp invocation to uip/spost.c (which was in a + #if 0 block). + + * Applied patch from Peter Maydell to clean up permissions handling + and error handling in uip/inc.c. + +Mon Jun 5 22:10:07 CEST 2000 Ruud de Rooij + + * Use cat instead of tsort if tsort cannot deal with loops in its + input (which is the case for tsort from GNU textutils). + +Mon Jun 5 21:14:36 CEST 2000 Ruud de Rooij + + * If lockfile is present, and its dotlockfile program is setgid, + inc does not need to be setgid. + +Sun Jun 4 21:35:40 CEST 2000 Ruud de Rooij + + * Added autoconf test for Miquel van Smoorenburg's liblockfile + library, as found on Debian systems. + + * Added liblockfile support to sbr/lock_file.c. + +Wed May 31 7:19:30 2000 Shantonu Sen + + * Fixed up dtimep.lex a bit. Added back memory options for AIX to + increase available memory. Took out %option noyywrap, which + wasn't understood by AT&T lex, as well as the -i + case-insensitivity flag. + +Wed May 31 07:40:45 2000 Doug Morris + + * Added a lint target to the Makefiles and a check in autoconf + to determine whether lint or lclint exists on the system. + +Fri May 30 19:21:48 2000 Dan Harkless + + * etc/Makefile.in was incorrectly installing mts.conf.in and + sendfiles.in -- fixed. Generated sendfiles script was not a + dependency of the `all' target, and was incorrectly included in + the distribution. Changed the suffix for the backed-up previous + versions of the etc files from the ambiguous .old to .prev. Added + call to diff -- only keep the .prev files around if different from + the newly-installed versions (intentionally didn't redirect output + to /dev/null so you'll notice when your changed versions are + getting moved aside). + + * INSTALL never documented the etc/*.old thing. Documented the + new etc/*.prev thing (including a note to watch for diff output). + + * Applied Alec Wolman 's dropsbr.c patch: + + In the map_write routine, a call is made to map_open and this + call is supposed to set the "clear" variable to 0 or 1, + depending on whether the map file is empty or not. In + mh6.8.3, this worked because map_open would set "clear" by + calling the mbx_Xopen routine. In nmh, the code for mbx_Xopen + was merged into mbx_open, but the interface for mbx_open + doesn't support the clear variable, so that functionality was + lost. The map_open interface still contains "int *clear" in + the prototype, but never sets it. + + My patch eliminates "clear" from the map_open interface (I + checked to make sure that map_write is the only client of + map_open). Furthermore, my patch also sets the "clear" + variable properly at the beginning of map_write by calling + fstat(). This eliminates the bug in that the value of "clear" + being used later in the routine was just stack garbage. + + Having a bad value of clear causes this next bug to be + triggered: The fp file pointer was being opened with fdopen, + but in two of the three switch cases it wasn't being closed. + In certain cases, this was causing packf to run out of file + descriptors if you attempted to pack a large folder. + +Mon May 29 7:48:15 2000 Shantonu Sen + + * Moved the date parsing routines from zotnet/tws to sbr/ (and + tws.h to h/). Updated all source files to reflect to new location + of tws.h. + + * Rewrote dparsetime (in dtimep.lex -> dtimep.c) to replace the + old zotnet/tws/dtimep.c, dtimep.lex, lexstring.c, lexedit.c, and + dtimep.c-lexed. It should now work with flex (although untested + with lex), and requires no sed-ing. For now, I have the lexed + version in the distribution, so that end-users don't need to worry + about running it through flex/lex. I have not added back support + for guessing the time zone when it's not specified. + +Sun May 28 17:44:15 CEST 2000 Ruud de Rooij + + * Added autoconf check for getutent(). + + * Changed uip/rcvtty.c and uip/slocal.c to use getutent() and + friends. Since I can only check on Linux, please check if + this works on other systems. + +Sun May 28 14:58:49 CEST 2000 Ruud de Rooij + + * Applied patch from Peter Maydell to uip/scansbr.c for more + checks for write failures. + + * Unlink temporary file properly in uip/rcvtty.c. + + * Moved viamail from bindir to libdir. + + * Changed sendfiles into sendfiles.in, so that path to viamail + is patched in. + + * Added gzip support to sendfiles. + + * Added References header to replcomps and replgroupcomps. + +Sun May 28 14:39:31 CEST 2000 Ruud de Rooij + + * Fixed m_getfld bug which caused segmentation faults when + incorporating messages which ended in multiple linefeeds crossing + a buffer boundary. + +Fri May 26 13:21:59 2000 Dan Harkless + + * msh has been unable to show MIME messages ever since 1.0. Alec + Wolman tracked down the problem to the + -show flag being passed to mhshow. mhshow is equivalent to the + old mhn -show, so we don't need the -show anymore. Removed it. + +Fri May 12 02:51:21 2000 Shantonu Sen + + * zotnet/bboards is not longer built by default. Goal is to move + the assorted functions in zotnet into sbr or some more logical + place. + + * Moved zotnet/mf to sbr, and changed mf.h references accordingly, + as well as Makefiles. + +Thu May 11 02:21:34 2000 Shantonu Sen + + * Simplified sbr/Makefile.in so that both SRCS and OBJS aren't + seperately and redundantly defined, but so that OBJS is a + pattern-substituted version of SRCS with suffix .c -> .o. This + should make maintainability easier. + + * Added section to MACHINES indicating what platforms nmh is known + to compile and work on, just to give users peace of mind, or + something. This is by no means complete or exhaustive, so add + whatever you know works. + +Tue May 09 20:38:04 2000 Dan Harkless + + * Alphabetized Shantonu's $pop_kinds output on configure's "pop is + enabled" line. If POP3 is the only kind of POP enabled, say so, + rather than just saying "yes" (which is ambiguous). + + * Fixed four warnings in Shantonu's new getpass.c. Needed to + #include for calloc(), for ttyname(), and + "h/mh.h" for adios(). Also changed ch from char to int to get rid + of "comparison is always 1 due to limited range of data type" on EOF. + + * Added steps to README.developers saying to change the version + number to X.Y.Z+dev. Did a little rearranging and changed the FTP + dir from /home/ftp to /var/ftp to reflect Doug's new machine. + + * Changed configure.in to use gcc -Wall even without + --enable-debug, to prevent developers compiling optimized from + introducing warnings, and to give end-users a warm, fuzzy feeling + as they (hopefully) see no warnings come out (except perhaps on + the lex output file) even with -Wall. + + * Renamed getpass() to nmh_getpass() since the prototype for + getpass() varies from OS to OS, and we want to _always_ use our + version of the function. Fixed all the callers to use + nmh_getpass() and added it to prototypes.h. Semi-arbitrarily + upped MAX_PASSWORD_LEN from 128 to 256. buf was being calloc()'d + and the memory leaked -- should have just been declared as static + char array. Prepended "Portions of this code are" to the + copyright message, as this version has been changed significantly + from the BSD version. + + * Added "nmh-local functions to use in preference to OS versions" + section to README.developers (currently just says to use + nmh_getpass() instead of system getpass()). + + * Prepended "Portions of this code are" to the copyright message + in ruserpass.c also. + + * Added mts.conf.5 page per Neil W Rickert 's + report: + + This happens on solaris: + + % man mts.conf + windex entry incorrect: mts.conf(5) not found. + No manual entry for mts.conf. + + It is fixed by + + % echo ".so man5/mh-tailor.5" > mts.conf.5 + + done in the man5 directory. We need to add 'mts.conf.5' as a + reference sourcing mh-tailor.5. + +Mon May 08 23:51:55 2000 Dan Harkless + + * Doug informed me that the way I had restored the "lost" version + histories was wrong, because `cvs checkout's of old versions of + nmh wouldn't work properly. It occurs to me that this could be + fixed by simply deleting those tags in the new-location *,v files, + but oh well. I'm putting everything back to the way Doug + originally had it. To get the old version history for a file that + used to be in the top directory, you'll need to "blindly" do a + `cvs log' there (even though you won't have a local copy of the + file in that directory). `cvs diff' will no longer be able to + diff pre-move versions vs. post-move versions -- you'll have to do + a lot of manual gyrations with `cvs checkout' and then use `diff'. + + * I had alphabetized the --configure options in the --help output + awhile back, but Shantonu added --enable-apop just under + --enable-pop. Put it in alphabetical order and clarified what + --enable-apop does vs. --enable-pop and --with-krb4. Also changed + --with-mts help line from "mail transport agent" to "mail + transport agent/service" so the 's' in "mts" doesn't seem to come + out of nowhere. + + * Added two steps to "releasing nmh" in README.developers. After + making the tarball, it's a good idea to diff the tree vs. the CVS + tree to make sure no files got left out, and then to chown the + files so that they're owned by root, preventing a Trojaning attack + by a malicious remote user with a UID matching yours. + + * Changed DIFFERENCES to say that RPOP is not currently supported + rather than implying it by saying that APOP, KPOP, and POP[3] are. + +Sun May 07 18:16:43 2000 Shantonu Sen + + * Imported NetBSD version of getpass() and made extensive + revisions for compatibility with programs that pipe the password + to stdin, such as exmh. + + * Removed tests for system ruserpass() which sometimes gave + phantom positive results. Also, bext to use internal functions if + we ever want to change .netrc format to something else, or access + other files. + +Sat May 06 08:28:09 2000 Dan Harkless + + * Restored lost version histories for those moved files by doing a + manual `mv' in the CVSROOT on mhost. CVS badly needs a `cvs mv' + command so that you can move files (without having physical access + to the CVSROOT) without losing versioning. Put MACHINES back at + the top level as it needs to be read before building. Fixed DIST + variable in {.,docs}/Makefile.in to reflect that and to add + missing entry for "INSTALL" file. + +Sat May 06 13:13:07 2000 Doug Morris + + * Re-cleaned up nmh documentation (by moving things to docs + subdir) and modified Makefile & configure.in to handle the change. + +Mon Apr 17 21:28:40 2000 Dan Harkless + + * Scott Blachowicz pointed out that the configure --help output + for --enable-masquerade was misleading. Clarified. + +Mon Apr 17 19:01:00 2000 Shantonu Sen + + * APOP support can be compiled in to inc and msgchk using + --enable-apop. + + * To access an APOP host, specify -apop on the command line + along with any -host or -user option. + +Fri Apr 14 23:10:44 2000 Dan Harkless + + * Upped the version number to 1.0.4+dev until the next nmh release. + + * Added a "releasing nmh" section to README.developers, while the + process was fresh in my mind. + +Fri Apr 14 18:21:34 2000 Dan Harkless + + * Added new files README.developers, ChangeLog_MH-3_to_MH-6.6, and + ChangeLog_MH-6.7.0_to_MH-6.8.4.html to DIST target in Makefile.in. + + * Released nmh-1.0.4. + +Tue Apr 11 21:37:03 2000 Dan Harkless + + * Applied Brian Campbell 's mhn.defaults.sh + patch: + + It appears that there shouldn't be quotes around the %s in the + iso-8859-1 charset entry; xterm passes the remaining arguments + to the program, quoting them means that xterm thinks they're + part of the program's name. + + This %s isn't the same as the "Insert content subtype" one from + mhshow-show-* -- it doesn't come from MIME headers and is safe not + to quote. + +Sun Apr 09 13:03:59 2000 Doug Morris + + * added check in fmt_compile() to handle a single-character + format string. fmt_compile() depends on having an array of + format characters with an empty item at the end. A + single-character format would cause programs using this + function to segfault because the algorithm used to decide on + the length of the array mistakenly created a single-item array + when the format string was one character. This eventually + caused problems when the program attempted to test item+1 + in the array. + +Thu Apr 06 21:53:50 2000 Dan Harkless + + * Richard Coleman threw out a lot of old MH-specific files in nmh. + Much of the stuff, indeed, is not worth saving, but there are + nuggets that are very worthwhile, and should probably be added + back in. Most important, IMHO, are the MH change logs, as they + can help answer questions like "Why is this code like this?" or + "How long has this been broken?" or "What was this ever used for?" + + I've added a new file to the nmh tree called + ChangeLog_MH-3_to_MH-6.6. It's cobbled together from the + mh-6.8.4/papers/mh*/MHCHANGES files. I've re-ordered the entries + to go from newest at the top to oldest at the bottom to match the + ChangeLog convention. Unfortunately there are no change logs for + versions of MH prior to 3 in the MH tar files available at + . Also, it appears to me that there + are MH-6.6 changes that aren't documented in the logs. + + I've also added ChangeLog_MH-6.7.0_to_MH-6.8.4.html. This is + based on mh-6.8.4/papers/changes/mh-changes.ms. The nroff format + and its "catman"-type output are a pain to deal with, but I was + loath to throw away the formatting, so I converted the file to + HTML. The only actual markup in the body are the "" and "" + tags, and "<" and ">" instead of '<' and '>', so it's quite + doable to view the file in plain ASCII mode as well. Note that + some of the changes this file documents as having been made in + MH-6.8.4 may not be present in nmh -- Richard started with 6.8.3 + and later put in certain 6.8.4 stuff. + +Wed Apr 05 21:09:28 2000 Dan Harkless + + * Applied Eric Schnoebelen 's mhshowsbr.c patch + fixing apparent bugs in Dan Winship's new security quoting code: + + Since upgrading, I've been getting the following errors + while attempting to process some MIME messages: + + (1) Syntax error: Unterminated quoted string + exit 2 + + and: + + (2) line 1/10 (END)Segmentation fault (core dumped) + + (2) appears to be due to the testing of an unset pointer in + mhshowsbr.c:show_multi_aux(). (1) appears to be caused by + mis-quoting a filename being handed to the shell in + mhshowsbr.c:show_content_aux(). + + Resolving the pointer reference issue in + mhshowsbr.c:show_multi_aux() turned up a similar mis-quoting + problem in the routine. + +Tue Mar 28 16:17:39 2000 Doug Morris + + * Applied Todd.Miller@courtesan.com's patch to dropsbr.c to + prevent core dumping on packf. Here's the note from his message: + + Since sizeof(buffer) == sizeof(tmpbuffer) packf will dump + core on a file w/o a From line with a line >= BUFSIZ. + I noticed this because I had a junk file in my mail + spool somehow. + +Fri Mar 17 11:59:33 2000 Dan Harkless + + * wesley.craig@umich.edu did not document his previous KPOP patch, + so I did so, and asked him to check what I wrote. Unfortunately + he didn't notice my misunderstanding of his patch. I wrote that + if you #define POPSERVICE "kpop", inc and msgchk will use KPOP + exclusively, but if you leave it as "pop3", you can use Wesley's + new -kpop switch on a given invocation. Instead, however, -kpop + turned out to be necessary on every invocation, and a KPOP user + complained. Applied Wesley's new patch, which makes things work + like I thought his original patch did. After that, did one more + clarifying pass to the documentation in inc.man and msgchk.man. + +Wed Mar 15 18:45:45 2000 Dan Harkless + + * When I fixed the long-standing makedir() bugs in January, I had + the code call strtoul(..., 0), which I believed to be safe as all + modes specified as ASCII constants in the nmh code started with a + leading zero (signifying octal), which I did as it would work if + internal constants were ever changed to hex. Unfortunately I was + unaware of the "Folder-Protect:" .mh_profile entry, which + mh-profile.man documents as an octal-only constant, with no + leading zero required. I've changed the strtoul() call to an + atooi() call and removed the misleading leading zeroes on the + ASCII octal constants in the code and man pages. Also changed the + "Folder-Protect:" example in the man page to something more + interesting than a duplication of the default. + + * When I added my --enable-masquerade option, you'll note that I + didn't make it --enable-nmh-masquerade. I find the --enable-nmh-* + options too wordy and I'm not sure why Richard went that route. + I've renamed them to just --enable-*, but the old versions will + still work as well (they just aren't advertised). + + * Added a line to the "nmh configuration" output saying whether + POP is enabled. + + * Added a new README.developers file. From the file: + + This file is intended to provide a few tips for anyone doing + development on nmh. Developers who learn things "the hard + way" about the nmh codebase (as opposed to local info best + encoded in a comment) are encouraged to share their wisdom + here. + + Currently the topics are "autoconf files" and "directory structure". + +Tue Mar 14 12:41:48 2000 Dan Harkless + + * Applied, after some finessing, + Simon Burge 's --with-smtpservers patch: + + Here's a patch that allows you to add + + --with-smtpservers= + + to the ./configure command line to set the "servers: " line in + etc/mts.conf. Around here, we use "mailhost" so that all + machines in the current domain just talk to a central machine + and nothing else runs an MTA. Now, I can use + + --with-smtpservers=mailhost + + instead of having to remember to fix this by hand (and often + forgetting to do so!). + + * Inspired by Simon's patch, added an --enable-masquerade option + to configure. It will set the "masquerade:" line of mts.conf. + You may specify a subset of the three types of masquerading, like + --enable-masquerade="draft_from mmailid", or leave off explicit + arguments to enable all three types. + + * Alphabetized the --enable and --with options in configure.in and + INSTALL and added documentation of the two new options to the latter. + + * Added new dependency for mts.conf: Makefile. If this isn't + done, then when you reconfigure nmh with new values for + --enable-masquerade or --with-smtpservers, you'll fail to get an + updated copy of mts.conf. + + * Applied Simon Burge 's dtimep.lex patch: + + It seems that some MUA's didn't handle y2k very well - ELM + seems to be one of them, and Ultrix's DXmail (based on MH!). + I've got a few emails this month that look like: + + 575 Jan 00 Xxxxxx Xxxx 3603 ... + and + 22+ Jan 00 Xxx Xxxxx 1771 ... + + The first has "15 Jan 100" as the date and the second has + "19 Jan 00" as the date. The following works around this so + that scan, show, sortm, etc work ok. + + I put Simon's patch under the control of a new #define called + FIX_NON_Y2K_COMPLIANT_MUA_DATES. There's some commentary in + acconfig.h about when you might not want to #define it. + + * Created new dtimep.c-lexed with Simon's change using dtimep.lex + lexed on Solaris 2.6. Added missing dependency in + zotnet/tws/Makefile.in for dtimep.c: dtimep.c-lexed. + + * Added scan.MMDDYY and scan.YYYYMMDD format files. + +Mon Mar 13 21:32:00 2000 Dan Harkless + + * Applied Sullivan N. Beck 's mhshow-suffix patch: + + With the patch below, you can add lines like: + + mhshow-suffix-application/msword: .doc + mhshow-suffix-application/PostScript: .ps + + to the mhn.defaults file to append the given suffix to a + scratch file. This allows applications which require a + certain suffix to run properly. + + * Removed -force_html from lynx entry in mhn.defaults.sh (I + believe older versions of lynx lack that option) and added + "mhshow-suffix-text/html: .html". + + * Modified username_extension masquerading to only use the + extended address on generated [Resent-]From: lines and SMTP + envelope From:. With Neil's original implementation, nmh's global + idea of the username was changed, which would result in inc lying + and saying you had no new mail because it was looking for a + mailbox called, for instance, "dan-nmh" (where username was "dan" + and $USERNAME_EXTENSION was "-nmh"). + + * Applied Simon Burge 's dtime.c patch: + + There's a wrap-around problem that affects the implementation + of Zeller's congruence in dtime.c. This causes the day-of-week + calculations to fail for dates after Feb 29, 2000 (probably up + until some year far in the future). + +Mon Mar 06 12:20:20 2000 Dan Harkless + + * Applied Neil W Rickert 's msh.c patch: + + I finally tracked down the problem in msh that was causing + errors whenever I tried to examine a 'mmdf' style mailbox. + + It turns out that not enough memory was being allocated with + calloc(), causing memory pointers to be overwritten and + corrupted. + +Fri Mar 03 16:07:33 2000 Dan Harkless + + * Changed the new "plussed_user" option to mts.conf's + "masquerade:" to "username_extension" after getting feedback from + qmail users, who use '-' as a separator rather than '+'. Removed + checking of $USERPLUS variable. Now check $USERNAME_EXTENSION, + which needs to include the appropriate separator for your MTA + ('-', '+', or whatever) as its first character. + +Thu Mar 02 23:04:30 2000 Dan Harkless + + * Added a new "boolean" type to mh.h and TRUE and FALSE constants. + + * Added a note to DIFFERENCES stating that it's out-of-date + (Richard was the last one to update it) and that we should + consider only documenting incompatibilities with MH there. + + * Implemented (and documented) a third kind of username + masquerading: "plussed user" masquerading. This one was suggested + by Neil Rickert . It's based on sendmail's + "plussed user" feature, where mail sent to + will be + delivered to . When it's enabled, it's controlled by the + $USERPLUS environment variable. How is it enabled? Well, that + leads me to: + + * Renamed the "mmailid:" setting in mts.conf to "masquerade:", and + changed it so that rather than being a boolean, it can be set to + any combination of the three values "draft_from", "mmailid", and + "plussed_user". Thus it is now possible to enable the three types + of masquerading individually. + + * Fixed a bug with "mmailid" masquerading (dating back to MH?) + where if it was turned on, ','s would no longer be considered + GECOS field delimiters. + +Wed Mar 01 23:30:50 2000 Dan Harkless + + * Changed the GECOS-field '&' translation behavior to be + controlled by the BSD42 #define rather than GCOS_HACK, since it's + apparently always appropriate on OSes where BSD42 is #defined, and + never appropriate on any other OSes. Thanks to Kimmo Suominen for + responding to my "What is this code here for?" comment in mts.c + and explaining the feature. + +Mon Feb 28 21:50:29 2000 Dan Harkless + + * Upped the version number to 1.0.3+dev (ideally this should be + done by whoever makes a release tar file, immediately after doing + so). + + * Applied Paul Fox 's scansbr.c + patch, posted to comp.mail.mh, which he says prevents loss of mail + when inc'ing into a full filesystem. + + * Changed "echo > stamp-h.in" in Makefile.in to "date > stamp-h.in" + so that stamp-h.in will be different each time configure.in and + related files are changed, making it easier to check it in (which + is necessary to prevent unnecessary autoconf calls). + + * My declaration of initgroups() in slocal.c to eliminate the "no + prototype" warning wasn't portable (FreeBSD 3.[23] choked). Now + use AC_EGREP_HEADER to see where initgroups() is declared, if + anywhere. + +Sun Feb 20 12:17:15 2000 Ruud de Rooij + + * Fix security hole in mhshowsbr.c which allowed untrusted shell + code to be executed. + + * Released nmh 1.0.3. + +Thu Feb 10 10:54:36 2000 Dan Harkless + + * Oops. %-escapes on mhstore lines in mhn.defaults.sh should not + be surrounded by single quotes, as a shell is not spawned when + just saving files, and the filenames will end up with literal + quotes embedded in them. + +Fri Feb 04 12:29:12 2000 Dan Harkless + + * Whoever originally added the -help switch to all the commands + got too cute and had the option itself print out as "-(help)" in + the -help output. One theory is that they were making reference + to the fact that clearly you know about the -help option since + you're currently looking at its output. I think it's a bad idea + to overload the meaning of the parentheses, however -- they're + supposed to indicate what abbreviated prefix of the switch you're + allowed to specify. + + The other theory is that because you can say something like + "mhstore -" and get "mhstore: - ambiguous. It matches" followed + by the same list of switches you get with -help, they were saying + you can "sorta" abbreviate "-help" as "-". You don't get the + "Usage:" string, though, so it's not really the same thing. + +Thu Feb 03 17:52:01 2000 Dan Harkless + + * Applied wesley.craig@umich.edu's KPOP patches. According to him: + + The following patch fixes a problem with requesting a + service key for a machine that has multiple 'A' records. It + also makes "-kpop" a command line option, for users who + would like to use both "kpop" and "pop". + + Did no testing of the new features, as I don't have access to a + KPOP server. + + * Modified inc.man and msgchk.man to document Wesley's new -kpop. + + * Modified INSTALL and config.h.in to reflect the new -kpop feature. + +Fri Jan 28 17:39:24 2000 Dan Harkless + + * All %-escapes in mhn.defaults that actually expand to something + should be surrounded by single quotes. Added quotes to the ones + in mhn.defaults.sh that were missing them. + + * Added check for lynx to write mhshow-show-text/html line in + mhn.defaults.sh. + +Thu Jan 27 12:22:25 2000 Dan Harkless + + * makedir() had multiple bugs dating back to MH. An octal + constant was apparently being interpreted as decimal, resulting in + directories with no user read or execute permissions, making + nested directory creation fail. And there wasn't even an + _attempt_ to set desired permissions (e.g. from "Folder-Protect:" + in .mh_profile) on the outer directories of a nested directory. + + * A second `make install' would always fail because the check for + whether mh_profile.5 existed was written incorrectly. + +Wed Jan 26 02:22:00 2000 Dan Harkless + + * Added documentation on both types of masquerading to post's man + page. + +Tue Jan 25 22:58:12 2000 Dan Harkless + + * Doug's portability fix of my setgid inc autodetection had a + caching bug -- if you re-ran configure, uip/Makefile would be + corrupted, and installation would bomb out on OSes where inc needs + to be setgid. + + * Implemented a new kind of email address masquerading. Usually, + when a user writes a custom "From:" header in a draft, nmh uses it + rather than generating one. However, the user's true address is + used in the SMTP envelope "From:" and is revealed in the "Sender:" + header. Now, when mmailid is set to non-zero, the envelope + "From:" uses the address specified in the draft "From:" header, + and there is no "Sender:" header. This is useful when sending on + behalf of a remote POP3 account or when remote mail robots + incorrectly use the envelope "From:" in preference to the body + "From:". This processing has only been implemented for post, not + for the undocumented spost (which was already missing some "From:" + processing that post has). + +Mon Jan 24 22:26:06 2000 Dan Harkless + + * Got rid of the rest of the gcc -Wall warnings that I didn't have + time for on 1999-07-15 (and, it would seem, some new ones people + introduced since then). The primary ones were the warnings that + default prototypes were being used for [v]snprintf() and + str[n]casecmp(). As of right now, there are _no_ compilation + warnings except on dtimep.c-lexed (at least under AIX 4.1.5 and + Solaris 2.6). + +Sun Jan 2 23:42:18 2000 Ruud de Rooij + + * Move mhtest from bindir to libdir. + + * Move sendfiles from libdir to bindir. + + * Updated sendfiles manpage to reflect this change. + + * Added documentation for -build and -file switches to repl and + forw manpages (patch from Peter Maydell). + + * Fixed interaction between specifying -cc in profile and -group on + command-line. + +Tue Nov 1 13:48:10 1999 Dan Harkless + + * Changed the version number from 1.0.3 to 1.0.2+dev. There was + not unanimous support for my proposed even/odd release/developer + version number dichotomy. 1.0.2+dev implies release 1.0.2 plus + some development. + +Fri Oct 29 13:42:51 1999 Dan Harkless + + * Upped the version number to 1.0.3. If we don't do this, then + when people report bugs against 1.0.2, we won't know "which" 1.0.2 + they're talking about (since the development source is publically + available via CVS). I think the Linux kernel version numbers are + a good model, so the next time we roll a tarball, it should be + version 1.0.4 (or higher -- anyhow, an even-numbered version). + +Fri Oct 29 06:41:08 1999 Doug Morris + + * Released nmh-1.0.2. + +Tue Oct 26 22:57:00 1999 Doug Morris + + * Added check for whether "libtool" is in fact gnu libtool. If + it is, it is not used. This is the wrong behavior. If vendor + XYZ later on decides to create yet another libtool, we'll be + caught again. This works for now. + + * Minor updates to MACHINES refering to Mac OS X. + +Thu Oct 21 20:45:37 1999 Doug Morris + + * Added check for "libtool" (a ranlib type tool for Mac OS X) + and modified Makefiles so that nmh will build under Mac OS X. + +Sun Oct 17 08:28:56 1999 Ruud de Rooij + + * Changed repl defaults to partly revert to MH behaviour, + "-cc all" is now only implied with -group. + + * The replcomps template includes cc: header again (as in MH). + + * Updated repl man page to reflect these changes. + +Sat Oct 16 02:57:47 1999 Doug Morris + + * Tweaked configure to handle Solaris and SunOS after the BIND + changes. Both need more cleanup. + +Sat Oct 16 00:17:36 1999 Doug Morris + + * Removed BIND define and replaced it with a check for + gethostbyname (to determine if the host is DNS aware) and a + check for sethostent. This appears to be the right thing to + do, but there is no explanation of the reasoning behind the + BIND define in the code and it appears to have been used for + multiple purposes. + +Wed Oct 13 15:53:53 1999 Doug Morris + + * Updated manpages Makefile to link mh-profile.5 to + mh_profile.5 after installation. Suggestion from Richard Cohen + . + + * Modified configure.in to check for _IO_write_ptr and libio.h + to determine whether to define LINUX_STDIO instead of using + config.guess. + +Mon Oct 4 15:22:46 1999 Dan Harkless + + * Added '-L' to the calls of 'ls' in configure.in -- I have seen + multiple machines in the past where the mail spool was a symlink + to a directory on another device with more free space. + +Fri Oct 1 22:36:56 1999 Dan Harkless + + * Fixed a portability problem in Doug's fix of a portability + problem in my MAILGROUP autoconf support ('ls -l' vs. 'ls -lg'). + +Sat Sep 25 18:40:43 1999 Ruud de Rooij + + * Added config.sub and config.guess to the list of files to be + distributed. + + * Fixed bug in sbr/fmt_scan.c where an extra newline would be + added if a list of addresses was split over several header lines. + + * In mts/smtp/smtp.c, undefine strlen and strcpy if they are + macros, regardless of platform. + + * Allow q to quit mhshow, and n to skip to next part. Patch from + Kimmo Suominen . + + * Modified mhstore to recognize attachments created by sendfiles + with x-conversions=gzip. + +Mon Sep 13 21:20:10 1999 Doug Morris + + * added explicit cast to long from time_t for tclock in + post.c. + + * Commented out #ifdefs for in termsbr.c since + it's needed for ioctl() anyway. This prevents a warning about + implicit definition of ioctl(). + + * Moved guesses performed by AC_CANONICAL_SYSTEM back into the + "User Configuration" section of config.h (moved @TOP@ in + acconfig.h) so they're easier to find, should someone actually + want to mess with them. + +Sun Sep 12 15:50:34 1999 Doug Morris + + * updated Makefile.in so it recognized COMPLETION-TCSH and + COMPLETION-ZSH (only used in make nmhdist). + + * added prototype for ruserpas to . Fixes + warnings in mhparse.c and mhbuildsbr.c. + + * added include checks for and to + prevent warnings in fmt_compile.c, fmt_scan.c, lock_file.c, + sendsbr.c, mhbuildsbr.c, mhcachesbr.c, picksbr.c, and post.c. + + * added include for to ali.c, scan.c, ap.c, + rcvdist.c, rcvstore.c, rcvtty.c, and spost.c to remove + warnings about implicit definition of mts_init(). + + * added to slocal.c to prevent warnings about + function initgroups. + + * added to prevent warning about missing SIGNAL + function. + + * added function prototypes to smtp.c, whatnowproc.c, + mhbuildsbr.c, mhparse.c, mshcmds.c, show.c, whatnow.c, mhl.c + to fix warnings. + + * explicitly declared mbx_style in mshcmds.c and lused in + fmtdump.c as type static int instead of just static to + prevent warnings. + + * various code cleanups to prevent ambiguous statements + (brackets for if/thens and parens for complicated if + statements). + + +Sun Sep 12 09:19:27 1999 Doug Morris + + * commented out _cleanup() in mf.c because it's the only + location in all of the source code where it exists. It was + preventing compilation on at least linux. + + * Added check for which is the new location where + linux systems appear to be stuffing this header file. + +Thu Sep 09 23:15:49 1999 Doug Morris + + * fixed varous mkstmep bugs introduced in 1.0.1 by me. Whups! + + * added mh_profile SEGV patch from Richard Cohen + that prevents crashing when + mh_profile doesn't end in a newline. A similar patch was + previously sent in by Andrew Bettison . + + * fixed bug in associated with MAILGROUP #define (group "mail" + is not universal) -- hard to believe, but true. + +Tue Sep 7 16:47:03 1999 Dan Harkless + + * Renamed ZSH.COMPLETION to COMPLETION-ZSH and added COMPLETION-TCSH. + +Tue Aug 17 16:06:29 1999 Dan Harkless + + * Automated #define of MAILGROUP and installation of inc as setgid mail + when the mail spool directory isn't world-writable. + +Thu Jul 15 18:37:07 1999 Dan Harkless + + * slocal -debug used to leave a file in /tmp for each message + processed. Very bad for folks with slocal -debug in their .forward! + + * Got rid of a ton of compilation warnings. Most were "junk" + warnings due to the use of gcc -Wall (without -Wno-parentheses), + but a few represented real bugs. There remain many warnings to be + tackled that are due to missing function prototypes (e.g. snprintf()). + + * Default rcvdistcomps no longer puts a copy of all outgoing + messages in outbox. Added an rcvdistcomps.outbox that does. + +Sat Jun 09 12:22:47 1999 Doug Morris + + * Updated configure to check for mkstemp (available on OpenBSD) and + substitute it for mktemp if available. + +Thu May 13 16:40:19 1999 Doug Morris + + * Added config.sub and config.guess and updated acconfig.h and + configure.in to automatically detect system type and set the + proper #defines. + +Wed May 12 23:41:33 1999 Dan Winship + + * Released nmh-1.0.1. + +Fri May 7 17:18:28 1999 Dan Winship + + * Fixed flist to properly deal with relative folder names. + Problem noted by Jerry Peek . + + * Fixed --with-krb4 to work with original Kerberos 4 libraries as + well as the Kerberos 5 compat libraries. Based on a patch from + Assar Westerlund . + + * Added a check in configure.in to test if modf is in libc and + link with libm if not. This is needed by at least Digital UNIX. + Problem pointed out by Kevin Oberman . + + * Fix a bug from the "mhn -show" to "mhshow" renaming that + made the "list" command in whatnow not work for some users. + From Ruud de Rooij . + + * Replaced "extern int errno" with "#include " in a + number of files. Suggested by Stephen Wilson Bailey + . + + * Fixed a problem in how "packf -mbox" translated "Return-Path:" + lines. From Kimmo Suominen . + + * Fixed a segmentation fault in inc. Patch originally from Ruud de + Rooij . + + * Allow display of 8bit encoded messages. From Kimmo Suominen + . + + * Fixed repl to not add line breaks in the middle of long + addresses when building a reply. From Ruud de Rooij + . + + * Added -library switch to spost so it can parse user aliases like + post does. From Ruud de Rooij . + + * Changed configure.in's check for sigsetjmp to properly deal + with systems like Linux where it is a macro. From + . + + * Fixed a bug in whatnow that could cause it to sometimes exit + without prompting the user. Based on a patch by Richard Geiger + . + + * Added code to deal with SIGPIPE in mhl so it doesn't print + "Broken pipe" if you quit out of the moreproc. + + * Documentation: Added a note to MACHINES about Irix make. Added a + pointer to the online copy of the MH book in INSTALL. Added + some additional information to the whatnow and packf man pages, + suggested by Jerry Peek . + + * Updated INSTALL, FAQ, etc to not refer to Richard as the + maintainer or math.gatech.edu as the home any more. + +1999-02-06 Richard Coleman + + * Released nmh-1.0. + + * Merged mbx_open and mbx_Xopen in dropsbr.c. Fixed + mbx_open so that the mode of zero length maildrops + would not be changed. + + * Replaced the substitute version of snprintf() with the + one from the Apache web server. + + * Changed to default mode for creating new messages to 0600 + (this should have been done a long time ago). + + * Changed "flist" to handle searching for multiple sequences + for each folder. Also flist will now correctly split + Unseen-Sequence if it consists of multiple sequences. + + * Added new switches `-unlink' and `-nounlink' to "refile". + + * Added new switches `-unlink' and `-nounlink' to "rmm". + + * More cleanups of slocal output. Changed adorn() to + send to stdout, instead of stderr (to match rest of + verbose printing). + + * Merged mbx_create() into mbx_open, so that creating and + opening a nonexistent maildrop is done atomically. This + removes a bad race condition. + + * Fixed bug that caused slocal to be unable to save to MMDF + style drop file. + + * Added new wrapper function usr_folder() to slocal.c to + handle adding message to folder (currently, it still uses + usr_pipe() to call rcvstore). + + * seq_list() checks for empty folder before scanning for + sequence information. + + * num_digits() in flist.c and folder.c now returns correct + value for 0. Also added sanity check. + + * folder_delmsgs() now correctly decrements internal message + count. + + * Don't attempt to read sequence information if folder + is empty. + + * Split seq_read into seq_public and seq_private. + + * Small change to sigmsg.awk, since newer versions of gawk + interpret 034 as octal. + + * In flist, don't scan for sequence information in empty folder. + + * Updated mhn.defaults.sh to output profile entries for mhshow, + mhstore, and mhbuild. + + * Changed configuration parameter "mhn-access-ftp" to + "nmh-access-ftp". Updated man pages + + * Moved the code in InitMultipart to reverse the order of the + parts in a multipart, into its own function "reverse_parts()". + + * Changed code in mhbuildsbr.c to store unencoded content + in the c_cefile structure when building. + + * Changed code in mhoutsbr.c to look for unencoded content + in the c_cefile structure when outputing message. + + * Changed configuration parameter "mhn-cache" and + "mhn-private-cache", to "nmh-cache" and "nmh-private-cache", + since it is used in mhstore, mhlist, and mhshow. Updated man pages + + * Change configuration parameter "mhn-storage" to + "nmh-storage", since it is now used in mhstore, mhlist, + and mhshow. Updated man pages + + * Add autoconf support for KPOP (kerberized pop). + + * Add autoconf support for Hesiod. + + * Split routines to output a message given a Content structure + (output_message, output_content, write7Bit, etc..) to a new + file "mhoutsbr.c". + + * Split output_content(), into output_content() and build_headers(). + + * Changed copy_some_headers() in mhstoresbr.c, to use the linked + list of header fields, rather than reopening the message. + + * Added free_header() to mhfree.c to free structures containing + header field information. + + * Changed get_content() to use the linked list of header fields + when parsing the various MIME headers (Content-XXX). + + * Changed get_content() to store linked list of header field + values when parsing a content. + + * Changed mhbuild, mhn, mhlist, mhshow, mhstore, to use the + routines in mhcachesbr.c to handle the content cache. + + * Split various funtions (find_cache, find_cache_aux, find_cache_aux2, + cache_content) into new file mhcachesbr.c. + + * More calls to sprintf/strcpy (primarily in mhparse.c + and mhbuildsbr.c) converted to snprintf/strncpy. + + * When a message is displayed with `mhshow', it is now + removed from the "unseen" sequence. + + * Change the default "showmimeproc" to "mhshow". + + * Split "mhn -show" off into separate command "mhshow". + + * Split "mhn -store" off into separate command "mhstore". + + * Split "mhn -list" off into separate command "mhlist". + + * Add sanity checks to context_find(), context_replace(), + and context_del(), to abort if context file hasn't been + read. + + * Add calls to context_read(), to the beginning of all nmh + commands (instead of being called indirectly by context_find). + + * Changes the "substitute" version of vsnprintf/snprintf for + operating systems without native versions, to just call the + native vsprintf(), and ignore the buffer length. This is + faster, but less secure than the previous version that used + temporary files. This should only be a problem for systems + which do not have a native snprintf(), and require `inc' to + be setuid/setgid. + + * Lots more calls to sprintf/strcpy converted to snprintf/strncpy. + + * Changes client() routine to take additional parameter, which is + the buffer length of the parameter "response". Then added + buffer length checks for this parameter. + + * Changed getws() to get_fields(), since that is apparently the + name of a wide character version of gets() on some archetitures. + + * Lots of sprintf/strcpy calls converted to snprintf/strncpy. + + * Change the code in most of the commands that take multiple + message names/sequences/ranges on the command, such that + the msgs array is expanded dynamically. This removes most + of the limits on the length of command lines. + + * Add additional parameter to copyip(), to specify the + maximum number of strings that can be copied (security + fix). + + * Create new function getarguments(), to massage the argument + vector before parsing it (add any arguments from your + profile to the beginning of the argument vector). This + also removed the general limit on the number of command line + arguments. + +1998-07-04 Richard Coleman + + * Released nmh-0.27. + + * Added a new command "delete", that is available during + a "whatnow" session. It is equivalent to "quit -delete". + + * Added another parameter to editfile (in whatnowsbr.c), + that controls whether editfile should remember the last + program that was exec'ed. This way the whatnow command + "mime", will not be re-executed if "edit" is later given + with no arguments. + + * Changed whatnowsbr.c, so that whatnow doesn't abort if + mhbuild returns an error. + + * Added parameter to sendsbr(), so you may specify whether to + rename the draft file. + + * Pass delay time to splitmsg() as a parameter, rather than + use a global variable. + + * Moved code to rename draft file after sending message from + splitmsg and sendaux, to sendsbr. + + * Removed all the code in viamail to split messages and then + mail them. Replaced this with the standard sendsbr.c routines. + + * Changed sendsbr(), so that when splitting messages into + messages of type "message/partial", the header fields that + are copied are more compliant with RFC-2046. + + * Fixed mhbuild to track temporary files better. They are + now correctly removed when mhbuild aborts. + + * Created a new man page for "sendfiles". The information + about "mhn -viamail" in the "mhn" man page was moved to + this new page. + + * Changed the name of the "viamail" shell script to + "sendfiles". Modified "sendfiles" to use the new + viamail program. + + * Moved the functionality for "mhn -viamail" out of mhn, + and into a separate executable called "viamail". + + * When storing MIME contents to a folder using mhn -store, + they are now accumulated in a temporary file, and then added + to the folder using folder_addmsg(). + + * Moved code to save content to a folder from store_content + to new function output_content_folder. + + * Moved code to save content to file from store_content to + new function output_content_file. + + * Moved code to parse storage format string from store_content + to new function parse_format_string. + + * Fix copy_some_headers() in mhstoresbr.c, so that the + correct header fields in the first enclosing message/partial + will be copied (according to RFC2046), when using mhn -store + to reassemble messages of type message/partial. + + * Fixed bug to openFTP() in mhparse.c, that caused the + tmp file to not be removed, when transferring a + message/external file from ftp. + + * Moved the code in mhparse.c to process -auto switch (scan + contents for the attribute "name"), to a new function + "get_storeproc" in mhstoresbr.c. + + * Moved routines to free data structures related to MIME + content from mhparse.c and mhbuildsbr.c, to new file + mhfree.c. + + * Moved code to show/display MIME content into new + file mhshowsbr.c. + + * Moved code to store MIME content from into + new file mhstoresbr.c + + * Moved code to parse MIME content into new + file mhparse.c. + + * Moved code to list information about MIME content + into new file mhlistsbr.c. + + * Move part_ok(), type_ok(), content_error(), flush_errors(), + and set_endian() to new file mhmisc.c. + + * Start to isolate the code to show, list, and store MIME + messages. One side effect is that only one flag (-show, + -list, or -store) can be used at a time now. + + * mhn -store -auto wasn't storing file in correct directory. + + * Removed a few dead variables from sbr/ruserpass.c + + * move code for creating tmp files, and renaming the + the composition draft in mhbuild, from build_mime() + to main(). + + * remove left-over code in mhbuild.c, mhbuildsbr.c, for + the -[no]auto switch (which isn't used in mhbuild). + + * split mhn.c into mhn.c and mhnsbr.c (name later changed + to mhparse.c). + + * split mhbuild.c into mhbuild.c and mhbuildsbr.c. + +1998-05-25 Richard Coleman + + * Released nmh-0.26. + + * Added (unlisted) options [no]dashstuffing to send, post, + and whatnow to determine whether to do RFC934 quoting + (dashstuffing) for encapsulated BCC messages. The default + is still the same (dashstuffing). + + * Changed the undocumented feature "nodashmunging" in forw + and mhl, into the documented feature "nodashstuffing". The + default for forw, is still "dashstuffing" for backward + compatibility, although I don't believe that bursting + RFC934 digests is very common anymore. + + * Added an option to define REALLYDUMB in the default config.h. + But it is not on by default. + + * moved creation of config file mts.conf from zotnet/mts + to etc. This simplified the Makefile in zotnet/mts. + + * simplified directory support/general to etc. + + * removed unneeded directory support/bboards. + + * split getusername() into getusername() and getuserinfo(). + + * Changed getusr() routine to getusername(). + + * Slight cleanup in folder_pack.c on code that records the new + number of the "cur" message when packing. + +1998-05-08 Richard Coleman + + * Released nmh-0.25. + + * Change install process, so that hard linking the correct mts + library to libmts.a, is not necessary. The final link process + uses the original name of the library. + + * Fixed bug in flist.c and folder.c, so that symbolic links which + point to directories, will not decrement the number of directory + links remaining. + + * Split the function list_content (in mhn.c and mhbuild.c) into + list_content and list_debug. + + * Don't pack (folder -pack) an empty folder. + + * Exit gracefully in flist.c, if no sequence is specified, + and no "Unseen-Sequence" is given in nmh profile. + +1998-02-27 Richard Coleman + + * Released nmh-0.24. + + * Small clarification to the man page for `ali'. + + * Fix bug in inc.c so that if both flags `-file' and `-truncate' + are given, that order doesn't matter. + + * Fix bug in seq_list.c when realloc'ing for + large sequence line. + +1998-02-23 Richard Coleman + + * Released nmh-0.23. + + * Add new section on "Transfer Encodings" to man page for mhbuild. + + * In mhbuild.c, split compose_content into compose_content + (parse and execute composition string), and scan_content (scan + content, decided transfer encoding, check for clash with boundary + string). I did a good amount of rearranging of this code. + + * Moved definitions for data structures for parsing MIME + messages from mhn.c and mhbuild.c to a new include + file h/mhnsbr.h. + + * Small amount of rearranging in sendsbr.c + + * Small changes to MAIL.FILTERING file. + + * Add the file MAIL.FILTERING to nmh distribution. + + * Add line to packf so that if message begins with + "X-Envelope-From:" field, it is converted to "From ". + + * Fix packf to add "From " line to beginning of message, + even if Return-Path doesn't exist. + + * Add note to MACHINES file that on Linux, configure + doesn't find the functions sigsetjmp/siglongjmp. + + * Fix configuration for machines that don't have (or find) + sigsetjmp/siglongjmp. + +1998-02-11 Richard Coleman + + * Released nmh-0.22. + + * Add a configure check for sigsetjmp. Add some conditional + #define's in h/signals.h in case it's not found. + + * Added additional notes about -auto switch in mhn man page. + + * Added note about MM_CHARSET environment variable to + mh-profile(5) man page. + + * Fix signal problem in mhn.c (change setjmp/longjmp to + sigsetjmp/siglongjmp). + +1998-02-09 Richard Coleman + + * Released nmh-0.22-pre1. + + * Changed the first line in mhl.format from + " -- using template mhl.format -- " to a blank line. + + * Added note about automimeproc to mh-profile man page. + + * Reorganize the main entry point for parsing a MIME message + or file in mhn. Add new function parse_file() as new main + entry point for parsing MIME files. + + * Add note to mhn man page, that "mhn -file -" will accept the + source message on the standard input. + + * Changed a sanity check in folder_realloc that was too strict. + + * -norfc934mode is now the default for mhbuild, + rather than -rfc934mode. + + * Fix mhbuild, so that Content-Description and RFC-822 comments + from #forw directive will be correctly included if there is + only one message. + + * Change mhn to correctly default parts of multipart/digest to + message/rfc822 (leftover code from rfc934mode was removed). + + * Restore HP specific code to zotnet/tws/lexstring.c. Apparently + it is still needed. + +1998-02-06 Richard Coleman + + * Released nmh-0.21. + + * If the file given to mhbuild is "-", then accept the draft on + standard input, and output the MIME message to standard output. + + * Cleaned up code in mhbuild.c that decides what transfer + encoding to use. + + * Cleaned up code in mhbuild.c that decides what character set + to use for text contents. + + * Removed old hpux specific code from zotnet/tws/lexstring.c + +1998-02-02 Richard Coleman + + * Released nmh-0.21-pre2. + + * Added the "decode" variable to mhl.format and mhl.header. + + * Added new variable "decode" to mhlsbr.c to decode text in + header fields as per RFC-2047. + + * Make sure that when decoding RFC-2047 header fields, that any + spaces at the ends of the encoded text are not ignored, but the + spaces between encoded word are. + + * Removed #ifdef's for MIME. MIME support is always compiled in. + + * scan/inc will now decode both Subject and From lines as + RFC-2047 encoded header fields. + + * Added new function write_charset_8bit() to sbr. It returns + the character set to use for 8bit text in composition draft. + Changed mhbuild to use this function. + + * Split mhn man page into man pages for mhn and mhbuild. + + * mhn -show will only now only use default method for content + of type plain, if it is NOT a part of a multipart/alternative. + + * Split mhn -build into mhbuild. Did some code cleanup. + + * Added support for %(decode) to fmtdump.c. + + * check_charset() now accepts US-ASCII as a subset of any + ISO-8859-X character set. + + * Changed the default "showproc" to mhl, instead of the + pager more. + + * When reading file into mhn composition file, only need read + permissions, not write permissions. + + * Added own version of strcasecmp to distribution, since + nmh calls it frequently with NULL pointers (ughh). + + * Replaced uleq.c with strcasecmp. Removed uleq.c from + distribution. + +1998-01-22 Richard Coleman + + * Released nmh-0.21-pre1. + + * If a message is missing charset parameter to text/plain, show + will assume US-ASCII, rather than just calling showmimeproc. + + * Change show.c and mshcmds.c to use check_charset to see if text + message contains valid character set. + + * Added new scan format file "scan.nomime" to support/general + that doesn't do any RFC-2047 decoding. + + * Modified all the scan format files in support/general to do + RFC-2047 decoding of Subject field. + + * Did more work on sbr/fmt_rfc2047.c, so that it will correctly + ignore whitespace between two valid encoded words, but not + between an encoded word and normal text. + + * Created new file sbr/check_charset.c. Moved code from + fmt_rfc2047.c to check for valid character set to this file. + + * Added format escape %(decode) to decode contents of "str" register + as a RFC-2047 header field. + + * The command install-mh now recognizes the switches -version + and -help. + + * Added a new argument to print_help.c to decide whether to + print profile entries (needed for install-mh to prevent weird + loops). + + * Changed folder_read.c and folder_realloc.c so that mp->lowoff + is initialize to max (mp->lowmsg, 1) rather than always 1. + + * Changed macros for sequence/attribute manipulation so that + message status array doesn't need to always start at 1. + + * Small cleanups in folder_realloc(). + +1998-01-09 Richard Coleman + + * Released nmh-0.20. + + * Added configure option --with-pager=PAGER. + + * Added configure option --with-editor=EDITOR. + + * Changed the default format file for mhl (mhl.format) to + also ignore (not display) the header fields Content-Type, + Content-Transfer-Encoding, and Content-ID + + * Fixed core dump in addrsbr.c when using %(proper) format function + and the To: line was missing. + + * Added the file ZSH.COMPLETION to the distribution. + +1998-01-04 Richard Coleman + + * Released nmh-0.20-pre2. + + * Added new switch -snoop to both `msgchk' and `inc', so you can + watch the POP transaction. + + * Changed "replgroupcomps" to check for Mail-Followup-To header + first, and use it if available. + + * Changed "replcomps" to check for Mail-Reply-To header + first, and use it if available. + +1998-01-03 Richard Coleman + + * Released nmh-0.20-pre1. + + * Changed seq_list.c to dynamically enlarge the buffer for + collecting the message ranges in a long sequence line. + This should remove the last hard limit on the size of a + sequence line. + + * Changed seq_read.c so that can read long sequence lines. + It will use multiple calls to m_getfld() when m_getfld() + returns the state FLDPLUS. + + * Changed brkstring.c to dynamically add more space for pointers + if necessary. This is needed when splitting up large sequence + lines. + + * Did some small cleanups in seq_save.c. + + * Added new switches `-[no]unseen' to rcvstore, to control + whether new messages are added to Unseen-Sequence. + + * Moved locking routines (zotnet/mts/lock.c) to sbr/lock_file.c + + * Changed the internal UNSEEN flag to SELECT_UNSEEN which is + more appropriate. Changed the MHPATH flag to ALLOW_NEW. + + * Changed "replcomps" to not include CC and TO lines so that + that reply message is only directed at the author of the + message to which you are replying. + + * Added new switch `-group' to command repl, which causes repl + to use new forms file "replgroupcomps". This is intended for + making group replies. + + * Removed #ifdef for ATHENA. + +1997-12-28 Richard Coleman + + * Released nmh-0.19. + + * Fix repl,forw so that switch `-form file' will not abort + as ambiguious (silly mistake on my part). + + * Cleaned up the mhn man page. Added info about a few escapes + for the formatting/display strings that were not documented + (%%, %t). Moved the BNF grammar for the mime composition file, + to the end of the man page. + + * Added the options -[no]format to the command repl. The + switch `-format' will filter the message to which you are + replying with the standard message filter "mhl.reply", which + is now included in the distribution. The `-noformat' option + will negate the use of -format or -filter and not include + the message to which you are replying in the draft. + + * Did some cleaning and reorganization on many of the man + pages. + + * Added debugging switch `-debug' to mhparam, which displays + the values of all `procs' (and some other misc configuration + info) that nmh keeps in global variables. + + * When using `refile -preserve', if a conflict occurs, then use + the next available number above the message number you wish + to preserve. + + * In forw.c, split the code for creating MIME style forwarding + out of copy_draft, and into copy_mime_draft. + + * Move routines in mark.c to print sequences, into new + file sbr/seq_print.c + + * flist will now update the current folder. + + * Added the switches -[no]fast to flist, to replace + -[no]total. The previous switches are still accepted + but now undocumented. + + * More reorganization in flist of the code for + traversing folders. + + * The command "flist +foo -all" will now scan the folder + "foo" and all its 1st level children. + + * Add missing include file to sbr/snprintf.c + + * Fix alarm bug in rcvtty, so that when it calls external + process, the alarm is never longer than 30 minutes. + +1997-12-17 Richard Coleman + + * Released nmh-0.18. + + * Fixed bug in mark, so that "mark -list -seq foo" will + correctly indicate if "foo" is a private sequence. I found + this bug mentioned in Jerry Peek's book. + + * Simplified the code in seq_setcur(), since seq_addmsg() now + retains the public/private status of sequences. + + * Changed sequence handling so that if the switches -public + or -nopublic, are not specified for the commands mark, pick, + or rcvstore, then existing sequences will retain their + previous public/private status. + + * mhparam now handles the mh-sequences profile entry + correctly. + + * flist -all will now also check readonly folders (for + private sequences). + + * Improve the leaf optimization for folder command. + It will now track the number of directories in a folder, + and stop stat'ing files once it has hit all the subfolders. + + * Renamed m_getfolder to getfolder. Changed getfolder to + take option to determine whether it should get current + folder, or just default folder (Inbox). Changed rcvstore, + inc, and rmf to use the new getfolder. + + * flist now indicates if a sequence is private. + + * Change WUNTRACED to 0, in pidwait.c, so that commands will + wait for stopped processes. + + * conflict will dynamically allocate space for group names, + so it can now handle system with more than 100 groups. + +1997-12-09 Richard Coleman + + * Released nmh-0.18-pre4. + + * Check if we have enough message status space, before we + call folder_realloc() in burst, mhpath, and m_draft(). + + * mhn will now correctly identify a formatting string of "-" + for the option -store, and send content to stdout. + + * Change the way that memory for message status is + allocated. It is dynamcially allocated separately from + the folder/message structure. This required changing + folder_read.c, folder_realloc.c, folder_free.c. + + * Removed all the MTR code (experimental code for message + status allocation). + + * Renamed m_readfolder.c to folder_read.c and simplified + the code. + + * Renamed m_freefolder.c to folder_free.c. + + * Add function trim() to slocal.c to pretty print + the debugging output. + + * Changed the name of m_packfolder() to folder_pack(). + Changed the name of m_remsg() to folder_realloc(). + +Wed Dec 3 23:33:38 1997 Richard Coleman + + * Released nmh-0.18-pre3. + + * Changed installation to add `flists' which is hard linked + to `flist'. This is a equivalent to `flist -all'. + + * For flist, -showzero is on by default. + + * Major changes to flist. Default is now for flist to search + current folder. The switch `-all' is now used to specify + searching all top level folders. The new switch `-showzero' + is used to print out folders that don't contain any messages + in the given sequence. + + * Split BuildFolderList in flist.c into 2 functions + (BuildFolderList, BuildFolderListR). Changed these functions + so that flist now does better leaf optimization, and will stop + stat'ing directory entries when it knows it has hit all the + subdirectories of a given directory. + + * Reorganized code in folder.c, so that all relevant folders + are scanned first and information recorded. Then all the + folder summaries at printed out at one time. + + * Made the options of folder(s) more orthogonal. Now + "folder -all -noheader -nototal" will do the right thing. + + * Added `-noall' switch to folder, for completeness. + + * Changed the default mode for creation of new folders + to 0700 (was 0711). + + * Slightly changed the format for flist. It now indicates + if a folder is current. Also the width of the various + fields are now calculated at runtime. + + * Changed the format for folder(s). Folder names + are now left justified. The width of the various fields + are calculated at runtime. + +Sun Nov 30 19:14:53 1997 Richard Coleman + + * Released nmh-0.18-pre2. + + * Add paragraph to man page for install-mh and to INSTALL file + about checking for global mh.profile. + + * Renamed m_find() to context_find(). + Renamed m_replace() to context_replace(). + Renamed m_delete() to context_del(). + Renamed m_update() to context_save(). + Renamed m_getdefs() to context_read(). + Renamed m_foil() to context_foil(). + + * Change rcvstore to use routine folder_addmsg(), instead of + adding message to folder itself. + + * Changed refile, so that if the switch -preserve is used, + and a conflict occurs for a particular folder, then folder_addmsg() + will just use next highest available number for that folder, + instead of exiting. + + * Make folder_addmsg() more robust. It will make repeated + attempts to link file into folder if link returns with + the error EEXIST. + + * Fix bug, so that that if forking sendmail, HELO will be sent + unless clientname: option is defined but empty (so now it + is the same as the direct smtp code). + + * Changed sprintb to snprintb (now we pass the buffer length + to new routine). Changed code to use new function. + + * Added snprintf to sbr. Added configure check to build it + if you don't have a native version (but haven't changed much + code to use it yet). + +Thu Nov 13 18:42:18 1997 Richard Coleman + + * Released nmh-0.18-pre1. + + * Fixed alarm bug in slocal, so that alarm is never + called with a value larger than 30 mintues. + + * Fixed race condition in rmm and refile, so that + context is updated before external rmmproc is called. + + * Removed all the OVERHEAD code. + + * Move code to add message to folder from refile.c + to folder_addmsg.c + +Fri Jul 25 19:39:29 1997 Richard Coleman + + * Did some rearranging of the internals of inc.c. + + * Make -inplace the default for anno, forw, dist, and repl. + + * Changed --enable-smtp to --with-mts={smtp,sendmail} + + * Created new directory mts/sendmail for direct sendmail + interface (although it currently still uses SMTP). + + * Removed all the TMA (trusted mail agent) code + + * Removed all the TTYD (terminal access daemon) code + + * Removed all the MF (uucp filtering) code. + + * Removed all the code for BERK. + + * Removed all the code for stand-alone delivery (MHMTS). + + * Split the file mts/sendmail/smail.c into sendmail.c and + smtp.c. Changed the name of the directory to mts/smtp. + + * Changed autoconf to use @sysconfdir@ for location of + configuration files. + + * Changed #define in mhn.c from FTP to BUILTIN_FTP. + +Mon Jul 21 03:22:34 1997 Richard Coleman + + * Released nmh-0.17. + + * MAKEDEFS weren't passed down to recursive makes correctly. + + * slocal.c now checks for UTMP_FILE and _PATH_UTMP instead + of hard-coding "/etc/utmp". + + * rcvtty.c check for _PATH_UTMP if UTMP_FILE is not + defined. + + * Remove configure checks for ulong and ushort. Changed + code to just use unsigned {short, long}. + + * Change addmsg function in refile.c to return new + number of refiled message. + + * Added check in get_returnpath for empty unixbuf. + + * Cleanup of sbr/pidstatus to use more POSIX macros + for return value of wait(). + + * Change configure to also check /bin for "more". + +Sat Jul 12 00:02:23 1997 Richard Coleman + + * Released nmh-0.16. + +Mon Jun 23 20:13:24 1997 Richard Coleman + + * Added automimeproc, which should replace automhnproc. + + * multipart messages will no longer abort for messages + of type 8bit or binary (although we still can't really + deal with binary messages, yet). + + * Fix double free of c_storage. From John MacMillan. + + * mhn now treats unknown subtypes of "text" as text/plain. + + * mhn changed so that specifying mhn-show-multipart, or + mhn-show-multipart/{mixed, alternate, etc...) will override + the use of the internal method for displaying these types. + Previously mhn would always use the internal method for subtypes + mixed, alternate, digest, and parallel (even if an alternate + method was specified in mhn.defaults). + + * mhn show treats unknown subtypes of multipart, as type + multipart/mixed (as specified RFC2046). + + * mhn checks for the parameter "name" rather than "x-name". + From MH-6.8.4 patch. + + * Fix double free of ctinfo in user_content when using + #forw with single message. From John MacMillan (and + MH-6.8.4 patch). + + * Changed -mhnproc switch for show, to -showmimeproc. + + * Changed profile entry "mhnproc" to "showmimeproc". + + * Added "mime" option to "whatnow", which calls the program + "buildmimeproc" (default is mhn -build) to process MIME + composition files. + + * Added -build switch to mhn, to process MIME composition + files. + + * Did some reorganizing of mhn.c. + + * Changed casting in mts/sendmail/smail.c from (char) to + (signed char) so SMTP reply codes work correctly for machines + which used unsigned chars by default. + +Sat Jun 21 01:21:47 1997 Richard Coleman + + * Released nmh-0.15. + + * Added new form "scan.unseen" to distribution. It marks messages + which are in any sequence in Unseen-Sequence. + + * Do some rearranging of date/time code in zotnet/tws/dtime.c + + * Fix sign extension bugs in fmt_scan.c. + + * Fix m_atoi.c so that strings ending in non-digit characters + return 0. + + * Split code in burst.c so that finding delimiters of digested + messages and bursting a message into multiple messages are + two separate functions (find_delim and burst). + + * Add workaround fo AC_PATH_PROG in configure.in, so + that BSD4.4 machines can find sendmail, vi, more. + + * Added "-width" option to rcvtty. + + * Change a few variable names in zotnet/mts/client.c since + they conflict with defines on AIX. + + * Makefile in zotnet/tws assumes lexing of dtimep.lex was + unsuccessful if resulting file is less than 500 lines long + (rather than 10, which was previous value), since AIX + sed gives mangled file of about 200 lines. + + * Extract code in rcvstore.c to link message into folder, + and put in own subroutine. + + * Extract code in refile.c to link message into folder, + and put in own subroutine. + + * Moved code to remove messages from folder into own + routine "folder_delmsgs" in sbr. Changed rmm.c and + refile.c to use new routine. + +Fri May 16 06:09:31 1997 Richard Coleman + + * Renamed m_seqok to seq_nameok. + + * Changed m_setunseen, msh, mshcmds, flist, and scan to use + seq_getnum. + + * Changed m_seqflag to return the number of a sequence rather + than its bit flag. Changed its name to seq_getnum and renamed + file to sbr/seq_getnum.c. + + * Removed function m_seqnew and file sbr/m_seqnew.c since it is + no longer used. + + * Added zero switch to m_seqadd function to zero out bits before + adding message to sequence. + + * Renamed function m_setvis to m_setunseen, and renamed + corresponding file in sbr. + + * Renamed function m_setseq to m_setprev, and renamed corresponding + file in sbr. + + * Changed mark.c and pick.c to use m_seqaddsel and m_seqdelsel. + + * Added new function m_seqdelsel to m_seqdel.c, which deletes + all selected messages from a sequence. + + * Added new function m_seqaddsel to m_seqadd.c, which adds all + selected messages to a sequence. + + * Split sbr/m_seqnew.c into m_seqadd.c, m_seqdel.c, m_seqnew.c, + and m_seqok.c. + +Thu May 15 00:53:17 1997 Richard Coleman + + * Renamed function pack_folder to m_packfolder, and moved it + from uip/folder.c into its own file sbr/m_packfolder.c + +Wed May 14 23:38:00 1997 Richard Coleman + + * Changed function m_gmsg to m_readfolder. Renamed file + sbr/m_gmsg.c to sbr/m_readfolder.c. + +Mon May 5 19:57:11 1997 Richard Coleman + + * Expanded rcvtty man page, and added small patch from + MH-6.8.4 distribution. + +Fri May 2 15:24:34 1997 Richard Coleman + + * Released nmh-0.14. + + * Comment out configure test and code for tgetent to allocate its + own termcap buffer when passed a NULL argument. + +Sat Apr 26 03:46:38 1997 Richard Coleman + + * Added new options `-checkmime', `-nocheckmime', and `-mhnproc' + to show. Restructured code to handle options to various + `procs' better. Deprecated `-noshowproc' option and NOMHNPROC + environment variable. + + * Added new man page `mh-draft' which documents the + draft folder facility in nmh. + + * Renamed fmtsbr.h to fmt_scan.h. Renamed fmtcompile.h + to fmt_compile.h. + + * split fmtsbr.c into fmt_scan.c and fmt_new.c. Renamed + fmtcompile.c to fmt_compile.c, and formataddr.c to + fmt_addr.c. + + * `send -help' wasn't showing the -(no)mime and -split + options. + +Fri Apr 25 02:50:36 1997 Richard Coleman + + * Released nmh-0.13. + + * Changed mhpath so it doesn't abort if a message sequence + such as "mhpath all" expands to more than 1000 messages. + Also mhpath now dynamically reallocated space for message + names (The number of command line arguments is still limited + to MAXARGS). + + * Did some general restructuring of the code in folder.c + that checks for folder information, and prints it. + +Thu Apr 24 01:04:37 1997 Richard Coleman + + * Changed `folder' to reallocate space for folder names if + necessary. So `folders' can now handle more than 300 folders. + +Tue Apr 22 14:01:26 1997 Richard Coleman + + * Change configure to use a compile check to see if the tm struct + has tm_gmtoff, rather than using egrep. + +Mon Apr 21 02:19:17 1997 Richard Coleman + + * Released nmh-0.12. + + * Had set_exists and unset_exists macros backwards. + + * Released nmh-0.11. + +Thu Apr 10 02:39:53 1997 Richard Coleman + + * Added documentation to mh-profile.man about the various + `procs' (mhlproc, showproc, lproc, etc...). + + * Replace the bit twiddling for SELECTED, UNSEEN, and + mp->attrstats with macros. + + * If system doesn't have SIGEMT (like Linux), then use SIGTERM + in msh.c instead. + + * Change fstat to stat in m_gmsg.c since Linux wants + to hide dd->dd_fd. + + * Merge Linux patch sent in by Michel Oosterhof (original + patch from bsa@kf8nh.wariat.org). + + * Document an undocumented MH feature. mhn -form mhl.null + will suppress the display of the message header. + + * mhparam will now return "mhparam etcdir". + + * Add catproc to /config/config.c and use that in show.c + and mshcmds.c, rather than hard coding in /bin/cat. + + * Add mhnproc to the list of `procs' in mh-profile.man. + + * Add configure test for lorder and tsort commands. + + * Commented out the padding in the `msgs` struct in h/mh.h + + * Change m_gmsg.c to allocate elements to the `info' array by + 500 elements at a time (rather than MAXFOLDERS / 5). + + * Add note to man page for mhmail that zero length messages are + not sent. Need to use -body "" to send empty messages. + + * zotnet/mts/mts.c : compare character with '\0', not NULL. + + * sbr/getcpy.c : assign '\0' to character, not NULL. + + * add m_fmsg to most programs in uip so that they explicitly free + folder/message structure when done with folder. + + * uip/slocal.c : cleanup processing of sender. Make sure it is + defined even if message is missing "From " line. + +Mon Mar 31 03:37:35 1997 Richard Coleman + + * Released nmh-0.10. + +Sun Mar 30 21:46:17 1997 Richard Coleman + + * Add configure check for . Turn on LOCALE support + by default. + +Thu Mar 20 03:21:24 1997 Richard Coleman + + * Reversed previous decision to retain "From " lines in slocal. + The "From " line is now removed from all messages. + + * inc now saves the date from the "From " envelope in the + Delivery-Date header for all messages. + + * sbr/m_getfld.c: Clean up processing of Return-Path and + Delivery-Date from the "From " envelope. + +Mon Mar 17 19:03:36 1997 Richard Coleman + + * client.c: cast iaddr to int before comparing return value + of inet_addr with NOTOK. + +Tue Mar 11 04:38:10 1997 Richard Coleman + + * Grep test for signal names was failing on some OS'es because + of missing tabs in regex. + +Sat Mar 8 01:58:22 1997 Richard Coleman + + * Released nmh-0.09. + + * Move config files and format files to *.old before installing. + + * Add configure check for killpg. + + * msh.c: include instead of and + . + + * prompter.c: don't include anymore. + +Thu Mar 6 04:03:24 1997 Richard Coleman + + * Added `-mime' and `-nomime' options to `repl'. + From MH-6.8.4 diff. + +Tue Mar 4 03:10:37 1997 Richard Coleman + + * ruserpass.c : removed conflicting prototypes. + + * rcvtty.c : Fixed rcvtty to obey terminal permissions granted + by `mesg' command. Previously only worked on BSD machines. + +Mon Mar 3 00:18:59 1997 Richard Coleman + + * rcvtty.c : Changed to use #define UTMP_FILE (if exists) rather + than hard coded "/etc/utmp". + + * Released nmh-0.08. + + * Changed slocal to lock .maildelivery (or file given by -maildelivery) + when accessing ndbm/db file for duplicate suppression, instead of + locking database itself. + +Thu Feb 27 05:28:09 1997 Richard Coleman + + * Added slocal action `mmdf' to deliver to a file in mmdf format. + + * Changed the slocal actions `file' and `>' to always deliver in + mbox (uucp) format rather than be determined by RPATHS config + option. + + * Changed the slocal action `mbox' to deliver in mbox (uucp) format + rather than mmdf format. + + * slocal now adds Delivery-Date field to all messages (previously it + only added it to messages when delivering them to a file). The + "From " line is now retained on all messages if compiling with + RPATHS, rather than being discarded. + + * rcvpack no longer adds the Delivery-Date field to messages. + +Sun Feb 23 22:03:54 1997 Richard Coleman + + * Removed the script packmbox, since it's functionality has been + added to packf. + + * Changed packf so that it uses mbox (uucp) format by default + rather than mmdf format. Added options -mbox and -mmdf to + packf so you can choose the preferred format. + + * Changed rcvpack so that it uses mbox (uucp) format by default + rather than mmdf format. Added options -mbox and -mmdf to + rcvpack so you can choose the preferred format. + +Tue Feb 18 00:01:05 1997 Richard Coleman + + * Changed nmh to use dot locking by default (although you + can still easily change this in config.h). + + * Simplified locking code. Removed code allowing setting of + locking type in mts.conf. Now the locking type and locking + directory (if any) can only be set at compile time. + +Fri Feb 14 02:49:18 1997 Richard Coleman + + * Prefer getting timezone information from tm->gmtoff rather + than tzset and external timezone variable. + +Thu Feb 13 00:35:45 1997 Richard Coleman + + * Fixed typo in ruserpass.c in the variable toktabs. + + * When ruserpass was added to LIBOBJS, it was missing + the suffix. + + * Released nmh-0.07. + +Tue Feb 11 01:29:47 1997 Richard Coleman + + * Add check to configure, so that if ruserpass, or _ruserpass + is not found, build version of ruserpass in sbr. + + * Added define's to discard.c, m_getfld.c, and scansbr.c so + the code that manipulates internals of stdio, will build + on SCO 5.x. + + * Added #define to control whether to compile the simple + built-in FTP client in mhn. + + * Added configure check for ushort and ulong. Change code + to use ushort/ulong rather than u_short/u_long. + + * A couple of small cleanups in locking code. + + * Added configure check for gmtoff element in struct tm. + + * Added configure check for tzset. + +Fri Feb 7 03:01:57 1997 Richard Coleman + + * Released nmh-0.06. + + * Removed code for machines that don't have socket + interface (how could they get mail anyway?). + + * Removed code for BSD41 machines. I don't think there are + many such machines around anymore. + + * Add configure check for function uname, and prefer it + over gethostname. General cleanup of zotnet/mts/mts.c. + + * Change all `lseek' calls to use POSIX symbolic constants + SEEK_SET, SEEK_CUR, SEEK_END. + +Thu Feb 6 01:16:30 1997 Richard Coleman + + * Check lex generated file in zotnet/tws and use + pre-generated version if necessary. + + * Released nmh-0.05. + + * Change to use reliable signals on all platforms that have + sigaction. Change so that interrupted system calls are + restarted for all signals except SIGALRM. This fixes alarm + handling code in smail.c for BSD based systems. + + * Added lorder and tsort commands so that created libs can + be linked in one pass. + +Tue Feb 4 01:33:00 1997 Richard Coleman + + * Changed pidwait so that while it is waiting for a child, + it should block signals rather than ignore them. + +Mon Feb 3 21:05:30 1997 Richard Coleman + + * Add checks to configure for dbm_open and -lndbm. + +Thu Jan 30 05:15:42 1997 Richard Coleman + + * folder -pop and folder -push were freeing some memory too + quickly, which caused the entry popped from the stack to not + become the current folder. + +Wed Jan 29 01:28:02 1997 Richard Coleman + + * Released nmh-0.04. + + * Define ospeed and PC in termsbr.c is OS doesn't have + it. + +Sun Jan 26 20:25:10 1997 Richard Coleman + + * editfile will create a symbolic link to the altmsg if it + can't make a link, on any machine supporting lstat. Formerly + this would happen only on BSD42 based machines. + +Sat Jan 25 22:54:26 1997 Richard Coleman + + * traverse (in popsbr.c) wasn't calling va_start before using + variable argument list. Fixes core dump in inc when using POP. + +Fri Jan 24 03:27:59 1997 Richard Coleman + + * The variable pass in remotemail needed to be set to + NULL. (From MH-6.8.4 diff). Fixes core dump of msgchk when + using POP. + + * inc and msgchk were using -rpop by default when configured + with POP support. Default is now -norpop. + +Thu Jan 23 02:01:17 1997 Richard Coleman + + * By default, post will now give the SMTP HELO command with + the local hostname. If you specify a hostname with the + clientname: option in mts.conf file, post will give the + HELO command with that name instead. If the argument to the + clientname: option is empty, no HELO command is given. + (From the MH-6.8.4 diff) + +Wed Jan 22 01:55:45 1997 Richard Coleman + + * When using `-help' for a command, it will also print its + profile compents from .mh_profile. (From MH-6.8.4 diff) + + * "slocal -file" will now correctly takes its input from + a file (currently need to specify full path). + +Sun Jan 19 20:37:21 1997 Richard Coleman + + * "slocal -debug" will now issue a warning if a non-blank + line in the .maildelivery file has less than 5 fields. + +Sat Jan 18 02:26:41 1997 Richard Coleman + + * Changed slocal so that code for duplicate suppression + (MH config was MSGID) is always built. Added the options + -[no]suppressdup to slocal to turn this on/off. + +Thu Jan 16 00:26:34 1997 Richard Coleman + + * Released nmh-0.03. + + * Fixed problem where mark would core dump if no + .mh_sequence file existed. + + * Fixed problem where slocal would core dump if -debug + option was given, and certain headers were missing. + + * Added patch to slocal to add `folder' (+) action, which + is shorthand for piping message to rcvstore. Updated + man page. + +Wed Jan 15 21:30:17 1997 Richard Coleman + + * Changed flist option -unseen to -[no]all. Cleaned up + flist man page. + +Fri Jan 10 20:36:33 1997 Richard Coleman + + * Fixed flist. Changed the profile component `Folder-Order' + to `Flist-Order. Added option `-sequence' to flist, so + you can specify the name of the sequence to search for. + +Thu Jan 9 00:20:48 1997 Richard Coleman + + * A few minor portability cleanups. Changed to use PATH_MAX + rather than MAXPATHLEN. Don't assume ospeed variable exists + in termsbr.c. Removed some conflicting prototypes. + +Wed Jan 8 11:05:02 1997 Richard Coleman + + * Add configure test to check if tgetent will accept NULL + and allocate its own buffer. Borrowed from zsh. + + * Changed libpath to etcpath. + +Mon Jan 6 04:15:35 1997 Richard Coleman + + * Cleaned up source code and Makefiles, so that if your `make' + supports the VPATH option, you can build nmh in a different + directory from where the source code is located. + +Fri Jan 3 05:05:18 1997 Richard Coleman + + * Released nmh-0.02. + +Wed Jan 1 17:41:52 1997 Richard Coleman + + * Split mhook man page into man pages for rcvdist, rcvpack, + and rcvtty. + +Tue Dec 31 03:07:48 1996 Richard Coleman + + * Changed code to use strerror, rather than using sys_errlist + and sys_nerr directly. + +Mon Dec 30 02:15:25 1996 Richard Coleman + + * -compat switch from install-mh removed. + + * Changed the default POP port from "pop" to "pop3". + +Sat Dec 28 13:25:05 1996 Richard Coleman + + * Changed mhn_defaults to mhn.defaults. Changed create_mhn_defaults + (again) to mhn.defaults.sh. Changed find_program (again) to + mhn.find.sh. mhn.defaults.sh now takes the search path + as an argument. Default search path is now specified in Makefile + rather than in script. + +Fri Dec 27 16:34:01 1996 Richard Coleman + + * Changed mtstailor file to mts.conf. Updated man pages. + + * Changed si_value to si_val in mhn.c, since it conflicts with + macro defined on Solaris. + +Thu Dec 26 02:50:15 1996 Richard Coleman + + * Added --enable-nmh-mhe (and --disable-nmh-mhe) to enable/disable + support for Emacs front-end mhe. It is on by default. + + * Added the following configure options: --enable-nmh-pop to + enable client side pop support, --enable-nmh-smtp to enable + SMTP support. Client-side pop support now compiles. Man + pages for inc, msgchk, mh-chart now correctly added pop + options if enabled. + +Tue Dec 24 14:33:20 1996 Richard Coleman + + * Added configure test for bug in C libraries where linker + can't find ruserpass, but can find _ruserpass. + + * Fixed configure test so that termcap variable ospeed is + correctly found. + +Mon Dec 23 19:40:17 1996 Richard Coleman + + * Source files converted to ANSI C. + + * md5 now compiled separately rather than being included + in mhn.c. Changed md5 to use memset and memcpy. + +Fri Dec 20 02:29:37 1996 Richard Coleman + + * Collected the error routines adios, advise, admonish, and advertise + into one file (error.c), and did some rearranging of the code. + +Thu Dec 19 19:05:29 1996 Richard Coleman + + * Added awk script sigmsg.awk (originally written by + Geoff Wing for zsh) to + automatically generate signal messages for pidstatus.c. + Added files sbr/signals.c, h/signals.h. Code now uses + sigprocmask to block signals (if available). Code now uses + signal blocking on non-BSD machines. + +Wed Dec 18 01:55:17 1996 Richard Coleman + + * Add configure check for ATTVIBUG. From Soren's mh autoconf work. + + * Released nmh-0.01. + + * Added configure code to check for type of signals functions + you have (POSIX or BSD style signals). Added function + SIGPROCMASK to simulate sigprocmask on machines that don't + have POSIX signals. + +Fri Dec 13 19:40:48 1996 Richard Coleman + + * Added -version switch to all commands. Also added to + their man pages. + +Mon Dec 9 16:36:54 1996 Richard Coleman + + * Renamed uip/trmsbr.c to termsbr.c and changed it to use + POSIX termios.h style functions if present. + +Tue Dec 3 16:18:39 1996 Richard Coleman + + * Changed support/general/bootmhn.sh to output new mhn_defaults + file to standard output by default (makes it easier for testing). + Changed name of script to create_mhn_defaults. Changed bootmhn.findit + script to find_program. + +Sun Dec 1 10:00:00 1996 Richard Coleman + + * Added patch to uip/folder.c from exmh distribution to + speed up -recurse option. + + * Added flist command from exmh distribution. It doesn't work + yet, but it compiles :-) + + * Changed default location for install to + /usr/local/nmh/{bin,etc,lib,man}. Split files so that format + and configuration files go in nmh/etc, and support binaries go + in nmh/lib. Of course, all this can now be changed in the top + level Makefile. + + * Started with mh-6.8.3 as based and converted to autoconf. + Rewrote all the Makefiles. Currently only works with sendmail/smtp. + Pop support and plenty of other things, are now broken. diff --git a/docs/DIFFERENCES b/docs/DIFFERENCES deleted file mode 100644 index 1540197..0000000 --- a/docs/DIFFERENCES +++ /dev/null @@ -1,278 +0,0 @@ -[NOTE: This file is out-of-date. Updating it every time new features are added - to nmh forevermore is a pain. Perhaps we should limit it to - documentation of _incompatibilities_ with MH (which should be rare).] - -The following are the differences between nmh and MH-6.8.3. UCI has -since released MH-6.8.4. Most of the new features it adds have -also been added to nmh, but those differences are not listed here. -There are a few new features in MH-6.8.4 that are missing from nmh, -but they are primarily undocumented in MH-6.8.4 (and no one has -ever asked me for them). - -GENERAL -------- -*) nmh has been converted to autoconf (configure) and should be - more portable and easier to install than MH. In particular, nmh - will now compile on Linux. -*) All of MH's Makefiles have been rewritten for nmh. You can now - use GNU make without any problems. Also, if your make supports - the VPATH variable (such as GNU make), you can now compile in a - different directory from the one containing the source code. -*) The source code for nmh has been substantially cleaned up. - It now requires an ANSI C compiler (gcc is fine) to compile. -*) A new option `-version' has been added to all the commands. -*) The POP server (popd) has been removed from the distribution. - RPOP on the client side is not currently supported. -*) The support for MH-style bulletin boards has been removed - (NNTP makes this obsolete anyway). -*) Currently nmh doesn't support using shared libraries for libmh. - This may return in the future, but is not a high priority, since - the nmh commands are not that large, and disk space gets cheaper - every day. -*) Almost all of the commands in nmh have been modified to accept - an arbitrary number of command line arguments (most MH commands - will not accept more than 1000 arguments on the command line). -*) nmh should be more secure than MH. Hundreds of buffer overflow - problems have been fixed in the source code. Of course, I still - don't make any guarantees. - -DOCUMENTATION -------------- -*) Many of the man pages have been cleaned up or clarified. -*) The mhook man page has been split into separate man pages for - rcvtty, rcvdist, and rcvpack. -*) Added new man page `mh-draft' which discusses the nmh draft - folder facility. -*) The various `procs' (rmmproc, moreproc, showmimeproc, etc...) - are now documented in the "mh-profile" man page. Many of these - were previously undocumented. - -FORMATTING ----------- -*) Added a new formatting string escape %(decode) to decode and - display RFC-2047 encoded header fields. - -SEQUENCES ---------- -*) The is no longer a limitation on the length of lines in the file - containing your public sequences (.mh_sequences). That should be - the end of the error message ".mh_sequences is poorly formatted". - -ANNO ----- -*) The switch -inplace is now on by default. - -CONFLICT --------- -*) Conflict now works on systems that define more - than 100 groups. - -DIST ----- -*) The switch -inplace is now on by default. - -FLIST ------ -*) A new command `flist' has been added to nmh, that will list the - folders that contain messages in a given sequence (such as the - unseen sequence). This was a much needed command in the MH suite - of programs. - -FOLDER ------- -*) `folder -all' now dynamically allocates space for folder names and can - handle more than 300 folders. -*) `folder' now uses the standard Unix trick of looking at the number of - links to a directory entry, in order to avoid doing a stat(2) call - on messages in folders with no subfolders. This greatly increases - the speed of `folder -all -recurse' on large mail setups. -*) The switches `-header' and `-total' are more orthogonal. The command - `folder -all -noheader -nototal' now does the right thing. - -FORW ----- -*) The switch -inplace is now on by default. -*) Added switches `-dashstuffing' and `-nodashstuffing', to determine - whether forwarded messages are RFC934 quotes (dashstuffed). - (This corresponds to the undocumented switch "nodashmunging" - in MH). - -INC ---- -*) If compiled with RPATHS, a Delivery-Date header is now added to all - messages incorporated with `inc'. -*) Using the new format string escape %(decode), the scan lines for `inc' - will correctly decode RFC-2047 encoded headers. - -MARK ----- -*) If neither of the switches -public/-nopublic are specified, then - existing sequences will retain their current public/private status, - instead of being changed to public. -*) The command "mark -list -sequence foo" will now indicate if the - sequence "foo" is a private sequence. - -MHBUILD -------- -*) The functionality in `mhn' to create MIME messages, has been cleaned - up substantially, and moved to separate command `mhbuild'. -*) If given a file argument of "-", mhbuild will now accept the MIME - composition file on the standard input, and output the new MIME - message to the standard output. This makes it much easier to use - this functionality in shell scripts. -*) The switch -norfc934mode is now the default. - -MHL ---- -*) There is a new variable "decode" which instructs `mhl' to decode - a component as a RFC-2047 encoded header field. - -MHLIST ------- -*) The functionality of `mhn -list' has been moved to the new - command `mhlist'. - -MHN ---- -*) mhn is now obsolete. It has been split into the commands mhbuild, - mhlist, mhshow, mhstore, and viamail. mhn still exists for - backward compatibility, but the new commands should be preferred. -*) Changed the profile entry automhnproc to automimeproc - (which has slightly different semantics). - -MHPATH ------- -*) `mhpath all' will no longer abort if the folder has more than - 998 messages. - -MHSHOW ------- -*) The functionality of `mhn -show' has been moved to the new - command `mhshow'. -*) mhshow now correctly treats unknown subtypes of text as - text/plain, as specified by RFC-2046. -*) mhshow now correctly treats unknown subtypes of multipart as - multipart/mixed, as specified by RFC-2046. -*) You can now override the default method by which mhshow handles - subtypes of multipart that are known internally (mixed, alternate, - etc...). Previously the behavior on these types could not be - changed. - -MHSTORE -------- -*) The functionality of `mhn -store' has been moved to the new - command `mhstore'. -*) mhstore will now correctly identify a formatting string of "-" - and send the content to stdout. - -PACKF ------ -*) When packing a folder, the default format is now `mbox' format, rather - than `mmdf' format. The options -mbox and -mmdf have been added to - `packf' so you can choose the desired format. - -PACKMBOX --------- -*) The script packmbox has been removed from the nmh distribution, since - its functionality has been added to the command packf. - -PICK ----- -*) If neither of the switches -public/-nopublic are specified, then - existing sequences will retain their current public/private status, - instead of being changed to public. - -RCVPACK -------- -*) The default format for `rcvpack' is now `mbox' format, rather than - `mmdf' format. The options -mbox and -mmdf have been added to - `rcvpack' so you can choose the desired format. -*) Rcvpack no longer adds the field "Delivery-Date", as that is added - by `slocal'. - -RCVSTORE --------- -*) Added new switches -unseen/-nounseen to control whether new messages - are added to the Unseen-Sequence. - -RCVTTY ------- -*) The option `-width' has been added. - -REFILE ------- -*) If an conflict occurs when using the `-preserve' switch, - then refile will search for and use the next available - message number above the one you wish to preserve, rather - than aborting with an error. -*) Added new options `-unlink' and `-nounlink' which specify - that that messages "removed" from the source folder should - just be unlinked, rather than moved to name with prefix. - -REPL ----- -*) Added new options `-format' and `-noformat'. The switch `-format' - will filter the message to which you are replying with a standard - message filter "mhl.reply" which is included in the distribution. - The switch `-noformat' will negate `-format' and `-filter', so that - the message to which you are replying is not included in the draft. -*) Added new options `-group' and `-nogroup'. These switches direct - repl as to whether or not this is a group reply. A group reply uses - a different forms (components) file (default is replgroupcomps). -*) The standard forms files "replcomps" and "replgroupcomps" now have - support for the "Mail-Reply-To:" and "Mail-Followup-To:" header fields. -*) The switch -inplace is now on by default. - -RMM ---- -*) Added new options `-unlink' and `-nounlink' which specify - that that "removed" messages should just be unlinked, rather - than moved to name with prefix. - -SCAN ----- -*) Using the new format string escape %(decode), the scan lines created - by `scan' will correctly decode RFC-2047 encoded headers. - -SHOW/NEXT/PREV --------------- -*) Added new options `-checkmime' and `-nocheckmime' which allow you - to enable and disable the test for MIME messages. -*) The "mhnproc" profile entry has been changed to "showmimeproc". -*) Added `-showmimeproc' switch to specify the showmimeproc at the - command line. -*) The default "showproc" has been changed to `mhl'. -*) The default "showmimeproc" is now `mhshow'. -*) `show' is better at handling alternate character sets. It knows that - US-ASCII is a subset of any ISO-8859-X character set. - -SLOCAL ------- -*) Added new action `folder' or `+' to slocal, which adds new message - to a nmh folder. Currently, this is handled by piping the new - message to rcvstore, although this may change in the future. -*) The action `mbox' now delivers to a file in mbox format. Previously - it delivered to a file in mmdf format. -*) Added new action `mmdf' to deliver to a file in mmdf format. -*) Added new options -[no]suppressdup to slocal to check for duplicate - messages. The code for suppression of duplicate messages (MH config - was MSGID) is now always built into slocal. -*) Improved the debugging of slocal ".maildelivery" files. It will now - warn when an entry in this file is skipped because there are not - enough fields. Also the debugging output of slocal has been cleaned up, - so that it is much easier to read. -*) Slocal now adds the Delivery-Date header to all delivered messages. - Previously it only added them to messages delivered to a file. - -VIAMAIL -------- -*) The functionality of this new command, was formerly part of - `mhn' as the (undocumented) option `mhn -viamail'. - -WHATNOW -------- -*) Added new action "mime" to whatnow, which causes whatnow to call - program specified by "buildmimeproc" profile entry, to process - MIME composition files (default is mhbuild). -*) Added new action "delete" to whatnow, which deletes draft file - and exits. diff --git a/docs/DIFFERENCES_nmh_MH b/docs/DIFFERENCES_nmh_MH new file mode 100644 index 0000000..1540197 --- /dev/null +++ b/docs/DIFFERENCES_nmh_MH @@ -0,0 +1,278 @@ +[NOTE: This file is out-of-date. Updating it every time new features are added + to nmh forevermore is a pain. Perhaps we should limit it to + documentation of _incompatibilities_ with MH (which should be rare).] + +The following are the differences between nmh and MH-6.8.3. UCI has +since released MH-6.8.4. Most of the new features it adds have +also been added to nmh, but those differences are not listed here. +There are a few new features in MH-6.8.4 that are missing from nmh, +but they are primarily undocumented in MH-6.8.4 (and no one has +ever asked me for them). + +GENERAL +------- +*) nmh has been converted to autoconf (configure) and should be + more portable and easier to install than MH. In particular, nmh + will now compile on Linux. +*) All of MH's Makefiles have been rewritten for nmh. You can now + use GNU make without any problems. Also, if your make supports + the VPATH variable (such as GNU make), you can now compile in a + different directory from the one containing the source code. +*) The source code for nmh has been substantially cleaned up. + It now requires an ANSI C compiler (gcc is fine) to compile. +*) A new option `-version' has been added to all the commands. +*) The POP server (popd) has been removed from the distribution. + RPOP on the client side is not currently supported. +*) The support for MH-style bulletin boards has been removed + (NNTP makes this obsolete anyway). +*) Currently nmh doesn't support using shared libraries for libmh. + This may return in the future, but is not a high priority, since + the nmh commands are not that large, and disk space gets cheaper + every day. +*) Almost all of the commands in nmh have been modified to accept + an arbitrary number of command line arguments (most MH commands + will not accept more than 1000 arguments on the command line). +*) nmh should be more secure than MH. Hundreds of buffer overflow + problems have been fixed in the source code. Of course, I still + don't make any guarantees. + +DOCUMENTATION +------------- +*) Many of the man pages have been cleaned up or clarified. +*) The mhook man page has been split into separate man pages for + rcvtty, rcvdist, and rcvpack. +*) Added new man page `mh-draft' which discusses the nmh draft + folder facility. +*) The various `procs' (rmmproc, moreproc, showmimeproc, etc...) + are now documented in the "mh-profile" man page. Many of these + were previously undocumented. + +FORMATTING +---------- +*) Added a new formatting string escape %(decode) to decode and + display RFC-2047 encoded header fields. + +SEQUENCES +--------- +*) The is no longer a limitation on the length of lines in the file + containing your public sequences (.mh_sequences). That should be + the end of the error message ".mh_sequences is poorly formatted". + +ANNO +---- +*) The switch -inplace is now on by default. + +CONFLICT +-------- +*) Conflict now works on systems that define more + than 100 groups. + +DIST +---- +*) The switch -inplace is now on by default. + +FLIST +----- +*) A new command `flist' has been added to nmh, that will list the + folders that contain messages in a given sequence (such as the + unseen sequence). This was a much needed command in the MH suite + of programs. + +FOLDER +------ +*) `folder -all' now dynamically allocates space for folder names and can + handle more than 300 folders. +*) `folder' now uses the standard Unix trick of looking at the number of + links to a directory entry, in order to avoid doing a stat(2) call + on messages in folders with no subfolders. This greatly increases + the speed of `folder -all -recurse' on large mail setups. +*) The switches `-header' and `-total' are more orthogonal. The command + `folder -all -noheader -nototal' now does the right thing. + +FORW +---- +*) The switch -inplace is now on by default. +*) Added switches `-dashstuffing' and `-nodashstuffing', to determine + whether forwarded messages are RFC934 quotes (dashstuffed). + (This corresponds to the undocumented switch "nodashmunging" + in MH). + +INC +--- +*) If compiled with RPATHS, a Delivery-Date header is now added to all + messages incorporated with `inc'. +*) Using the new format string escape %(decode), the scan lines for `inc' + will correctly decode RFC-2047 encoded headers. + +MARK +---- +*) If neither of the switches -public/-nopublic are specified, then + existing sequences will retain their current public/private status, + instead of being changed to public. +*) The command "mark -list -sequence foo" will now indicate if the + sequence "foo" is a private sequence. + +MHBUILD +------- +*) The functionality in `mhn' to create MIME messages, has been cleaned + up substantially, and moved to separate command `mhbuild'. +*) If given a file argument of "-", mhbuild will now accept the MIME + composition file on the standard input, and output the new MIME + message to the standard output. This makes it much easier to use + this functionality in shell scripts. +*) The switch -norfc934mode is now the default. + +MHL +--- +*) There is a new variable "decode" which instructs `mhl' to decode + a component as a RFC-2047 encoded header field. + +MHLIST +------ +*) The functionality of `mhn -list' has been moved to the new + command `mhlist'. + +MHN +--- +*) mhn is now obsolete. It has been split into the commands mhbuild, + mhlist, mhshow, mhstore, and viamail. mhn still exists for + backward compatibility, but the new commands should be preferred. +*) Changed the profile entry automhnproc to automimeproc + (which has slightly different semantics). + +MHPATH +------ +*) `mhpath all' will no longer abort if the folder has more than + 998 messages. + +MHSHOW +------ +*) The functionality of `mhn -show' has been moved to the new + command `mhshow'. +*) mhshow now correctly treats unknown subtypes of text as + text/plain, as specified by RFC-2046. +*) mhshow now correctly treats unknown subtypes of multipart as + multipart/mixed, as specified by RFC-2046. +*) You can now override the default method by which mhshow handles + subtypes of multipart that are known internally (mixed, alternate, + etc...). Previously the behavior on these types could not be + changed. + +MHSTORE +------- +*) The functionality of `mhn -store' has been moved to the new + command `mhstore'. +*) mhstore will now correctly identify a formatting string of "-" + and send the content to stdout. + +PACKF +----- +*) When packing a folder, the default format is now `mbox' format, rather + than `mmdf' format. The options -mbox and -mmdf have been added to + `packf' so you can choose the desired format. + +PACKMBOX +-------- +*) The script packmbox has been removed from the nmh distribution, since + its functionality has been added to the command packf. + +PICK +---- +*) If neither of the switches -public/-nopublic are specified, then + existing sequences will retain their current public/private status, + instead of being changed to public. + +RCVPACK +------- +*) The default format for `rcvpack' is now `mbox' format, rather than + `mmdf' format. The options -mbox and -mmdf have been added to + `rcvpack' so you can choose the desired format. +*) Rcvpack no longer adds the field "Delivery-Date", as that is added + by `slocal'. + +RCVSTORE +-------- +*) Added new switches -unseen/-nounseen to control whether new messages + are added to the Unseen-Sequence. + +RCVTTY +------ +*) The option `-width' has been added. + +REFILE +------ +*) If an conflict occurs when using the `-preserve' switch, + then refile will search for and use the next available + message number above the one you wish to preserve, rather + than aborting with an error. +*) Added new options `-unlink' and `-nounlink' which specify + that that messages "removed" from the source folder should + just be unlinked, rather than moved to name with prefix. + +REPL +---- +*) Added new options `-format' and `-noformat'. The switch `-format' + will filter the message to which you are replying with a standard + message filter "mhl.reply" which is included in the distribution. + The switch `-noformat' will negate `-format' and `-filter', so that + the message to which you are replying is not included in the draft. +*) Added new options `-group' and `-nogroup'. These switches direct + repl as to whether or not this is a group reply. A group reply uses + a different forms (components) file (default is replgroupcomps). +*) The standard forms files "replcomps" and "replgroupcomps" now have + support for the "Mail-Reply-To:" and "Mail-Followup-To:" header fields. +*) The switch -inplace is now on by default. + +RMM +--- +*) Added new options `-unlink' and `-nounlink' which specify + that that "removed" messages should just be unlinked, rather + than moved to name with prefix. + +SCAN +---- +*) Using the new format string escape %(decode), the scan lines created + by `scan' will correctly decode RFC-2047 encoded headers. + +SHOW/NEXT/PREV +-------------- +*) Added new options `-checkmime' and `-nocheckmime' which allow you + to enable and disable the test for MIME messages. +*) The "mhnproc" profile entry has been changed to "showmimeproc". +*) Added `-showmimeproc' switch to specify the showmimeproc at the + command line. +*) The default "showproc" has been changed to `mhl'. +*) The default "showmimeproc" is now `mhshow'. +*) `show' is better at handling alternate character sets. It knows that + US-ASCII is a subset of any ISO-8859-X character set. + +SLOCAL +------ +*) Added new action `folder' or `+' to slocal, which adds new message + to a nmh folder. Currently, this is handled by piping the new + message to rcvstore, although this may change in the future. +*) The action `mbox' now delivers to a file in mbox format. Previously + it delivered to a file in mmdf format. +*) Added new action `mmdf' to deliver to a file in mmdf format. +*) Added new options -[no]suppressdup to slocal to check for duplicate + messages. The code for suppression of duplicate messages (MH config + was MSGID) is now always built into slocal. +*) Improved the debugging of slocal ".maildelivery" files. It will now + warn when an entry in this file is skipped because there are not + enough fields. Also the debugging output of slocal has been cleaned up, + so that it is much easier to read. +*) Slocal now adds the Delivery-Date header to all delivered messages. + Previously it only added them to messages delivered to a file. + +VIAMAIL +------- +*) The functionality of this new command, was formerly part of + `mhn' as the (undocumented) option `mhn -viamail'. + +WHATNOW +------- +*) Added new action "mime" to whatnow, which causes whatnow to call + program specified by "buildmimeproc" profile entry, to process + MIME composition files (default is mhbuild). +*) Added new action "delete" to whatnow, which deletes draft file + and exits. diff --git a/docs/FAQ b/docs/FAQ index f086862..4786c02 100644 --- a/docs/FAQ +++ b/docs/FAQ @@ -48,7 +48,7 @@ Posting-Frequency: monthly MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ---------------------------------------------------------------------- - + Subject: Table of Contents From: Bill Wohler Date: Sat, 3 Mar 2001 11:29:16 -0800 @@ -215,7 +215,7 @@ Appendix Removing duplicate messages (Perl) ------------------------------ - + Subject: Viewing This Article From: Bill Wohler Date: Mon, 27 Nov 1995 14:44:19 -0800 @@ -265,7 +265,7 @@ Date: Mon, 27 Nov 1995 14:44:19 -0800 Note that due to bottom feeding email address harvesting spam scum, mailto links have been removed and @s in addresses have been replaced by "at." - + ------------------------------ Subject: 01.00 ***** Introduction ***** @@ -310,7 +310,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 MH is free, powerful, flexible--and the basics are easy to learn. ------------------------------ - + Subject: !01.02 What is the current version/status of MH. From: Bill Wohler Date: Sun, 23 Sep 2007 23:51:52 -0700 @@ -349,13 +349,13 @@ Date: Sun, 23 Sep 2007 23:51:52 -0700 http://www.gnu.org/software/mailutils/. ------------------------------ - + Subject: !01.03 Where can I get MH? From: Bill Wohler Date: Sun, 23 Sep 2007 23:51:46 -0700 MH comes standard with: - + Berkeley Software Design BSD/386 . . . . MH 6.8.3 Control Data Corp. CDC4680-MP . . . . . . EMH 1.4.2 (modified MH) Debian GNU/Linux 4.0 . . . . . . . . . . nmh 1.1-RC4 @@ -378,11 +378,11 @@ Date: Sun, 23 Sep 2007 23:51:46 -0700 http://download.savannah.nongnu.org/releases/nmh/nmh-1.2.tar.gz 831kB Download GNU mailutils: - + http://ftp.gnu.org/gnu/mailutils/mailutils-1.2.tar.gz 3.4MB ------------------------------ - + Subject: !01.04 What references exist for MH? From: Bill Wohler Date: Sun, 23 Sep 2007 23:51:41 -0700 @@ -426,15 +426,15 @@ Date: Sun, 23 Sep 2007 23:51:41 -0700 gmane.mail.mh-e.devel gmane.mail.mh-e.user gmane.mail.nmh.devel - + Mailing lists: There are three mailing lists for nmh: nmh-announce, nmh-workers, and nmh-commits. See: http://savannah.nongnu.org/mail/?group=nmh - + The page for each list contains a link to the archives. - + MH-users archives: Current archives can be found at: @@ -473,7 +473,7 @@ Date: Sun, 23 Sep 2007 23:51:41 -0700 http://www.faqs.org/faqs/usenet/signature-faq/ ------------------------------ - + Subject: 01.05 What other MH software is available? From: Stephen Gildea , Bill Wohler Date: Thu, 19 May 2005 21:20:57 -0700 @@ -560,7 +560,7 @@ Date: Fri, 26 Jan 1996 13:51:08 +0100 [MH-E has had these capabilities since version 7.0 so mew is obsolete if you use MH-E. --Ed] -From: James Perkins +From: James Perkins Date: Fri, 1 Jan 1993 00:00:00 -0800 Vmh is designed for people using the bulletin-board features of MH, @@ -800,14 +800,14 @@ Date: Sun, 11 Mar 2001 00:23:21 -0800 compile nmh with the Cygwin tools (http://www.cygwin.com/). ------------------------------ - + Subject: !01.06 How can I print a MH manual? From: Bill Wohler , Jos Vos Date: Sun, 23 Sep 2007 23:51:33 -0700 Documentation in text and PostScript format is found in the MH-doc.tgz tarball on: - + http://sourceforge.net/project/showfiles.php?group_id=143658&package_id=188464 To generate your own copy for printing, first obtain the MH sources @@ -824,7 +824,7 @@ Date: Sun, 23 Sep 2007 23:51:33 -0700 tmac.h file in the MH lib directory is made in the manual pages. ------------------------------ - + Subject: 01.07 How should I report bugs? From: Bill Wohler Date: Wed, 29 Sep 2004 00:12:42 -0700 @@ -838,7 +838,7 @@ Date: Wed, 29 Sep 2004 00:12:42 -0700 http://sourceforge.net/tracker/?atid=113357&group_id=13357 ------------------------------ - + Subject: 01.08 How can I convert from my mailer to MH? From: Mike Sutton Date: 7 Jul 1995 10:03:50 GMT @@ -912,7 +912,7 @@ Date: Sun, 1 May 1994 00:00:00 -0800 See also MH book second edition (Appendix D). ------------------------------ - + Subject: 01.09 What is the copyright status of nmh? From: Richard Coleman Date: Mon, 10 Oct 2005 18:16:58 -0700 @@ -947,7 +947,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 If you have a computer running Unix, you can probably run MH. ------------------------------ - + Subject: 02.02 How do I build MH? From: Bill Wohler Date: Sun, 8 Sep 1996 15:13:12 -0700 @@ -968,7 +968,7 @@ Date: Sun, 8 Sep 1996 15:13:12 -0700 info. ------------------------------ - + Subject: 02.03 What options should I use? From: Bill Wohler Date: Tue, 1 Dec 1992 00:00:00 -0800 @@ -1013,7 +1013,7 @@ Date: Tue, 1 Dec 1992 00:00:00 -0800 tools like from work. ------------------------------ - + Subject: 02.04 What do I need to do to use POP? From: Bill Wohler Date: Sun, 8 Sep 1996 23:31:01 -0700 @@ -1041,7 +1041,7 @@ Date: 06 Feb 1997 03:43:17 -0500 configuration and recompile: ------------------------------ - + Subject: 02.05 Does MH support IMAP? From: Lyndon Nerenberg Date: 27 Jul 1999 11:33:39 -0600 @@ -1148,7 +1148,7 @@ Date: Sun, 8 Sep 1996 15:45:32 -0700 campus email server. There are current IETF working groups revising IMAP and readying it to become an Internet standard. A copy of the latest IMAP draft may be obtained from: - + ftp://ftp.cac.washington.edu/mail/latest-imap-draft For a list of IMAP clients, see the file imap.software, in the same @@ -1173,7 +1173,7 @@ Date: Mon, 1 Aug 1994 00:00:00 -0800 future develop a version of MH that can use IMAP. ------------------------------ - + Subject: 02.06 Why does "mailgroup mail" only affect inc but not slocal? From: John Romine Date: Fri, 1 Jan 1993 00:00:00 -0800 @@ -1194,11 +1194,11 @@ Date: Fri, 1 Jan 1993 00:00:00 -0800 (See "What mail filters are available?") ------------------------------ - + Subject: 02.07 How can I build MH on Solaris 2? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 - + nmh builds out of the box on Solaris. From: Bill Wohler @@ -1279,7 +1279,7 @@ Date: Fri, 04 Apr 1997 15:30:36 GMT MH configuration. ------------------------------ - + Subject: 02.08 How can I build MH on Linux? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -1342,7 +1342,7 @@ Date: Sun, 26 Nov 1995 16:18:50 -0800 please let me know if they are missing. ------------------------------ - + Subject: 02.09 How can I build MH on IRIX? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -1383,7 +1383,7 @@ Date: 25 Jul 1995 02:35:41 GMT (See "IRIX config file") below. ------------------------------ - + Subject: 02.10 How can I get MH to interpret the Content-Length field? From: Casper H.S. Dik Date: Sun, 8 Sep 1996 15:38:30 -0700 @@ -1395,7 +1395,7 @@ Date: Sun, 8 Sep 1996 15:38:30 -0700 http://www.gw.com/mail/mh/patches/solaris/si_value_2.3 ------------------------------ - + Subject: 02.11 How can I build MH on HP-UX? From: Bill Wohler Date: Sun, 8 Sep 1996 15:50:54 -0700 @@ -1407,7 +1407,7 @@ Date: Sun, 8 Sep 1996 15:50:54 -0700 See http://www.gw.com/mail/mh/patches/hp/ for for patches you may need. ------------------------------ - + Subject: 02.12 Can I prevent adding the local hostname to addresses behind firewalls? From: Ted Remillard @@ -1446,7 +1446,7 @@ Date: 18 Aug 1995 23:51:48 -0400 around line 613. ------------------------------ - + Subject: 02.13 Is there a patch to fix this or that? From: Kimmo Suominen Date: Sat, 3 Mar 2001 13:40:35 -0800 @@ -1476,7 +1476,7 @@ Date: Sat, 3 Mar 2001 13:40:35 -0800 gw.com>. ------------------------------ - + Subject: 02.14 How can I build MH on OS/2? From: Sanjay Aiyagari Date: 21 Nov 1996 19:37:10 GMT @@ -1484,7 +1484,7 @@ Date: 21 Nov 1996 19:37:10 GMT ftp://ftp.jaist.ac.jp/pub/os/os2/network/MH/ ------------------------------ - + Subject: 02.15 Do any POP/IMAP servers handle MH format? From: "Carl S. Gutekunst" Date: 27 May 1997 07:24:34 GMT @@ -1525,7 +1525,7 @@ Date: 11 Feb 2003 04:23:38 -0800 .mailboxlist file in your home directory. ------------------------------ - + Subject: 02.16 How can I build MH on Windows? From: Satyaki Das Date: Wed, 19 Jun 2002 20:57:19 -0700 @@ -1570,7 +1570,7 @@ Date: 25 May 1999 18:13:55 GMT If you have Windows, consider looking at VMware http://www.vmware.com/ - + which provides a virtual machine where you can run Unix and therefore MH under Windows. @@ -1580,11 +1580,11 @@ Date: 24 May 99 17:20:27 GMT The latest Cygnus Cygwin, GNU tools that run under Windows, http://www.cygwin.com/ - + seems to work pretty well and may well be able to build nmh. ------------------------------ - + Subject: !02.17 How can I build MH on a Mac? From: Dr Eberhard W Lisse Date: Sun, 05 Jun 2005 13:43:19 +0100 @@ -1633,7 +1633,7 @@ Date: 19 Jan 2000 23:01:10 -0800 I have submitted patches to nmh-workers. ------------------------------ - + Subject: 03.02 How would one go about reading Usenet with MH? From: Bill Wohler Date: Sun, 26 Nov 1995 12:32:09 -0800 @@ -1724,7 +1724,7 @@ Date: Tue, 1 Nov 1994 00:00:00 -0800 See mhunify in (see also "What other MH software is available?"). ------------------------------ - + Subject: 03.03 How can I search through multiple folders? From: Jerry Peek Date: Mon, 1 Mar 1993 00:00:00 -0800 @@ -1756,7 +1756,7 @@ Date: Mon, 1 Mar 1993 00:00:00 -0800 http://rand-mh.sourceforge.net/book/mh/usilin.html#AFoFuoLi ------------------------------ - + Subject: 03.04 Why don't MH format commands such as %(friendly) work? From: Anthony Baxter Date: Sun, 1 May 1994 00:00:00 -0800 @@ -1765,7 +1765,7 @@ Date: Sun, 1 May 1994 00:00:00 -0800 such as %(friendly). Recompile MH without the BERK option. ------------------------------ - + Subject: 03.05 Why doesn't "show" display all of a MIME message? From: Jerry Peek Date: Mon, 1 Aug 1994 00:00:00 -0800 @@ -1836,7 +1836,7 @@ Date: Tue, 1 Nov 1994 00:00:00 -0800 mhn-charset-iso-8859-1: /bin/sh -c '%s' # MH ------------------------------ - + Subject: 03.06 Can I get show not to run "less" so much on MIME messages? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -1862,7 +1862,7 @@ Date: Tue, 1 Nov 1994 00:00:00 -0800 http://rand-mh.sourceforge.net/book/mh/remime.html#Alttomhn ------------------------------ - + Subject: 03.07 Why do I get "mhn: don't know how to display content"? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -1876,13 +1876,13 @@ Date: Sun, 8 Sep 1996 15:49:50 -0700 if it doesn't know about foo. The patch: http://www.gw.com/mail/mh/patches/all/mhn_multipart - + tells it to treat such things as if they were multipart/mixed. (See also "Why doesn't "show" display all of a MIME message?"). ------------------------------ - + Subject: 03.08 How can I automatically delete MH backup files? From: mccammaa at expt05.stp.xfi.bp.com (Andy McCammont) Date: 22 May 1995 06:27:36 -0400 @@ -1898,7 +1898,7 @@ Date: 22 May 1995 06:27:36 -0400 5 5 * * * find /PATH/TO/HOME/Mail -name ",*" -mtime +5 -exec rm {} \; ------------------------------ - + Subject: 03.09 Fixing "cannot fopen and lock /var/spool/mail/(user)" From: Patrick.Wambacq at esat.kuleuven.ac.be Date: Mon, 30 Sep 96 15:00:16 +0200 @@ -1933,7 +1933,7 @@ Date: Mon, 9 Sep 1996 01:01:16 -0700 (See also "Why does inc hang (on Sun)?") ------------------------------ - + Subject: 03.10 Can I read my mail with a Web browser? From: Jerry Heyman Date: Sat, 09 Oct 2004 12:41:03 -0400 @@ -1984,7 +1984,7 @@ Date: 8 Sep 1995 16:36:03 GMT http://www.mhonarc.org/ ------------------------------ - + Subject: 03.11 How can I run inc automatically with POP? From: Bill Wohler Date: Mon, 27 Nov 1995 12:23:51 -0800 @@ -2016,7 +2016,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 other means (e.g., with SMTP). ------------------------------ - + Subject: 03.12 Why does inc hang (on Sun)? From: ericding at mit.edu (Eric J. Ding) Date: 30 Apr 1996 00:22:01 -0400 @@ -2026,7 +2026,7 @@ Date: 30 Apr 1996 00:22:01 -0400 so that MH uses dotfile locking rather than FLOCK or LOCKF. ------------------------------ - + Subject: 03.13 How can I get POP to work? From: Jonathan George Date: Tue, 23 Apr 1996 10:23:16 GMT @@ -2047,7 +2047,7 @@ Date: Tue, 23 Apr 1996 10:23:16 GMT Try running inc with -noapop -norpop flags. ------------------------------ - + Subject: 03.14 How do I persuade mhshow (mhn) not to bring up a new window? From: Joel Reicher Date: Tue, 13 Nov 2001 16:49:04 +1100 @@ -2068,13 +2068,13 @@ Date: 27 Mar 1996 16:53:39 -0600 mhn-charset-iso-8859-1: %s # MH ------------------------------ - + Subject: 03.15 How do I turn off of all the mhshow (mhn) prompts? From: Bill Wohler Date: Sun, 11 Mar 2001 11:33:10 -0800 In nmh, use mhshow -nopause. - + From: Larry Daffner Date: 27 Mar 1996 16:53:39 -0600 @@ -2086,7 +2086,7 @@ Date: 27 Mar 1996 16:53:39 -0600 worth reading. ------------------------------ - + Subject: 03.16 Why is inc splitting messages improperly? From: Mayank Choudhary Date: Mon, 29 Apr 1996 09:39:29 -0700 @@ -2095,15 +2095,15 @@ Date: Mon, 29 Apr 1996 09:39:29 -0700 is found within the body, inc splits the message. Add the following line to your .forward - + "|/usr/bin/mailcompat " - + where user-name is your login-id. See mailcompat(1) for more information. ------------------------------ - + Subject: 03.17 Can MH thread messages? From: "John W. Coomes" Date: 30 Apr 1997 13:02:10 -0500 @@ -2113,7 +2113,7 @@ Date: 30 Apr 1997 13:02:10 -0500 sortm -textfield subject ------------------------------ - + Subject: 03.18 How can I avoid reading the HTML version of the message? From: Bill Wohler Date: 23 Jun 2000 10:19:34 -0700 @@ -2131,7 +2131,7 @@ Date: 23 Jun 2000 10:19:34 -0700 able to view text/html at all, but you probably wouldn't care. ------------------------------ - + Subject: 03.19 How do I view or save attachments? From: Bill Wohler Date: Mon, 5 Mar 2001 09:12:15 -0800 @@ -2140,7 +2140,7 @@ Date: Mon, 5 Mar 2001 09:12:15 -0800 the man pages for more details. ------------------------------ - + Subject: 03.20 How do I view HTML attachments with Netscape? From: Bill Wohler Date: Mon, 5 Mar 2001 09:58:05 -0800 @@ -2156,7 +2156,7 @@ Date: Mon, 5 Mar 2001 09:58:05 -0800 M-w and go back to reading mail. ------------------------------ - + Subject: 03.21 Fixing folders: unable to allocate storage for msgstats From: Pete Phillips Date: 30 Jan 2003 03:33:57 -0800 @@ -2172,7 +2172,7 @@ Date: 30 Jan 2003 03:33:57 -0800 fixed the problem. ------------------------------ - + Subject: 03.22 How do I recursively list message attachments? From: Joel Reicher Date: 31 Oct 2001 00:36:14 +1100 @@ -2197,7 +2197,7 @@ Date: 31 Oct 2001 00:36:14 +1100 env MHSTORE=mhn.rec mhstore ------------------------------ - + Subject: 03.23 Why do folder and flist overlook some of my sub-folders? From: Richard Coleman Date: Mon, 10 Oct 2005 18:14:24 -0700 @@ -2228,7 +2228,7 @@ Date: Fri, 1 Jan 1993 00:00:00 -0800 Yes, see $MHLIB/packmbox. ------------------------------ - + Subject: 04.02 Can I append MH messages to a GNU Emacs rmail BABYL-format file? From: Bill Wohler Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -2258,7 +2258,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 MMDF to BABYL, since there may be really strange results. ------------------------------ - + Subject: 04.03 Why do I get ".../.mh_sequences is poorly formatted?" From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -2308,7 +2308,7 @@ Date: Mon, 1 Aug 1994 00:00:00 -0800 a quick-&-dirty way to write xargs(1) if you don't have it. ------------------------------ - + Subject: 04.04 How can you save News articles into an MH folder? From: Jerry Peek Date: Mon, 1 May 1995 00:00:00 -0800 @@ -2330,7 +2330,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 Of course, you can also put that in a little shell script. ------------------------------ - + Subject: !04.05 Are there any good tools to archive MH messages? From: Bill Wohler Date: Sun, 23 Sep 2007 18:35:53 -0700 @@ -2359,7 +2359,7 @@ Date: Sun, 4 Mar 2001 10:26:24 -0800 http://www.webglimpse.org/ ------------------------------ - + Subject: 04.06 How can I remove duplicate messages? From: Bill Wohler Date: Sun, 17 Oct 2004 13:04:57 -0700 @@ -2389,7 +2389,7 @@ Date: 20 Nov 1995 18:51:24 GMT not require that you first sort the folder. ------------------------------ - + Subject: 04.07 How can I remove holes in numbering? From: Bill Wohler @@ -2411,7 +2411,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 went away. ------------------------------ - + Subject: 05.02 How do I include messages in repl with or without ">"? From: Richard Coleman Date: Tue, 20 Jan 1998 02:19:58 -0500 @@ -2469,7 +2469,7 @@ Date: Fri, 1 Jan 1993 00:00:00 -0800 http://rand-mh.sourceforge.net/book/mh/verrep.html#IncRep ------------------------------ - + Subject: 05.03 How can I eliminate duplicate copies of letters to myself? From: Bill Wohler Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -2518,7 +2518,7 @@ Date: Fri, 24 Jan 1997 09:33:19 -0800 Alternate-Mailboxes: asriniva ------------------------------ - + Subject: 05.04 How can I include my signature? From: Eric W. Ziegast , Hardy Mayer @@ -2631,7 +2631,7 @@ Date: Tue, 1 Nov 1994 00:00:00 -0800 See also the Signature FAQ (see "What references exist for MH?"). ------------------------------ - + Subject: 05.05 How do I call my editor with arguments? From: John Romine Date: Mon, 1 May 1995 00:00:00 -0800 @@ -2649,7 +2649,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 different arguments depending on your EDITOR environment variable. ------------------------------ - + Subject: 05.06 How can I digestify messages in a folder for mail to another user? From: Jerry Peek , Bill Wohler Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -2684,7 +2684,7 @@ Date: Tue, 1 Nov 1994 00:00:00 -0800 works beautifully with MIME-capable mail readers, especially exmh. ------------------------------ - + Subject: 05.07 How can I change my return address? From: Bill Wohler Date: Tue, 1 Dec 1992 00:00:00 -0800 @@ -2700,7 +2700,7 @@ Date: Tue, 1 Dec 1992 00:00:00 -0800 Reply-To: jack@newt.com ------------------------------ - + Subject: 05.08 How can I change my From header? From: Bill Wohler Date: Mon, 27 Nov 1995 11:40:50 -0800 @@ -2733,7 +2733,7 @@ Date: Tue, 1 Dec 1992 00:00:00 -0800 thinks is your real address. ------------------------------ - + Subject: 05.09 How can I save a copy of all messages I send? From: Ping Huang Date: Mon, 18 Dec 1995 17:51:33 -0800 @@ -2782,7 +2782,7 @@ Date: 30 Oct 1995 10:23:55 -0500 as sendmail's--it doesn't include the date. ------------------------------ - + Subject: 05.10 Can the folder in Fcc: be dynamically specified? From: Andy Rabagliati Date: Mon, 1 Aug 1994 00:00:00 -0800 @@ -2796,7 +2796,7 @@ Date: Mon, 1 Aug 1994 00:00:00 -0800 for incoming and outgoing mail. ------------------------------ - + Subject: 05.11 Can I post secure/encryped mail? From: Bill Wohler Date: Thu, 19 May 2005 18:06:39 -0700 @@ -2868,7 +2868,7 @@ Date: Wed, 16 Apr 1997 00:06:59 -0700 for details. ------------------------------ - + Subject: 05.12 How can I send multi-media (MIME) attachments? From: Brian Exelbierd Date: Mon, 09 Oct 1995 08:05:55 -0400 @@ -2902,7 +2902,7 @@ Date: Mon, 09 Oct 1995 08:05:55 -0400 http://rand-mh.sourceforge.net/book/overall/tocs/intmime.html ------------------------------ - + Subject: 05.13 What's the best way to send mail to a long list of people? From: Bill Wohler Date: Thu, 12 Oct 1995 07:53:53 -0700 @@ -2935,7 +2935,7 @@ Date: Thu, 12 Oct 1995 07:53:53 -0700 (See "What is the Dcc header?") ------------------------------ - + Subject: 05.14 What is the Dcc header? From: jpeek at jpeek.com (Jerry Peek) Date: 14 Sep 96 05:51:13 GMT @@ -2950,7 +2950,7 @@ Date: 14 Sep 96 05:51:13 GMT field with some address (like yours) in it. I use a comment that tells people what's really happening--like this, more or less: - To: "Faculty members, c/o" + To: "Faculty members, c/o" dcc: faculty There are some other choices, like using an un-replyable group list @@ -2974,7 +2974,7 @@ From: John Romine (or worse). ------------------------------ - + Subject: 05.15 How can I make sense of the replcomps file? From: Bill Wohler Date: Thu, 9 Mar 2006 19:27:14 -0800 @@ -3050,7 +3050,7 @@ Date: Thu, 9 Mar 2006 19:27:14 -0800 Comments fields above. ------------------------------ - + Subject: 05.16 How can I convert quoted-printable to 8bit in quoted text in replies? From: Jarle F. Greipsland Date: 22 Aug 1995 10:42:07 +0200 @@ -3134,7 +3134,7 @@ Date: 22 Aug 1995 10:42:07 +0200 in the .mh_profile, isoextract exec's this editor. ------------------------------ - + Subject: 05.17 Can I have aliases include aliases? From: Bruce Cox Date: Fri, 16 Aug 1996 14:26:12 +1000 @@ -3163,7 +3163,7 @@ Date: Fri, 16 Aug 1996 14:26:12 +1000 presidents, authors ------------------------------ - + Subject: 05.18 Why doesn't mhmail understand aliases? From: "John L. Romine" Date: 25 Apr 1996 16:34:10 GMT @@ -3174,7 +3174,7 @@ Date: 25 Apr 1996 16:34:10 GMT them before passing them as arguments (e.g., "mhmail `ali joe`"). ------------------------------ - + Subject: 05.19 How do I send blind carbon copies? From: Bill Wohler Date: Mon, 9 Sep 1996 00:32:14 -0700 @@ -3198,7 +3198,7 @@ Date: Mon, 9 Sep 1996 00:32:14 -0700 inadvertently. Read the warning in (see "What is the Dcc header?"). ------------------------------ - + Subject: 05.20 When I forward a message, can I use its Subject? From: Jerry Peek Date: Sun, 17 Nov 1996 20:16:31 -0800 @@ -3208,7 +3208,7 @@ Date: Sun, 17 Nov 1996 20:16:31 -0800 http://rand-mh.sourceforge.net/book/examples/mh/bin/forwedit ------------------------------ - + Subject: 05.21 Why is the timezone field in my 'Date:' field wrong? From: Alex Tomlinson Date: Wed, 11 Jun 1997 09:16:41 -0500 @@ -3221,7 +3221,7 @@ Date: Wed, 11 Jun 1997 09:16:41 -0500 rebuild. ------------------------------ - + Subject: 05.22 Can I automate the comp -editor mhn process? From: Soren Dayton Date: Tue, 21 Jan 1997 17:23:32 GMT @@ -3233,7 +3233,7 @@ Date: Tue, 21 Jan 1997 17:23:32 GMT to your MH profile. ------------------------------ - + Subject: 05.23 How can I remove those "=20" characters when forwarding? From: Dave Marquardt Date: 12 Oct 2000 10:27:38 -0500 @@ -3241,7 +3241,7 @@ Date: 12 Oct 2000 10:27:38 -0500 Use `forw -mime'. ------------------------------ - + Subject: 05.24 Can I use mh-format substitution with forw? From: Dave Marquardt Date: Tue, 3 Aug 1999 13:28:30 -0500 (EST) @@ -3249,7 +3249,7 @@ Date: Tue, 3 Aug 1999 13:28:30 -0500 (EST) The answer is no, and the real question is why not? ------------------------------ - + Subject: 05.25 How can I keep repl from breaking long lines? From: Jerry Peek Date: Fri, 14 May 1999 11:15:07 -0400 @@ -3302,7 +3302,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 Then complain to your vendor that "vi" is broken, and they shouldfix it. ------------------------------ - + Subject: 06.02 Can I run my message through a program (e.g., ispell) before sending? From: Jerry Peek Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -3338,7 +3338,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 http://rand-mh.sourceforge.net/book/mh/chaedi.html#Edi ------------------------------ - + Subject: 06.03 What to do with "bad address 'xxx' - no at-sign after local-part". From: Owen Rees Date: Fri, 1 Jan 1993 00:00:00 -0800 @@ -3357,7 +3357,7 @@ Date: Fri, 1 Jan 1993 00:00:00 -0800 (Mr. Foo Bar) fb@somewhere.edu ------------------------------ - + Subject: 06.04 Fixing "post: problem initializing server; [BHST] no servers available" From: Peter Marvit , Eric Bracken @@ -3408,9 +3408,9 @@ Date: Sun, 02 Sep 2001 02:13:42 -0400 Solution: Try specifying the path explicitly by adding a line to mts.conf thus: - + sendmail: /usr/sbin/sendmail - + or wherever your sendmail daemon executable lives. From: Neil W Rickert @@ -3426,7 +3426,7 @@ Date: 13 Apr 2001 18:47:43 -0500 command line sendmail. ------------------------------ - + Subject: 06.05 Fixing "post: problem initializing server; [RPLY] 503 Sender already specified" From: Paul Pomes Date: Mon, 1 Mar 1993 00:00:00 -0800 @@ -3440,7 +3440,7 @@ Date: Mon, 1 Mar 1993 00:00:00 -0800 MH sources to not use the ONEX verb. ------------------------------ - + Subject: 06.06 Fixing "post: unexpected response; [BHST] no socket opened" From: Steve Lembark , Bill Wohler Date: Mon, 1 Aug 1994 00:00:00 -0800 @@ -3505,7 +3505,7 @@ Date: Mon, 1 Aug 1994 00:00:00 -0800 solutions seem to be the most prevalent. ------------------------------ - + Subject: 06.07 How do I fix the "X-Authentication-Warning" header? From: Bill Wohler Date: Mon, 9 Sep 1996 01:32:15 -0700 @@ -3513,7 +3513,7 @@ Date: Mon, 9 Sep 1996 01:32:15 -0700 (See "Fixing "Sender didn't use the HELO protocol"".) ------------------------------ - + Subject: 06.08 Fixing "post: unexpected response; [RPLY] 503 Need MAIL before RCPT" From: Bjoern Stabell Date: Mon, 1 May 1995 00:00:00 -0800 @@ -3525,7 +3525,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 in the $MHLIB/mts.conf (mtstailor) file, and that fixed the problem. ------------------------------ - + Subject: 06.09 Fixing "post: problem initializing server; [BHST] premature end-of-file on socket" From: Ginko Date: Thu, 8 Mar 2001 09:18:14 +0000 (UTC) @@ -3551,7 +3551,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 ". ------------------------------ - + Subject: 06.10 Fixing "Sender didn't use the HELO protocol" From: rickert at cs.niu.edu (Neil Rickert) Date: Tue, 20 Mar 2001 22:01:16 -0800 @@ -3605,7 +3605,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 in your sendmail.cf. ------------------------------ - + Subject: 06.11 Fixing "post: problem initializing server; [RPLY] 553 Local configuration error, hostname not recognized as local" From: "Matthew V. J. Whalen" Date: Mon, 1 May 1995 00:00:00 -0800 @@ -3726,7 +3726,7 @@ Date: Tue, 28 Jul 1998 13:22:07 +0200 http://www.cpan.org/authors/Raphael_Manfredi/ ------------------------------ - + Subject: 07.02 Why slocal writes messages to system mailbox that from(1) can't read. From: Bill Wohler Date: Mon, 1 May 1995 00:00:00 -0800 @@ -3735,7 +3735,7 @@ Date: Mon, 1 May 1995 00:00:00 -0800 MH-like command instead of from: "scan -file $MAIL". ------------------------------ - + Subject: 07.03 Where can I read about slocal and the format of .maildelivery? From: Bill Wohler Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -3768,7 +3768,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 (See "What mail filters are available?") ------------------------------ - + Subject: 07.04 How do I debug my .maildelivery file? From: Bill Wohler Date: Mon, 1 Mar 1993 00:00:00 -0800 @@ -3796,7 +3796,7 @@ Date: Mon, 1 Mar 1993 00:00:00 -0800 http://rand-mh.sourceforge.net/book/mh/debugti.html ------------------------------ - + Subject: 07.05 Why isn't slocal working? From: Bill Wohler Date: Mon, 1 Mar 1993 00:00:00 -0800 @@ -3816,7 +3816,7 @@ Date: Mon, 1 Mar 1993 00:00:00 -0800 See also "How do I debug my .maildelivery file?" ------------------------------ - + Subject: 07.06 Are there any good biff applications for MH? From: Rob Austein Date: Tue, 01 Dec 1998 03:02:34 -0500 @@ -3846,7 +3846,7 @@ Date: 7 Jul 97 09:36:32 GMT character for readability. ------------------------------ - + Subject: 07.07 How do I read new messages filed by procmail? From: Bill Wohler Date: Sun, 17 Oct 2004 15:17:14 -0700 @@ -3948,7 +3948,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 in the Appendix "Switching xmh's editor". ------------------------------ - + Subject: 09.02 Does xmh support subfolders? From: Steve Malowany Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -3973,7 +3973,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 http://rand-mh.sourceforge.net/book/xmh/orgfol.html#FolaSub ------------------------------ - + Subject: 09.03 How do I precede included messages with ">" when replying in xmh? From: Len Makin Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -4018,7 +4018,7 @@ Date: Wed, 29 Sep 2004 00:04:34 -0700 SMTP Simple Mail Transport Protocol (STD 10; RFC 821) ------------------------------ - + Subject: Acknowledgments From: Bill Wohler Date: Mon, 9 Sep 1996 01:37:27 -0700 @@ -4046,7 +4046,7 @@ Suominen for maintaining the MH patch page, and Richard Coleman for taking MH to nmh. ------------------------------ - + Subject: Switching xmh's editor From: Andrew Wason Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -4238,7 +4238,7 @@ echo shar: End of shell archive. exit 0 ------------------------------ - + Subject: babyl2mh.pl From: Vivek Khera Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -4287,7 +4287,7 @@ while () { } ------------------------------ - + Subject: inco - babyl to MH converter From: Juergen Nickelsen Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -4329,7 +4329,7 @@ inc -file $tmpmbox $folder rm -f $lispfile $tmpmbox ------------------------------ - + Subject: t2h - add hyperlinks to message viewed From: TANAKA Tomoyuki Date: Mon, 13 Sep 1999 11:35:43 -0600 @@ -4355,7 +4355,7 @@ $a\ ------------------------------ - + Subject: srvrsmtp.c patch From: Paul Pomes Date: Fri, 1 Mar 1991 13:03:15 -0800 @@ -4381,7 +4381,7 @@ Date: Fri, 1 Mar 1991 13:03:15 -0800 case CMDVRFY: /* vrfy -- verify address */ ------------------------------ - + Subject: IRIX config file From: Jack Repenning Date: 25 Jul 1995 02:35:41 GMT @@ -4449,7 +4449,7 @@ options MSGPROT='"0600"' RPATHS SENDMTS SGI SMTP SOCKETS SYS5 options TYPESIG="void" ncr MIME VSPRINTF UNISTD SYSVR4 SYS5DIR ------------------------------ - + Subject: HP-UX 10.20 config file From: Marko Heikkinen Date: 06 Jan 1997 17:19:07 +0000 @@ -4470,7 +4470,7 @@ mts sendmail/smtp pop off slibdir: /opt/mail/lib options SYS5 -options MHE +options MHE options MIME options ATZ options BIND @@ -4525,7 +4525,7 @@ Date: 20 Nov 1995 18:51:24 GMT gets too big, your system may complain. And I'm sure there are some more-efficient ways to find the list of duplicate message-ids. But that's the idea. - + Subject: Removing duplicate messages (Perl) From: rtor at ansa.co.uk (Owen Rees) Date: 20 Nov 1995 12:39:47 GMT @@ -4567,7 +4567,7 @@ Date: Sun, 17 Oct 2004 13:00:20 -0700 #!/usr/bin/perl -w # -# Id: mhfinddup 6593 2004-09-02 16:34:24Z wohler +# Id: mhfinddup 6593 2004-09-02 16:34:24Z wohler =head1 NAME @@ -4666,7 +4666,7 @@ B(1), B(1), B(1) =head1 VERSION -Revision: 6593 +Revision: 6593 =head1 AUTHOR diff --git a/docs/MACHINES b/docs/MACHINES new file mode 100644 index 0000000..9601431 --- /dev/null +++ b/docs/MACHINES @@ -0,0 +1,97 @@ +# +# MACHINE -- operating system specific information +# + +nmh is known to compile on the following platforms (save the +exceptions noted below), using an ANSI C compiler, such as gcc. + +AIX 4.1.5.0.01 +FreeBSD +IRIX 6.5 +Linux 2.2, 2.3, 2.4 (glibc 2.1, glibc 2.2) +Mac OS X Public Beta +NetBSD 1.4.2 +OpenBSD +Solaris 7 and 8 (sparc,x86) +SunOS 4.1 + +Known Compilation problems: +-------------------------------------- +FreeBSD: +OpenBSD: +NetBSD: + +Some BSD4.4 machines have problems when running nmh's configure script. +They will be unable to find the location of vi and sendmail. This is +due to POSIX features (breakage?) in the shell sh. The solution is to +run the configure script under the shell `bash': + + % bash configure + +-------------------------------------- +Mac OS X/Rhapsody 5: + +Version 5.3 at least has the same sh/bash bug as the *BSD systems +above. This appears to be fixed in 5.5. + +Will not compile correctly unless you configure with the --enable-debug +option. It appears to find conflicts in the headers only when debugging +is disabled. With debugging enabled, it compiles and runs happily. + +-------------------------------------- +HPUX: + +Lots of problems have been reported with using HPUX `cc'. In particular, +problems with `scan' giving incorrect dates (everything is 01/00). +It is highly recommended that you use `gcc' instead. + +Also, new versions of HPUX (10.20?) will core dump in `scan' because +of some workaround code in zotnet/tws/lexstring.c. This workaround is +needed for older versions of HPUX, but causes problems on newer versions. +The solution is the added line (minus our indentation): + + #undef hpux + +after line 15 of the file zotnet/tws/lexstring.c. + +-------------------------------------- +Irix (SGI): + +Irix make is notoriously buggy. If you're using it, you should "touch +config.h.in" before configuring to prevent a problem where it tries to +rebuild targets that shouldn't be rebuilt. (Alternately, you can just +use GNU make instead of Irix make.) + +-------------------------------------- +Linux: + +The configuration script does a test to discover if your vi is broken +(if it reports non-zero exit codes on certain pseudo-errors). This test +will hang if the program `ex' on your system is a link to the vi clone +`vile'. The workaround is to replace the command ex as a link to another +vi clone such as nvi or elvis. + +-------------------------------------- +Solaris: + +With --enable-debug you'll see a lot of warnings. This is even worse +when compiling using the Sun Workshop compiler since it issues a +warning for every instance of a problem instead of summarizing them. +The main one concerns arrays with an index of type char. This is ok. +The array itself is a hash of chars, so the array size and the type +match. There isn't another safe and portable way to do this at the +moment. An explicit cast would get rid of the warnings, but I think +it's better to leave it complaining for now until we come up with +a better solution. The whole thing is probablly going to be chucked +with UTF-8 support anyway. + +Other than the warnings, it builds ok. +-------------------------------------- +SunOS 4.1.1/4.1.3/4.1.4: + +You can't use the C compiler that comes with SunOS 4 since +it isn't ANSI C. But nmh builds just fine with gcc. With +--enable-debug you will see a lot of warnings. +-------------------------------------- + + diff --git a/docs/MAIL.FILTERING b/docs/MAIL.FILTERING deleted file mode 100644 index b0b5e8d..0000000 --- a/docs/MAIL.FILTERING +++ /dev/null @@ -1,107 +0,0 @@ - -INTRODUCTION ------------- -It is a common practice when using nmh to filter your inbound mail -directly into nmh folders. There are several programs which allow you -to do this, of which two common ones are procmail and slocal. - -SLOCAL ------- -The slocal command is part of the nmh distribution. It is a fairly -simple mail filtering program. Check the slocal man page for an example -filtering file (called .maildelivery). - -PROCMAIL --------- -Probably the most popular mail filtering command is procmail. It can -filter mail into standard mbox-style spool files, as well as into MH/nmh -style folders. - -Although procmail knows how to put a message directly into an nmh folder, -this is not recommended. Procmail doesn't know about nmh sequences. -Instead you should have procmail use the nmh command `rcvstore' to put -the message into the folder. The `rcvstore' command will (by default) -add each new message to the "unseen" sequence, so you can detect new -messages in folders with the `flist' command. - -Also, nmh commands generally like to keep mail messages in RFC-822 -format. But by default, procmail will leave the first line of the -message unchanged. This line (which usually begins with "From ") is -not in the standard RFC-822 format. It is recommended that you use the -command `formail' (which comes in the procmail distribution) to rewrite -this line so that it begins with the header name "X-Envelope-From:". -An example of how to do this is given below. - -The reason the header name "X-Envelope-From:" is recommended, is that the -nmh command `packf' (as of version 0.23) will check for this header when -packing folders. The `packf' command knows how to undo the rewriting -of the "From " line to the "X-Envelope-From:" line. By checking for -this header name, `packf' is able to pack the folder into exactly the -form that is used if procmail delivers to the standard mail spool. - -If you do not rewrite the "From " line into this format, the `packf' -command will still work. But it may create fake "From " lines which -are not the same as the originals. - -Alternatively, you might be able to suppress generation of the "From " -line. If your procmail invocation includes the -f or -r option, -remove. Those options add a "From " line to incoming beginning of -messages that do not have them. - -Here is a typical .procmailrc file for using procmail in conjunction -with nmh. For more information, see the manual pages for procmail, -procmailrc and procmailex. - -################################################################### -# .procmailrc -################################################################### -# To use procmail, put the next line in your .forward file: -# "|IFS=' ' && exec /usr/local/bin/procmail -f- || exit 75 #XXX" -# Do not remove the double quotes. Change XXX to your username. -# Edit path to procmail above, and the VARIABLES below, as needed. -# Adapt the MAILING LIST section below for lists you subscribe to. -# Your .forward needs to be world-readable, but not world-writable. -################################################################### -# This .procmailrc is written for use with nmh/mh/exmh/mh-e -################################################################### - -### VARIABLES ### -VERBOSE=off -SHELL=/bin/sh -PATH=/usr/local/nmh/lib:/usr/local/nmh/bin:/usr/bin:/usr/local/bin -MAILDIR=$HOME/Mail -LOGFILE=$MAILDIR/procmail.log -LOCKEXT=.lock - -################# -# CLEANUP MESSAGE -################# - -# Force the "From user date" to become part of header -:0 Whf -| formail -z -R 'From ' X-Envelope-From: - -############### -# MAILING LISTS -############### - -:0 w: nmh-workers/$LOCKEXT -* ^Resent-from: *nmh-workers -| rcvstore +nmh-workers - -# catches exmh-{announce,users,workers} -:0 w: exmh/$LOCKEXT -* ^TOexmh -| rcvstore +exmh - -# Catch junk. Don't add it to "unseen" sequence (nmh only) -:0 w: junk/$LOCKEXT -* ^(reply-to|from|sender):.*(spammer|flamer|evil-host) -| rcvstore -nounseen +junk - -################ -# DEFAULT ACTION -################ -:0 w: inbox/$LOCKEXT -| rcvstore +inbox - diff --git a/docs/MAILING-LISTS b/docs/MAILING-LISTS index 66d49a9..ca6c7c3 100644 --- a/docs/MAILING-LISTS +++ b/docs/MAILING-LISTS @@ -1,34 +1,36 @@ There are currently three mailing lists related to nmh: -nmh-announce@mhost.com +nmh-announce@nongnu.org ---------------------- This is a very low-traffic mailing list for announcing new releases, -patches, and important events related to nmh. +patches, and important events related to nmh. -nmh-bugs@mhost.com ------------------- -This an open-submission list for reporting bugs. It is moderated to -prevent being spammed. Any nmh-related mail is approved. +To subscribe or manage your subscription options, go to: + https://lists.nongnu.org/mailman/listinfo/nmh-announce -nmh-workers@mhost.com ---------------------- -This is the main list for discussing work on nmh. Both of the above -mailing lists are forwarded to this one. There is currently no -nmh-users mailing list, so user questions are acceptable here (the -comp.mail.mh newsgroup is another good option). + +nmh-workers@nongnu.org +---------------------- +This is the main list for discussing work on nmh. There is currently +no nmh-users mailing list, so user questions are acceptable here (the +comp.mail.mh newsgroup is another good option). Bug reports and +feedback should be submitted here. + +To subscribe or manage your subscription options, go to: + https://lists.nongnu.org/mailman/listinfo/nmh-workers + + +nmh-commits@nongnu.org +---------------------- +All commits to the nmh source code repository are copied to this list. +Therefore, it is probably only of interest to nmh developers. + +To subscribe or manage your subscription options, go to: + https://lists.nongnu.org/mailman/listinfo/nmh-commit mail archives ------------- -The mail archives are only available to people subscribed to the -mailing list. This restriction is in place to prevent harvesting of -email addresses by spammers. To access the archives, you need to send -mail to nmh-workers-request with an archive access command. You can -get a current list of commands the archive server understands by -sending a message to nmh-workers-request@mhost.com with the subject -"archive help". - -Of interest in the archive are the directories "latest" which contains -everything since the nmh-workers mailing list has been hosted on -mhost.com, and "old-list" which contians all the mail from when the -list was formerly hosted at math.gatech.edu. +The nmh-workers and nmh-commits mailings lists archives are available here: + http://lists.nongnu.org/archive/html/nmh-workers/ + http://lists.nongnu.org/archive/html/nmh-commits/ diff --git a/docs/Makefile.in b/docs/Makefile.in index 695bdf0..e9092a0 100644 --- a/docs/Makefile.in +++ b/docs/Makefile.in @@ -5,13 +5,15 @@ SHELL = /bin/sh srcdir = @srcdir@ +datarootdir = @datarootdir@ VPATH = @srcdir@ # header files included in distribution FILES = COMPLETION-BASH COMPLETION-TCSH COMPLETION-ZSH \ ChangeLog_MH-3_to_MH-6.6 ChangeLog_MH-6.7.0_to_MH-6.8.4.html \ - DIFFERENCES FAQ MAIL.FILTERING MAILING-LISTS README.about \ - README-ATTACHMENTS README-HOOKS README.SASL \ + ChangeLog_nmh DIFFERENCES_nmh_MH MACHINES \ + FAQ README.mail-filtering MAILING-LISTS README.about \ + README.attachments README.hooks README.SASL \ README.developers README.manpages TODO # auxiliary files @@ -50,9 +52,9 @@ subdir = docs Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: +mmhdist: @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ diff --git a/docs/README-ATTACHMENTS b/docs/README-ATTACHMENTS deleted file mode 100644 index ff9db2a..0000000 --- a/docs/README-ATTACHMENTS +++ /dev/null @@ -1,281 +0,0 @@ -Jon Steinhart's (jon@fourwinds.com) Attachment Handling Mods -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A bunch of changes have been made to improve the nmh user interface for -handling MIME attachments. - -Why Did I Do This? -~~~~~~~~~~~~~~~~~~ - -Although nmh contains the necessary functionality for MIME message handing, -the interface to this functionality is pretty obtuse. There's no way that -I'm ever going to convince my partner to write mhbuild composition files! -And even though I know how to write them, I often screw up when sending a -message that contains a shell script because I forget that I have to double -any # at the start of a line, which shell scripts have galore. - -These changes simplify the task of managing attachments on draft files. -They allow attachments to be added, listed, and deleted. MIME messages are -automatically created when drafts with attachments are sent. - -The Simple Setup -~~~~~~~~~~~~~~~~ - -The gory details are all given below. Here's how to set things up simply. This -only works if you're using the "standard" interface, i.e., whatnow. Life is more -complicated if you run mh-e. - -Add the following to your .mh_profile: - - send: -attach X-MH-Attachment - whatnow: -attach X-MH-Attachment - -You may already have send and whatnow lines in your .mh_profile; if you do, just add -the new stuff to the end of the line. For example, mine looks like: - - send: -alias aliases -attach X-MH-Attachment - whatnow: -attach X-MH-Attachment - -That's it. Next time you want to send an attachment, say "attach filename" at the -whatnow prompt and you're done. You can check your attachments by saying "alist". - -Did I Do This Correctly? -~~~~~~~~~~~~~~~~~~~~~~~~ - -Hard to say. Despite lots of time looking at the nmh code, I can't say that -I get the philosophy behind its structure. - -I am aware of two deviations from what I saw in the nmh code. - - 1. I commented my changes. - - 2. It's been years since I've used a VT-100, so I don't try to make code - fit into 80 columns anymore. Seems silly to me. - -What Did I Do? -~~~~~~~~~~~~~~ - -I made changes to the following files: - - h/ - prototypes.h - man/ - anno.man - send.man - whatnow.man - uip/ - Makefile.in - anno.c - annosbr.c - send.c - sendsbr.c - viamail.c (needed change for new sendsbr argument) - whatnowsbr.c - -Attachments are associated with messages using header fields. For example, a -draft that looks like this - - To: jon - Subject: test of attachments - X-MH-Attachment: /export/home/jon/foo - X-MH-Attachment: /export/home/jon/bar - X-MH-Attachment: /export/home/jon/test/foo - -------- - -has the files "foo", "bar", and foo as attachments. - -Although I use the header field name "X-MH-Attachment" to indicate -attachments, the implementation allows any header field name. - -The advantage of using header fields is that the list of attachments -travels with the draft so it remains valid across editing sessions. - -Note that the header fields for attachments are removed from the message -before it is sent. - -Since I was adding header fields to messages, it seemed sensible to use the -existing anno program to do this for me. This required several changes to -generalize anno: - - o I added a -draft option that permits annotations (header fields) to - be added to the draft instead of a message sequence. - - o I added a -delete option that allows annotations to be deleted. - - o I added a -list option that allows annotations to be listed. - - o I added a -number option that modifies the behavior of -delete and -list. - - o I added a -append option so that annotations are appended to the headers - instead of the default prepend. Without this, attachments come out in - reverse order. - -Using the modified anno, the example above could be created (assuming that the -draft exists) by - - prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/foo -nodate -append - prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/bar -nodate -append - prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/test/foo -nodate -append - -One can quite easily make an "attach" command using shell scripts, aliases or functions. -For example, here's a bash function that does the job: - - function attach() { for i in $*; do anno -append -nodate -draft -comp X-MH-Attachment -text "$i"; done; } - -The following examples show the different ways in which attachments can be -listed. - - prompt% anno -list -draft -comp X-MH-Attachment - foo - bar - foo - - prompt% anno -list -draft -comp X-MH-Attachment -text / - /export/home/jon/foo - /export/home/jon/bar - /export/home/jon/test/foo - - prompt% anno -list -draft -comp X-MH-Attachment -number - 1 foo - 2 bar - 3 foo - - prompt% anno -list -draft -comp X-MH-Attachment -text / -number - 1 /export/home/jon/foo - 2 /export/home/jon/bar - 3 /export/home/jon/test/foo - - prompt% - -Why all these listing options? - -I feel that the listing as produced by the first example is what most people -would want most of the time. - -The listing as produced by the second example seemed necessary for situations -where there were several attachments with the same file name in different -directories. - -I included the numbering option so that attachments could be deleted by number -which might be easier in situations where there were several attachments with -the same file name in different directories, as in the above example. - -Attachments are deleted using the -delete option. - - prompt% anno -delete -draft -comp X-MH-Attachment -text foo - -deletes the first attachment since the foo matches the basename of the attachment -name. - - prompt% anno -delete -draft -comp X-MH-Attachment -text /export/home/jon/test/foo - -deletes the third attachment since the text is a full path name and matches. - - prompt% anno -delete -draft -comp X-MH-Attachment -number 2 - -deletes the second attachment. - -The attachment annotations are converted to a MIME message by send. I'm not -completely sure that this is the right place to do it, as opposed to doing -it in post, but both would work. It seemed to me to make more sense to do -it in send so that all of the various post options would apply to the MIME -message instead of the original draft file. - -I added an -attach option to send that specifies the header field name used -for attachments. Send performs the following additional steps if this option -is set: - - o It scans the header of the draft for attachments. Normal behavior applies - if none exist. - - o A temporary mhbuild composition file is created if there are attachments. - - o All non-attachment headers are copied from the draft file to the - composition file. - - o The body of the draft is copied to a temporary body file if it contains at - least one non-whitespace character. A mhbuild directive for this file is - appended to the composition file. Note that this eliminates the problem - of lines beginning with the # character in the message body. - - o A mhbuild directive is appended to the composition file for each attachment - header. - - o mhbuild is run on the composition file, converting it to a MIME message. - - o The converted composition file is substituted for the original draft file - and run through the rest of send. - - o The original draft file is renamed instead of the converted composition - file. This preserves the original message instead of the composition file - which is really what a user would want. - - o The ,file.orig file created by mhbuild is removed as it's a nuisance. - -The mhbuild directives appended to the composition file are constructed as -follows: - - o The content-type a file with a dot-suffix is obtained from the list of - mhshow-suffix- entries in the profile. - - o A file with no dot-suffix or no entry in the profile is assigned a - content-type of application/octet-stream if it contains any non-ASCII - characters. - - o A file with no dot-suffix or no entry in the profile is assigned a - content-type of text/plain if it contains only ASCII characters. - - o The directive is of the form: - - #content-type; name="basename"; x-unix-mode=mode [ description ] filename - - The content type is derived as discussed above. The basename is the - last component of the pathname given in the body of the attachment header - field. The mode is file permissions. The description is obtained by - running the file command on the attachment file. The filename is the - field body from the attachment header field. - -I added an -attach option to whatnow that specifies the header field name for -attachments. - -I added to the commands available at the whatnow prompt to provide an interface -to the attachment mechanism. - -I'm not completely happy with some of these additions because they duplicate -shell functionality. I'm not sure that there's a good way around it other than -to not use whatnow. - -The first three additions (the ones I'm not happy with) are cd, ls, and pwd. -These do the same thing as their system counterparts. As a matter of fact, -these are implemented by running the commands in a subshell. I did this because -I wanted proper interpretation of shell-specific things like ~ and wildcard -expansion. - -The next command is attach. This takes a list of files and adds them to the draft -as attachments using the same code as the modified anno. The list of files is -run through ls using the user's shell, so wildcard expansion and all that works. - -The alist command lists the attachments on the current draft using listing function -that I added to anno. It takes two optional options, -l for a long listing meaning -full path names, and -n for a numbered listing. - -The detach command removes attachments from the current draft, again using the -modified anno. The arguments are interpreted as numbers if the -n option is used, -otherwise they're interpreted as file names. File names are shoveled through ls -using the user's shell in the directory containing the file for wildcard expansion -and such. File names are matched against the last pathname component unless they -begin with a / in which case they're matched against the entire name. - -What's Left To Do? -~~~~~~~~~~~~~~~~~~ - -Nothing on this stuff. When I get time I'd like to improve the interface -for reading messages with attachments. It's my opinion that, because of the -command line nature of nmh, it makes the most sense to treat attachments as -separate messages. In other words one should be able to read the next -attachment using next, and the previous one using prev. One should be able -to show and scan attachments. This would probably involve a major change -in the message numbering scheme to allow something like 123.4 to indicate -attachment 4 on message 123. - - Jon Steinhart diff --git a/docs/README-HOOKS b/docs/README-HOOKS deleted file mode 100644 index 83b6bf7..0000000 --- a/docs/README-HOOKS +++ /dev/null @@ -1,111 +0,0 @@ -Jon Steinhart's (jon@fourwinds.com) External Program Hooks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This blurb describes a changes to nmh that implement an interface -to external programs. This interface is different than the limited -interface provided by things like the rmmproc context entry. - - -Why Did I Do This? -~~~~~~~~~~~~~~~~~~ - -I'm working on a project (grokmail) that will get released via GPL sometime -soon. This project keeps a database synchronized with the messages in the -mail system. New functionality is built on top of this database. This -functionality allows fast searching, and searching based on interest -criteria. The latter can be used for spam filtering. - -The changes to nmh allow external programs to be run whenever a message is -added to a folder, removed from a folder, or refiled. The changes are -implemented in a general way so that it can be used for other purposes than -mine. - -What Are The Changes? -~~~~~~~~~~~~~~~~~~~~~ - -The changes add four new profile components: - -add-hook: This is the full pathname of a program that is invoked - whenever a message is added to a folder. The program - is passed one argument which is the full pathname of the - message file. The program is executed after the message - is written so that it can act upon that message. - -del-hook: This is the full pathname of a program that is invoked - whenever a message is deleted from a folder. The program - is passed one argument which is the full pathname of the - message file. The program is executed before the message - is written so that it can act upon that message. - -ref-hook: This is the full pathname of a program that is invoked - whenever a message is refiled. The program is passed two - arguments: the first is the full pathname of the original - message file, the second is the full pathname of the final - message file. The program is executed after the message - is written. - -msg-hook: This is a text message that is output if the execution of - one of the external hook programs fails. There is a built-in - default message if none is specified. - -The definition of refiling is a bit tricky. The refile hook is executed if a -message is moved from one place to another. So, for example, the command - - refile -link - -causes the add hook to be executed, not the refile hook, because a new message -is created, the old one isn't moved. - -These changes affect the following commands: - -burst: The add hook is executed for messages burst from a digest, and - for the table of contents if -inplace is specified. The delete - hook is executed for the original message if -inplace is - specified. The refile hook is executed for messages that are - moved. - -folder: The refile hook is executed for -pack. - -inc: The add hook is executed when messages are incorporated. - -refile: Either the add or refile hooks are executed. - -rmf: The delete hook is executed when messages are deleted. - -rmm: The delete hook is executed when messages are deleted. - -sortm: The refile hook is executed for each message moved. Note that - a magic temporary message number of 2147483647 is used to hold - messages as they are being shuffled. - -rcvstore: The add hook is executed when messages are stored. - -mhstore: The add hook is executed when messages are stored. - -Did I Do This Correctly? -~~~~~~~~~~~~~~~~~~~~~~~~ - -Well, sort of. This all works, but I'm not really happy with it. The issue -is that an examination of the nmh code shows that message handling is scattered -all over the place. Although there are library routines such as folder_addmsg -and folder_delmsgs, they are not used consistently. Long term, I think that it -would be better to make all message handling go through the same choke points. - -Also, I added a function to run the external programs. This sort of stuff is -also scattered around the nmh code, for example in the code to run the rmmproc. -Again, I'd like to make this more consistent in the long term. - -What Files Did I Change? -~~~~~~~~~~~~~~~~~~~~~~~~ -uip/ - burst.c - inc.c - refile.c - rmf.c - sortm.c - -sbr/ - folder_addmsg.c - folder_delmsgs.c - folder_pack.c - ext_hook.c (new file) diff --git a/docs/README.SASL b/docs/README.SASL index 24a85ab..c06568b 100644 --- a/docs/README.SASL +++ b/docs/README.SASL @@ -6,10 +6,10 @@ SASL is short for the Simple Authentication and Security Layer. Is is a framework for adding authentication and encryption to network protocols. It is described in IETF RFC 2222. -This release of nmh supports SASL for POP and SMTP. The SASL support -is implemented using the Cyrus-SASL library. This library can be found -at ftp://ftp.andrew.cmu.edu/pub/cyrus-mail. Obviously, SASL support only -works if you use --enable-pop and the SMTP mail transport. +This release of nmh supports SASL for SMTP. The SASL support is +implemented using the Cyrus-SASL library. This library can be found at +ftp://ftp.andrew.cmu.edu/pub/cyrus-mail. Obviously, SASL support only +works if you use the SMTP mail transport. This release of NMH only supports "Version 2" of the Cyrus SASL library. It should work with any newer Cyrus SASL release, but it was tested with @@ -19,18 +19,17 @@ could manifest when negotiating encrypting depending on the encryption type you used, so a newer version of Cyrus-SASL is recommended. Currently, security layers ("encryption" in SASL-speak) are supported -for both POP and SMTP. This means that if your POP or SMTP server -_and_ the selected SASL mechanism supports it, client-server -communications will be encrypted. In theory this should work with -any SASL mechanism that supports security layers; it has only been -tested with the GSSAPI mechanism. +for SMTP. This means that if your SMTP server _and_ the selected SASL +mechanism supports it, client-server communications will be encrypted. +In theory this should work with any SASL mechanism that supports security +layers; it has only been tested with the GSSAPI mechanism. If you are curious as to whether or not your communications are actually -encrypted or not, you can use the -snoop flag to the POP or SMTP utilities. +encrypted or not, you can use the -snoop flag to the SMTP utilities. Communication that is encrypted is preceeded by an (encrypted) or (decrypted), depending on the direction of communication. If you would like to use the GSSAPI SASL mechanism (Kerberos V), you -should read very carefully the documentation that comes with -Cyrus-SASL, specifically the GSSAPI documentation. Getting the GSSAPI -plugin to work correctly with SASL can be "interesting" to say the least. +should read very carefully the documentation that comes with Cyrus-SASL, +specifically the GSSAPI documentation. Getting the GSSAPI plugin to +work correctly with SASL can be "interesting" to say the least. diff --git a/docs/README.about b/docs/README.about index eba3004..41f4482 100644 --- a/docs/README.about +++ b/docs/README.about @@ -11,9 +11,9 @@ a (mostly) compatible drop-in replacement for MH. If you have previously used MH, check the file DIFFERENCES for a list of the differences between nmh and MH (not up-to-date as of this writing). -Although development of nmh is ongoing, it is generally stable and -is in current use. But it is possible that we may break things as -changes are made. +Although development of nmh is ongoing, it is generally stable and +is in current use. But it is possible that we may break things as +changes are made. -------------------------------- ftp and web sites, mailing lists diff --git a/docs/README.attachments b/docs/README.attachments new file mode 100644 index 0000000..ff9db2a --- /dev/null +++ b/docs/README.attachments @@ -0,0 +1,281 @@ +Jon Steinhart's (jon@fourwinds.com) Attachment Handling Mods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A bunch of changes have been made to improve the nmh user interface for +handling MIME attachments. + +Why Did I Do This? +~~~~~~~~~~~~~~~~~~ + +Although nmh contains the necessary functionality for MIME message handing, +the interface to this functionality is pretty obtuse. There's no way that +I'm ever going to convince my partner to write mhbuild composition files! +And even though I know how to write them, I often screw up when sending a +message that contains a shell script because I forget that I have to double +any # at the start of a line, which shell scripts have galore. + +These changes simplify the task of managing attachments on draft files. +They allow attachments to be added, listed, and deleted. MIME messages are +automatically created when drafts with attachments are sent. + +The Simple Setup +~~~~~~~~~~~~~~~~ + +The gory details are all given below. Here's how to set things up simply. This +only works if you're using the "standard" interface, i.e., whatnow. Life is more +complicated if you run mh-e. + +Add the following to your .mh_profile: + + send: -attach X-MH-Attachment + whatnow: -attach X-MH-Attachment + +You may already have send and whatnow lines in your .mh_profile; if you do, just add +the new stuff to the end of the line. For example, mine looks like: + + send: -alias aliases -attach X-MH-Attachment + whatnow: -attach X-MH-Attachment + +That's it. Next time you want to send an attachment, say "attach filename" at the +whatnow prompt and you're done. You can check your attachments by saying "alist". + +Did I Do This Correctly? +~~~~~~~~~~~~~~~~~~~~~~~~ + +Hard to say. Despite lots of time looking at the nmh code, I can't say that +I get the philosophy behind its structure. + +I am aware of two deviations from what I saw in the nmh code. + + 1. I commented my changes. + + 2. It's been years since I've used a VT-100, so I don't try to make code + fit into 80 columns anymore. Seems silly to me. + +What Did I Do? +~~~~~~~~~~~~~~ + +I made changes to the following files: + + h/ + prototypes.h + man/ + anno.man + send.man + whatnow.man + uip/ + Makefile.in + anno.c + annosbr.c + send.c + sendsbr.c + viamail.c (needed change for new sendsbr argument) + whatnowsbr.c + +Attachments are associated with messages using header fields. For example, a +draft that looks like this + + To: jon + Subject: test of attachments + X-MH-Attachment: /export/home/jon/foo + X-MH-Attachment: /export/home/jon/bar + X-MH-Attachment: /export/home/jon/test/foo + -------- + +has the files "foo", "bar", and foo as attachments. + +Although I use the header field name "X-MH-Attachment" to indicate +attachments, the implementation allows any header field name. + +The advantage of using header fields is that the list of attachments +travels with the draft so it remains valid across editing sessions. + +Note that the header fields for attachments are removed from the message +before it is sent. + +Since I was adding header fields to messages, it seemed sensible to use the +existing anno program to do this for me. This required several changes to +generalize anno: + + o I added a -draft option that permits annotations (header fields) to + be added to the draft instead of a message sequence. + + o I added a -delete option that allows annotations to be deleted. + + o I added a -list option that allows annotations to be listed. + + o I added a -number option that modifies the behavior of -delete and -list. + + o I added a -append option so that annotations are appended to the headers + instead of the default prepend. Without this, attachments come out in + reverse order. + +Using the modified anno, the example above could be created (assuming that the +draft exists) by + + prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/foo -nodate -append + prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/bar -nodate -append + prompt% anno -draft -comp X-MH-Attachment -text /export/home/jon/test/foo -nodate -append + +One can quite easily make an "attach" command using shell scripts, aliases or functions. +For example, here's a bash function that does the job: + + function attach() { for i in $*; do anno -append -nodate -draft -comp X-MH-Attachment -text "$i"; done; } + +The following examples show the different ways in which attachments can be +listed. + + prompt% anno -list -draft -comp X-MH-Attachment + foo + bar + foo + + prompt% anno -list -draft -comp X-MH-Attachment -text / + /export/home/jon/foo + /export/home/jon/bar + /export/home/jon/test/foo + + prompt% anno -list -draft -comp X-MH-Attachment -number + 1 foo + 2 bar + 3 foo + + prompt% anno -list -draft -comp X-MH-Attachment -text / -number + 1 /export/home/jon/foo + 2 /export/home/jon/bar + 3 /export/home/jon/test/foo + + prompt% + +Why all these listing options? + +I feel that the listing as produced by the first example is what most people +would want most of the time. + +The listing as produced by the second example seemed necessary for situations +where there were several attachments with the same file name in different +directories. + +I included the numbering option so that attachments could be deleted by number +which might be easier in situations where there were several attachments with +the same file name in different directories, as in the above example. + +Attachments are deleted using the -delete option. + + prompt% anno -delete -draft -comp X-MH-Attachment -text foo + +deletes the first attachment since the foo matches the basename of the attachment +name. + + prompt% anno -delete -draft -comp X-MH-Attachment -text /export/home/jon/test/foo + +deletes the third attachment since the text is a full path name and matches. + + prompt% anno -delete -draft -comp X-MH-Attachment -number 2 + +deletes the second attachment. + +The attachment annotations are converted to a MIME message by send. I'm not +completely sure that this is the right place to do it, as opposed to doing +it in post, but both would work. It seemed to me to make more sense to do +it in send so that all of the various post options would apply to the MIME +message instead of the original draft file. + +I added an -attach option to send that specifies the header field name used +for attachments. Send performs the following additional steps if this option +is set: + + o It scans the header of the draft for attachments. Normal behavior applies + if none exist. + + o A temporary mhbuild composition file is created if there are attachments. + + o All non-attachment headers are copied from the draft file to the + composition file. + + o The body of the draft is copied to a temporary body file if it contains at + least one non-whitespace character. A mhbuild directive for this file is + appended to the composition file. Note that this eliminates the problem + of lines beginning with the # character in the message body. + + o A mhbuild directive is appended to the composition file for each attachment + header. + + o mhbuild is run on the composition file, converting it to a MIME message. + + o The converted composition file is substituted for the original draft file + and run through the rest of send. + + o The original draft file is renamed instead of the converted composition + file. This preserves the original message instead of the composition file + which is really what a user would want. + + o The ,file.orig file created by mhbuild is removed as it's a nuisance. + +The mhbuild directives appended to the composition file are constructed as +follows: + + o The content-type a file with a dot-suffix is obtained from the list of + mhshow-suffix- entries in the profile. + + o A file with no dot-suffix or no entry in the profile is assigned a + content-type of application/octet-stream if it contains any non-ASCII + characters. + + o A file with no dot-suffix or no entry in the profile is assigned a + content-type of text/plain if it contains only ASCII characters. + + o The directive is of the form: + + #content-type; name="basename"; x-unix-mode=mode [ description ] filename + + The content type is derived as discussed above. The basename is the + last component of the pathname given in the body of the attachment header + field. The mode is file permissions. The description is obtained by + running the file command on the attachment file. The filename is the + field body from the attachment header field. + +I added an -attach option to whatnow that specifies the header field name for +attachments. + +I added to the commands available at the whatnow prompt to provide an interface +to the attachment mechanism. + +I'm not completely happy with some of these additions because they duplicate +shell functionality. I'm not sure that there's a good way around it other than +to not use whatnow. + +The first three additions (the ones I'm not happy with) are cd, ls, and pwd. +These do the same thing as their system counterparts. As a matter of fact, +these are implemented by running the commands in a subshell. I did this because +I wanted proper interpretation of shell-specific things like ~ and wildcard +expansion. + +The next command is attach. This takes a list of files and adds them to the draft +as attachments using the same code as the modified anno. The list of files is +run through ls using the user's shell, so wildcard expansion and all that works. + +The alist command lists the attachments on the current draft using listing function +that I added to anno. It takes two optional options, -l for a long listing meaning +full path names, and -n for a numbered listing. + +The detach command removes attachments from the current draft, again using the +modified anno. The arguments are interpreted as numbers if the -n option is used, +otherwise they're interpreted as file names. File names are shoveled through ls +using the user's shell in the directory containing the file for wildcard expansion +and such. File names are matched against the last pathname component unless they +begin with a / in which case they're matched against the entire name. + +What's Left To Do? +~~~~~~~~~~~~~~~~~~ + +Nothing on this stuff. When I get time I'd like to improve the interface +for reading messages with attachments. It's my opinion that, because of the +command line nature of nmh, it makes the most sense to treat attachments as +separate messages. In other words one should be able to read the next +attachment using next, and the previous one using prev. One should be able +to show and scan attachments. This would probably involve a major change +in the message numbering scheme to allow something like 123.4 to indicate +attachment 4 on message 123. + + Jon Steinhart diff --git a/docs/README.developers b/docs/README.developers index f026c74..935d0d1 100644 --- a/docs/README.developers +++ b/docs/README.developers @@ -16,10 +16,10 @@ autoconf files If you wish to change the `configure' script or its related files, you'll need to first install GNU m4, available from and then GNU autoconf (). Nmh is currently using -a minimum of autoconf 2.54. +a minimum of autoconf 2.61. Most of the configure-related files are automatically generated. The only files -you should need to manually edit are acconfig.h and configure.in. Don't, for +you should need to manually edit are acconfig.h and configure.ac. Don't, for instance, edit config.h.in. Though it is an input file from the point of view of the users (and the configure script) it is an output file from the point of view of the developers (and the autoconf script). @@ -38,7 +38,7 @@ directory structure Following is a list of nmh's directories along with a brief description of the purpose of each one. Meanings are given for the abbreviations, but note that these meanings are just informed guesses as to what the MH developers were -thinking. +thinking. ./ The top-level directory. Contains files like README and INSTALL. @@ -47,7 +47,7 @@ config/ Contains utility files for the `configure' process. Ordinarily nothing in here needs to be messed with. -doc/ +docs/ Contains more specialized documentation, such as this file and the FAQ. @@ -63,27 +63,11 @@ man/ Contains all the input files that are processed to generate nmh's manual pages. -mts/ - "mts" stands for "Message Transfer Service". Source files specific to the - different MTSs go in the subdirectories. - -mts/mmdf/ (deprecated) - "mmdf" stands for "Multichannel Memorandum Distribution Facility". It is an - alternative to sendmail used primarily on SCO UNIX. - -mts/sendmail/ (deprecated: handled by mts.conf) - When nmh is configured --with-mts=sendmail, the files in this directory are - used. - -mts/smtp/ - When nmh is configured to just talk to an SMTP server over TCP/IP, the - source in this directory is compiled. - sbr/ "sbr" stands for "subroutine(s)". For the most part, each source file in this directory contains a single function with the same name as the source file. These functions are of general use and are called from throughout - nmh. + nmh. uip/ "uip" stands for "User Interface Programs". Most nmh commands have a file @@ -92,32 +76,6 @@ uip/ sbr.c which contains additional subroutines called from .c (which would contain not much else besides main()). -zotnet/ (deprecated) - Files in this hierarchy were either written by or moved here by UCI - (University of California, Irvine) after they took over MH from the Rand - Corporation. "Zot!" is the sound effect made by the anteater in the "B.C." - comic strip when its tongue lashes out at ants. The anteater is UCI's - official mascot. Not sure whether UCInet was once called ZotNet... - -zotnet/bboards/ (deprecated) - UCI added Bulletin Board functionality to MH with the `bbc' command. This - functionality has been removed from nmh but apparently files in this - directory are still needed for other purposes. - -zotnet/mf/ (deprecated, now in sbr/) - "mf" stands for "Mail Filter". The filtering in this case apparently refers - to translation between different address and mailbox formats. - -zotnet/mts/ (deprecated, now in sbr/) - MTS code not specific to any single MTS apparently goes here. - -zotnet/tws/ (deprecated, now in sbr/) - "tws" apparently stands for "time with structure", a rather odd phrase. - This directory used to be the place for date and time manipulation code, but - currently nothing in here is compiled. There are new, more portable - versions of the key files in h/ and sbr/, and this directory will soon go - away completely. - --- git @@ -130,6 +88,11 @@ the nmh repository: % git clone git://git.savannah.nongnu.org/nmh.git +That will create a workspace called nmh. To update that workspace +with changes to the master, cd to it and run: + + % git pull + ------------------------------------------------------- nmh-local functions to use in preference to OS versions @@ -139,7 +102,7 @@ For some system functions whose availability or behavior varies from OS to OS, nmh conditionally uses a local definition with the same name as the OS function (e.g. snprintf()). For other functions, developers need to avoid the OS versions and always use the nmh-supplied function. Here is a list of such -functions: +functions: OS function nmh-local version to use instead =========== ================================ @@ -150,28 +113,26 @@ getpass() nmh_getpass() releasing nmh ------------- -To make a public release of nmh (we'll use version 1.0.4 and my mhost.com -account, danh, as examples here; the convention for release candidates -is to use something like "1.0.4-RC1"): +To make a public release of nmh (we'll use version 1.0.4 as examples +here; the convention for release candidates is to use something like +"1.0.4-RC1"): 1. % echo 1.0.4 > VERSION % date +"%e %B %Y" > DATE (DATE should contain something like "30 December 2000") - 2. Put a comment like "Released nmh-1.0.4." in the ChangeLog. - - 3. % cvs commit ChangeLog VERSION DATE + 2. % git commit VERSION DATE; git push - 4. % cvs tag nmh-1_0_4 - (cvs treats dots specially, so underscores are substituted here.) + 3. % git tag -a nmh-1_0_4 -m 'Releasing nmh-1_0_4.' - 5. % make nmhdist + 4. % make nmhdist - 6. Untar nmh-1.0.4.tar.gz and `diff -r' it vs. your CVS tree. Make sure no - files got left out of the distribution that should be in it (due to someone - forgetting to update the DIST variables in the Makefiles). + 5. Untar nmh-1.0.4.tar.gz and `diff -r' it vs. your workspace. Make + sure no files got left out of the distribution that should be in it + (due to someone forgetting to update the DIST variables in the + Makefiles). - 7. If you have root access on your machine, it's good at this point to do: + 6. If you have root access on your machine, it's good at this point to do: % chown -R 0:0 nmh-1.0.4 % tar cvf nmh-1.0.4.tar nmh-1.0.4 @@ -182,26 +143,23 @@ is to use something like "1.0.4-RC1"): making it possible for that user to Trojan the nmh code before the system administrator finishes installing it. - 8. Make sure your new tarball uncompresses and untars with no problem. Make + 7. Make sure your new tarball uncompresses and untars with no problem. Make sure you can configure, make, and install nmh from it. - 9. If all is well and your tarball is final, go back to your CVS tree and do: + 8. If all is well and your tarball is final, go back to your workspace and do: % echo 1.0.4+dev > VERSION -10. Put a comment like "Upped the version number to 1.0.4+dev until the next nmh - release." in the ChangeLog. - -11. % cvs commit ChangeLog VERSION + 9. % git commit VERSION; git push -12. If possible, make an MD5 hash and/or a PGP signature of nmh-1.0.4.tar.gz. +10. If possible, make an MD5 hash and/or a PGP signature of nmh-1.0.4.tar.gz. Assuming you have gpg set up, this should be: % gpg --output nmh-1.0.4.tar.gz.sig --detach-sig nmh-1.0.4.tar.gz You can verify the signature with % gpg --verify nmh-1.0.4.tar.gz.sig nmh-1.0.4.tar.gz -13. Upload the files to savannah. First make sure they are mode 664 so +11. Upload the files to savannah. First make sure they are mode 664 so they will have the right permissions on the server end (see https://savannah.gnu.org/maintenance/SharedDownloadArea) % chmod 664 nmh-1.0.4.tar.gz* @@ -209,13 +167,13 @@ is to use something like "1.0.4-RC1"): Then scp them across: % scp -p nmh-1.0.4.tar.gz* youruser@dl.sv.nongnu.org:/releases/nmh/ -14. Update the http://www.nongnu.org/nmh/ homepage. (It lives in the 'webpages - repository'; see https://savannah.nongnu.org/cvs/?group=nmh) +12. Update the http://www.nongnu.org/nmh/ homepage. (It lives in the CVS + 'webpages repository'; see https://savannah.nongnu.org/cvs/?group=nmh) -15. Add a news item to the savannah nmh page. You'll have to submit it first +13. Add a news item to the savannah nmh page. You'll have to submit it first and then separately approve it (under News->Manage). -16. Send the release announcement email to the following places: +14. Send the release announcement email to the following places: nmh-workers@nongnu.org nmh-announce@nongnu.org exmh-users@redhat.com @@ -232,9 +190,10 @@ is to use something like "1.0.4-RC1"): Preferably, the announcement should contain the MD5 hash generated above, and should be PGP-signed. It should include the URL for the tarball as well as the URL of the website. It should contain a brief summary of - visible changes, as well as the URL of the cvsweb diff page that would show - a detailed list of changes. The changes between 1.2 and 1.3 would be - shown by: + visible changes, as well as the URL of the git diff page that would show + a detailed list of changes. The changes between 1.5 and 1.4 would be + shown by [this is just a guess, I don't know anything about cgit, and + it assumes that we tag with nmh-x_x-release from now on]: - http://cvs.savannah.gnu.org/viewvc/nmh/ChangeLog?root=nmh&r1=1.215&r2=1.254.2.13 + http://git.savannah.gnu.org/cgit/nmh.git/diff/?h=nmh-1_5-release?h=nmh-1_4-release diff --git a/docs/README.hooks b/docs/README.hooks new file mode 100644 index 0000000..714ba00 --- /dev/null +++ b/docs/README.hooks @@ -0,0 +1,111 @@ +Jon Steinhart's (jon@fourwinds.com) External Program Hooks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This blurb describes a changes to nmh that implement an interface +to external programs. This interface is different than the limited +interface provided by things like the rmmproc context entry. + + +Why Did I Do This? +~~~~~~~~~~~~~~~~~~ + +I'm working on a project (grokmail) that will get released via GPL sometime +soon. This project keeps a database synchronized with the messages in the +mail system. New functionality is built on top of this database. This +functionality allows fast searching, and searching based on interest +criteria. The latter can be used for spam filtering. + +The changes to nmh allow external programs to be run whenever a message is +added to a folder, removed from a folder, or refiled. The changes are +implemented in a general way so that it can be used for other purposes than +mine. + +What Are The Changes? +~~~~~~~~~~~~~~~~~~~~~ + +The changes add four new profile components: + +add-hook: This is the full pathname of a program that is invoked + whenever a message is added to a folder. The program + is passed one argument which is the full pathname of the + message file. The program is executed after the message + is written so that it can act upon that message. + +del-hook: This is the full pathname of a program that is invoked + whenever a message is deleted from a folder. The program + is passed one argument which is the full pathname of the + message file. The program is executed before the message + is written so that it can act upon that message. + +ref-hook: This is the full pathname of a program that is invoked + whenever a message is refiled. The program is passed two + arguments: the first is the full pathname of the original + message file, the second is the full pathname of the final + message file. The program is executed after the message + is written. + +msg-hook: This is a text message that is output if the execution of + one of the external hook programs fails. There is a built-in + default message if none is specified. + +The definition of refiling is a bit tricky. The refile hook is executed if a +message is moved from one place to another. So, for example, the command + + refile -link + +causes the add hook to be executed, not the refile hook, because a new message +is created, the old one isn't moved. + +These changes affect the following commands: + +burst: The add hook is executed for messages burst from a digest, and + for the table of contents if -inplace is specified. The delete + hook is executed for the original message if -inplace is + specified. The refile hook is executed for messages that are + moved. + +folder: The refile hook is executed for -pack. + +inc: The add hook is executed when messages are incorporated. + +refile: Either the add or refile hooks are executed. + +rmf: The delete hook is executed when messages are deleted. + +rmm: The delete hook is executed when messages are deleted. + +sortm: The refile hook is executed for each message moved. Note that + a magic temporary message number of 2147483647 is used to hold + messages as they are being shuffled. + +rcvstore: The add hook is executed when messages are stored. + +mhstore: The add hook is executed when messages are stored. + +Did I Do This Correctly? +~~~~~~~~~~~~~~~~~~~~~~~~ + +Well, sort of. This all works, but I'm not really happy with it. The issue +is that an examination of the nmh code shows that message handling is scattered +all over the place. Although there are library routines such as folder_addmsg +and folder_delmsgs, they are not used consistently. Long term, I think that it +would be better to make all message handling go through the same choke points. + +Also, I added a function to run the external programs. This sort of stuff is +also scattered around the nmh code, for example in the code to run the rmmproc. +Again, I'd like to make this more consistent in the long term. + +What Files Did I Change? +~~~~~~~~~~~~~~~~~~~~~~~~ +uip/ + burst.c + inc.c + refile.c + rmf.c + sortm.c + +sbr/ + folder_addmsg.c + folder_delmsgs.c + folder_pack.c + ext_hook.c (new file) diff --git a/docs/README.mail-filtering b/docs/README.mail-filtering new file mode 100644 index 0000000..b0b5e8d --- /dev/null +++ b/docs/README.mail-filtering @@ -0,0 +1,107 @@ + +INTRODUCTION +------------ +It is a common practice when using nmh to filter your inbound mail +directly into nmh folders. There are several programs which allow you +to do this, of which two common ones are procmail and slocal. + +SLOCAL +------ +The slocal command is part of the nmh distribution. It is a fairly +simple mail filtering program. Check the slocal man page for an example +filtering file (called .maildelivery). + +PROCMAIL +-------- +Probably the most popular mail filtering command is procmail. It can +filter mail into standard mbox-style spool files, as well as into MH/nmh +style folders. + +Although procmail knows how to put a message directly into an nmh folder, +this is not recommended. Procmail doesn't know about nmh sequences. +Instead you should have procmail use the nmh command `rcvstore' to put +the message into the folder. The `rcvstore' command will (by default) +add each new message to the "unseen" sequence, so you can detect new +messages in folders with the `flist' command. + +Also, nmh commands generally like to keep mail messages in RFC-822 +format. But by default, procmail will leave the first line of the +message unchanged. This line (which usually begins with "From ") is +not in the standard RFC-822 format. It is recommended that you use the +command `formail' (which comes in the procmail distribution) to rewrite +this line so that it begins with the header name "X-Envelope-From:". +An example of how to do this is given below. + +The reason the header name "X-Envelope-From:" is recommended, is that the +nmh command `packf' (as of version 0.23) will check for this header when +packing folders. The `packf' command knows how to undo the rewriting +of the "From " line to the "X-Envelope-From:" line. By checking for +this header name, `packf' is able to pack the folder into exactly the +form that is used if procmail delivers to the standard mail spool. + +If you do not rewrite the "From " line into this format, the `packf' +command will still work. But it may create fake "From " lines which +are not the same as the originals. + +Alternatively, you might be able to suppress generation of the "From " +line. If your procmail invocation includes the -f or -r option, +remove. Those options add a "From " line to incoming beginning of +messages that do not have them. + +Here is a typical .procmailrc file for using procmail in conjunction +with nmh. For more information, see the manual pages for procmail, +procmailrc and procmailex. + +################################################################### +# .procmailrc +################################################################### +# To use procmail, put the next line in your .forward file: +# "|IFS=' ' && exec /usr/local/bin/procmail -f- || exit 75 #XXX" +# Do not remove the double quotes. Change XXX to your username. +# Edit path to procmail above, and the VARIABLES below, as needed. +# Adapt the MAILING LIST section below for lists you subscribe to. +# Your .forward needs to be world-readable, but not world-writable. +################################################################### +# This .procmailrc is written for use with nmh/mh/exmh/mh-e +################################################################### + +### VARIABLES ### +VERBOSE=off +SHELL=/bin/sh +PATH=/usr/local/nmh/lib:/usr/local/nmh/bin:/usr/bin:/usr/local/bin +MAILDIR=$HOME/Mail +LOGFILE=$MAILDIR/procmail.log +LOCKEXT=.lock + +################# +# CLEANUP MESSAGE +################# + +# Force the "From user date" to become part of header +:0 Whf +| formail -z -R 'From ' X-Envelope-From: + +############### +# MAILING LISTS +############### + +:0 w: nmh-workers/$LOCKEXT +* ^Resent-from: *nmh-workers +| rcvstore +nmh-workers + +# catches exmh-{announce,users,workers} +:0 w: exmh/$LOCKEXT +* ^TOexmh +| rcvstore +exmh + +# Catch junk. Don't add it to "unseen" sequence (nmh only) +:0 w: junk/$LOCKEXT +* ^(reply-to|from|sender):.*(spammer|flamer|evil-host) +| rcvstore -nounseen +junk + +################ +# DEFAULT ACTION +################ +:0 w: inbox/$LOCKEXT +| rcvstore +inbox + diff --git a/docs/README.manpages b/docs/README.manpages index c4dc67b..0d435ef 100644 --- a/docs/README.manpages +++ b/docs/README.manpages @@ -10,13 +10,13 @@ nmh manpages should be in this general form: comp \- compose a message .SH SYNOPSIS .HP 5 -.B comp +.B comp .RI [ +folder ] .RI [ msgs ] .RB [ \-form .IR formfile ] .RB [ \-use " | " \-nouse ] -.RB [ \-version ] +.RB [ \-Version ] .RB [ \-help ] .SH DESCRIPTION .B Comp @@ -69,8 +69,8 @@ Source files .PP Of course, replace "components" with a unique identifier that - reflects the content being included, like "mts_conf" for - etc/mts.conf. Then, add two lines to the man.sed target in + reflects the content being included, like "mhl_reply" for + etc/mhl.reply. Then, add two lines to the man.sed target in Makefile.in like: echo '/%components%/r $(top_srcdir)/etc/components' >> $@ @@ -105,7 +105,7 @@ SYNPOSIS section .RI [ +folder ] <---- parameter .RI [ msgs ] <---- parameter - .RB [ \-version ] <---- flag + .RB [ \-Version ] <---- flag .RB [ \-editor <---- flag with .IR editor ] parameter .RB [ \-use " | " \-nouse ] <---- exclusive parameters @@ -156,14 +156,14 @@ Other italicized text Italicize file names, profile entries, and folder names: If a file named - .RI \*(lq components \*(rq + .RI ` components ' exists in the user's nmh directory, If the user's profile contains a - .RI \*(lq "Msg\-Protect: nnn" \*(rq + .RI ` "Msg\-Protect: nnn" ' entry, it - The \*(lq+\*(rq after + The `+' after .I inbox indicates that it is the current folder. diff --git a/docs/README.mhsign-mhpgp b/docs/README.mhsign-mhpgp new file mode 100644 index 0000000..61269c6 --- /dev/null +++ b/docs/README.mhsign-mhpgp @@ -0,0 +1,145 @@ +mhpgp, mhsign +------------- + +This software (shell scripts) written by Neil Rickert. + +It is placed in the public domain. You are free to use it and modify +it to suit your needs. + + +The scripts are adjusted to mmh by markus schnalke . +They work a bit different today. The following excrept of the README +and CHANGES files of the Neil's distribution is preserved for +documentation. + + +These are scripts for using with MH or nmh. + +The two scripts are tuned for the use of gnupg. It is not too hard +to adapt to pgp2, pgp5 or pgp6.5. But why bother, since gnupg has +clearly become the way to go for unix. + +Use: + + mhpgp ## to verify signature or decrypt current message. + + edit mhsign [-e] ## to sign [encrypt] at the whatnow prompt. + +See the man page for mhsign on creating a file "pgpkeys" in your MH +directory or GNUPGHOME directory. + + +Change log for mhsign: + +RCS file: RCS/mhsign,v +Working file: mhsign +head: 1.1 +branch: 1.1.0 +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 10; selected revisions: 10 +description: +Program to sign [encrypt] a message from whatnow prompt. +---------------------------- +revision 1.1 +date: 2003/06/14 18:38:14; author: rickert; state: Exp; +branches: 1.1.0; +Initial revision +---------------------------- +revision 1.1.0.9 +date: 2007/05/30 14:48:40; author: rickert; state: Exp; lines: +14 -9 +Make sure that an MD5 hash is used with "-R" when signing. +---------------------------- +revision 1.1.0.8 +date: 2007/01/21 04:18:04; author: rickert; state: Exp; lines: +2 -2 +Fix unmatched quote +---------------------------- +revision 1.1.0.7 +date: 2004/06/13 20:14:52; author: rickert; state: Exp; lines: +3 -3 +Make sure that gnupg-1.3.6 uses the correct digest in pgp2 compatibility mode +---------------------------- +revision 1.1.0.6 +date: 2004/05/23 00:49:43; author: rickert; state: Exp; lines: +6 -6 +Use "--always-trust", and ignore any "encrypt-to" in options file +---------------------------- +revision 1.1.0.5 +date: 2004/02/25 04:03:44; author: rickert; state: Exp; lines: +12 -7 +When using -b with mime signature, turn off textmode and include the +trailing blanks in the signed data. There is no point in using -b +unless the trailing blanks are significant, in which case they should +be protected by the signature. +---------------------------- +revision 1.1.0.4 +date: 2003/09/13 19:56:53; author: rickert; state: Exp; lines: +10 -6 +Skip comment lines in '.pgpkeys'. +Allow preferred keys to come from environment +Use case insensitive search (grep -i) for .pgpkeys lookup of + addresses. +---------------------------- +revision 1.1.0.3 +date: 2003/07/19 14:30:32; author: rickert; state: Exp; lines: +20 -3 +Put personal keys in ".pgpkeys" database, so that script does not +need to be personalized. +---------------------------- +revision 1.1.0.2 +date: 2003/07/18 23:26:41; author: rickert; state: Exp; lines: +17 -13 +Force pgp/mime format if the message is already multipart mime. +---------------------------- +revision 1.1.0.1 +date: 2003/06/22 00:48:09; author: rickert; state: Exp; lines: +8 -2 +Check in $GNUPGHOME for .pgpkeys . This allows a per-keyring list +============================================================================= + +Change log for mhpgp: + +RCS file: RCS/mhpgp,v +Working file: mhpgp +head: 1.1 +branch: 1.1.0 +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 8; selected revisions: 8 +description: +Script for pgp verify/decrypt of mh messages (uses gnupg) +---------------------------- +revision 1.1 +date: 2003/07/19 16:50:32; author: rickert; state: Exp; +branches: 1.1.0; +Initial revision +---------------------------- +revision 1.1.0.7 +date: 2005/11/29 06:25:05; author: rickert; state: Exp; lines: +3 -1 +If a message does not end in "\n" after decryption, then add "\n". +---------------------------- +revision 1.1.0.6 +date: 2005/07/13 01:00:10; author: rickert; state: Exp; lines: +2 -2 +Fix mishandling of boundary=string; +---------------------------- +revision 1.1.0.5 +date: 2004/09/05 14:49:59; author: rickert; state: Exp; lines: +2 -2 +Fix line endings when building a decrypted message (-w flag), the +encrypted text might use CRLF. +---------------------------- +revision 1.1.0.4 +date: 2004/02/22 17:14:02; author: rickert; state: Exp; lines: +27 -10 +Add "-b" option to strip blanks on pgpmime signature +Use "getopts" for checking options. +---------------------------- +revision 1.1.0.3 +date: 2003/09/09 04:29:11; author: rickert; state: Exp; lines: +3 -2 +Don't use exec, as that skips the trap and temp files are not deleted +---------------------------- +revision 1.1.0.2 +date: 2003/07/26 00:06:40; author: rickert; state: Exp; lines: +33 -11 +Drop "-o outfile". Add "-w" to write back as a message to current folder. +This allows easier examination of mime components that might be in +the encrypted portion. +---------------------------- +revision 1.1.0.1 +date: 2003/07/19 16:57:16; author: rickert; state: Exp; lines: +4 -7 +Clean up script, for more general usefulness +============================================================================= diff --git a/docs/README.start-devel b/docs/README.start-devel new file mode 100644 index 0000000..192c3ff --- /dev/null +++ b/docs/README.start-devel @@ -0,0 +1,122 @@ +How to start developing nmh +=========================== + +markus schnalke +2010-12 + + +I started using nmh in Fall 2009. Soon afterwards, I used it exclusivly. +In Spring 2010, I subscribed to the nmh-workers mailing list. From +October until December 2010, I worked for two month full-time on nmh as +a private project. + +First of all, I needed to become familiar with the code. This had been +the most difficult part. This document is based on my experience on +starting to hack nmh. It describes how I would do it a second time. +These are my recommendations. + + +Prerequisites +------------- + +You should be familiar with nmh. Use it! + +Adjust nmh to your needs. This is almost a requirement for using it +for modern emailing. It took me several month until I had a satisfying +setup. Lots of research and reading was necessary. + +Subscribe to the nmh-workers mailing list [0] and read it. + + +Reading documentation +--------------------- + +Read Jerry Peek's book ``MH & nmh: Email for Users & Programmers'' [1], +at least the history, concepts, and get an overview of the rest. This +book is a wonderful resource for everything about nmh. + +Cross-read the FAQs [2] although they are old. + +Read README and docs/README.developers. The rest below docs/ is +valuable too. You might want to read it now or later. + + +Reading code +------------ + +I split the task of code reading into five stages. + +(1) Get an overview: + +Understand the directory structure. Get a feeling for what kinds of +files are unter sbr/ and what under uip/. Scrolling through the files +is sufficient for that. These two directories will be most important. +See docs/README.developers for help. + +(2) Take a look at some simple tool: + +I recommend reading uip/rmm.c, which is a pretty straight-forward +tool. It shows the structure of the common tool code in nmh pretty +well. You don't need to fully understand it, but you should try to +find out how things work generally. The identifiers and comments in +the code will provide most of that information. + +(3) Read through the header files: + +Read h/mh.h, the central header file of the project. It contains a lot +of important information. Like above, you don't need to understand it +fully now. Later, jump back to this header file as needed in order to +incrementally understand it better and better. + +(4) Read code in uip/, starting with simple tools: + +Now you can continue reading tool code in uip/. Go from the simple +tools (e.g. mhparam, mhpath) to the more complex ones (e.g. send, +pick, spost). Defer everything with MIME involved (e.g. mhshow, +mhbuild) and the tools that use format or component files until the +end. As a rule of thumb: Simple tools are those with few lines of code +and no *sbr.c files. + +(5) Jump to sbr/ as needed: + +As you read through the code, you'll encounter several functions that +are not part of the C standard library but of similar style. Look for +these below sbr/. There most files are named like the single function +they contain. You can often guess from the filename what is inside. +Read their sources as you need them. I found it useful to write down +short explanations of functions whose names didn't express enough +information. + +Once you reached this point, I'm sure you'll find your further way +alone. + + +Code history +------------ + +Note that large parts of the code are very old and were written by a +whole bunch of different people. You will likely encounter code that +simply puzzles you. Check the ChangeLog and similar sources first. If +you still don't understand, ask on the mailing list. You'll see that +the folks there sometimes don't know either. A lot of knowledge was +lost in time. + + +The Community +------------- + +A short note for those who come from the modern Free Software world: +Don't expect nmh to be like modern Free Software projects. Nmh is old +and MH is much older. The community still carries old spirits; you +might not be used to them. Also, keep in mind that nmh is matured +back-end software, thus the view on change may be different than you +might expect. Nontheless, I encourage you to interact with the +community. You will learn a lot and you will recieve valuable comments. + + + +REFERENCES +---------- +[0] http://lists.nongnu.org/mailman/listinfo/nmh-workers +[1] http://rand-mh.sourceforge.net/book/ +[2] http://www.newt.com/faq/mh.html diff --git a/docs/TODO b/docs/TODO index 97d4ef6..a9de6dd 100644 --- a/docs/TODO +++ b/docs/TODO @@ -52,13 +52,6 @@ ENVIRONMENT/PROFILE * Maybe add profile entry "Pager" to change the default pager? * Should nmh check for EDITOR or PAGER environment variable? -POP ---- -* Clean up uip/spop.c (I dont' think it's needed any longer). -* Need to decide if want to support APOP, RPOP, MPOP. APOP - and RPOP still work, but need autoconf support added. Does - anyone still use this stuff? - OPTIONS ------- * change switches to accept two dashes (--help) diff --git a/docs/m_getfld.c.humor b/docs/m_getfld.c.humor new file mode 100644 index 0000000..e722c85 --- /dev/null +++ b/docs/m_getfld.c.humor @@ -0,0 +1,834 @@ +This is the pre-mmh version of sbr/m_getfld.c (dated 2008-12-26). +The current version is still unbearbable, but this one is original. +Enjoy! :-) -- 2012-04-01 markus schnalke + +/* + * m_getfld.c -- read/parse a message + * + * This code is Copyright (c) 2002, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. + */ + +#include +#include +#include + +/* This module has a long and checkered history. First, it didn't burst + maildrops correctly because it considered two CTRL-A:s in a row to be + an inter-message delimiter. It really is four CTRL-A:s followed by a + newline. Unfortunately, MMDF will convert this delimiter *inside* a + message to a CTRL-B followed by three CTRL-A:s and a newline. This + caused the old version of m_getfld() to declare eom prematurely. The + fix was a lot slower than + + c == '\001' && peekc (iob) == '\001' + + but it worked, and to increase generality, MBOX style maildrops could + be parsed as well. Unfortunately the speed issue finally caught up with + us since this routine is at the very heart of MH. + + To speed things up considerably, the routine Eom() was made an auxilary + function called by the macro eom(). Unless we are bursting a maildrop, + the eom() macro returns FALSE saying we aren't at the end of the + message. + + The next thing to do is to read the mts.conf file and initialize + delimiter[] and delimlen accordingly... + + After mhl was made a built-in in msh, m_getfld() worked just fine + (using m_unknown() at startup). Until one day: a message which was + the result of a bursting was shown. Then, since the burst boundaries + aren't CTRL-A:s, m_getfld() would blinding plunge on past the boundary. + Very sad. The solution: introduce m_eomsbr(). This hook gets called + after the end of each line (since testing for eom involves an fseek()). + This worked fine, until one day: a message with no body portion arrived. + Then the + + while (eom (c = Getc (iob), iob)) + continue; + + loop caused m_getfld() to return FMTERR. So, that logic was changed to + check for (*eom_action) and act accordingly. + + This worked fine, until one day: someone didn't use four CTRL:A's as + their delimiters. So, the bullet got bit and we read mts.h and + continue to struggle on. It's not that bad though, since the only time + the code gets executed is when inc (or msh) calls it, and both of these + have already called mts_init(). + + ------------------------ + (Written by Van Jacobson for the mh6 m_getfld, January, 1986): + + This routine was accounting for 60% of the cpu time used by most mh + programs. I spent a bit of time tuning and it now accounts for <10% + of the time used. Like any heavily tuned routine, it's a bit + complex and you want to be sure you understand everything that it's + doing before you start hacking on it. Let me try to emphasize + that: every line in this atrocity depends on every other line, + sometimes in subtle ways. You should understand it all, in detail, + before trying to change any part. If you do change it, test the + result thoroughly (I use a hand-constructed test file that exercises + all the ways a header name, header body, header continuation, + header-body separator, body line and body eom can align themselves + with respect to a buffer boundary). "Minor" bugs in this routine + result in garbaged or lost mail. + + If you hack on this and slow it down, I, my children and my + children's children will curse you. + + This routine gets used on three different types of files: normal, + single msg files, "packed" unix or mmdf mailboxs (when used by inc) + and packed, directoried bulletin board files (when used by msh). + The biggest impact of different file types is in "eom" testing. The + code has been carefully organized to test for eom at appropriate + times and at no other times (since the check is quite expensive). + I have tried to arrange things so that the eom check need only be + done on entry to this routine. Since an eom can only occur after a + newline, this is easy to manage for header fields. For the msg + body, we try to efficiently search the input buffer to see if + contains the eom delimiter. If it does, we take up to the + delimiter, otherwise we take everything in the buffer. (The change + to the body eom/copy processing produced the most noticeable + performance difference, particularly for "inc" and "show".) + + There are three qualitatively different things this routine busts + out of a message: field names, field text and msg bodies. Field + names are typically short (~8 char) and the loop that extracts them + might terminate on a colon, newline or max width. I considered + using a Vax "scanc" to locate the end of the field followed by a + "bcopy" but the routine call overhead on a Vax is too large for this + to work on short names. If Berkeley ever makes "inline" part of the + C optimiser (so things like "scanc" turn into inline instructions) a + change here would be worthwhile. + + Field text is typically 60 - 100 characters so there's (barely) + a win in doing a routine call to something that does a "locc" + followed by a "bmove". About 30% of the fields have continuations + (usually the 822 "received:" lines) and each continuation generates + another routine call. "Inline" would be a big win here, as well. + + Messages, as of this writing, seem to come in two flavors: small + (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers + so message bodies average at least a few hundred characters. + Assuming your system uses reasonably sized stdio buffers (1K or + more), this routine should be able to remove the body in large + (>500 byte) chunks. The makes the cost of a call to "bcopy" + small but there is a premium on checking for the eom in packed + maildrops. The eom pattern is always a simple string so we can + construct an efficient pattern matcher for it (e.g., a Vax "matchc" + instruction). Some thought went into recognizing the start of + an eom that has been split across two buffers. + + This routine wants to deal with large chunks of data so, rather + than "getc" into a local buffer, it uses stdio's buffer. If + you try to use it on a non-buffered file, you'll get what you + deserve. This routine "knows" that struct FILEs have a _ptr + and a _cnt to describe the current state of the buffer and + it knows that _filbuf ignores the _ptr & _cnt and simply fills + the buffer. If stdio on your system doesn't work this way, you + may have to make small changes in this routine. + + This routine also "knows" that an EOF indication on a stream is + "sticky" (i.e., you will keep getting EOF until you reposition the + stream). If your system doesn't work this way it is broken and you + should complain to the vendor. As a consequence of the sticky + EOF, this routine will never return any kind of EOF status when + there is data in "name" or "buf"). + */ + + +/* + * static prototypes + */ +static int m_Eom (int, FILE *); +static unsigned char *matchc(int, char *, int, char *); +static unsigned char *locc(int, unsigned char *, unsigned char); + +#define Getc(iob) getc(iob) +#define eom(c,iob) (msg_style != MS_DEFAULT && \ + (((c) == *msg_delim && m_Eom(c,iob)) ||\ + (eom_action && (*eom_action)(c)))) + +static unsigned char **pat_map; + +/* + * defined in sbr/m_msgdef.c = 0 + * This is a disgusting hack for "inc" so it can know how many + * characters were stuffed in the buffer on the last call + * (see comments in uip/scansbr.c). + */ +extern int msg_count; + +/* + * defined in sbr/m_msgdef.c = MS_DEFAULT + */ +extern int msg_style; + +/* + * The "full" delimiter string for a packed maildrop consists + * of a newline followed by the actual delimiter. E.g., the + * full string for a Unix maildrop would be: "\n\nFrom ". + * "Fdelim" points to the start of the full string and is used + * in the BODY case of the main routine to search the buffer for + * a possible eom. Msg_delim points to the first character of + * the actual delim. string (i.e., fdelim+1). Edelim + * points to the 2nd character of actual delimiter string. It + * is used in m_Eom because the first character of the string + * has been read and matched before m_Eom is called. + */ +extern char *msg_delim; /* defined in sbr/m_msgdef.c = "" */ +static unsigned char *fdelim; +static unsigned char *delimend; +static int fdelimlen; +static unsigned char *edelim; +static int edelimlen; + +static int (*eom_action)(int) = NULL; + +#ifdef _FSTDIO +# define _ptr _p /* Gag */ +# define _cnt _r /* Retch */ +# define _filbuf __srget /* Puke */ +# define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC +#endif + +#ifdef SCO_5_STDIO +# define _ptr __ptr +# define _cnt __cnt +# define _base __base +# define _filbuf(fp) ((fp)->__cnt = 0, __filbuf(fp)) +# define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC +#endif + +#ifndef DEFINED__FILBUF_TO_SOMETHING_SPECIFIC +extern int _filbuf(FILE*); +#endif + + +int +m_getfld (int state, unsigned char *name, unsigned char *buf, + int bufsz, FILE *iob) +{ + register unsigned char *bp, *cp, *ep, *sp; + register int cnt, c, i, j; + + if ((c = Getc(iob)) < 0) { + msg_count = 0; + *buf = 0; + return FILEEOF; + } + if (eom (c, iob)) { + if (! eom_action) { + /* flush null messages */ + while ((c = Getc(iob)) >= 0 && eom (c, iob)) + ; + if (c >= 0) + ungetc(c, iob); + } + msg_count = 0; + *buf = 0; + return FILEEOF; + } + + switch (state) { + case FLDEOF: + case BODYEOF: + case FLD: + if (c == '\n' || c == '-') { + /* we hit the header/body separator */ + while (c != '\n' && (c = Getc(iob)) >= 0) + ; + + if (c < 0 || (c = Getc(iob)) < 0 || eom (c, iob)) { + if (! eom_action) { + /* flush null messages */ + while ((c = Getc(iob)) >= 0 && eom (c, iob)) + ; + if (c >= 0) + ungetc(c, iob); + } + msg_count = 0; + *buf = 0; + return FILEEOF; + } + state = BODY; + goto body; + } + /* + * get the name of this component. take characters up + * to a ':', a newline or NAMESZ-1 characters, whichever + * comes first. + */ + cp = name; + i = NAMESZ - 1; + for (;;) { +#ifdef LINUX_STDIO + bp = sp = (unsigned char *) iob->_IO_read_ptr - 1; + j = (cnt = ((long) iob->_IO_read_end - + (long) iob->_IO_read_ptr) + 1) < i ? cnt : i; +#elif defined(__DragonFly__) + bp = sp = (unsigned char *) ((struct __FILE_public *)iob)->_p - 1; + j = (cnt = ((struct __FILE_public *)iob)->_r+1) < i ? cnt : i; +#else + bp = sp = (unsigned char *) iob->_ptr - 1; + j = (cnt = iob->_cnt+1) < i ? cnt : i; +#endif + while (--j >= 0 && (c = *bp++) != ':' && c != '\n') + *cp++ = c; + + j = bp - sp; + if ((cnt -= j) <= 0) { +#ifdef LINUX_STDIO + iob->_IO_read_ptr = iob->_IO_read_end; + if (__underflow(iob) == EOF) { +#elif defined(__DragonFly__) + if (__srget(iob) == EOF) { +#else + if (_filbuf(iob) == EOF) { +#endif + *cp = *buf = 0; + advise (NULL, "eof encountered in field \"%s\"", name); + return FMTERR; + } +#ifdef LINUX_STDIO + iob->_IO_read_ptr++; /* NOT automatic in __underflow()! */ +#endif + } else { +#ifdef LINUX_STDIO + iob->_IO_read_ptr = bp + 1; +#elif defined(__DragonFly__) + ((struct __FILE_public *)iob)->_p = bp + 1; + ((struct __FILE_public *)iob)->_r = cnt - 1; +#else + iob->_ptr = bp + 1; + iob->_cnt = cnt - 1; +#endif + } + if (c == ':') + break; + + /* + * something went wrong. possibilities are: + * . hit a newline (error) + * . got more than namesz chars. (error) + * . hit the end of the buffer. (loop) + */ + if (c == '\n') { + /* We hit the end of the line without seeing ':' to + * terminate the field name. This is usually (always?) + * spam. But, blowing up is lame, especially when + * scan(1)ing a folder with such messages. Pretend such + * lines are the first of the body (at least mutt also + * handles it this way). */ + + /* See if buf can hold this line, since we were assuming + * we had a buffer of NAMESZ, not bufsz. */ + /* + 1 for the newline */ + if (bufsz < j + 1) { + /* No, it can't. Oh well, guess we'll blow up. */ + *cp = *buf = 0; + advise (NULL, "eol encountered in field \"%s\"", name); + state = FMTERR; + goto finish; + } + memcpy (buf, name, j - 1); + buf[j - 1] = '\n'; + buf[j] = '\0'; + /* mhparse.c:get_content wants to find the position of the + * body start, but it thinks there's a blank line between + * the header and the body (naturally!), so seek back so + * that things line up even though we don't have that + * blank line in this case. Simpler parsers (e.g. mhl) + * get extra newlines, but that should be harmless enough, + * right? This is a corrupt message anyway. */ + fseek (iob, ftell (iob) - 2, SEEK_SET); + return BODY; + } + if ((i -= j) <= 0) { + *cp = *buf = 0; + advise (NULL, "field name \"%s\" exceeds %d bytes", name, NAMESZ - 2); + state = LENERR; + goto finish; + } + } + + while (isspace (*--cp) && cp >= name) + ; + *++cp = 0; + /* fall through */ + + case FLDPLUS: + /* + * get (more of) the text of a field. take + * characters up to the end of this field (newline + * followed by non-blank) or bufsz-1 characters. + */ + cp = buf; i = bufsz-1; + for (;;) { +#ifdef LINUX_STDIO + cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; + bp = (unsigned char *) --iob->_IO_read_ptr; +#elif defined(__DragonFly__) + cnt = ((struct __FILE_public *)iob)->_r++; + bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; +#else + cnt = iob->_cnt++; + bp = (unsigned char *) --iob->_ptr; +#endif + c = cnt < i ? cnt : i; + while ((ep = locc( c, bp, '\n' ))) { + /* + * if we hit the end of this field, return. + */ + if ((j = *++ep) != ' ' && j != '\t') { +#ifdef LINUX_STDIO + j = ep - (unsigned char *) iob->_IO_read_ptr; + memcpy (cp, iob->_IO_read_ptr, j); + iob->_IO_read_ptr = ep; +#elif defined(__DragonFly__) + j = ep - (unsigned char *) ((struct __FILE_public *)iob)->_p; + memcpy (cp, ((struct __FILE_public *)iob)->_p, j); + ((struct __FILE_public *)iob)->_p = ep; + ((struct __FILE_public *)iob)->_r -= j; +#else + j = ep - (unsigned char *) iob->_ptr; + memcpy (cp, iob->_ptr, j); + iob->_ptr = ep; + iob->_cnt -= j; +#endif + cp += j; + state = FLD; + goto finish; + } + c -= ep - bp; + bp = ep; + } + /* + * end of input or dest buffer - copy what we've found. + */ +#ifdef LINUX_STDIO + c += bp - (unsigned char *) iob->_IO_read_ptr; + memcpy( cp, iob->_IO_read_ptr, c); +#elif defined(__DragonFly__) + c += bp - (unsigned char *) ((struct __FILE_public *)iob)->_p; + memcpy( cp, ((struct __FILE_public *)iob)->_p, c); +#else + c += bp - (unsigned char *) iob->_ptr; + memcpy( cp, iob->_ptr, c); +#endif + i -= c; + cp += c; + if (i <= 0) { + /* the dest buffer is full */ +#ifdef LINUX_STDIO + iob->_IO_read_ptr += c; +#elif defined(__DragonFly__) + ((struct __FILE_public *)iob)->_r -= c; + ((struct __FILE_public *)iob)->_p += c; +#else + iob->_cnt -= c; + iob->_ptr += c; +#endif + state = FLDPLUS; + break; + } + /* + * There's one character left in the input buffer. + * Copy it & fill the buffer. If the last char + * was a newline and the next char is not whitespace, + * this is the end of the field. Otherwise loop. + */ + --i; +#ifdef LINUX_STDIO + *cp++ = j = *(iob->_IO_read_ptr + c); + iob->_IO_read_ptr = iob->_IO_read_end; + c = __underflow(iob); + iob->_IO_read_ptr++; /* NOT automatic! */ +#elif defined(__DragonFly__) + *cp++ =j = *(((struct __FILE_public *)iob)->_p + c); + c = __srget(iob); +#else + *cp++ = j = *(iob->_ptr + c); + c = _filbuf(iob); +#endif + if (c == EOF || + ((j == '\0' || j == '\n') && c != ' ' && c != '\t')) { + if (c != EOF) { +#ifdef LINUX_STDIO + --iob->_IO_read_ptr; +#elif defined(__DragonFly__) + --((struct __FILE_public *)iob)->_p; + ++((struct __FILE_public *)iob)->_r; +#else + --iob->_ptr; + ++iob->_cnt; +#endif + } + state = FLD; + break; + } + } + break; + + case BODY: + body: + /* + * get the message body up to bufsz characters or the + * end of the message. Sleazy hack: if bufsz is negative + * we assume that we were called to copy directly into + * the output buffer and we don't add an eos. + */ + i = (bufsz < 0) ? -bufsz : bufsz-1; +#ifdef LINUX_STDIO + bp = (unsigned char *) --iob->_IO_read_ptr; + cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; +#elif defined(__DragonFly__) + bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; + cnt = ++((struct __FILE_public *)iob)->_r; +#else + bp = (unsigned char *) --iob->_ptr; + cnt = ++iob->_cnt; +#endif + c = (cnt < i ? cnt : i); + if (msg_style != MS_DEFAULT && c > 1) { + /* + * packed maildrop - only take up to the (possible) + * start of the next message. This "matchc" should + * probably be a Boyer-Moore matcher for non-vaxen, + * particularly since we have the alignment table + * all built for the end-of-buffer test (next). + * But our vax timings indicate that the "matchc" + * instruction is 50% faster than a carefully coded + * B.M. matcher for most strings. (So much for elegant + * algorithms vs. brute force.) Since I (currently) + * run MH on a vax, we use the matchc instruction. --vj + */ + if ((ep = matchc( fdelimlen, fdelim, c, bp ))) + c = ep - bp + 1; + else { + /* + * There's no delim in the buffer but there may be + * a partial one at the end. If so, we want to leave + * it so the "eom" check on the next call picks it up. + * Use a modified Boyer-Moore matcher to make this + * check relatively cheap. The first "if" figures + * out what position in the pattern matches the last + * character in the buffer. The inner "while" matches + * the pattern against the buffer, backwards starting + * at that position. Note that unless the buffer + * ends with one of the characters in the pattern + * (excluding the first and last), we do only one test. + */ + ep = bp + c - 1; + if ((sp = pat_map[*ep])) { + do { + /* This if() is true unless (a) the buffer is too + * small to contain this delimiter prefix, or + * (b) it contains exactly enough chars for the + * delimiter prefix. + * For case (a) obviously we aren't going to match. + * For case (b), if the buffer really contained exactly + * a delim prefix, then the m_eom call at entry + * should have found it. Thus it's not a delim + * and we know we won't get a match. + */ + if (((sp - fdelim) + 2) <= c) { + cp = sp; + /* Unfortunately although fdelim has a preceding NUL + * we can't use this as a sentinel in case the buffer + * contains a NUL in exactly the wrong place (this + * would cause us to run off the front of fdelim). + */ + while (*--ep == *--cp) + if (cp < fdelim) + break; + if (cp < fdelim) { + /* we matched the entire delim prefix, + * so only take the buffer up to there. + * we know ep >= bp -- check above prevents underrun + */ + c = (ep - bp) + 2; + break; + } + } + /* try matching one less char of delim string */ + ep = bp + c - 1; + } while (--sp > fdelim); + } + } + } + memcpy( buf, bp, c ); +#ifdef LINUX_STDIO + iob->_IO_read_ptr += c; +#elif defined(__DragonFly__) + ((struct __FILE_public *)iob)->_r -= c; + ((struct __FILE_public *)iob)->_p += c; +#else + iob->_cnt -= c; + iob->_ptr += c; +#endif + if (bufsz < 0) { + msg_count = c; + return (state); + } + cp = buf + c; + break; + + default: + adios (NULL, "m_getfld() called with bogus state of %d", state); + } +finish: + *cp = 0; + msg_count = cp - buf; + return (state); +} + + +#ifdef RPATHS +static char unixbuf[BUFSIZ] = ""; +#endif /* RPATHS */ + +void +m_unknown(FILE *iob) +{ + register int c; + register long pos; + char text[10]; + register char *cp; + register char *delimstr; + +/* + * Figure out what the message delimitter string is for this + * maildrop. (This used to be part of m_Eom but I didn't like + * the idea of an "if" statement that could only succeed on the + * first call to m_Eom getting executed on each call, i.e., at + * every newline in the message). + * + * If the first line of the maildrop is a Unix "From " line, we + * say the style is MBOX and eat the rest of the line. Otherwise + * we say the style is MMDF and look for the delimiter string + * specified when nmh was built (or from the mts.conf file). + */ + + msg_style = MS_UNKNOWN; + + pos = ftell (iob); + if (fread (text, sizeof(*text), 5, iob) == 5 + && strncmp (text, "From ", 5) == 0) { + msg_style = MS_MBOX; + delimstr = "\nFrom "; +#ifndef RPATHS + while ((c = getc (iob)) != '\n' && c >= 0) + ; +#else /* RPATHS */ + cp = unixbuf; + while ((c = getc (iob)) != '\n' && cp - unixbuf < BUFSIZ - 1) + *cp++ = c; + *cp = 0; +#endif /* RPATHS */ + } else { + /* not a Unix style maildrop */ + fseek (iob, pos, SEEK_SET); + if (mmdlm2 == NULL || *mmdlm2 == 0) + mmdlm2 = "\001\001\001\001\n"; + delimstr = mmdlm2; + msg_style = MS_MMDF; + } + c = strlen (delimstr); + fdelim = (unsigned char *) mh_xmalloc((size_t) (c + 3)); + *fdelim++ = '\0'; + *fdelim = '\n'; + msg_delim = (char *)fdelim+1; + edelim = (unsigned char *)msg_delim+1; + fdelimlen = c + 1; + edelimlen = c - 1; + strcpy (msg_delim, delimstr); + delimend = (unsigned char *)msg_delim + edelimlen; + if (edelimlen <= 1) + adios (NULL, "maildrop delimiter must be at least 2 bytes"); + /* + * build a Boyer-Moore end-position map for the matcher in m_getfld. + * N.B. - we don't match just the first char (since it's the newline + * separator) or the last char (since the matchc would have found it + * if it was a real delim). + */ + pat_map = (unsigned char **) calloc (256, sizeof(unsigned char *)); + + for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ ) + pat_map[(unsigned char)*cp] = (unsigned char *) cp; + + if (msg_style == MS_MMDF) { + /* flush extra msg hdrs */ + while ((c = Getc(iob)) >= 0 && eom (c, iob)) + ; + if (c >= 0) + ungetc(c, iob); + } +} + + +void +m_eomsbr (int (*action)(int)) +{ + if ((eom_action = action)) { + msg_style = MS_MSH; + *msg_delim = 0; + fdelimlen = 1; + delimend = fdelim; + } else { + msg_style = MS_MMDF; + msg_delim = (char *)fdelim + 1; + fdelimlen = strlen((char *)fdelim); + delimend = (unsigned char *)(msg_delim + edelimlen); + } +} + + +/* + * test for msg delimiter string + */ + +static int +m_Eom (int c, FILE *iob) +{ + register long pos = 0L; + register int i; + char text[10]; +#ifdef RPATHS + register char *cp; +#endif /* RPATHS */ + + pos = ftell (iob); + if ((i = fread (text, sizeof *text, edelimlen, iob)) != edelimlen + || strncmp (text, (char *)edelim, edelimlen)) { + if (i == 0 && msg_style == MS_MBOX) + /* the final newline in the (brain damaged) unix-format + * maildrop is part of the delimitter - delete it. + */ + return 1; + +#if 0 + fseek (iob, pos, SEEK_SET); +#endif + + fseek (iob, (long)(pos-1), SEEK_SET); + getc (iob); /* should be OK */ + return 0; + } + + if (msg_style == MS_MBOX) { +#ifndef RPATHS + while ((c = getc (iob)) != '\n') + if (c < 0) + break; +#else /* RPATHS */ + cp = unixbuf; + while ((c = getc (iob)) != '\n' && c >= 0 && cp - unixbuf < BUFSIZ - 1) + *cp++ = c; + *cp = 0; +#endif /* RPATHS */ + } + + return 1; +} + + +#ifdef RPATHS +/* + * Return the Return-Path and Delivery-Date + * header information. + * + * Currently, I'm assuming that the "From " line + * takes one of the following forms. + * + * From sender date remote from host (for UUCP delivery) + * From sender@host date (for sendmail delivery) + */ + +int +get_returnpath (char *rp, int rplen, char *dd, int ddlen) +{ + char *ap, *bp, *cp, *dp; + + ap = unixbuf; + if (!(bp = cp = strchr(ap, ' '))) + return 0; + + /* + * Check for "remote from" in envelope to see + * if this message uses UUCP style addressing + */ + while ((cp = strchr(++cp, 'r'))) { + if (strncmp (cp, "remote from", 11) == 0) { + cp = strrchr (cp, ' '); + break; + } + } + + /* + * Get the Return-Path information from + * the "From " envelope. + */ + if (cp) { + /* return path for UUCP style addressing */ + dp = strchr (++cp, '\n'); + snprintf (rp, rplen, "%.*s!%.*s\n", (int)(dp - cp), cp, (int)(bp - ap), ap); + } else { + /* return path for standard domain addressing */ + snprintf (rp, rplen, "%.*s\n", (int)(bp - ap), ap); + } + + /* + * advance over the spaces to get to + * delivery date on envelope + */ + while (*bp == ' ') + bp++; + + /* Now get delivery date from envelope */ + snprintf (dd, ddlen, "%.*s\n", 24, bp); + + unixbuf[0] = 0; + return 1; +} +#endif /* RPATHS */ + + +static unsigned char * +matchc(int patln, char *pat, int strln, char *str) +{ + register char *es = str + strln - patln; + register char *sp; + register char *pp; + register char *ep = pat + patln; + register char pc = *pat++; + + for(;;) { + while (pc != *str++) + if (str > es) + return 0; + if (str > es+1) + return 0; + sp = str; pp = pat; + while (pp < ep && *sp++ == *pp) + pp++; + if (pp >= ep) + return ((unsigned char *)--str); + } +} + + +/* + * Locate character "term" in the next "cnt" characters of "src". + * If found, return its address, otherwise return 0. + */ + +static unsigned char * +locc(int cnt, unsigned char *src, unsigned char term) +{ + while (*src++ != term && --cnt > 0); + + return (cnt > 0 ? --src : (unsigned char *)0); +} + diff --git a/etc/MailAliases b/etc/MailAliases deleted file mode 100644 index 5037a54..0000000 --- a/etc/MailAliases +++ /dev/null @@ -1,27 +0,0 @@ -; -; MailAliases -- nmh global aliases file -; -; This file is used to define aliases that are valid for all mh users. -; This file is almost empty as MH now supports personal aliases. -; -; If you need to define system wide aliases such as "everyone", it is -; preferable that this be done as the mail transport level, so that they -; will be valid for users of other mail clients. - -; everyone: * - -; Blank lines and lines beginning with a ; are ignored. -; < file -> read more aliases from "file" -; foo: fum -> simple replacement -; foo: fum, fie -> list replacement -; foo: < file -> list replacement from "file" -; foo: = group -> list replacement from UNIX group -; foo: + group -> list replacement by ALL users in /etc/passwd -; with gid == group -; foo: * -> list replacement by ALL users in /etc/passwd -; with uid >= 200 -; foo*: fum -> matches foo (including the empty string) -; -; using a ';' instead of a ':' indicates that the alias should be displayed -; along with the addresses used (normally, the addresses replace the alias -; completely) diff --git a/etc/Makefile.in b/etc/Makefile.in index 4bec6a1..8277cc8 100644 --- a/etc/Makefile.in +++ b/etc/Makefile.in @@ -14,111 +14,56 @@ bindir = @bindir@ libdir = @libdir@ etcdir = @sysconfdir@ -MTS = @MTS@ mailspool = @mailspool@ -masquerade = @masquerade@ -smtpservers = @smtpservers@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_DATA = @INSTALL_DATA@ -# Path to search for programs to handle MIME -# content. Used to create mhn.defaults -MHNSEARCHPATH = "$(PATH):/usr/demo/SOUND" - -# Program used to search path for various programs to -# handle MIME content. Used to create mhn.defaults -MHNSEARCHPROG = $(srcdir)/mhn.find.sh - SED = sed .SUFFIXES: # static configuration, format, and components files -STATIC_FILES = MailAliases components digestcomps distcomps forwcomps \ - mhl.body mhl.digest mhl.format mhl.forward mhl.headers \ - mhl.reply rcvdistcomps rcvdistcomps.outbox \ - replcomps replgroupcomps scan.MMDDYY scan.YYYYMMDD \ - scan.default scan.mailx scan.nomime scan.size scan.time \ - scan.timely scan.unseen - -# templates and scripts from which non-static files are generated -GENERATED_FILE_SRCS = mhn.defaults.sh mhn.find.sh mts.conf.in sendfiles.in - -# scripts generated using above GENERATED_FILE_SRCs; don't add binaries -# to this list, as they'll get installed with INSTALL_SCRIPT and won't -# be stripped. -GENERATED_BIN_FILES = sendfiles - -# non-scripts generated using above GENERATED_FILE_SRCs -GENERATED_ETC_FILES = mhn.defaults mts.conf +STATIC_FILES = components digestcomps distcomps forwcomps \ + mhl.body mhl.format mhl.forward mhl.headers \ + mhl.reply rcvdistcomps rcvdistcomps.outbox \ + replcomps replgroupcomps scan.MMDDYY scan.YYYYMMDD \ + scan.nmh scan.mailx scan.nomime scan.size scan.time \ + scan.timely scan.unseen scan.meillo mhn.defaults # auxiliary files (included in distribution but not installed) AUX = Makefile.in # all non-generated files in this directory are included in the distribution -DIST = $(STATIC_FILES) $(GENERATED_FILE_SRCS) $(AUX) +DIST = $(STATIC_FILES) $(AUX) # ========= DEPENDENCIES FOR BUILDING ========== -all: $(GENERATED_BIN_FILES) $(GENERATED_ETC_FILES) - -mhn.defaults: $(srcdir)/mhn.defaults.sh $(MHNSEARCHPROG) - rm -f $@ - $(srcdir)/mhn.defaults.sh $(MHNSEARCHPATH) $(MHNSEARCHPROG) > $@ - -mts.conf: $(srcdir)/mts.conf.in Makefile - rm -f $@ - $(SED) -e 's,%mts%,$(MTS),' \ - -e 's,%mailspool%,$(mailspool),' \ - -e 's,%etcdir%,$(etcdir),' \ - -e 's,%masquerade%,$(masquerade),' \ - -e 's,%smtpservers%,$(smtpservers),' < $(srcdir)/mts.conf.in > $@ +all: -sendfiles: $(srcdir)/sendfiles.in Makefile - rm -f $@ - $(SED) -e 's,%libdir%,$(libdir),' < $(srcdir)/sendfiles.in > $@ - -install: install-bin-files install-etc-files - -install-bin-files: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) - for script in $(GENERATED_BIN_FILES); do \ - $(INSTALL_SCRIPT) $$script $(DESTDIR)$(bindir)/$$script; \ - done +install: install-etc-files install-etc-files: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(etcdir) - INSTALL_FILES="$(GENERATED_ETC_FILES)"; \ + mkdir -p $(DESTDIR)$(etcdir) for file in $(STATIC_FILES); do \ - INSTALL_FILES="$$INSTALL_FILES $(srcdir)/$$file"; \ - done; \ - for path in $$INSTALL_FILES; do \ - file=`basename $$path`; \ - echo "Installing $$file..."; \ if [ -f "$(DESTDIR)$(etcdir)/$$file" ]; then \ - if cmp -s "$$path" "$(DESTDIR)$(etcdir)/$$file"; then \ - echo "$(DESTDIR)$(etcdir)/$$file unchanged, skipped"; \ + if cmp -s "$(srcdir)/$$file" "$(DESTDIR)$(etcdir)/$$file" ; then \ + :; \ else \ - $(INSTALL_DATA) "$$path" "$(DESTDIR)$(etcdir)/$$file.dist"; \ - echo "INFO: $(DESTDIR)$(etcdir)/$$file installed with .dist extension"; \ + $(INSTALL_DATA) "$(srcdir)/$$file" "$(DESTDIR)$(etcdir)/$$file.dist"; \ + echo "$(DESTDIR)$(etcdir)/$$file has local modifications; installing with .dist suffix"; \ fi; \ else \ - $(INSTALL_DATA) $$path $(DESTDIR)$(etcdir)/$$file; \ + $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(etcdir)/$$file; \ fi; \ done -uninstall: uninstall-bin-files uninstall-etc-files - -uninstall-bin-files: - for script in $(GENERATED_BIN_FILES); do \ - rm -f $(DESTDIR)$(bindir)/$$script; \ - done +uninstall: uninstall-etc-files uninstall-etc-files: - for file in $(STATIC_FILES) $(GENERATED_ETC_FILES); do \ + for file in $(STATIC_FILES) ; do \ rm -f $(DESTDIR)$(etcdir)/$$file; \ done @@ -128,7 +73,6 @@ mostlyclean: rm -f *~ clean: mostlyclean - rm -f $(GENERATED_ETC_FILES) $(GENERATED_BIN_FILES) distclean: clean rm -f Makefile @@ -143,11 +87,10 @@ subdir = etc Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ done - diff --git a/etc/components b/etc/components index 7f255ea..585814b 100644 --- a/etc/components +++ b/etc/components @@ -1,5 +1,5 @@ To: -cc: -Fcc: +outbox +Cc: +Fcc: +sent Subject: -------- diff --git a/etc/digestcomps b/etc/digestcomps index 7f5036d..49c8881 100644 --- a/etc/digestcomps +++ b/etc/digestcomps @@ -1,9 +1,10 @@ -From: %{digest}-Request -To: %{digest} Distribution: dist-%{digest}; +From: %{digest}-request +To: %{digest} Distribution: dist-%{digest}; Subject: %{digest} Digest V%(cur) #%(msg) Reply-To: %{digest} -------- -%{digest} Digest %(weekday{date}), %2(mday{date}) %(month{date}) %(year{date}) - Volume %(cur) : Issue %(msg) +%{digest} Digest +Volume %(cur) : Issue %(msg) +%(weekday{date}), %02(mday{date}) %(month{date}) %(year{date}) -Today's Topics: +Today's Topics are attached. diff --git a/etc/distcomps b/etc/distcomps index d30819a..aac1354 100644 --- a/etc/distcomps +++ b/etc/distcomps @@ -1,3 +1,3 @@ Resent-To: -Resent-cc: -Resent-fcc: +Resent-Cc: +Resent-Fcc: diff --git a/etc/forwcomps b/etc/forwcomps index 7f255ea..585814b 100644 --- a/etc/forwcomps +++ b/etc/forwcomps @@ -1,5 +1,5 @@ To: -cc: -Fcc: +outbox +Cc: +Fcc: +sent Subject: -------- diff --git a/etc/mhl.digest b/etc/mhl.digest deleted file mode 100644 index ea4a6d5..0000000 --- a/etc/mhl.digest +++ /dev/null @@ -1,7 +0,0 @@ -width=80,overflowoffset=10 -leftadjust,compress,compwidth=9 -Date:formatfield="%<(nodate{text})%{text}%|%(tws{text})%>" -From: -Subject: -: -body:nocomponent,overflowoffset=0,noleftadjust,nocompress diff --git a/etc/mhl.format b/etc/mhl.format index 7f8a567..9636dbb 100644 --- a/etc/mhl.format +++ b/etc/mhl.format @@ -7,9 +7,9 @@ overflowtext="***",overflowoffset=5 leftadjust,compwidth=9 ignores=msgid,message-id,received,content-type,content-transfer-encoding,content-id Date:formatfield="%<(nodate{text})%{text}%|%(pretty{text})%>" -To: -cc: From:decode +To: +Cc: Subject:decode : extras:nocomponent diff --git a/etc/mhl.forward b/etc/mhl.forward index 82b4ebc..a24462f 100644 --- a/etc/mhl.forward +++ b/etc/mhl.forward @@ -7,7 +7,7 @@ leftadjust,compress,compwidth=9 Date:formatfield="%<(nodate{text})%{text}%|%(tws{text})%>" From: To: -cc: +Cc: Subject: : body:nocomponent,overflowoffset=0,noleftadjust,nocompress diff --git a/etc/mhl.headers b/etc/mhl.headers index 8fee181..1a01a7f 100644 --- a/etc/mhl.headers +++ b/etc/mhl.headers @@ -1,17 +1,14 @@ ; mhl.headers ; ; Default format file for displaying headers in -; MIME messages. mhn calls the mhlproc with this +; MIME messages. show calls mhl with this ; filter to display message header. ; overflowtext="***",overflowoffset=5 leftadjust,compwidth=9 -ignores=msgid,message-id,received,content-type,content-transfer-encoding,content-id Date:formatfield="%<(nodate{text})%{text}%|%(pretty{text})%>" -To: -cc: From:decode +To: +Cc: Subject:decode : -extras:nocomponent -: diff --git a/etc/mhn.defaults b/etc/mhn.defaults new file mode 100644 index 0000000..71c754d --- /dev/null +++ b/etc/mhn.defaults @@ -0,0 +1,60 @@ +mhshow-suffix-application/msword: .doc +mhshow-suffix-application/msword: .docx +mhshow-suffix-application/ogg: .ogg +mhshow-suffix-application/pdf: .pdf +mhshow-suffix-application/postscript: .ps +mhshow-suffix-application/rtf: .rtf +mhshow-suffix-application/vnd.ms-excel: .xla +mhshow-suffix-application/vnd.ms-excel: .xlc +mhshow-suffix-application/vnd.ms-excel: .xld +mhshow-suffix-application/vnd.ms-excel: .xll +mhshow-suffix-application/vnd.ms-excel: .xlm +mhshow-suffix-application/vnd.ms-excel: .xls +mhshow-suffix-application/vnd.ms-excel: .xlt +mhshow-suffix-application/vnd.ms-excel: .xlw +mhshow-suffix-application/vnd.ms-powerpoint: .pot +mhshow-suffix-application/vnd.ms-powerpoint: .pps +mhshow-suffix-application/vnd.ms-powerpoint: .ppt +mhshow-suffix-application/vnd.ms-powerpoint: .ppz +mhshow-suffix-application/x-bzip2: .bz2 +mhshow-suffix-application/x-cpio: .cpio +mhshow-suffix-application/x-dvi: .dvi +mhshow-suffix-application/x-gzip: .gz +mhshow-suffix-application/x-java-archive: .jar +mhshow-suffix-application/x-javascript: .js +mhshow-suffix-application/x-latex: .latex +mhshow-suffix-application/x-sh: .sh +mhshow-suffix-application/x-tar: .tar +mhshow-suffix-application/x-texinfo: .texinfo +mhshow-suffix-application/x-tex: .tex +mhshow-suffix-application/x-troff-man: .man +mhshow-suffix-application/x-troff-me: .me +mhshow-suffix-application/x-troff-ms: .ms +mhshow-suffix-application/x-troff: .t +mhshow-suffix-application/zip: .zip +mhshow-suffix-audio/basic: .au +mhshow-suffix-audio/midi: .midi +mhshow-suffix-audio/mpeg: .mp3 +mhshow-suffix-audio/mpeg: .mpg +mhshow-suffix-audio/x-ms-wma: .wma +mhshow-suffix-audio/x-wav: .wav +mhshow-suffix-image/gif: .gif +mhshow-suffix-image/jpeg: .jpeg +mhshow-suffix-image/jpeg: .jpg +mhshow-suffix-image/png: .png +mhshow-suffix-image/tiff: .tif +mhshow-suffix-image/tiff: .tiff +mhshow-suffix-text/calendar: .ics +mhshow-suffix-text/css: .css +mhshow-suffix-text/html: .html +mhshow-suffix-text/rtf: .rtf +mhshow-suffix-text/sgml: .sgml +mhshow-suffix-text/xml: .xml +mhshow-suffix-video/mpeg: .mpeg +mhshow-suffix-video/mpeg: .mpg +mhshow-suffix-video/quicktime: .moov +mhshow-suffix-video/quicktime: .mov +mhshow-suffix-video/quicktime: .qt +mhshow-suffix-video/quicktime: .qtvr +mhshow-suffix-video/x-msvideo: .avi +mhshow-suffix-video/x-ms-wmv: .wmv diff --git a/etc/mhn.defaults.sh b/etc/mhn.defaults.sh deleted file mode 100755 index 0db5d3a..0000000 --- a/etc/mhn.defaults.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/sh -# -# mhn.defaults.sh -- create extra profile file for MIME handling -# -# USAGE: mhn.defaults.sh [ search-path [ search-prog ]] - -# If a search path is passed to the script, we -# use that, else we use a default search path. -if [ -n "$1" ]; then - SEARCHPATH=$1 -else - SEARCHPATH="$PATH:/usr/demo/SOUND" -fi - -# If a search program is passed to the script, we -# use that, else we use a default search program. -if [ -n "$2" ]; then - SEARCHPROG=$2 -else - SEARCHPROG="mhn.find.sh" -fi - -# put output into a temporary file, so we -# can sort it before output. -TMP=/tmp/nmh_temp.$$ -trap "rm -f $TMP" 0 1 2 3 13 15 - -echo "mhstore-store-text: %m%P.txt" >> $TMP -echo "mhstore-store-text/richtext: %m%P.rt" >> $TMP -echo "mhstore-store-video/mpeg: %m%P.mpg" >> $TMP -echo "mhstore-store-application/PostScript: %m%P.ps" >> $TMP - -PGM="`$SEARCHPROG $SEARCHPATH xwud`" -if [ ! -z "$PGM" ]; then - XWUD="$PGM" X11DIR="`echo $PGM | awk -F/ '{ for(i=2;i> $TMP -elif [ ! -z $"PBM" -a ! -z "$XWUD" ]; then - echo "mhshow-show-image/gif: %p${PBMDIR}giftoppm | ${PBMDIR}ppmtopgm | ${PBMDIR}pgmtopbm | ${PBMDIR}pbmtoxwd | $XWUD -geometry =-0+0" >> $TMP - echo "mhshow-show-image/x-pbm: %p${PBMDIR}pbmtoxwd | $XWUD -geometry =-0+0" >> $TMP - echo "mhshow-show-image/x-pgm: %p${PBMDIR}pgmtopbm | ${PBMDIR}pbmtoxwd | $XWUD -geometry =-0+0" >> $TMP - echo "mhshow-show-image/x-ppm: %p${PBMDIR}ppmtopgm | ${PBMDIR}pgmtopbm | ${PBMDIR}pbmtoxwd | $XWUD -geometry =-0+0" >> $TMP - echo "mhshow-show-image/x-xwd: %p$XWUD -geometry =-0+0" >> $TMP - - PGM="`$SEARCHPROG $SEARCHPATH djpeg`" - if [ ! -z "$PGM" ]; then - echo "mhshow-show-image/jpeg: %p$PGM -Pg | ${PBMDIR}ppmtopgm | ${PBMDIR}pgmtopbm | ${PBMDIR}pbmtoxwd | $XWUD -geometry =-0+0" >> $TMP - fi -fi - -if [ -f "/dev/audioIU" ]; then - PGM="`$SEARCHPROG $SEARCHPATH recorder`" - if [ ! -z "$PGM" ]; then - echo "mhstore-store-audio/basic: %m%P.au" >> $TMP - echo "mhbuild-compose-audio/basic: ${AUDIODIR}recorder '%f' -au -pause > /dev/tty" >> $TMP - echo "mhshow-show-audio/basic: %p${AUDIODIR}splayer -au" >> $TMP - fi -elif [ -f "/dev/audio" ]; then - PGM="`$SEARCHPROG $SEARCHPATH raw2audio`" - if [ ! -z "$PGM" ]; then - AUDIODIR="`echo $PGM | awk -F/ '{ for(i=2;i %m%P.au" >> $TMP - echo "mhstore-store-audio/x-next: %m%P.au" >> $TMP - AUDIOTOOL="`$SEARCHPROG $SEARCHPATH audiotool`" - if [ ! -z "$AUDIOTOOL" ]; then - echo "mhbuild-compose-audio/basic: $AUDIOTOOL '%f' && ${AUDIODIR}raw2audio -F < '%f'" >> $TMP - else - echo "mhbuild-compose-audio/basic: trap \"exit 0\" 2 && ${AUDIODIR}record | ${AUDIODIR}raw2audio -F" >> $TMP - fi - echo "mhshow-show-audio/basic: %p${AUDIODIR}raw2audio 2>/dev/null | ${AUDIODIR}play" >> $TMP - - PGM="`$SEARCHPROG $SEARCHPATH adpcm_enc`" - if [ ! -z "$PGM" ]; then - DIR="`echo $PGM | awk -F/ '{ for(i=2;i> $TMP - else - echo "mhbuild-compose-audio/x-next: ${AUDIODIR}record | ${DIR}adpcm_enc" >> $TMP - fi - echo "mhshow-show-audio/x-next: %p${DIR}adpcm_dec | ${AUDIODIR}play" >> $TMP - else - if [ ! -z "$AUDIOTOOL" ]; then - echo "mhbuild-compose-audio/x-next: $AUDIOTOOL '%f'" >> $TMP - else - echo "mhbuild-compose-audio/x-next: ${AUDIODIR}record" >> $TMP - fi - echo "mhshow-show-audio/x-next: %p${AUDIODIR}play" >> $TMP - fi - else - echo "mhbuild-compose-audio/basic: cat < /dev/audio" >> $TMP - echo "mhshow-show-audio/basic: %pcat > /dev/audio" >> $TMP - fi -fi - -PGM="`$SEARCHPROG $SEARCHPATH mpeg_play`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-video/mpeg: %p$PGM '%f'" >> $TMP -fi - -PGM="`$SEARCHPROG $SEARCHPATH lpr`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-application/PostScript: %plpr -Pps" >> $TMP -else - PGM="`$SEARCHPROG $SEARCHPATH lp`" - if [ ! -z "$PGM" ]; then - echo "mhshow-show-application/PostScript: %plp -dps" >> $TMP - fi -fi - -PGM="`$SEARCHPROG $SEARCHPATH ivs_replay`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-application/x-ivs: %p$PGM -o '%F'" >> $TMP -fi - -echo "mhshow-suffix-text/html: .html" >> $TMP - -# I'd like to check if netscape is available and use it preferentially to lynx, -# but only once I've added a new %-escape that makes more permanent temp files, -# so netscape -remote can be used (without -remote you get a complaint dialog -# that another netscape is already running and certain things can't be done). -PGM="`$SEARCHPROG $SEARCHPATH lynx`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-text/html: %p$PGM '%F'" >> $TMP -fi - -PGM="`$SEARCHPROG $SEARCHPATH richtext`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-text/richtext: %p$PGM -p '%F'" >> $TMP -else - PGM="`$SEARCHPROG $SEARCHPATH rt2raw`" - if [ ! -z "$PGM" ]; then - echo "mhshow-show-text/richtext: %p$PGM < '%f' | fmt -78 | more" >> $TMP - fi -fi - -# staroffice to read .doc files -PGM="`$SEARCHPROG $SEARCHPATH soffice`" -if [ ! -z "$PGM" ]; then - echo "mhshow-show-application/msword: %psoffice '%F'" >> $TMP - echo "mhshow-suffix-application/msword: .doc" >> $TMP -fi - -# output a sorted version of the file -sort < $TMP - -exit 0 - -: not until we get a "safe" postscript environment... - -PGM="`$SEARCHPROG $SEARCHPATH pageview`" -if [ "$DISPLAY" = "unix:0.0" -a ! -z "$PGM" ]; then - echo "mhshow-show-application/PostScript: %p$PGM -" >> $TMP -else - PGM="`$SEARCHPROG $SEARCHPATH gs`" - if [ ! -z "$PGM" ]; then - echo "mhshow-show-application/PostScript: %p$PGM -- '%F'" >> $TMP - echo "mhshow-suffix-application/PostScript: .ps" >> $TMP - fi -fi - -: have to experiment more with this - -PGM="`$SEARCHPROG $SEARCHPATH ivs_record`" -if [ ! -z "$PGM" ]; then - echo "mhbuild-compose-application/x-ivs: $PGM -u localhost '%F'" >> $TMP -fi diff --git a/etc/mhn.find.sh b/etc/mhn.find.sh deleted file mode 100755 index 3e5e98a..0000000 --- a/etc/mhn.find.sh +++ /dev/null @@ -1,39 +0,0 @@ -#! /bin/sh -# -# mhn.find.sh -- check if a particular command is available -# - -if test -z "$2"; then - echo "usage: mhn.find.sh search-path program" 1>&2 - exit 1 -fi - -# PATH to search for programs -SEARCHPATH=$1 - -# program to search for -PROGRAM=$2 - -PGM= oIFS="$IFS" IFS=":" -for A in $SEARCHPATH; do - - # skip the directories `.' and `..' - if test "$A" = "." -o "$A" = ".."; then - continue - fi - - # if program was found in /usr/local/bin, then - # just echo program name, else echo full pathname - if test -f "$A/$PROGRAM"; then - if test "$A" = "/usr/local/bin"; then - PGM="$PROGRAM" - else - PGM="$A/$PROGRAM" - fi - - echo "$PGM" - exit 0 - fi -done -IFS="$oIFS" - diff --git a/etc/mts.conf.in b/etc/mts.conf.in deleted file mode 100644 index c3c946d..0000000 --- a/etc/mts.conf.in +++ /dev/null @@ -1,38 +0,0 @@ -# -# nmh mail transport interface customization file. -# -# Check the mh-tailor(5) man page for a list of -# all the available options for this file. -# - -# The delivery method to use. Supported values are `smtp' and `sendmail'. -# When `smtp', nmh will open a socket connection to the mail port on the -# machine specified below, and speak SMTP directly. -# When `sendmail', nmh will pipe messages directly to the sendmail program. -mts: %mts% - -# The exceptions file for /etc/hosts used by -# `post' to try to find official names. -hostable: %etcdir%/hosts - -# Name that nmh considers `local'. If not set, nmh will -# query the system for this value (gethostname, etc...). -#localname: foo.bar.com - -# The following directive allows email address masquerading. The string -# "draft_from mmailid username_extension" will allow all three types. -masquerade: %masquerade% - -# Default location of mail drops. If this option is -# set, but empty, the user's home directory is used. -mmdfldir: %mailspool% - -# The name of the maildrop file in the directory where maildrops -# are kept. If this is empty, the user's login name is used. -mmdflfil: - -# Hardcoded POP server name (prevents inc'ing from local mail spool). -#pophost: localhost - -# List of smtp servers to try if using smtp support -servers: %smtpservers% diff --git a/etc/rcvdistcomps.outbox b/etc/rcvdistcomps.outbox index 13fe808..872ffc0 100644 --- a/etc/rcvdistcomps.outbox +++ b/etc/rcvdistcomps.outbox @@ -1,3 +1,3 @@ %(lit)%(formataddr{addresses})\ %<(nonnull)%(void(width))%(putaddr Resent-To: )\n%>\ -Resent-Fcc: outbox +Resent-Fcc: sent diff --git a/etc/replcomps b/etc/replcomps index 9166411..3b94380 100644 --- a/etc/replcomps +++ b/etc/replcomps @@ -1,9 +1,9 @@ %; $Header$ %; -%; These next lines slurp in lots of addresses for To: and cc:. +%; These next lines slurp in lots of addresses for To: and Cc:. %; Use with repl -query or else you may get flooded with addresses! %; -%; If no To:/cc:/Fcc: text, we output empty fields for prompter to fill in. +%; If no To:/Cc:/Fcc: text, we output empty fields for prompter to fill in. %; %(lit)%(formataddr{reply-to})\ %(formataddr %<{from}%(void{from})%|%(void{apparently-from})%>)\ @@ -18,8 +18,8 @@ %(formataddr{resent-cc})\ %(formataddr{prev-resent-cc})\ %(formataddr(me))\ -%(void(width))%(putaddr cc: ) -Fcc: %<{fcc}%{fcc}%|+outbox%> +%(void(width))%(putaddr Cc: ) +Fcc: +sent Subject: %<{subject}Re: %(void{subject})%(trim)%(putstr)%> %; %; Make References: and In-reply-to: fields for threading. diff --git a/etc/replgroupcomps b/etc/replgroupcomps index 210a3e0..789633f 100644 --- a/etc/replgroupcomps +++ b/etc/replgroupcomps @@ -16,8 +16,8 @@ %; %; AND %; -%; cc: To (and) -%; cc (and) +%; Cc: To (and) +%; Cc (and) %; personal address %; %(lit)%(formataddr{mail-followup-to})\ @@ -26,9 +26,9 @@ %(lit)%(formataddr %<{mail-reply-to}%?{reply-to}%?{from}%?{sender}%?{return-path}%>)\ %<(nonnull)%(void(width))%(putaddr To: )\n%>\ %(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\ -%<(nonnull)%(void(width))%(putaddr cc: )\n%>%>\ +%<(nonnull)%(void(width))%(putaddr Cc: )\n%>%>\ %; -Fcc: %<{fcc}%{fcc}%|+outbox%> +Fcc: +sent Subject: %<{subject}Re: %(void{subject})%(trim)%(putstr)%> %; %; Make References: and In-reply-to: fields for threading. diff --git a/etc/scan.MMDDYY b/etc/scan.MMDDYY index dd20b29..6d83b64 100644 --- a/etc/scan.MMDDYY +++ b/etc/scan.MMDDYY @@ -3,8 +3,8 @@ %; Like scan.default, but the date is printed in MM/DD/YY format rather than %; MM/DD. %; -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %02(mon{date})/%02(mday{date})/%(void(year{date}))%02(modulo 100)%<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%> +%(decode{subject}) diff --git a/etc/scan.YYYYMMDD b/etc/scan.YYYYMMDD index 741681d..efe63d3 100644 --- a/etc/scan.YYYYMMDD +++ b/etc/scan.YYYYMMDD @@ -3,8 +3,8 @@ %; Like scan.default, but the date is printed in YYYY-MM-DD format rather than %; MM/DD. %; -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %4(year{date})-%02(mon{date})-%02(mday{date})%<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%> +%(decode{subject}) diff --git a/etc/scan.default b/etc/scan.default deleted file mode 100644 index f898e86..0000000 --- a/etc/scan.default +++ /dev/null @@ -1,11 +0,0 @@ -%; scan.default -%; -%; This file is supplied for reference only; it shows the default -%; format string (for non-UK sites) which was compiled into the -%; command "scan". See the source file "h/scansbr.h" for details. -%; -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ -%02(mon{date})/%02(mday{date})%<{date} %|*%>\ -%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ -%<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%> diff --git a/etc/scan.mailx b/etc/scan.mailx index 27d18d3..4f00a3c 100644 --- a/etc/scan.mailx +++ b/etc/scan.mailx @@ -1,6 +1,6 @@ %<(cur)>%| %>\ %<{status} %|N%>\ -%<{replied}R%?{encrypted}E%| %>\ +%<{replied}R%| %>\ %4(msg) \ %<(mymbox{from})%<{to}To: %13(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ diff --git a/etc/scan.meillo b/etc/scan.meillo new file mode 100644 index 0000000..53f7bb9 --- /dev/null +++ b/etc/scan.meillo @@ -0,0 +1,21 @@ +%; scan.meillo +%; +%; The listing format I use myself. +%; +%4(year{date})-%02(mon{date})-%02(mday{date}) %02(hour{date}):%02(min{date})\ + \ +%<(unseen)u%| %>\ +%<{replied}r%| %>\ +%<{forwarded}f%| %>\ +%(void(msg))%<(gt 9999)%(msg)%|%4(msg)%>\ + \ +%<(cur)*%| %>\ + \ +%<(mymbox{from})%<{to}-> %17(decode(friendly{to}))%>%>\ +%<(zero)%20(decode(friendly{from}))%>\ + \ +%;(void(size))%<(gt 1000)%4(divide 1000)%|%4(size)b%>) +%(void(size))%4(divide 1024)\ +%<{mime-version} %|~%>\ + \ +%(decode{subject}) diff --git a/etc/scan.nmh b/etc/scan.nmh new file mode 100644 index 0000000..019bc3e --- /dev/null +++ b/etc/scan.nmh @@ -0,0 +1,9 @@ +%; scan.nmh +%; +%; This is nmh's default format string (for non-UK sites). +%; +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ +%02(mon{date})/%02(mday{date})%<{date} %|*%>\ +%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ +%<(zero)%17(decode(friendly{from}))%> \ +%(decode{subject}) diff --git a/etc/scan.nomime b/etc/scan.nomime index 8e2cedf..c6ead71 100644 --- a/etc/scan.nomime +++ b/etc/scan.nomime @@ -4,7 +4,7 @@ %; format for scan, that doesn't do any RFC-2047 decoding of %; header components. %; -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %02(mon{date})/%02(mday{date})%<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(friendly{to})%>%>%<(zero)%17(friendly{from})%> \ -%{subject}%<{body}<<%{body}>>%> +%{subject} diff --git a/etc/scan.size b/etc/scan.size index a6b6698..d595f7a 100644 --- a/etc/scan.size +++ b/etc/scan.size @@ -1,6 +1,6 @@ -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %02(mon{date})/%02(mday{date})%<{date} %|*%>\ %5(size) \ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}%> +%(decode{subject}) diff --git a/etc/scan.time b/etc/scan.time index ee54a52..99df666 100644 --- a/etc/scan.time +++ b/etc/scan.time @@ -1,7 +1,7 @@ -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %02(mon{date})/%02(mday{date}) \ %02(hour{date}):%02(min{date})%3(tzone{date})\ %<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}%> +%(decode{subject}) diff --git a/etc/scan.timely b/etc/scan.timely index 06c068c..d8e07be 100644 --- a/etc/scan.timely +++ b/etc/scan.timely @@ -1,4 +1,4 @@ -%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ %(void(rclock{date}))\ %<(gt 15768000)%03(month{date})%(void(year{date}))%02(modulo 100)\ %?(gt 604800)%02(mday{date})%03(month{date})\ @@ -7,4 +7,4 @@ %<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}%> +%(decode{subject}) diff --git a/etc/scan.unseen b/etc/scan.unseen index d1cd195..ba1fee3 100644 --- a/etc/scan.unseen +++ b/etc/scan.unseen @@ -1,5 +1,5 @@ -%4(msg)%<(cur)+%| %>%<(unseen)U%| %>%<{replied}-%?{encrypted}E%| %>\ +%4(msg)%<(cur)+%| %>%<(unseen)U%| %>%<{replied}-%| %>\ %02(mon{date})/%02(mday{date})%<{date} %|*%>\ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ %<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%> +%(decode{subject}) diff --git a/etc/sendfiles.in b/etc/sendfiles.in deleted file mode 100755 index 85ec6f0..0000000 --- a/etc/sendfiles.in +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh -# -# Send multiples files and/or directories as a tar/compressed -# image, in a MIME message. -# - -DELAY=0 -FROM= - -# compression method (none, gzip or compress) -METHOD=none -# compression filter -COMPRESS=cat -# uncompression filter -UNCOMPRESS=cat -# compression description to append to content-type -CONVERSION= - -# default compression method based on installed software -# prefer compress over gzip for backward compatibility -if command -v compress >/dev/null 2>&1 ; then - METHOD=compress -elif command -v gzip >/dev/null 2>&1 ; then - METHOD=gzip -fi - -# handle command-line options to override compression method and delay -while [ $# -gt 3 ]; do - case "$1" in - -gzip) METHOD=gzip - shift - ;; - -compress) METHOD=compress - shift - ;; - -none) METHOD=none - shift - ;; - -*) DELAY="`echo $1 | sed -e 's%-%%'`" - shift - ;; - *) break - ;; - esac -done - -# set variables based on chosen compression method -if [ $METHOD = compress ]; then - COMPRESS=compress - UNCOMPRESS=uncompress - CONVERSION="; x-conversions=compress" -elif [ $METHOD = gzip ]; then - COMPRESS="gzip -c" - UNCOMPRESS="gzip -dc" - CONVERSION="; x-conversions=gzip" -fi - -if [ ! -z "$PERSON" ]; then - FROM="-from $PERSON" -fi - -if [ $# -lt 3 ]; then - echo 'usage: sendfiles: "mailpath" "subject-string" directory-or-file ...' 1>&2 - exit 1; -fi - -mailpath="$1" -echo "mailpath = $mailpath" 1>&2 -shift - -subject="$1" -echo "subject-string = $subject" 1>&2 -shift - -echo "files = $*" 1>&2 - -tar cvf - "$@" | $COMPRESS | \ - %libdir%/viamail -to "$mailpath" -subject "$subject" \ - -parameters "type=tar$CONVERSION" \ - -comment "extract with $UNCOMPRESS | tar xvpf -" \ - -delay "$DELAY" \ - -verbose $FROM diff --git a/h/Makefile.in b/h/Makefile.in index b616524..78db70b 100644 --- a/h/Makefile.in +++ b/h/Makefile.in @@ -8,10 +8,10 @@ srcdir = @srcdir@ VPATH = @srcdir@ # header files included in distribution -HDRS = addrsbr.h aliasbr.h crawl_folders.h dropsbr.h fmt_compile.h fmt_scan.h \ - md5.h mf.h mh.h mhcachesbr.h mhparse.h mime.h msh.h mts.h \ - netdb.h nmh.h picksbr.h popsbr.h prototypes.h rcvmail.h \ - scansbr.h signals.h tws.h vmhsbr.h utils.h +HDRS = addrsbr.h aliasbr.h crawl_folders.h dropsbr.h fmt_compile.h \ + fmt_scan.h mf.h mh.h mhparse.h mime.h \ + nmh.h prototypes.h rcvmail.h \ + scansbr.h signals.h tws.h utils.h # auxiliary files AUX = Makefile.in @@ -49,11 +49,10 @@ subdir = h Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ done - diff --git a/h/addrsbr.h b/h/addrsbr.h index a6c7a41..a86a90d 100644 --- a/h/addrsbr.h +++ b/h/addrsbr.h @@ -1,40 +1,36 @@ - /* - * addrsbr.h -- definitions for the address parsing system - */ +** addrsbr.h -- definitions for the address parsing system +*/ -#define AD_HOST 1 /* getm(): lookup official hostname */ -#define AD_NHST 0 /* getm(): do not lookup official name */ -#define AD_NAME AD_NHST /* AD_HOST is TOO slow */ +#define AD_HOST 1 /* getm(): lookup official hostname */ +#define AD_NHST 0 /* getm(): do not lookup official name */ +#define AD_NAME AD_NHST /* AD_HOST is TOO slow */ -#define UUCPHOST (-1) -#define LOCALHOST 0 -#define NETHOST 1 -#define BADHOST 2 +#define LOCALHOST 0 +#define NETHOST 1 +#define BADHOST 2 struct mailname { - struct mailname *m_next; - char *m_text; - char *m_pers; - char *m_mbox; - char *m_host; - char *m_path; - int m_type; - char m_nohost; - char m_bcc; - int m_ingrp; - char *m_gname; - char *m_note; + struct mailname *m_next; + char *m_text; + char *m_pers; + char *m_mbox; + char *m_host; + char *m_path; + int m_type; + char m_nohost; + char m_bcc; + int m_ingrp; + char *m_gname; + char *m_note; }; -#define adrformat(m) auxformat ((m), 1) /* - * prototypes - */ +** prototypes +*/ void mnfree(struct mailname *); int ismymbox(struct mailname *); char *getname(char *); -char *adrsprintf(char *, char *); -char *auxformat(struct mailname *, int); +char *adrformat(struct mailname *); struct mailname *getm(char *, char *, int, int, char *); diff --git a/h/aliasbr.h b/h/aliasbr.h index cc4da7f..759c9a7 100644 --- a/h/aliasbr.h +++ b/h/aliasbr.h @@ -1,61 +1,49 @@ - /* - * aliasbr.h -- definitions for the aliasing system - * - */ - -extern char *AliasFile; /* mh-alias(5) */ -#define PASSWD "/etc/passwd" /* passwd(5) */ -#define GROUP "/etc/group" /* group(5) */ -#define EVERYONE 200 /* lowest uid for everyone */ +** aliasbr.h -- definitions for the aliasing system +*/ struct aka { - char *ak_name; /* name to match against */ - struct adr *ak_addr; /* list of addresses that it maps to */ - struct aka *ak_next; /* next aka in list */ - char ak_visible; /* should be visible in headers */ + char *ak_name; /* name to match against */ + struct adr *ak_addr; /* list of addresses that it maps to */ + struct aka *ak_next; /* next aka in list */ + char ak_visible; /* should be visible in headers */ }; struct adr { - char *ad_text; /* text of this address in list */ - struct adr *ad_next; /* next adr in list */ - char ad_local; /* text is local (check for expansion) */ + char *ad_text; /* text of this address in list */ + struct adr *ad_next; /* next adr in list */ + char ad_local; /* text is local (check for expansion) */ }; /* - * incore version of /etc/passwd - */ +** incore version of /etc/passwd +*/ struct home { - char *h_name; /* user name */ - uid_t h_uid; /* user id */ - gid_t h_gid; /* user's group */ - char *h_home; /* user's home directory */ - char *h_shell; /* user's shell */ - int h_ngrps; /* number of groups this user belongs to */ - struct home *h_next; /* next home in list */ + char *h_name; /* user name */ + uid_t h_uid; /* user id */ + gid_t h_gid; /* user's group */ + char *h_home; /* user's home directory */ + char *h_shell; /* user's shell */ + int h_ngrps; /* number of groups this user belongs to */ + struct home *h_next; /* next home in list */ }; -struct home *seek_home (char *); +struct home *seek_home(char *); /* - * prototypes - */ -int alias (char *); -int akvisible (void); -void init_pw (void); -char *akresult (struct aka *); -char *akvalue (char *); -char *akerror (int); +** prototypes +*/ +int alias(char *); +int akvisible(void); +void init_pw(void); +char *akresult(struct aka *); +char *akvalue(char *); +char *akerror(int); /* codes returned by alias() */ -#define AK_OK 0 /* file parsed ok */ -#define AK_NOFILE 1 /* couldn't read file */ -#define AK_ERROR 2 /* error parsing file */ -#define AK_LIMIT 3 /* memory limit exceeded */ -#define AK_NOGROUP 4 /* no such group */ - -/* should live here, not in mts.c */ - -extern int Everyone; -extern char *NoShell; +#define AK_OK 0 /* file parsed ok */ +#define AK_NOFILE 1 /* couldn't read file */ +#define AK_ERROR 2 /* error parsing file */ +#define AK_LIMIT 3 /* memory limit exceeded */ +#define AK_NOGROUP 4 /* no such group */ diff --git a/h/crawl_folders.h b/h/crawl_folders.h index 51fc882..afc249c 100644 --- a/h/crawl_folders.h +++ b/h/crawl_folders.h @@ -1,16 +1,19 @@ - /* - * crawl_folders.h -- crawl folder hierarchy - */ +** crawl_folders.h -- crawl folder hierarchy +*/ #define CRAWL_NUMFOLDERS 100 -/* Callbacks return TRUE crawl_folders should crawl the children of `folder'. - * Callbacks need not duplicate folder, as crawl_folders does not free it. */ +/* +** Callbacks return TRUE crawl_folders should crawl the children of `folder'. +** Callbacks need not duplicate folder, as crawl_folders does not free it. +*/ typedef boolean (crawl_callback_t)(char *folder, void *baton); -/* Crawl the folder hierarchy rooted at the relative path `dir'. For each - * folder, pass `callback' the folder name (as a path relative to the current - * directory) and `baton'; the callback may direct crawl_folders not to crawl - * its children; see above. */ -void crawl_folders (char *dir, crawl_callback_t *callback, void *baton); +/* +** Crawl the folder hierarchy rooted at the relative path `dir'. For each +** folder, pass `callback' the folder name (as a path relative to the current +** directory) and `baton'; the callback may direct crawl_folders not to crawl +** its children; see above. +*/ +void crawl_folders(char *dir, crawl_callback_t *callback, void *baton); diff --git a/h/dropsbr.h b/h/dropsbr.h index 5a84ae1..f3270be 100644 --- a/h/dropsbr.h +++ b/h/dropsbr.h @@ -1,57 +1,10 @@ - -/* - * dropsbr.h -- definitions for maildrop-style files - */ - -/* - * A file which is formatted like a maildrop may have a corresponding map - * file which is an index to the bounds of each message. The first record - * of such an map is special, it contains: - * - * d_id = number of messages in file - * d_size = version number of map - * d_start = last message read - * d_stop = size of file - * - * Each record after that contains: - * - * d_id = BBoard-ID: of message, or similar info - * d_size = size of message in ARPA Internet octets (\n == 2 octets) - * d_start = starting position of message in file - * d_stop = stopping position of message in file - * - * Note that d_start/d_stop do NOT include the message delimiters, so - * programs using the map can simply fseek to d_start and keep reading - * until the position is at d_stop. - */ - /* - * various formats for maildrop files - */ -#define OTHER_FORMAT 0 -#define MBOX_FORMAT 1 -#define MMDF_FORMAT 2 - -#define DRVRSN 3 - -struct drop { - int d_id; - int d_size; - off_t d_start; - off_t d_stop; -}; +** dropsbr.h -- definitions for maildrop-style files +*/ /* - * prototypes - */ -int mbx_open (char *, int, uid_t, gid_t, mode_t); -int mbx_read (FILE *, long, struct drop **, int); -int mbx_write(char *, int, FILE *, int, long, long, off_t, int, int); -int mbx_copy (char *, int, int, int, int, char *, int); -int mbx_size (int, off_t, off_t); -int mbx_close (char *, int); -char *map_name (char *); -int map_read (char *, long, struct drop **, int); -int map_write (char *, int, int, long, off_t, off_t, long, int, int); -int map_chk (char *, int, struct drop *, long, int); - +** prototypes +*/ +int mbox_open(char *, uid_t, gid_t, mode_t); +int mbox_copy(int, int); +int mbox_close(char *, int); diff --git a/h/fmt_compile.h b/h/fmt_compile.h index 22be450..a84efae 100644 --- a/h/fmt_compile.h +++ b/h/fmt_compile.h @@ -1,108 +1,104 @@ - /* - * fmt_compile.h -- format types - */ +** fmt_compile.h -- format types +*/ /* types that output text */ -#define FT_COMP 1 /* the text of a component */ -#define FT_COMPF 2 /* comp text, filled */ -#define FT_LIT 3 /* literal text */ -#define FT_LITF 4 /* literal text, filled */ -#define FT_CHAR 5 /* a single ascii character */ -#define FT_NUM 6 /* "value" as decimal number */ -#define FT_NUMF 7 /* "value" as filled dec number */ -#define FT_STR 8 /* "str" as text */ -#define FT_STRF 9 /* "str" as text, filled */ -#define FT_STRFW 10 /* "str" as text, filled, width in "value" */ -#define FT_PUTADDR 11 /* split and print address line */ +#define FT_COMP 1 /* the text of a component */ +#define FT_COMPF 2 /* comp text, filled */ +#define FT_LIT 3 /* literal text */ +#define FT_LITF 4 /* literal text, filled */ +#define FT_CHAR 5 /* a single ascii character */ +#define FT_NUM 6 /* "value" as decimal number */ +#define FT_NUMF 7 /* "value" as filled dec number */ +#define FT_STR 8 /* "str" as text */ +#define FT_STRF 9 /* "str" as text, filled */ +#define FT_STRFW 10 /* "str" as text, filled, width in "value" */ +#define FT_PUTADDR 11 /* split and print address line */ -/* types that modify the "str" or "value" registers */ -#define FT_LS_COMP 12 /* set "str" to component text */ -#define FT_LS_LIT 13 /* set "str" to literal text */ -#define FT_LS_GETENV 14 /* set "str" to getenv(text) */ -#define FT_LS_CFIND 15 /* set "str" to context_find(text) */ -#define FT_LS_DECODECOMP 16 /* set "str" to decoded component text */ -#define FT_LS_DECODE 17 /* decode "str" as RFC-2047 header */ -#define FT_LS_TRIM 18 /* trim trailing white space from "str" */ -#define FT_LV_COMP 19 /* set "value" to comp (as dec. num) */ -#define FT_LV_COMPFLAG 20 /* set "value" to comp flag word */ -#define FT_LV_LIT 21 /* set "value" to literal num */ -#define FT_LV_DAT 22 /* set "value" to dat[n] */ -#define FT_LV_STRLEN 23 /* set "value" to length of "str" */ -#define FT_LV_PLUS_L 24 /* set "value" += literal */ -#define FT_LV_MINUS_L 25 /* set "value" -= literal */ -#define FT_LV_DIVIDE_L 26 /* set "value" to value / literal */ -#define FT_LV_MODULO_L 27 /* set "value" to value % literal */ -#define FT_LV_CHAR_LEFT 28 /* set "value" to char left in output */ +/* types that modify the "str" or "value" registers */ +#define FT_LS_COMP 12 /* set "str" to component text */ +#define FT_LS_LIT 13 /* set "str" to literal text */ +#define FT_LS_GETENV 14 /* set "str" to getenv(text) */ +#define FT_LS_CFIND 15 /* set "str" to context_find(text) */ +#define FT_LS_DECODECOMP 16 /* set "str" to decoded component text */ +#define FT_LS_DECODE 17 /* decode "str" as RFC-2047 header */ +#define FT_LS_TRIM 18 /* trim trailing white space from "str" */ +#define FT_LV_COMP 19 /* set "value" to comp (as dec. num) */ +#define FT_LV_COMPFLAG 20 /* set "value" to comp flag word */ +#define FT_LV_LIT 21 /* set "value" to literal num */ +#define FT_LV_DAT 22 /* set "value" to dat[n] */ +#define FT_LV_STRLEN 23 /* set "value" to length of "str" */ +#define FT_LV_PLUS_L 24 /* set "value" += literal */ +#define FT_LV_MINUS_L 25 /* set "value" -= literal */ +#define FT_LV_DIVIDE_L 26 /* set "value" to value / literal */ +#define FT_LV_MODULO_L 27 /* set "value" to value % literal */ +#define FT_LV_CHAR_LEFT 28 /* set "value" to char left in output */ -#define FT_LS_MONTH 29 /* set "str" to tws month */ -#define FT_LS_LMONTH 30 /* set "str" to long tws month */ -#define FT_LS_ZONE 31 /* set "str" to tws timezone */ -#define FT_LS_DAY 32 /* set "str" to tws weekday */ -#define FT_LS_WEEKDAY 33 /* set "str" to long tws weekday */ -#define FT_LS_822DATE 34 /* set "str" to 822 date str */ -#define FT_LS_PRETTY 35 /* set "str" to pretty (?) date str */ -#define FT_LV_SEC 36 /* set "value" to tws second */ -#define FT_LV_MIN 37 /* set "value" to tws minute */ -#define FT_LV_HOUR 38 /* set "value" to tws hour */ -#define FT_LV_MDAY 39 /* set "value" to tws day of month */ -#define FT_LV_MON 40 /* set "value" to tws month */ -#define FT_LV_YEAR 41 /* set "value" to tws year */ -#define FT_LV_YDAY 42 /* set "value" to tws day of year */ -#define FT_LV_WDAY 43 /* set "value" to tws weekday */ -#define FT_LV_ZONE 44 /* set "value" to tws timezone */ -#define FT_LV_CLOCK 45 /* set "value" to tws clock */ -#define FT_LV_RCLOCK 46 /* set "value" to now - tws clock */ -#define FT_LV_DAYF 47 /* set "value" to tws day flag */ -#define FT_LV_DST 48 /* set "value" to tws daylight savings flag */ -#define FT_LV_ZONEF 49 /* set "value" to tws timezone flag */ +#define FT_LS_MONTH 29 /* set "str" to tws month */ +#define FT_LS_LMONTH 30 /* set "str" to long tws month */ +#define FT_LS_ZONE 31 /* set "str" to tws timezone */ +#define FT_LS_DAY 32 /* set "str" to tws weekday */ +#define FT_LS_WEEKDAY 33 /* set "str" to long tws weekday */ +#define FT_LS_822DATE 34 /* set "str" to 822 date str */ +#define FT_LS_PRETTY 35 /* set "str" to pretty (?) date str */ +#define FT_LV_SEC 36 /* set "value" to tws second */ +#define FT_LV_MIN 37 /* set "value" to tws minute */ +#define FT_LV_HOUR 38 /* set "value" to tws hour */ +#define FT_LV_MDAY 39 /* set "value" to tws day of month */ +#define FT_LV_MON 40 /* set "value" to tws month */ +#define FT_LV_YEAR 41 /* set "value" to tws year */ +#define FT_LV_YDAY 42 /* set "value" to tws day of year */ +#define FT_LV_WDAY 43 /* set "value" to tws weekday */ +#define FT_LV_ZONE 44 /* set "value" to tws timezone */ +#define FT_LV_CLOCK 45 /* set "value" to tws clock */ +#define FT_LV_RCLOCK 46 /* set "value" to now - tws clock */ +#define FT_LV_DAYF 47 /* set "value" to tws day flag */ +#define FT_LV_DST 48 /* set "value" to tws daylight savings flag */ +#define FT_LV_ZONEF 49 /* set "value" to tws timezone flag */ -#define FT_LS_PERS 50 /* set "str" to person part of addr */ -#define FT_LS_MBOX 51 /* set "str" to mbox part of addr */ -#define FT_LS_HOST 52 /* set "str" to host part of addr */ -#define FT_LS_PATH 53 /* set "str" to route part of addr */ -#define FT_LS_GNAME 54 /* set "str" to group part of addr */ -#define FT_LS_NOTE 55 /* set "str" to comment part of addr */ -#define FT_LS_ADDR 56 /* set "str" to mbox@host */ -#define FT_LS_822ADDR 57 /* set "str" to 822 format addr */ -#define FT_LS_FRIENDLY 58 /* set "str" to "friendly" format addr */ -#define FT_LV_HOSTTYPE 59 /* set "value" to addr host type */ -#define FT_LV_INGRPF 60 /* set "value" to addr in-group flag */ -#define FT_LS_UNQUOTE 61 /* remove RFC 2822 quotes from "str" */ -#define FT_LV_NOHOSTF 62 /* set "value" to addr no-host flag */ +#define FT_LS_PERS 50 /* set "str" to person part of addr */ +#define FT_LS_MBOX 51 /* set "str" to mbox part of addr */ +#define FT_LS_HOST 52 /* set "str" to host part of addr */ +#define FT_LS_PATH 53 /* set "str" to route part of addr */ +#define FT_LS_GNAME 54 /* set "str" to group part of addr */ +#define FT_LS_NOTE 55 /* set "str" to comment part of addr */ +#define FT_LS_ADDR 56 /* set "str" to mbox@host */ +#define FT_LS_822ADDR 57 /* set "str" to 822 format addr */ +#define FT_LS_FRIENDLY 58 /* set "str" to "friendly" format addr */ +#define FT_LV_HOSTTYPE 59 /* set "value" to addr host type */ +#define FT_LV_INGRPF 60 /* set "value" to addr in-group flag */ +#define FT_LS_UNQUOTE 61 /* remove RFC 2822 quotes from "str" */ +#define FT_LV_NOHOSTF 62 /* set "value" to addr no-host flag */ /* Date Coercion */ -#define FT_LOCALDATE 63 /* Coerce date to local timezone */ -#define FT_GMTDATE 64 /* Coerce date to gmt */ +#define FT_LOCALDATE 63 /* Coerce date to local timezone */ +#define FT_GMTDATE 64 /* Coerce date to gmt */ /* pre-format processing */ -#define FT_PARSEDATE 65 /* parse comp into a date (tws) struct */ -#define FT_PARSEADDR 66 /* parse comp into a mailaddr struct */ -#define FT_FORMATADDR 67 /* let external routine format addr */ -#define FT_MYMBOX 68 /* do "mymbox" test on comp */ - -/* misc. */ /* ADDTOSEQ only works if you include "options LBL" */ -#define FT_ADDTOSEQ 69 /* add current msg to a sequence */ +#define FT_PARSEDATE 65 /* parse comp into a date (tws) struct */ +#define FT_PARSEADDR 66 /* parse comp into a mailaddr struct */ +#define FT_FORMATADDR 67 /* let external routine format addr */ +#define FT_MYMBOX 68 /* do "mymbox" test on comp */ /* conditionals & control flow (must be last) */ -#define FT_SAVESTR 70 /* save current str reg */ -#define FT_DONE 71 /* stop formatting */ -#define FT_PAUSE 72 /* pause */ -#define FT_NOP 73 /* nop */ -#define FT_GOTO 74 /* (relative) goto */ -#define FT_IF_S_NULL 75 /* test if "str" null */ -#define FT_IF_S 76 /* test if "str" non-null */ -#define FT_IF_V_EQ 77 /* test if "value" = literal */ -#define FT_IF_V_NE 78 /* test if "value" != literal */ -#define FT_IF_V_GT 79 /* test if "value" > literal */ -#define FT_IF_MATCH 80 /* test if "str" contains literal */ -#define FT_IF_AMATCH 81 /* test if "str" starts with literal */ -#define FT_S_NULL 82 /* V = 1 if "str" null */ -#define FT_S_NONNULL 83 /* V = 1 if "str" non-null */ -#define FT_V_EQ 84 /* V = 1 if "value" = literal */ -#define FT_V_NE 85 /* V = 1 if "value" != literal */ -#define FT_V_GT 86 /* V = 1 if "value" > literal */ -#define FT_V_MATCH 87 /* V = 1 if "str" contains literal */ -#define FT_V_AMATCH 88 /* V = 1 if "str" starts with literal */ +#define FT_SAVESTR 70 /* save current str reg */ +#define FT_DONE 71 /* stop formatting */ +#define FT_PAUSE 72 /* pause */ +#define FT_NOP 73 /* nop */ +#define FT_GOTO 74 /* (relative) goto */ +#define FT_IF_S_NULL 75 /* test if "str" null */ +#define FT_IF_S 76 /* test if "str" non-null */ +#define FT_IF_V_EQ 77 /* test if "value" = literal */ +#define FT_IF_V_NE 78 /* test if "value" != literal */ +#define FT_IF_V_GT 79 /* test if "value" > literal */ +#define FT_IF_MATCH 80 /* test if "str" contains literal */ +#define FT_IF_AMATCH 81 /* test if "str" starts with literal */ +#define FT_S_NULL 82 /* V = 1 if "str" null */ +#define FT_S_NONNULL 83 /* V = 1 if "str" non-null */ +#define FT_V_EQ 84 /* V = 1 if "value" = literal */ +#define FT_V_NE 85 /* V = 1 if "value" != literal */ +#define FT_V_GT 86 /* V = 1 if "value" > literal */ +#define FT_V_MATCH 87 /* V = 1 if "str" contains literal */ +#define FT_V_AMATCH 88 /* V = 1 if "str" starts with literal */ -#define IF_FUNCS FT_S_NULL /* start of "if" functions */ +#define IF_FUNCS FT_S_NULL /* start of "if" functions */ diff --git a/h/fmt_scan.h b/h/fmt_scan.h index 9872e09..d7f43af 100644 --- a/h/fmt_scan.h +++ b/h/fmt_scan.h @@ -1,84 +1,83 @@ - /* - * fmt_scan.h -- definitions for fmt_scan() - */ +** fmt_scan.h -- definitions for fmt_scan() +*/ /* - * This structure describes an "interesting" component. It holds - * the name & text from the component (if found) and one piece of - * auxilary info. The structure for a particular component is located - * by (open) hashing the name and using it as an index into the ptr array - * "wantcomp". All format entries that reference a particular component - * point to its comp struct (so we only have to do component specific - * processing once. e.g., parse an address.). - */ +** This structure describes an "interesting" component. It holds +** the name & text from the component (if found) and one piece of +** auxilary info. The structure for a particular component is located +** by (open) hashing the name and using it as an index into the ptr array +** "wantcomp". All format entries that reference a particular component +** point to its comp struct (so we only have to do component specific +** processing once. e.g., parse an address.). +*/ struct comp { - char *c_name; /* component name (in lower case) */ - char *c_text; /* component text (if found) */ - struct comp *c_next; /* hash chain linkage */ - short c_flags; /* misc. flags (from fmt_scan) */ - short c_type; /* type info (from fmt_compile) */ - union { - struct tws *c_u_tws; - struct mailname *c_u_mn; - } c_un; + char *c_name; /* component name (in lower case) */ + char *c_text; /* component text (if found) */ + struct comp *c_next; /* hash chain linkage */ + short c_flags; /* misc. flags (from fmt_scan) */ + short c_type; /* type info (from fmt_compile) */ + union { + struct tws *c_u_tws; + struct mailname *c_u_mn; + } c_un; }; #define c_tws c_un.c_u_tws #define c_mn c_un.c_u_mn /* - * c_type bits - */ -#define CT_ADDR (1<<0) /* referenced as address */ -#define CT_DATE (1<<1) /* referenced as date */ +** c_type bits +*/ +#define CT_ADDR (1<<0) /* referenced as address */ +#define CT_DATE (1<<1) /* referenced as date */ /* - * c_flags bits - */ -#define CF_TRUE (1<<0) /* usually means component is present */ -#define CF_PARSED (1<<1) /* address/date has been parsed */ -#define CF_DATEFAB (1<<2) /* datefield fabricated */ +** c_flags bits +*/ +#define CF_TRUE (1<<0) /* usually means component is present */ +#define CF_PARSED (1<<1) /* address/date has been parsed */ +#define CF_DATEFAB (1<<2) /* datefield fabricated */ extern int fmt_norm; /* - * Hash table for deciding if a component is "interesting". - */ +** Hash table for deciding if a component is "interesting". +*/ extern struct comp *wantcomp[128]; -/* - * Hash function for component name. The function should be - * case independent and probably shouldn't involve a routine - * call. This function is pretty good but will not work on - * single character component names. - */ -#define CHASH(nm) (((((nm)[0]) - ((nm)[1])) & 0x1f) + (((nm)[2]) & 0x5f)) +/* +** Hash function for component name. The function should be +** case independent and probably shouldn't involve a routine +** call. This function is pretty good but will not work on +** single character component names. +*/ +#define CHASH(nm) (((((nm)[0]) - ((nm)[1])) & 0x1f) + (((nm)[2]) & 0x5f)) /* - * Find a component in the hash table. - */ +** Find a component in the hash table. +*/ #define FINDCOMP(comp,name) \ for (comp = wantcomp[CHASH(name)]; \ - comp && strcmp(comp->c_name,name); \ - comp = comp->c_next) ; + comp && strcmp(comp->c_name,name)!=0; \ + comp = comp->c_next) ; /* - * This structure defines one formatting instruction. - */ +** This structure defines one formatting instruction. +*/ struct format { - unsigned char f_type; - char f_fill; - short f_width; /* output field width */ - union { - struct comp *f_u_comp; /* associated component */ - char *f_u_text; /* literal text */ - char f_u_char; /* literal character */ - int f_u_value; /* literal value */ - } f_un; + unsigned char f_type; + char f_fill; + short f_width; /* output field width */ + union { + struct comp *f_u_comp; /* associated component */ + char *f_u_text; /* literal text */ + char f_u_char; /* literal character */ + int f_u_value; /* literal value */ + } f_un; }; -#define f_skip f_width /* instr to skip (false "if") */ +#define f_skip f_width /* instr to skip (false "if") */ #define f_comp f_un.f_u_comp #define f_text f_un.f_u_text @@ -86,8 +85,8 @@ struct format { #define f_value f_un.f_u_value /* - * prototypes - */ -struct format *fmt_scan (struct format *, char *, int, int *); -char *new_fs (char *, char *, char *); -int fmt_compile (char *, struct format **); +** prototypes +*/ +struct format *fmt_scan(struct format *, char *, int, int *); +int fmt_compile(char *, struct format **); +char *formataddr(char *, char *); diff --git a/h/md5.h b/h/md5.h deleted file mode 100644 index e49ef4e..0000000 --- a/h/md5.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * md5.h -- header file for md5 message digest - * taken from RFC-1321/Appendices A.1/A.2 - */ - -/* - * RSAREF types and constants - */ - -/* - * Use include for nmh/mh - */ - -#include - -/* - * Use prototypes for nmh/mh - */ -#define PROTOTYPES 1 - -/* - * PROTOTYPES should be set to one if and only if the compiler - * supports function argument prototyping. The following makes - * PROTOTYPES default to 0 if it has not already been defined - * with C compiler flags. - */ -#ifndef PROTOTYPES -#define PROTOTYPES 0 -#endif - -/* POINTER defines a generic pointer type */ -typedef unsigned char *POINTER; - -/* UINT2 defines a two byte word */ -typedef unsigned short int UINT2; - -/* UINT4 defines a four byte word */ -typedef unsigned long int UINT4; - -/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. -If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it - returns an empty list. - */ -#if PROTOTYPES -#define PROTO_LIST(list) list -#else -#define PROTO_LIST(list) () -#endif - -/* MD5.H - header file for MD5C.C - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* MD5 context. */ -typedef struct { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; - -void MD5Init PROTO_LIST ((MD5_CTX *)); -void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); -void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); - diff --git a/h/mf.h b/h/mf.h index 6063e60..75245e0 100644 --- a/h/mf.h +++ b/h/mf.h @@ -1,80 +1,45 @@ - /* - * mf.h -- include file for mailbox filters - */ +** mf.h -- include file for mailbox filters +*/ #include -#ifndef TRUE +#ifndef TRUE # define TRUE 1 #endif -#ifndef FALSE +#ifndef FALSE # define FALSE 0 #endif -#ifndef NOTOK +#ifndef NOTOK # define NOTOK (-1) #endif -#ifndef OK +#ifndef OK # define OK 0 #endif -#ifndef DONE +#ifndef DONE # define DONE 1 #endif -#define LINESIZ 512 - -#define MBXMODE 0600 -#define TMPMODE 0600 - -#define OWIDTH 75 /* length of a header line */ - -#define HFROM 1 /* header has From: component */ -#define HSNDR 2 /* header has Sender: component */ -#define HADDR 3 /* header has address component */ -#define HDATE 4 /* header has Date: component */ -#define HOTHR 5 /* header is unimportant */ - struct adrx { - char *text; - char *pers; - char *mbox; - char *host; - char *path; - char *grp; - int ingrp; - char *note; - char *err; + char *text; + char *pers; + char *mbox; + char *host; + char *path; + char *grp; + int ingrp; + char *note; + char *err; }; -/* - * Codes returned by uucp2mmdf(), mmdf2uucp() - */ - -#define MFOK 0 /* all went well */ - /* remaining codes must > DONE */ -#define MFPRM 2 /* bad parameter */ -#define MFSIO 3 /* stdio package went screwy */ -#define MFROM 4 /* from line was bad */ -#define MFHDR 5 /* headers were bad */ -#define MFTXT 6 /* text was bad */ -#define MFERR 7 /* I/O or system error */ -#define MFDLM 8 /* Bad delimiter in MMDF file */ - - /* - * prototypes - */ -int isfrom(char *); -int lequal (unsigned char *, unsigned char *); -int mfgets (FILE *, char **); -char *legal_person (char *); -struct adrx *seekadrx (char *); -struct adrx *getadrx (char *); -struct adrx *uucpadrx (char *); - +** prototypes +*/ +char *legal_person(char *); +struct adrx *getadrx(char *); diff --git a/h/mh.h b/h/mh.h index abcf445..1331a14 100644 --- a/h/mh.h +++ b/h/mh.h @@ -1,192 +1,180 @@ - /* - * mh.h -- main header file for all of nmh - */ +** mh.h -- main header file for all of nmh +*/ #include /* - * Well-used constants - */ -#define NOTOK (-1) /* syscall()s return this on error */ -#define OK 0 /* ditto on success */ -#define DONE 1 /* trinary logic */ +** Well-used constants +*/ +#define NOTOK (-1) /* syscall()s return this on error */ +#define OK 0 /* ditto on success */ +#define DONE 1 /* trinary logic */ #define ALL "" -#define Nbby 8 /* number of bits/byte */ +#define Nbby 8 /* number of bits/byte */ -#define MAXARGS 1000 /* max arguments to exec */ -#define NFOLDERS 1000 /* max folder arguments on command line */ -#define DMAXFOLDER 4 /* typical number of digits */ -#define MAXFOLDER 1000 /* message increment */ +#define MAXARGS 1000 /* max arguments to exec */ +#define NFOLDERS 1000 /* max folder arguments on command line */ +#define DMAXFOLDER 4 /* typical number of digits */ +#define MAXFOLDER 1000 /* message increment */ #ifndef FALSE -#define FALSE 0 +# define FALSE 0 #endif #ifndef TRUE -#define TRUE 1 +# define TRUE 1 #endif typedef unsigned char boolean; /* not int so we can pack in a structure */ /* If we're using gcc then give it some information about - * functions that abort. - */ +** functions that abort. +*/ #if __GNUC__ > 2 -#define NORETURN __attribute__((__noreturn__)) +# define NORETURN __attribute__((__noreturn__)) #else -#define NORETURN +# define NORETURN #endif /* - * user context/profile structure - */ +** user context/profile structure +*/ struct node { - char *n_name; /* key */ - char *n_field; /* value */ - char n_context; /* context, not profile */ - struct node *n_next; /* next entry */ + char *n_name; /* key */ + char *n_field; /* value */ + char n_context; /* context, not profile */ + struct node *n_next; /* next entry */ }; /* - * switches structure - */ -#define AMBIGSW (-2) /* from smatch() on ambiguous switch */ -#define UNKWNSW (-1) /* from smatch() on unknown switch */ +** switches structure +*/ +#define AMBIGSW (-2) /* from smatch() on ambiguous switch */ +#define UNKWNSW (-1) /* from smatch() on unknown switch */ struct swit { - char *sw; - - /* The minchars field is apparently used like this: - - -# : Switch can be abbreviated to # characters; switch hidden in -help. - 0 : Switch can't be abbreviated; switch shown in -help. - # : Switch can be abbreviated to # characters; switch shown in -help. */ - int minchars; + char *sw; + /* + ** The minchars field is apparently used like this: + ** + ** -# : Switch can be abbreviated to # chars; switch hidden in -help. + ** 0 : Switch can't be abbreviated; switch shown in -help. + ** # : Switch can be abbreviated to # chars; switch shown in -help. + */ + int minchars; }; -extern struct swit anoyes[]; /* standard yes/no switches */ - -#define ATTACHFORMATS 3 /* Number of send attach formats. */ +extern struct swit anoyes[]; /* standard yes/no switches */ /* - * general folder attributes - */ -#define READONLY (1<<0) /* No write access to folder */ -#define SEQMOD (1<<1) /* folder's sequences modifed */ -#define ALLOW_NEW (1<<2) /* allow the "new" sequence */ -#define OTHERS (1<<3) /* folder has other files */ -#define MODIFIED (1<<4) /* msh in-core folder modified */ +** general folder attributes +*/ +#define READONLY (1<<0) /* No write access to folder */ +#define SEQMOD (1<<1) /* folder's sequences modifed */ +#define ALLOW_BEYOND (1<<2) /* allow the beyond sequence */ +#define OTHERS (1<<3) /* folder has other files */ -#define FBITS "\020\01READONLY\02SEQMOD\03ALLOW_NEW\04OTHERS\05MODIFIED" +#define FBITS "\020\01READONLY\02SEQMOD\03ALLOW_BEYOND\04OTHERS" /* - * type for holding the sequence set of a message - */ +** type for holding the sequence set of a message +*/ typedef unsigned int seqset_t; /* - * Determine the number of user defined sequences we - * can have. The first 5 sequence flags are for - * internal nmh message flags. - */ -#define NUMATTRS ((sizeof(seqset_t) * Nbby) - 5) +** internal messages attributes (sequences) +*/ +#define EXISTS (1<<0) /* exists */ +#define SELECTED (1<<1) /* selected for use */ +#define SELECT_UNSEEN (1<<2) /* inc/show "unseen" */ -/* - * first free slot for user defined sequences - * and attributes - */ -#define FFATTRSLOT 5 +#define MBITS "\020\01EXISTS\02SELECTED\03UNSEEN" /* - * internal messages attributes (sequences) - */ -#define EXISTS (1<<0) /* exists */ -#define DELETED (1<<1) /* deleted */ -#define SELECTED (1<<2) /* selected for use */ -#define SELECT_EMPTY (1<<3) /* "new" message */ -#define SELECT_UNSEEN (1<<4) /* inc/show "unseen" */ +** first free slot for user-defined sequences +*/ +#define FFATTRSLOT 3 -#define MBITS "\020\01EXISTS\02DELETED\03SELECTED\04NEW\05UNSEEN" +/* +** Determine the number of user defined sequences we +** can have. The first few sequence flags are for +** internal nmh message flags. +*/ +#define NUMATTRS ((sizeof(seqset_t) * Nbby) - FFATTRSLOT) /* - * Primary structure of folder/message information - */ +** Primary structure of folder/message information +*/ struct msgs { - int lowmsg; /* Lowest msg number */ - int hghmsg; /* Highest msg number */ - int nummsg; /* Actual Number of msgs */ - - int lowsel; /* Lowest selected msg number */ - int hghsel; /* Highest selected msg number */ - int numsel; /* Number of msgs selected */ - - int curmsg; /* Number of current msg if any */ - - int msgflags; /* Folder attributes (READONLY, etc) */ - char *foldpath; /* Pathname of folder */ - - /* - * Name of sequences in this folder. We add an - * extra slot, so we can NULL terminate the list. - */ - char *msgattrs[NUMATTRS + 1]; - - /* - * bit flags for whether sequence - * is public (0), or private (1) - */ - seqset_t attrstats; - - /* - * These represent the lowest and highest possible - * message numbers we can put in the message status - * area, without calling folder_realloc(). - */ - int lowoff; - int hghoff; - - /* - * This is an array of seqset_t which we allocate dynamically. - * Each seqset_t is a set of bits flags for a particular message. - * These bit flags represent general attributes such as - * EXISTS, SELECTED, etc. as well as track if message is - * in a particular sequence. - */ - seqset_t *msgstats; /* msg status */ + int lowmsg; /* Lowest msg number */ + int hghmsg; /* Highest msg number */ + int nummsg; /* Actual Number of msgs */ + + int lowsel; /* Lowest selected msg number */ + int hghsel; /* Highest selected msg number */ + int numsel; /* Number of msgs selected */ + + int curmsg; /* Number of current msg if any */ + + int msgflags; /* Folder attributes (READONLY, etc) */ + char *foldpath; /* Pathname of folder */ + + /* + ** Name of sequences in this folder. We add an + ** extra slot, so we can NULL terminate the list. + */ + char *msgattrs[NUMATTRS + 1]; + + /* + ** bit flags for whether sequence + ** is public (0), or private (1) + */ + seqset_t attrstats; + + /* + ** These represent the lowest and highest possible + ** message numbers we can put in the message status + ** area, without calling folder_realloc(). + */ + int lowoff; + int hghoff; + + /* + ** This is an array of seqset_t which we allocate dynamically. + ** Each seqset_t is a set of bits flags for a particular message. + ** These bit flags represent general attributes such as + ** EXISTS, SELECTED, etc. as well as track if message is + ** in a particular sequence. + */ + seqset_t *msgstats; /* msg status */ }; /* - * Amount of space to allocate for msgstats. Allocate - * the array to have space for messages numbers lo to hi. - */ +** Amount of space to allocate for msgstats. Allocate +** the array to have space for messages numbers lo to hi. +*/ #define MSGSTATSIZE(mp,lo,hi) ((size_t) (((hi) - (lo) + 1) * sizeof(*(mp)->msgstats))) /* - * macros for message and sequence manipulation - */ +** macros for message and sequence manipulation +*/ #define clear_msg_flags(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] = 0) #define copy_msg_flags(mp,i,j) \ - ((mp)->msgstats[(i) - mp->lowoff] = (mp)->msgstats[(j) - mp->lowoff]) + ((mp)->msgstats[(i) - mp->lowoff] = (mp)->msgstats[(j) - mp->lowoff]) #define get_msg_flags(mp,ptr,msgnum) (*(ptr) = (mp)->msgstats[(msgnum) - mp->lowoff]) #define set_msg_flags(mp,ptr,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] = *(ptr)) -#define does_exist(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & EXISTS) -#define unset_exists(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~EXISTS) -#define set_exists(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= EXISTS) +#define does_exist(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & EXISTS) +#define unset_exists(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~EXISTS) +#define set_exists(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= EXISTS) -#define is_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECTED) -#define unset_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECTED) -#define set_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECTED) +#define is_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECTED) +#define unset_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECTED) +#define set_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECTED) -#define is_select_empty(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECT_EMPTY) -#define set_select_empty(mp,msgnum) \ - ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECT_EMPTY) +#define is_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECT_UNSEEN) +#define unset_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECT_UNSEEN) +#define set_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECT_UNSEEN) -#define is_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECT_UNSEEN) -#define unset_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECT_UNSEEN) -#define set_unseen(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECT_UNSEEN) - -/* for msh only */ -#define set_deleted(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] |= DELETED) #define in_sequence(mp,seqnum,msgnum) \ ((mp)->msgstats[(msgnum) - mp->lowoff] & (1 << (FFATTRSLOT + seqnum))) @@ -205,66 +193,54 @@ struct msgs { ((mp)->attrstats = 0) /* - * macros for folder attributes - */ +** macros for folder attributes +*/ #define clear_folder_flags(mp) ((mp)->msgflags = 0) -#define is_readonly(mp) ((mp)->msgflags & READONLY) -#define set_readonly(mp) ((mp)->msgflags |= READONLY) +#define is_readonly(mp) ((mp)->msgflags & READONLY) +#define set_readonly(mp) ((mp)->msgflags |= READONLY) -#define other_files(mp) ((mp)->msgflags & OTHERS) -#define set_other_files(mp) ((mp)->msgflags |= OTHERS) +#define other_files(mp) ((mp)->msgflags & OTHERS) +#define set_other_files(mp) ((mp)->msgflags |= OTHERS) -#define NULLMP ((struct msgs *) 0) +#define NULLMP ((struct msgs *) 0) /* - * m_getfld() message parsing - */ - -#define NAMESZ 999 /* Limit on component name size. - RFC 2822 limits line lengths to - 998 characters, so a header name - can be at most that long. - m_getfld limits header names to 2 - less than NAMESZ, which is fine, - because header names must be - followed by a colon. Add one for - terminating NULL. */ - -#define LENERR (-2) /* Name too long error from getfld */ -#define FMTERR (-3) /* Message Format error */ -#define FLD 0 /* Field returned */ -#define FLDPLUS 1 /* Field returned with more to come */ -#define FLDEOF 2 /* Field returned ending at eom */ -#define BODY 3 /* Body returned with more to come */ -#define BODYEOF 4 /* Body returned ending at eom */ -#define FILEEOF 5 /* Reached end of input file */ +** m_getfld() message parsing +*/ + +#define NAMESZ 999 /* + ** Limit on component name size. + ** RFC 2822 limits line lengths to + ** 998 characters, so a header name + ** can be at most that long. + ** m_getfld limits header names to 2 + ** less than NAMESZ, which is fine, + ** because header names must be + ** followed by a colon. Add one for + ** terminating NULL. + */ + +#define LENERR (-2) /* Name too long error from getfld */ +#define FMTERR (-3) /* Message Format error */ +#define FLD 0 /* Field returned */ +#define FLDPLUS 1 /* Field returned with more to come */ +#define FLDEOF 2 /* Field returned ending at eom */ +#define BODY 3 /* Body returned with more to come */ +#define BODYEOF 4 /* Body returned ending at eom */ +#define FILEEOF 5 /* Reached end of input file */ + +extern int msg_count; /* m_getfld() indicators (That's a hack!) */ + +#define NOUSE 0 /* draft being re-used */ + +#define OUTPUTLINELEN 72 /* default line length for headers */ /* - * Maildrop styles - */ -#define MS_DEFAULT 0 /* default (one msg per file) */ -#define MS_UNKNOWN 1 /* type not known yet */ -#define MS_MBOX 2 /* Unix-style "from" lines */ -#define MS_MMDF 3 /* string mmdlm2 */ -#define MS_MSH 4 /* whacko msh */ - -extern int msg_count; /* m_getfld() indicators */ -extern int msg_style; /* .. */ -extern char *msg_delim; /* .. */ +** miscellaneous macros +*/ -#define NOUSE 0 /* draft being re-used */ - -#define TFOLDER 0 /* path() given a +folder */ -#define TFILE 1 /* path() given a file */ -#define TSUBCWF 2 /* path() given a @folder */ - -#define OUTPUTLINELEN 72 /* default line length for headers */ - -/* - * miscellaneous macros - */ -#define pidXwait(pid,cp) pidstatus (pidwait (pid, NOTOK), stdout, cp) +#define pidXwait(pid,cp) pidstatus(pidwait(pid, NOTOK), stdout, cp) #ifndef max # define max(a,b) ((a) > (b) ? (a) : (b)) @@ -274,84 +250,75 @@ extern char *msg_delim; /* .. */ # define min(a,b) ((a) < (b) ? (a) : (b)) #endif -#ifndef abs -# define abs(a) ((a) > 0 ? (a) : -(a)) -#endif - /* - * GLOBAL VARIABLES - */ -#define CTXMOD 0x01 /* context information modified */ -#define DBITS "\020\01CTXMOD" +** GLOBAL VARIABLES +*/ +#define CTXMOD 0x01 /* context information modified */ +#define DBITS "\020\01CTXMOD" extern char ctxflags; -extern char *invo_name; /* command invocation name */ -extern char *mypath; /* user's $HOME */ -extern char *defpath; /* pathname of user's profile */ -extern char *ctxpath; /* pathname of user's context */ -extern struct node *m_defs; /* list of profile/context entries */ +extern char *invo_name; /* command invocation name */ +extern char *mypath; /* user's $HOME */ +extern char *mmhdir; +extern char *mmhpath; +extern char *defpath; /* pathname of user's profile */ +extern char *ctxpath; /* pathname of user's context */ +extern struct node *m_defs; /* list of profile/context entries */ +extern char *mailstore; /* name of mail storage directory */ /* - * These standard strings are defined in config.c. They are the - * only system-dependent parameters in nmh, and thus by redefining - * their values and reloading the various modules, nmh will run - * on any system. - */ -extern char *buildmimeproc; -extern char *catproc; +** These standard strings are defined in config.c. They are the +** only system-dependent parameters in nmh, and thus by redefining +** their values and reloading the various modules, nmh will run +** on any system. +*/ +extern char *attach_hdr; +extern char *sign_hdr; +extern char *enc_hdr; extern char *components; extern char *context; -extern char *current; +extern char *curfolder; extern char *defaulteditor; +extern char *defaultpager; extern char *defaultfolder; extern char *digestcomps; extern char *distcomps; -extern char *draft; -extern char *faceproc; -extern char *fileproc; +extern char *draftfolder; extern char *foldprot; extern char *forwcomps; extern char *inbox; -extern char *incproc; -extern char *installproc; -extern char *lproc; -extern char *mailproc; -extern char *mh_defaults; -extern char *mh_profile; +extern char *listproc; +extern char *mhetcdir; +extern char *mailspool; extern char *mh_seq; extern char *mhlformat; -extern char *mhlforward; -extern char *mhlproc; extern char *mhlreply; -extern char *moreproc; +extern char *mimetypequery; +extern char *mimetypequeryproc; extern char *msgprot; -extern char *mshproc; -extern char *nmhaccessftp; extern char *nmhstorage; -extern char *nmhcache; -extern char *nmhprivcache; extern char *nsequence; -extern char *packproc; -extern char *postproc; -extern char *pfolder; +extern char *profile; extern char *psequence; extern char *rcvdistcomps; -extern char *rcvstoreproc; extern char *replcomps; extern char *replgroupcomps; -extern char *rmfproc; -extern char *rmmproc; -extern char *sendproc; -extern char *showmimeproc; -extern char *showproc; +extern char *sendmail; +extern char *seq_all; +extern char *seq_beyond; +extern char *seq_cur; +extern char *seq_first; +extern char *seq_last; +extern char *seq_next; +extern char *seq_prev; +extern char *seq_unseen; +extern char *seq_neg; +extern char *trashfolder; extern char *usequence; extern char *version_num; extern char *version_str; -extern char *vmhproc; extern char *whatnowproc; -extern char *whomproc; extern void (*done) (int) NORETURN; #include - diff --git a/h/mhcachesbr.h b/h/mhcachesbr.h deleted file mode 100644 index 9c1db6a..0000000 --- a/h/mhcachesbr.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * mhcachesbr.h -- definitions for manipulating MIME content cache - */ - -/* - * various cache policies - */ -static struct swit caches[] = { -#define CACHE_NEVER 0 - { "never", 0 }, -#define CACHE_PRIVATE 1 - { "private", 0 }, -#define CACHE_PUBLIC 2 - { "public", 0 }, -#define CACHE_ASK 3 - { "ask", 0 }, - { NULL, 0 } -}; diff --git a/h/mhparse.h b/h/mhparse.h index 48f221f..1954d89 100644 --- a/h/mhparse.h +++ b/h/mhparse.h @@ -1,254 +1,228 @@ - /* - * mhparse.h -- definitions for parsing/building of MIME content - * -- (mhparse.c/mhbuildsbr.c) - */ +** mhparse.h -- definitions for parsing/building of MIME content +** -- (mhparse.c/mhbuild.c) +*/ -#define NPARTS 50 -#define NTYPES 20 -#define NPARMS 10 +#define NPARTS 50 +#define NTYPES 20 +#define NPARMS 10 /* - * Abstract type for header fields - */ +** Abstract type for header fields +*/ typedef struct hfield *HF; /* - * Abstract types for MIME parsing/building - */ +** Abstract types for MIME parsing/building +*/ typedef struct cefile *CE; typedef struct CTinfo *CI; typedef struct Content *CT; /* - * type for Init function (both type and transfer encoding) - */ +** type for Init function (both type and transfer encoding) +*/ typedef int (*InitFunc) (CT); /* - * types for various transfer encoding access functions - */ +** types for various transfer encoding access functions +*/ typedef int (*OpenCEFunc) (CT, char **); typedef void (*CloseCEFunc) (CT); typedef unsigned long (*SizeCEFunc) (CT); /* - * Structure for storing/encoding/decoding - * a header field and its value. - */ +** Structure for storing/encoding/decoding +** a header field and its value. +*/ struct hfield { - char *name; /* field name */ - char *value; /* field body */ - int hf_encoding; /* internal flag for transfer encoding to use */ - HF next; /* link to next header field */ + char *name; /* field name */ + char *value; /* field body */ + int hf_encoding; /* internal flag for transfer encoding to use */ + HF next; /* link to next header field */ }; /* - * Structure for storing parsed elements - * of the Content-Type component. - */ +** Structure for storing parsed elements +** of the Content-Type component. +*/ struct CTinfo { - char *ci_type; /* content type */ - char *ci_subtype; /* content subtype */ - char *ci_attrs[NPARMS + 2]; /* attribute names */ - char *ci_values[NPARMS]; /* attribute values */ - char *ci_comment; /* RFC-822 comments */ - char *ci_magic; + char *ci_type; /* content type */ + char *ci_subtype; /* content subtype */ + char *ci_attrs[NPARMS + 2]; /* attribute names */ + char *ci_values[NPARMS]; /* attribute values */ + char *ci_comment; /* RFC-822 comments */ + char *ci_magic; }; /* - * Structure for storing decoded contents after - * removing Content-Transfer-Encoding. - */ +** Structure for storing decoded contents after +** removing Content-Transfer-Encoding. +*/ struct cefile { - char *ce_file; /* decoded content (file) */ - FILE *ce_fp; /* decoded content (stream) */ - int ce_unlink; /* remove file when done? */ + char *ce_file; /* decoded content (file) */ + FILE *ce_fp; /* decoded content (stream) */ + int ce_unlink; /* remove file when done? */ }; /* - * Primary structure for handling Content (Entity) - */ +** Primary structure for handling Content (Entity) +*/ struct Content { - /* source (read) file */ - char *c_file; /* read contents (file) */ - FILE *c_fp; /* read contents (stream) */ - int c_unlink; /* remove file when done? */ - - long c_begin; /* where content body starts in file */ - long c_end; /* where content body ends in file */ - - /* linked list of header fields */ - HF c_first_hf; /* pointer to first header field */ - HF c_last_hf; /* pointer to last header field */ - - /* copies of MIME related header fields */ - char *c_vrsn; /* MIME-Version: */ - char *c_ctline; /* Content-Type: */ - char *c_celine; /* Content-Transfer-Encoding: */ - char *c_id; /* Content-ID: */ - char *c_descr; /* Content-Description: */ - char *c_dispo; /* Content-Disposition: */ - char *c_partno; /* within multipart content */ - - /* Content-Type info */ - struct CTinfo c_ctinfo; /* parsed elements of Content-Type */ - int c_type; /* internal flag for content type */ - int c_subtype; /* internal flag for content subtype */ - - /* Content-Transfer-Encoding info (decoded contents) */ - CE c_cefile; /* structure holding decoded content */ - int c_encoding; /* internal flag for encoding type */ - - /* Content-MD5 info */ - int c_digested; /* have we seen this header before? */ - unsigned char c_digest[16]; /* decoded MD5 checksum */ - - /* pointers to content-specific structures */ - void *c_ctparams; /* content type specific data */ - struct exbody *c_ctexbody; /* data for type message/external */ - - /* function pointers */ - InitFunc c_ctinitfnx; /* parse content body */ - OpenCEFunc c_ceopenfnx; /* get a stream to decoded contents */ - CloseCEFunc c_ceclosefnx; /* release stream */ - SizeCEFunc c_cesizefnx; /* size of decoded contents */ - - int c_umask; /* associated umask */ - pid_t c_pid; /* process doing display */ - int c_rfc934; /* rfc934 compatibility flag */ - - char *c_showproc; /* default, if not in profile */ - char *c_termproc; /* for charset madness... */ - char *c_storeproc; /* overrides profile entry, if any */ - - char *c_storage; /* write contents (file) */ - char *c_folder; /* write contents (folder) */ + /* source (read) file */ + char *c_file; /* read contents (file) */ + FILE *c_fp; /* read contents (stream) */ + int c_unlink; /* remove file when done? */ + + long c_begin; /* where content body starts in file */ + long c_end; /* where content body ends in file */ + + /* linked list of header fields */ + HF c_first_hf; /* pointer to first header field */ + HF c_last_hf; /* pointer to last header field */ + + /* copies of MIME related header fields */ + char *c_vrsn; /* MIME-Version: */ + char *c_ctline; /* Content-Type: */ + char *c_celine; /* Content-Transfer-Encoding: */ + char *c_id; /* Content-ID: */ + char *c_descr; /* Content-Description: */ + char *c_dispo; /* Content-Disposition: */ + char *c_partno; /* within multipart content */ + + /* Content-Type info */ + struct CTinfo c_ctinfo; /* parsed elements of Content-Type */ + int c_type; /* internal flag for content type */ + int c_subtype; /* internal flag for content subtype */ + char *c_charset; /* charset string */ + + /* Content-Transfer-Encoding info (decoded contents) */ + CE c_cefile; /* structure holding decoded content */ + int c_encoding; /* internal flag for encoding type */ + + /* pointers to content-specific structures */ + void *c_ctparams; /* content type specific data */ + + /* function pointers */ + InitFunc c_ctinitfnx; /* parse content body */ + OpenCEFunc c_ceopenfnx; /* get a stream to decoded contents */ + CloseCEFunc c_ceclosefnx; /* release stream */ + SizeCEFunc c_cesizefnx; /* size of decoded contents */ + + int c_umask; /* associated umask */ + + char *c_showproc; /* default, if not in profile */ + char *c_storeproc; /* overrides profile entry, if any */ + + char *c_storage; /* write contents (file) */ + char *c_folder; /* write contents (folder) */ }; /* - * Flags for Content-Type (Content->c_type) - */ -#define CT_UNKNOWN 0x00 -#define CT_APPLICATION 0x01 -#define CT_AUDIO 0x02 -#define CT_IMAGE 0x03 -#define CT_MESSAGE 0x04 -#define CT_MULTIPART 0x05 -#define CT_TEXT 0x06 -#define CT_VIDEO 0x07 -#define CT_EXTENSION 0x08 +** Flags for Content-Type (Content->c_type) +*/ +#define CT_UNKNOWN 0x00 +#define CT_APPLICATION 0x01 +#define CT_AUDIO 0x02 +#define CT_IMAGE 0x03 +#define CT_MESSAGE 0x04 +#define CT_MULTIPART 0x05 +#define CT_TEXT 0x06 +#define CT_VIDEO 0x07 +#define CT_EXTENSION 0x08 /* - * Flags for Content-Transfer-Encoding (Content->c_encoding) - */ -#define CE_UNKNOWN 0x00 -#define CE_BASE64 0x01 -#define CE_QUOTED 0x02 -#define CE_8BIT 0x03 -#define CE_7BIT 0x04 -#define CE_BINARY 0x05 -#define CE_EXTENSION 0x06 -#define CE_EXTERNAL 0x07 /* for external-body */ +** Flags for Content-Transfer-Encoding (Content->c_encoding) +*/ +#define CE_UNKNOWN 0x00 +#define CE_BASE64 0x01 +#define CE_QUOTED 0x02 +#define CE_8BIT 0x03 +#define CE_7BIT 0x04 +#define CE_BINARY 0x05 +#define CE_EXTENSION 0x06 +#define CE_EXTERNAL 0x07 /* for external-body */ /* - * TEXT content - */ +** TEXT content +*/ /* Flags for subtypes of TEXT */ -#define TEXT_UNKNOWN 0x00 -#define TEXT_PLAIN 0x01 -#define TEXT_RICHTEXT 0x02 -#define TEXT_ENRICHED 0x03 +#define TEXT_UNKNOWN 0x00 +#define TEXT_PLAIN 0x01 +#define TEXT_RICHTEXT 0x02 +#define TEXT_ENRICHED 0x03 /* Flags for character sets */ -#define CHARSET_UNKNOWN 0x00 -#define CHARSET_UNSPECIFIED 0x01 /* only needed when building drafts */ -#define CHARSET_USASCII 0x01 -#define CHARSET_LATIN 0x02 +#define CHARSET_UNKNOWN 0x00 +#define CHARSET_UNSPECIFIED 0x01 /* only needed when building drafts */ +#define CHARSET_USASCII 0x01 +#define CHARSET_LATIN 0x02 /* Structure for text content */ struct text { - int tx_charset; /* flag for character set */ + int tx_charset; /* flag for character set */ }; /* - * MULTIPART content - */ +** MULTIPART content +*/ /* Flags for subtypes of MULTIPART */ -#define MULTI_UNKNOWN 0x00 -#define MULTI_MIXED 0x01 -#define MULTI_ALTERNATE 0x02 -#define MULTI_DIGEST 0x03 -#define MULTI_PARALLEL 0x04 +#define MULTI_UNKNOWN 0x00 +#define MULTI_MIXED 0x01 +#define MULTI_ALTERNATE 0x02 +#define MULTI_DIGEST 0x03 +#define MULTI_PARALLEL 0x04 /* Structure for subparts of a multipart content */ struct part { - CT mp_part; /* Content structure for subpart */ - struct part *mp_next; /* pointer to next subpart structure */ + CT mp_part; /* Content structure for subpart */ + struct part *mp_next; /* pointer to next subpart structure */ }; /* Main structure for multipart content */ struct multipart { - char *mp_start; /* boundary string separating parts */ - char *mp_stop; /* terminating boundary string */ - struct part *mp_parts; /* pointer to first subpart structure */ + char *mp_start; /* boundary string separating parts */ + char *mp_stop; /* terminating boundary string */ + struct part *mp_parts; /* pointer to first subpart structure */ }; /* - * MESSAGE content - */ +** MESSAGE content +*/ /* Flags for subtypes of MESSAGE */ -#define MESSAGE_UNKNOWN 0x00 -#define MESSAGE_RFC822 0x01 -#define MESSAGE_PARTIAL 0x02 -#define MESSAGE_EXTERNAL 0x03 +#define MESSAGE_UNKNOWN 0x00 +#define MESSAGE_RFC822 0x01 +#define MESSAGE_PARTIAL 0x02 +#define MESSAGE_EXTERNAL 0x03 /* Structure for message/partial */ struct partial { - char *pm_partid; - int pm_partno; - int pm_maxno; - int pm_marked; - int pm_stored; -}; - -/* Structure for message/external */ -struct exbody { - CT eb_parent; /* pointer to controlling content structure */ - CT eb_content; /* pointer to internal content structure */ - char *eb_partno; - char *eb_access; - int eb_flags; - char *eb_name; - char *eb_permission; - char *eb_site; - char *eb_dir; - char *eb_mode; - unsigned long eb_size; - char *eb_server; - char *eb_subject; - char *eb_body; + char *pm_partid; + int pm_partno; + int pm_maxno; + int pm_marked; + int pm_stored; }; /* - * APPLICATION content - */ +** APPLICATION content +*/ /* Flags for subtype of APPLICATION */ -#define APPLICATION_UNKNOWN 0x00 -#define APPLICATION_OCTETS 0x01 -#define APPLICATION_POSTSCRIPT 0x02 +#define APPLICATION_UNKNOWN 0x00 +#define APPLICATION_OCTETS 0x01 +#define APPLICATION_POSTSCRIPT 0x02 /* - * Structures for mapping types to their internal flags - */ +** Structures for mapping types to their internal flags +*/ struct k2v { - char *kv_key; - int kv_value; + char *kv_key; + int kv_value; }; extern struct k2v SubText[]; extern struct k2v Charset[]; @@ -257,27 +231,23 @@ extern struct k2v SubMessage[]; extern struct k2v SubApplication[]; /* - * Structures for mapping (content) types to - * the functions to handle them. - */ +** Structures for mapping (content) types to +** the functions to handle them. +*/ struct str2init { - char *si_key; - int si_val; - InitFunc si_init; + char *si_key; + int si_val; + InitFunc si_init; }; extern struct str2init str2cts[]; extern struct str2init str2ces[]; -extern struct str2init str2methods[]; /* - * prototypes - */ -int pidcheck (int); -CT parse_mime (char *); -int add_header (CT, char *, char *); -int get_ctinfo (unsigned char *, CT, int); -int params_external (CT, int); -int open7Bit (CT, char **); -void close_encoding (CT); - -extern int checksw; /* Add Content-MD5 field */ +** prototypes +*/ +int pidcheck(int); +CT parse_mime(char *); +int add_header(CT, char *, char *); +int get_ctinfo(unsigned char *, CT, int); +int open7Bit(CT, char **); +void close_encoding(CT); diff --git a/h/mime.h b/h/mime.h index 3e50ce2..22c2349 100644 --- a/h/mime.h +++ b/h/mime.h @@ -1,37 +1,32 @@ - /* - * mime.h -- definitions for MIME - */ +** mime.h -- definitions for MIME +*/ -#define VRSN_FIELD "MIME-Version" -#define VRSN_VALUE "1.0" -#define XXX_FIELD_PRF "Content-" -#define TYPE_FIELD "Content-Type" -#define ENCODING_FIELD "Content-Transfer-Encoding" -#define ID_FIELD "Content-ID" -#define DESCR_FIELD "Content-Description" -#define DISPO_FIELD "Content-Disposition" -#define MD5_FIELD "Content-MD5" +#define VRSN_FIELD "MIME-Version" +#define VRSN_VALUE "1.0" +#define XXX_FIELD_PRF "Content-" +#define TYPE_FIELD "Content-Type" +#define ENCODING_FIELD "Content-Transfer-Encoding" +#define ID_FIELD "Content-ID" +#define DESCR_FIELD "Content-Description" +#define DISPO_FIELD "Content-Disposition" -#define isatom(c) (!isspace (c) && !iscntrl (c) && (c) != '(' \ - && (c) != ')' && (c) != '<' && (c) != '>' \ - && (c) != '@' && (c) != ',' && (c) != ';' \ - && (c) != ':' && (c) != '\\' && (c) != '"' \ - && (c) != '.' && (c) != '[' && (c) != ']') +#define isatom(c) (!isspace (c) && !iscntrl (c) && (c) != '(' \ + && (c) != ')' && (c) != '<' && (c) != '>' \ + && (c) != '@' && (c) != ',' && (c) != ';' \ + && (c) != ':' && (c) != '\\' && (c) != '"' \ + && (c) != '.' && (c) != '[' && (c) != ']') /* - * Test for valid characters used in "token" - * as defined in RFC2045 - */ -#define istoken(c) (!isspace (c) && !iscntrl (c) && (c) != '(' \ - && (c) != ')' && (c) != '<' && (c) != '>' \ - && (c) != '@' && (c) != ',' && (c) != ';' \ - && (c) != ':' && (c) != '\\' && (c) != '"' \ - && (c) != '/' && (c) != '[' && (c) != ']' \ - && (c) != '?' && (c) != '=') - -#define CPERLIN 76 -#define BPERLIN (CPERLIN / 4) -#define LPERMSG 632 -#define CPERMSG (LPERMSG * CPERLIN) +** Test for valid characters used in "token" +** as defined in RFC2045 +*/ +#define istoken(c) (!isspace (c) && !iscntrl (c) && (c) != '(' \ + && (c) != ')' && (c) != '<' && (c) != '>' \ + && (c) != '@' && (c) != ',' && (c) != ';' \ + && (c) != ':' && (c) != '\\' && (c) != '"' \ + && (c) != '/' && (c) != '[' && (c) != ']' \ + && (c) != '?' && (c) != '=') +#define CPERLIN 76 +#define BPERLIN (CPERLIN / 4) diff --git a/h/msh.h b/h/msh.h deleted file mode 100644 index 201c7ec..0000000 --- a/h/msh.h +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * msh.h -- definitions for msh - */ - -/* flags for stream */ -#define STDIO 0 /* regular stdoutput */ -#define CRTIO 1 /* create re-direct */ -#define APPIO 2 /* append re-direct */ -#define PIPIO 3 /* pipe re-direct */ - -struct Cmd { - char line[BUFSIZ]; - char *args[MAXARGS]; - char *redirect; - int direction; - FILE *stream; -}; - -#define NULLCMD ((struct Cmd *) 0) - -#define MHNCHK 0x0001 /* did nontext check */ -#define MHNYES 0x0002 /* .. and known to be non-text */ - -#define CUR (1 << (FFATTRSLOT + NUMATTRS - 1)) - -#ifdef BPOP -# define VIRTUAL SELECT_EMPTY - -# define is_virtual(mp,msgnum) ((mp)->msgstats[msgnum] & VIRTUAL) -# define unset_virtual(mp,msgnum) ((mp)->msgstats[msgnum] &= ~VIRTUAL) -# define set_virtual(mp,msgnum) ((mp)->msgstats[msgnum] |= VIRTUAL) -#endif - -struct Msg { - struct drop m_drop; - char *m_scanl; - struct tws m_tb; - short m_flags; - seqset_t m_stats; -}; - -#define m_bboard_id m_drop.d_id -#define m_top m_drop.d_size -#define m_start m_drop.d_start -#define m_stop m_drop.d_stop - -/* - * FOLDER - */ -extern char *fmsh; /* folder instead of file */ -extern int modified; /* command modified folder */ -extern struct msgs *mp; /* used a lot */ -extern struct Msg *Msgs; /* Msgs[0] not used */ - -FILE *msh_ready (); - -/* - * COMMAND - */ -extern int interactive; /* running from a /dev/tty */ -extern int redirected; /* re-directing output */ -extern FILE *sp; /* original stdout */ -extern char *cmd_name; /* command being run */ -extern char myfilter[]; /* path to mhl.forward */ - -extern char *BBoard_ID; /* BBoard-ID constant */ - -/* - * SIGNALS - */ -extern SIGNAL_HANDLER istat; /* original SIGINT */ -extern SIGNAL_HANDLER qstat; /* original SIGQUIT */ -extern int interrupted; /* SIGINT detected */ -extern int broken_pipe; /* SIGPIPE detected */ -extern int told_to_quit; /* SIGQUIT detected */ - -#ifdef BSD42 -extern int should_intr; /* signal handler should interrupt call */ -extern jmp_buf sigenv; /* the environment pointer */ -#endif - -/* - * prototypes - */ -int readid (int); -int expand (char *); -void m_reset (void); -void fsetup (char *); -void setup (char *); -void readids (int); -void display_info (int); - -void forkcmd (char **s, char *); -void distcmd (char **); -void explcmd (char **); -int filehak (char **); -void filecmd (char **); -void foldcmd (char **); -void forwcmd (char **); -void helpcmd (char **); -void markcmd (char **); -void mhncmd (char **); -void showcmd (char **); -int pack (char *, int, int); -int packhak (char **); -void packcmd (char **); -void pickcmd (char **); -void replcmd (char **); -void rmmcmd (char **); -void scancmd (char **); -void sortcmd (char **); diff --git a/h/mts.h b/h/mts.h deleted file mode 100644 index 2d2aa95..0000000 --- a/h/mts.h +++ /dev/null @@ -1,72 +0,0 @@ - -/* - * mts.h -- definitions for the mail system - */ - -/* - * Local and UUCP Host Name - */ -char *LocalName(void); -char *SystemName(void); - -/* - * Mailboxes - */ -extern char *mmdfldir; -extern char *mmdflfil; -extern char *uucpldir; -extern char *uucplfil; - -#define MAILDIR (mmdfldir && *mmdfldir ? mmdfldir : getenv ("HOME")) -#define MAILFIL (mmdflfil && *mmdflfil ? mmdflfil : getusername ()) -#define UUCPDIR (uucpldir && *uucpldir ? uucpldir : getenv ("HOME")) -#define UUCPFIL (uucplfil && *uucplfil ? uucplfil : getusername ()) - -char *getusername(void); -char *getfullname(void); - -/* - * Separators - */ -extern char *mmdlm1; -extern char *mmdlm2; - -#define isdlm1(s) (strcmp (s, mmdlm1) == 0) -#define isdlm2(s) (strcmp (s, mmdlm2) == 0) - -/* - * Read mts.conf file - */ -void mts_init (char *); - -/* - * MTS specific variables - */ -#if defined (SMTPMTS) - -/* whether to speak SMTP to localhost:25 or to /usr/sbin/sendmail */ -#define MTS_SMTP 0 -#define MTS_SENDMAIL 1 -extern int sm_mts; - -extern char *hostable; -extern char *sendmail; -#endif - -/* - * SMTP/POP stuff - */ -extern char *clientname; -extern char *servers; -extern char *pophost; - -/* - * Global MailDelivery File - */ -extern char *maildelivery; - -/* - * Aliasing Facility (doesn't belong here) - */ -extern int Everyone; -extern char *NoShell; diff --git a/h/nmh.h b/h/nmh.h index f1711d5..eb85a4a 100644 --- a/h/nmh.h +++ b/h/nmh.h @@ -1,81 +1,31 @@ - /* - * nmh.h -- system configuration header file - */ +** nmh.h -- system configuration header file +*/ #include -#ifdef HAVE_UNISTD_H -# include -# include -#endif - +#include #include #include #include -#if HAVE_DIRENT_H -# include -# define NLENGTH(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NLENGTH(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#ifdef HAVE_STDLIB_H -# include -#endif +#include +#define NLENGTH(dirent) strlen((dirent)->d_name) +#include #include - -#if STDC_HEADERS || HAVE_STRING_H -# include -/* An ANSI string.h and pre-ANSI memory.h might conflict. */ -# if !STDC_HEADERS && HAVE_MEMORY_H -# include -# endif /* not STDC_HEADERS and HAVE_MEMORY_H */ -#else /* not STDC_HEADERS and not HAVE_STRING_H */ -# include -/* memory.h and strings.h conflict on some systems. */ -#endif /* not STDC_HEADERS and not HAVE_STRING_H */ +#include #ifdef HAVE_SYS_PARAM_H # include #endif -#ifdef HAVE_LOCALE_H -# include -#endif - -#ifdef HAVE_LIMITS_H -# include -#endif - -/* - * symbolic constants for lseek and fseek - */ -#ifndef SEEK_SET -# define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -# define SEEK_CUR 1 -#endif -#ifndef SEEK_END -# define SEEK_END 2 -#endif +#include +#include /* - * we should be getting this value from pathconf(_PC_PATH_MAX) - */ +** we should be getting this value from pathconf(_PC_PATH_MAX) +*/ #ifndef PATH_MAX # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN @@ -86,19 +36,8 @@ #endif /* - * we should get this value from sysconf(_SC_NGROUPS_MAX) - */ -#ifndef NGROUPS_MAX -# ifdef NGROUPS -# define NGROUPS_MAX NGROUPS -# else -# define NGROUPS_MAX 16 -# endif -#endif - -/* - * we should be getting this value from sysconf(_SC_OPEN_MAX) - */ +** we should be getting this value from sysconf(_SC_OPEN_MAX) +*/ #ifndef OPEN_MAX # ifdef NOFILE # define OPEN_MAX NOFILE @@ -109,52 +48,3 @@ #endif #include - -#define bcmp(b1,b2,length) memcmp(b1, b2, length) -#define bcopy(b1,b2,length) memcpy (b2, b1, length) -#define bcpy(b1,b2,length) memcmp (b1, b2, length) -#define bzero(b,length) memset (b, 0, length) - -#ifdef HAVE_KILLPG -# define KILLPG(pgrp,sig) killpg(pgrp,sig); -#else -# define KILLPG(pgrp,sig) kill((-pgrp),sig); -#endif - -/* - * If your stat macros are broken, - * we will just undefine them. - */ -#ifdef STAT_MACROS_BROKEN -# ifdef S_ISBLK -# undef S_ISBLK -# endif -# ifdef S_ISCHR -# undef S_ISCHR -# endif -# ifdef S_ISDIR -# undef S_ISDIR -# endif -# ifdef S_ISFIFO -# undef S_ISFIFO -# endif -# ifdef S_ISLNK -# undef S_ISLNK -# endif -# ifdef S_ISMPB -# undef S_ISMPB -# endif -# ifdef S_ISMPC -# undef S_ISMPC -# endif -# ifdef S_ISNWK -# undef S_ISNWK -# endif -# ifdef S_ISREG -# undef S_ISREG -# endif -# ifdef S_ISSOCK -# undef S_ISSOCK -# endif -#endif /* STAT_MACROS_BROKEN. */ - diff --git a/h/picksbr.h b/h/picksbr.h deleted file mode 100644 index 27c2e66..0000000 --- a/h/picksbr.h +++ /dev/null @@ -1,10 +0,0 @@ - -/* - * picksbr.h -- definitions for picksbr.c - */ - -/* - * prototypes - */ -int pcompile (char **, char *); -int pmatches (FILE *, int, long, long); diff --git a/h/popsbr.h b/h/popsbr.h deleted file mode 100644 index fc06f0b..0000000 --- a/h/popsbr.h +++ /dev/null @@ -1,17 +0,0 @@ - -/* - * popsbr.h -- header for POP client subroutines - */ - -int pop_init (char *, char *, char *, char *, char *, int, int, char *); -int pop_fd (char *, int, char *, int); -int pop_stat (int *, int *); -int pop_retr (int, int (*)(char *)); -int pop_dele (int); -int pop_noop (void); -int pop_rset (void); -int pop_top (int, int, int (*)(char *)); -int pop_quit (void); -int pop_done (void); -int pop_set (int, int, int); -int pop_list (int, int *, int *, int *); diff --git a/h/prototypes.h b/h/prototypes.h index 1bc19d4..a9e081d 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -1,166 +1,129 @@ - /* - * prototypes.h -- various prototypes - */ +** prototypes.h -- various prototypes +*/ /* - * missing system prototypes - */ +** missing system prototypes +*/ #ifndef HAVE_TERMCAP_H -extern int tgetent (char *bp, char *name); -extern int tgetnum (char *id); -extern int tgetflag (char *id); -extern char *tgetstr (char *id, char **area); -extern char *tgoto (char *cm, int destcol, int destline); -extern int tputs (char *cp, int affcnt, int (*outc) (int)); +extern int tgetent(char *bp, char *name); +extern int tgetnum(char *id); +extern int tgetflag(char *id); +extern char *tgetstr(char *id, char **area); +extern char *tgoto(char *cm, int destcol, int destline); +extern int tputs(char *cp, int affcnt, int (*outc) (int)); #endif /* - * prototype from config.h - */ +** prototype from config.h +*/ char *etcpath(char *); /* - * prototypes from the nmh subroutine library - */ -void adios (char *, char *, ...) NORETURN; -void admonish (char *, char *, ...); -void advertise (char *, char *, char *, va_list); -void advise (char *, char *, ...); -void ambigsw (char *, struct swit *); -int atooi(char *); -char **brkstring (char *, char *, char *); -int check_charset (char *, int); -int client(char *, char *, char *, int, int); -void closefds(int); -char *concat (char *, ...); -int context_del (char *); -char *context_find (char *); -int context_foil (char *); -void context_read (void); -void context_replace (char *, char *); -void context_save (void); -char *copy (char *, char *); -char **copyip (char **, char **, int); -void cpydata (int, int, char *, char *); -void cpydgst (int, int, char *, char *); -int decode_rfc2047 (char *, char *, size_t); -void discard (FILE *); -int default_done (int); +** prototypes from the nmh subroutine library +*/ +void adios(char *, char *, ...) NORETURN; +void admonish(char *, char *, ...); +void advertise(char *, char *, char *, va_list); +void advise(char *, char *, ...); +void ambigsw(char *, struct swit *); +char **brkstring(char *, char *, char *); +int is_native_charset(char *); +char *concat(char *, ...); +int context_del(char *); +char *context_find(char *); +void context_read(void); +void context_replace(char *, char *); +void context_save(void); +void cpydata(int, int, char *, char *); +void cpydgst(int, int, char *, char *); +int decode_rfc2047(char *, char *, size_t); +void discard(FILE *); +int default_done(int); +char *expandfol(char *); +char *expanddir(char *); int ext_hook(char *, char *, char *); -int fdcompare (int, int); -int folder_addmsg (struct msgs **, char *, int, int, int, int, char *); -int folder_delmsgs (struct msgs *, int, int); -void folder_free (struct msgs *); -int folder_pack (struct msgs **, int); -struct msgs *folder_read (char *); -struct msgs *folder_realloc (struct msgs *, int, int); -int gans (char *, struct swit *); -char **getans (char *, struct swit *); -int getanswer (char *); -char **getarguments (char *, int, char **, int); +int folder_addmsg(struct msgs **, char *, int, int, int, int, char *); +int folder_delmsgs(struct msgs *, int); +void folder_free(struct msgs *); +struct msgs *folder_read(char *); +struct msgs *folder_realloc(struct msgs *, int, int); +int gans(char *, struct swit *); +char **getans(char *, struct swit *); +int getanswer(char *); +char **getarguments(char *, int, char **, int); char *get_charset(); -char *getcpy (char *); -char *getfolder(int); +char *getcpy(char *); +char *getcurfol(void); +char *getdeffol(void); int lkclose(int, char*); int lkfclose(FILE *, char *); FILE *lkfopen(char *, char *); int lkopen(char *, int, mode_t); -int m_atoi (char *); -char *m_backup (char *); -int m_convert (struct msgs *, char *); -char *m_draft (char *, char *, int, int *); -void m_eomsbr (int (*)(int)); -int m_getfld (int, unsigned char *, unsigned char *, int, FILE *); -int m_gmprot (void); -char *m_maildir (char *); -char *m_mailpath (char *); -char *m_name (int); -int m_putenv (char *, char *); -char *m_scratch (char *, char *); -char *m_tmpfil (char *); +int m_atoi(char *); +char *m_backup(char *); +int m_convert(struct msgs *, char *); +char *m_draft(char *); +int m_getfld(int, unsigned char *, unsigned char *, int, FILE *); +int m_gmprot(void); +char *m_name(int); +int m_putenv(char *, char *); char *m_mktemp(const char *, int *, FILE **); char *m_mktemp2(const char *, const char *, int *, FILE **); -void m_unknown(FILE *); -int makedir (char *); +void thisisanmbox(FILE *); +int makedir(char *); char *nmh_getpass(const char *); char *norm_charmap(char *); -char *new_fs (char *, char *, char *); -char *path(char *, int); -int peekc(FILE *ib); -int pidwait (pid_t, int); -int pidstatus (int, FILE *, char *); -char *pluspath(char *); -void print_help (char *, struct swit *, int); -void print_sw (char *, struct swit *, char *, FILE *); -void print_version (char *); -void push (void); -char *pwd (void); -char *r1bindex(char *, int); -void readconfig (struct node **, FILE *, char *, int); -int refile (char **, char *); -void ruserpass(char *, char **, char **); -int remdir (char *); -int seq_addmsg (struct msgs *, char *, int, int, int); -int seq_addsel (struct msgs *, char *, int, int); -char *seq_bits (struct msgs *); -int seq_delmsg (struct msgs *, char *, int); -int seq_delsel (struct msgs *, char *, int, int); -int seq_getnum (struct msgs *, char *); -char *seq_list (struct msgs *, char *); -int seq_nameok (unsigned char *); -void seq_print (struct msgs *, char *); -void seq_printall (struct msgs *); -void seq_read (struct msgs *); -void seq_save (struct msgs *); -void seq_setcur (struct msgs *, int); -void seq_setprev (struct msgs *); -void seq_setunseen (struct msgs *, int); -int showfile (char **, char *); +char *new_fs(char *, char *); +int pidwait(pid_t, int); +int pidstatus(int, FILE *, char *); +void print_help(char *, struct swit *, int); +void print_sw(char *, struct swit *, char *, FILE *); +void print_version(char *); +void push(void); +char *pwd(void); +char *mhbasename(char *); +void readconfig(struct node **, FILE *, char *, int); +int seq_addmsg(struct msgs *, char *, int, int, int); +int seq_addsel(struct msgs *, char *, int, int); +char *seq_bits(struct msgs *); +int seq_delmsg(struct msgs *, char *, int); +int seq_delsel(struct msgs *, char *, int, int); +int seq_getnum(struct msgs *, char *); +char *seq_list(struct msgs *, char *); +int seq_nameok(unsigned char *); +void seq_print(struct msgs *, char *); +void seq_printall(struct msgs *); +void seq_read(struct msgs *); +void seq_save(struct msgs *); +void seq_setcur(struct msgs *, int); +void seq_setprev(struct msgs *); +void seq_setunseen(struct msgs *, int); +int showfile(char **, char *); int smatch(char *, struct swit *); -char *snprintb (char *, size_t, unsigned, char *); -int ssequal (char *, char *); -int stringdex (char *, char *); -char *trimcpy (unsigned char *); -int unputenv (char *); -int uprf (char *, char *); -int vfgets (FILE *, char **); -char *write_charset_8bit (void); +char *snprintb(char *, size_t, unsigned, char *); +int stringdex(char *, char *); +char *toabsdir(char *); +char *trimcpy(unsigned char *); +int unputenv(char *); +int uprf(char *, char *); +int vfgets(FILE *, char **); +char *write_charset_8bit(void); -#ifdef RPATHS -int get_returnpath (char *, int, char *, int); -#endif - -/* - * prototypes for compatibility functions in library - */ -#ifndef HAVE_SNPRINTF_PROTOTYPE -int snprintf (char *, size_t, const char *, ...); -int vsnprintf (char *, size_t, const char *, va_list); -#endif - -int mh_strcasecmp (const char *s1, const char *s2); -int strncasecmp (const char *s1, const char *s2, size_t n); +int mh_strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); /* - * some prototypes for address parsing system - * (others are in addrsbr.h) - */ -char *LocalName(void); -char *SystemName(void); -char *OfficialName(char *); +** prototypes for some routines in uip +*/ +int distout(char *, char *, char *); +int what_now(char *, int, char *, char *, int, struct msgs *, + char *, char *); /* - * prototypes for some routines in uip - */ -int annotate (char *, char *, char *, int, int, int, int); -void annolist(char *, char *, char *, int); -void annopreserve(int); -int distout (char *, char *, char *); -void replout (FILE *, char *, char *, struct msgs *, int, - int, char *, char *, char *); -int sendsbr (char **, int, char *, struct stat *, int, char *, int); -int what_now (char *, int, int, char *, char *, - int, struct msgs *, char *, int, char *); - +** from the former mts.h +*/ +char *LocalName(void); /* hostname */ +char *getusername(void); +char *getfullname(void); diff --git a/h/rcvmail.h b/h/rcvmail.h index 37fba4d..6a62284 100644 --- a/h/rcvmail.h +++ b/h/rcvmail.h @@ -1,27 +1,12 @@ - /* - * rcvmail.h -- rcvmail hook definitions - */ +** rcvmail.h -- rcvmail hook definitions +*/ -#if defined(SMTPMTS) # include # include # include # include # include -# include -#endif /* SMTPMTS */ - - -#if defined(SMTPMTS) -# define RCV_MOK 0 -# define RCV_MBX 1 -#endif /* SMTPMTS */ - -#ifdef NRTC /* sigh */ -# undef RCV_MOK -# undef RCV_MBX -# define RCV_MOK RP_MOK -# define RCV_MBX RP_MECH -#endif /* NRTC */ +# define RCV_MOK 0 +# define RCV_MBX 1 diff --git a/h/scansbr.h b/h/scansbr.h index f6cd35c..91b2ff6 100644 --- a/h/scansbr.h +++ b/h/scansbr.h @@ -1,40 +1,30 @@ - /* - * scansbr.h -- definitions for scan() - */ +** scansbr.h -- definitions for scan() +*/ extern char *scanl; -#define SCNENC 2 /* message just fine, but encrypted(!!) */ -#define SCNMSG 1 /* message just fine */ -#define SCNEOF 0 /* empty message */ -#define SCNERR (-1) /* error message */ -#define SCNNUM (-2) /* number out of range */ -#define SCNFAT (-3) /* fatal error */ +#define SCNMSG 1 /* message just fine */ +#define SCNEOF 0 /* empty message */ +#define SCNERR (-1) /* error message */ +#define SCNNUM (-2) /* number out of range */ +#define SCNFAT (-3) /* fatal error */ /* - * default format for `scan' and `inc' - */ - -#ifndef UK -#define FORMAT \ -"%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ -%02(mon{date})/%02(mday{date})%<{date} %|*%>\ +** default format for `scan' and `inc' +*/ +# define FORMAT \ +"=%4(msg)%<(cur)+%| %>%<{replied}-%| %>\ +%4(year{date})-%02(mon{date})-%02(mday{date}) %02(hour{date}):%02(min{date}) \ %<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ -%<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%>\n" -#else -#define FORMAT \ -"%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ -%02(mday{date})/%02(mon{date})%<{date} %|*%>\ -%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ -%<(zero)%17(decode(friendly{from}))%> \ -%(decode{subject})%<{body}<<%{body}>>%>\n" -#endif +%<(zero)%17(decode(friendly{from}))%> %(decode{subject})\n" + +#define WIDTH 78 -#define WIDTH 78 +#define SCN_MBOX (-1) +#define SCN_FOLD 0 /* - * prototypes - */ -int scan (FILE *, int, int, char *, int, int, int, char *, long, int); +** prototypes +*/ +int scan(FILE *, int, int, char *, int, int, int); diff --git a/h/signals.h b/h/signals.h index 4ad2b57..480bf6d 100644 --- a/h/signals.h +++ b/h/signals.h @@ -1,32 +1,16 @@ - /* - * signals.h -- header file for nmh signal interface - */ +** signals.h -- header file for nmh signal interface +*/ #include /* - * The type for a signal handler - */ -typedef RETSIGTYPE (*SIGNAL_HANDLER)(int); - -/* - * If not a POSIX machine, then we create our - * own POSIX style signal sets functions. This - * currently assumes you have 31 signals, which - * should be true on most pure BSD machines. - */ -#ifndef POSIX_SIGNALS -# define sigemptyset(s) (*(s) = 0) -# define sigfillset(s) (*(s) = ~((sigset_t) 0), 0) -# define sigaddset(s,n) (*(s) |= (1 << ((n) - 1)), 0) -# define sigdelset(s,n) (*(s) &= ~(1 << ((n) - 1)), 0) -# define sigismember(s,n) ((*(s) & (1 << ((n) - 1))) != 0) -#endif +** The type for a signal handler +*/ +typedef void (*SIGNAL_HANDLER)(int); /* - * prototypes - */ -int SIGPROCMASK (int, const sigset_t *, sigset_t *); -SIGNAL_HANDLER SIGNAL (int, SIGNAL_HANDLER); -SIGNAL_HANDLER SIGNAL2 (int, SIGNAL_HANDLER); +** prototypes +*/ +SIGNAL_HANDLER SIGNAL(int, SIGNAL_HANDLER); +SIGNAL_HANDLER SIGNAL2(int, SIGNAL_HANDLER); diff --git a/h/tws.h b/h/tws.h index 5d99cf5..420275c 100644 --- a/h/tws.h +++ b/h/tws.h @@ -1,68 +1,68 @@ - /* - * tws.h - */ +** tws.h +*/ -/* If the following is #defined, a timezone given as a numeric-only offset will - be treated specially if it's in a zone that observes Daylight Saving Time. - For instance, during DST, a Date: like "Mon, 24 Jul 2000 12:31:44 -0700" will - be printed as "Mon, 24 Jul 2000 12:31:44 PDT". Without the code activated by - the following #define, that'd be incorrectly printed as "...MST". */ -#define ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST 1 +/* +** If the following is #defined, a timezone given as a numeric-only +** offset will be treated specially if it's in a zone that observes +** Daylight Saving Time. For instance, during DST, a Date: like "Mon, +** 24 Jul 2000 12:31:44 -0700" will be printed as "Mon, 24 Jul 2000 +** 12:31:44 PDT". Without the code activated by the following #define, +** that'd be incorrectly printed as "...MST". +*/ +#define ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST 1 struct tws { - int tw_sec; /* seconds after the minute - [0, 61] */ - int tw_min; /* minutes after the hour - [0, 59] */ - int tw_hour; /* hour since midnight - [0, 23] */ - int tw_mday; /* day of the month - [1, 31] */ - int tw_mon; /* months since January - [0, 11] */ - int tw_year; /* 4 digit year (ie, 1997) */ - int tw_wday; /* days since Sunday - [0, 6] */ - int tw_yday; /* days since January 1 - [0, 365] */ - int tw_zone; - time_t tw_clock; /* if != 0, corresponding calendar value */ - int tw_flags; + int tw_sec; /* seconds after the minute - [0, 61] */ + int tw_min; /* minutes after the hour - [0, 59] */ + int tw_hour; /* hour since midnight - [0, 23] */ + int tw_mday; /* day of the month - [1, 31] */ + int tw_mon; /* months since January - [0, 11] */ + int tw_year; /* 4 digit year (ie, 1997) */ + int tw_wday; /* days since Sunday - [0, 6] */ + int tw_yday; /* days since January 1 - [0, 365] */ + int tw_zone; + time_t tw_clock; /* if != 0, corresponding calendar value */ + int tw_flags; }; -#define TW_NULL 0x0000 +#define TW_NULL 0x0000 -#define TW_SDAY 0x0003 /* how day-of-week was determined */ -#define TW_SNIL 0x0000 /* not given */ -#define TW_SEXP 0x0001 /* explicitly given */ -#define TW_SIMP 0x0002 /* implicitly given */ +#define TW_SDAY 0x0003 /* how day-of-week was determined */ +#define TW_SNIL 0x0000 /* not given */ +#define TW_SEXP 0x0001 /* explicitly given */ +#define TW_SIMP 0x0002 /* implicitly given */ -#define TW_SZONE 0x0004 /* how timezone was determined */ -#define TW_SZNIL 0x0000 /* not given */ -#define TW_SZEXP 0x0004 /* explicitly given */ +#define TW_SZONE 0x0004 /* how timezone was determined */ +#define TW_SZNIL 0x0000 /* not given */ +#define TW_SZEXP 0x0004 /* explicitly given */ -#define TW_DST 0x0010 /* daylight savings time */ -#define TW_ZONE 0x0020 /* use numeric timezones only */ +#define TW_DST 0x0010 /* daylight savings time */ -#define TW_SUCC 0x0040 /* whether parsing was successful */ -#define TW_YES 0x0040 /* yes, found */ -#define TW_NO 0x0000 /* no, not found */ +#define TW_SUCC 0x0040 /* whether parsing was successful */ +#define TW_YES 0x0040 /* yes, found */ +#define TW_NO 0x0000 /* no, not found */ -#define dtwszone(tw) dtimezone (tw->tw_zone, tw->tw_flags) +#define dtwszone(tw) dtimezone(tw->tw_zone, tw->tw_flags) extern char *tw_dotw[]; extern char *tw_ldotw[]; extern char *tw_moty[]; /* - * prototypes - */ -char *dtime (time_t *, int); -char *dtimenow (int); -char *dctime (struct tws *); -struct tws *dlocaltimenow (void); -struct tws *dlocaltime (time_t *); -struct tws *dgmtime (time_t *); -char *dasctime (struct tws *, int); -char *dtimezone (int, int); -void twscopy (struct tws *, struct tws *); -int twsort (struct tws *, struct tws *); -time_t dmktime (struct tws *); -void set_dotw (struct tws *); - -struct tws *dparsetime (char *); +** prototypes +*/ +char *dtime(time_t *); +char *dtimenow(void); +char *dctime(struct tws *); +struct tws *dlocaltimenow(void); +struct tws *dlocaltime(time_t *); +struct tws *dgmtime(time_t *); +char *dasctime(struct tws *); +char *dtimezone(int, int); +void twscopy(struct tws *, struct tws *); +int twsort(struct tws *, struct tws *); +time_t dmktime(struct tws *); +void set_dotw(struct tws *); +struct tws *dparsetime(char *); diff --git a/h/utils.h b/h/utils.h index b9660a5..a8059ea 100644 --- a/h/utils.h +++ b/h/utils.h @@ -1,13 +1,11 @@ - /* - * utils.h -- utility prototypes - */ +** utils.h -- utility prototypes +*/ void *mh_xmalloc(size_t); void *mh_xrealloc(void *, size_t); char *pwd(void); char *add(char *, char *); -int folder_exists(char *); void create_folder(char *, int, void (*)(int)); int num_digits(int); @@ -17,4 +15,3 @@ struct msgs_array { }; void app_msgarg(struct msgs_array *, char *); -int open_form(char **, char *); diff --git a/h/vmhsbr.h b/h/vmhsbr.h deleted file mode 100644 index 0b5a9a3..0000000 --- a/h/vmhsbr.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* - * vmhsbr.h -- definitions for the vmh protocol - */ - -#define RC_VRSN 1 - -/* flags for rh_type */ -#define RC_INI 0x01 /* must be greater than OK */ -#define RC_ACK 0x02 -#define RC_ERR 0x03 -#define RC_CMD 0x04 -#define RC_QRY 0x05 -#define RC_TTY 0x06 -#define RC_WIN 0x07 -#define RC_DATA 0x08 -#define RC_EOF 0x09 -#define RC_FIN 0x0a -#define RC_XXX 0x0b - -struct record { - struct rcheader { - char rh_type; /* type of record */ - int rh_len; /* length of data */ - } rc_header; - char *rc_data; /* extensible array */ -}; - -#define rc_head(rc) (&rc->rc_header) -#define RHSIZE(rc) (sizeof rc->rc_header) -#define rc_type rc_header.rh_type -#define rc_len rc_header.rh_len - -#define initrc(rc) rc->rc_data = NULL - -/* - * prototypes - */ -int rcinit (int, int); -int rcdone (void); -int rc2rc (char, int, char *, struct record *); -int str2rc (char, char *, struct record *); -int peer2rc (struct record *); -int rc2peer (char, int, char *); -int str2peer (char, char *); -int fmt2peer (char, char *, ...); -int err2peer (char, char *, char *, ...); -int verr2peer (char, char *, char *, va_list); - diff --git a/man/Makefile.in b/man/Makefile.in index c94ab00..9e01e93 100644 --- a/man/Makefile.in +++ b/man/Makefile.in @@ -16,145 +16,142 @@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ etcdir = @sysconfdir@ +datarootdir = @datarootdir@ mandir = @mandir@ manext1 = 1 manext5 = 5 +manext7 = 7 manext8 = 8 mailspool = @mailspool@ sendmailpath = @sendmailpath@ -default_editor = @editorpath@ -default_pager = @pagerpath@ - INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ SED = sed SEDMAN = $(SED) -f man.sed $< > $@ -# sed line for editing pop information in man pages -POPSED = @POPSED@ - .SUFFIXES: -.SUFFIXES: .man .$(manext1) .$(manext5) .$(manext8) +.SUFFIXES: .man1 .man5 .man7 .man8 \ + .$(manext1) .$(manext5) .$(manext7) .$(manext8) + +.man1.$(manext1): + $(SEDMAN) -.man.$(manext1): +.man5.$(manext5): $(SEDMAN) -.man.$(manext5): +.man7.$(manext7): $(SEDMAN) -.man.$(manext8): +.man8.$(manext8): $(SEDMAN) # man pages to install in $(mandir)/$(manext1) -MAN1SRC = ali. anno. burst. comp. \ - dist. flist. flists. folder. folders. \ - forw. inc. install-mh. mark. mh-chart. \ - nmh. mhbuild. mhl. mhlist. mhmail. \ - mhn. mhparam. mhpath. mhshow. \ - mhstore. msgchk. msh. \ - new. fnext. fprev. unseen. \ - next. packf. pick. prev. \ - prompter. rcvdist. rcvpack. \ - rcvstore. rcvtty. refile. \ - repl. rmf. rmm. scan. \ - send. sendfiles. show. slocal. \ - sortm. whatnow. whom. - -MAN5SRC = mh-alias. mh-draft. mh-format. \ - mh-mail. mh-profile. mh-sequence. \ - mh-tailor. mts.conf. - -MAN8SRC = ap. conflict. dp. fmtdump. \ - post. +MAN1SRC = ali. anno. burst. comp. dist. flist. flists. folder. folders. \ + forw. inc. mark. mhbuild. mhl. mhlist. mhsign. mhpgp. mmh. mmhwrap. \ + mhmail. mhparam. mhpath. mhstore. new. fnext. \ + fprev. unseen. next. packf. pick. prev. prompter. rcvdist. rcvpack. \ + rcvstore. refile. repl. rmf. rmm. scan. send. sendfiles. \ + show. slocal. sortm. whatnow. whom. + +MAN5SRC = mh-alias. mh-format. mh-mail. mh-profile. mh-tailor. + +MAN7SRC = mmh-intro. mh-chart. mh-draft. mh-sequence. + +MAN8SRC = spost. ap. dp. fmtdump. MAN1 = $(MAN1SRC:.=.$(manext1)) MAN5 = $(MAN5SRC:.=.$(manext5)) +MAN7 = $(MAN7SRC:.=.$(manext7)) MAN8 = $(MAN8SRC:.=.$(manext8)) -# Since vmh is not built or distributed, neither should vmh.1 be -# MANEXTRA = vmh. - # source for man pages -DIST_MANSRC = $(MAN1SRC) $(MAN5SRC) $(MAN8SRC) -DIST_MAN = $(DIST_MANSRC:.=.man) +DIST_MAN1 = $(MAN1SRC:.=.man1) +DIST_MAN5 = $(MAN5SRC:.=.man5) +DIST_MAN7 = $(MAN7SRC:.=.man7) +DIST_MAN8 = $(MAN8SRC:.=.man8) # auxiliary files -AUX = Makefile.in +AUX = Makefile.in mh-chart-gen.sh # all files in this directory included in the distribution -DIST = $(DIST_MAN) $(AUX) +DIST = $(DIST_MAN1) $(DIST_MAN5) $(DIST_MAN7) $(DIST_MAN8) $(AUX) +ALLPROGS = $(DIST_MAN1) $(DIST_MAN8) # ========= DEFAULT TARGET ========== -all: $(MAN1) $(MAN5) $(MAN8) +all: $(MAN1) $(MAN5) $(MAN7) $(MAN8) + +mh-chart.man7: $(ALLPROGS) + $(srcdir)/mh-chart-gen.sh $(ALLPROGS) >$@ -$(MAN1) $(MAN5) $(MAN8): man.sed +$(MAN1) $(MAN5) $(MAN7) $(MAN8): man.sed # create the sed file for building man pages man.sed: Makefile - echo 's,%nmhwarning%,THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.,g' > $@ - echo 's,%nmhversion%,nmh-$(VERSION),g' >> $@ - echo 's,%nmhdate%,$(DATE),g' >> $@ - echo 's,%bindir%,$(bindir),g' >> $@ - echo 's,%etcdir%,$(etcdir),g' >> $@ - echo 's,%libdir%,$(libdir),g' >> $@ - echo 's,%mandir%,$(mandir),g' >> $@ - echo 's,%mailspool%,$(mailspool),g' >> $@ - echo 's,%sendmailpath%,$(sendmailpath),g' >> $@ - echo 's,%default_editor%,$(default_editor),g' >> $@ - echo 's,%default_pager%,$(default_pager),g' >> $@ - echo 's,%manext1%,$(manext1),g' >> $@ - echo 's,%manext5%,$(manext5),g' >> $@ - echo 's,%manext8%,$(manext8),g' >> $@ - echo '$(POPSED)' >> $@ - echo '/%components%/r $(top_srcdir)/etc/components' >> $@ - echo ' s,%components%,,g' >> $@ - echo '/%distcomps%/r $(top_srcdir)/etc/distcomps' >> $@ - echo ' s,%distcomps%,,g' >> $@ - echo '/%forwcomps%/r $(top_srcdir)/etc/forwcomps' >> $@ - echo ' s,%forwcomps%,,g' >> $@ - echo '/%mhl_forward%/r $(top_srcdir)/etc/mhl.forward' >> $@ - echo ' s,%mhl_forward%,,g' >> $@ - echo '/%mhl_format%/r $(top_srcdir)/etc/mhl.format' >> $@ - echo ' s,%mhl_format%,,g' >> $@ - echo '/%mhl_reply%/r $(top_srcdir)/etc/mhl.reply' >> $@ - echo ' s,%mhl_reply%,,g' >> $@ + @echo 's,%nmhwarning%,THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.,g' > $@ + @echo 's,%nmhversion%,mmh-$(VERSION),g' >> $@ + @echo 's,%nmhdate%,$(DATE),g' >> $@ + @echo 's,%bindir%,$(bindir),g' >> $@ + @echo 's,%etcdir%,$(etcdir),g' >> $@ + @echo 's,%libdir%,$(libdir),g' >> $@ + @echo 's,%mandir%,$(mandir),g' >> $@ + @echo 's,%mailspool%,$(mailspool),g' >> $@ + @echo 's,%sendmailpath%,$(sendmailpath),g' >> $@ + @echo 's,%manext1%,$(manext1),g' >> $@ + @echo 's,%manext5%,$(manext5),g' >> $@ + @echo 's,%manext7%,$(manext7),g' >> $@ + @echo 's,%manext8%,$(manext8),g' >> $@ + @echo '/%components%/r $(top_srcdir)/etc/components' >> $@ + @echo ' s,%components%,,g' >> $@ + @echo '/%distcomps%/r $(top_srcdir)/etc/distcomps' >> $@ + @echo ' s,%distcomps%,,g' >> $@ + @echo '/%forwcomps%/r $(top_srcdir)/etc/forwcomps' >> $@ + @echo ' s,%forwcomps%,,g' >> $@ + @echo '/%mhl_forward%/r $(top_srcdir)/etc/mhl.forward' >> $@ + @echo ' s,%mhl_forward%,,g' >> $@ + @echo '/%mhl_format%/r $(top_srcdir)/etc/mhl.format' >> $@ + @echo ' s,%mhl_format%,,g' >> $@ + @echo '/%mhl_reply%/r $(top_srcdir)/etc/mhl.reply' >> $@ + @echo ' s,%mhl_reply%,,g' >> $@ # ========= INSTALL TARGETS ========= -install: install-man1 install-man5 install-man8 +install: install-man1 install-man5 install-man7 install-man8 # install the man pages in man1 install-man1: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/man$(manext1) + mkdir -p $(DESTDIR)$(mandir)/man$(manext1) for file in $(MAN1); do \ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$(manext1) ; \ done # install the man pages in man5 install-man5: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/man$(manext5) + mkdir -p $(DESTDIR)$(mandir)/man$(manext5) for file in $(MAN5); do \ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$(manext5) ; \ done - if [ ! -f $(DESTDIR)$(mandir)/man$(manext5)/mh_profile.$(manext5) ] ; then \ - ( cd $(DESTDIR)$(mandir)/man$(manext5) ; ln mh-profile.$(manext5) \ - mh_profile.$(manext5) ) \ - fi + +# install the man pages in man7 +install-man7: + mkdir -p $(DESTDIR)$(mandir)/man$(manext7) + for file in $(MAN7); do \ + $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$(manext7) ; \ + done # install the man pages in man8 install-man8: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/man$(manext8) + mkdir -p $(DESTDIR)$(mandir)/man$(manext8) for file in $(MAN8); do \ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$(manext8) ; \ done # ========= UNINSTALL TARGETS ========= -uninstall: uninstall-man1 uninstall-man5 uninstall-man8 +uninstall: uninstall-man1 uninstall-man5 uninstall-man7 uninstall-man8 # uninstall the man pages in man1 uninstall-man1: @@ -168,6 +165,12 @@ uninstall-man5: rm -f $(DESTDIR)$(mandir)/man$(manext5)/$$file; \ done +# uninstall the man pages in man7 +uninstall-man7: + for file in $(MAN7); do \ + rm -f $(DESTDIR)$(mandir)/man$(manext7)/$$file; \ + done + # uninstall the man pages in man8 uninstall-man8: for file in $(MAN8); do \ @@ -180,7 +183,8 @@ mostlyclean: rm -f *~ clean: mostlyclean - rm -f man.sed *.$(manext1) *.$(manext5) *.$(manext8) + rm -f $(MAN1) $(MAN5) $(MAN7) $(MAN8) + rm -f man.sed mh-chart.man7 distclean: clean rm -f Makefile @@ -197,9 +201,9 @@ subdir = man Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ diff --git a/man/ali.man b/man/ali.man deleted file mode 100644 index f2fb580..0000000 --- a/man/ali.man +++ /dev/null @@ -1,100 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH ALI %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -ali \- list mail aliases -.SH SYNOPSIS -.HP 5 -.na -.B ali -.RB [ \-alias -.IR aliasfile ] -.RB [ \-list " | " \-nolist ] -.RB [ \-normalize " | " \-nonormalize ] -.RB [ \-user " | " \-nouser ] -.RB [ \-version ] -.RB [ \-help ] -.RI [ aliases " ...]" -.ad -.SH DESCRIPTION -.B Ali -searches the named mail alias files for each of the given -.IR aliases . -It creates a list of addresses for those -.IR aliases , -and writes that list on standard output. If no arguments are given, -.B ali -outputs all alias entries. -.PP -By default, when an aliases expands to multiple addresses, the addresses -are separated by commas and printed on as few lines as possible. If the -.B \-list -option is specified, then when an address expands to multiple -addresses, each address will appear on a separate line. -.PP -The switch -.B \-user -directs -.B ali -to perform its processing in -an inverted fashion: instead of listing the addresses that each given -alias expands to, -.B ali -will list the aliases that expand to each -given address. If the -.B \-normalize -switch is given, -.B ali -will -try to track down the official hostname of the address. -.PP -The files specified by the profile entry -.RI \*(lq Aliasfile \*(rq -and any additional alias files given by the -.B \-alias -.I aliasfile -switch will be read. Each -.I alias -is processed as described in -.BR mh\-alias (5). - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^/etc/passwd~^List of users -^/etc/group~^List of groups -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Aliasfile:~^For a default alias file -.fi - -.SH "SEE ALSO" -mh\-alias(5) - -.SH DEFAULTS -.nf -.RB ` aliasfiles "' defaults to %etcdir%/MailAliases" -.RB ` \-nolist ' -.RB ` \-nonormalize ' -.RB ` \-nouser ' -.fi - -.SH CONTEXT -None - -.SH BUGS -The -.B \-user -option with -.B \-nonormalize -is not entirely accurate, as it -does not replace local nicknames for hosts with their official site names. diff --git a/man/ali.man1 b/man/ali.man1 new file mode 100644 index 0000000..b45fb92 --- /dev/null +++ b/man/ali.man1 @@ -0,0 +1,108 @@ +.\" +.\" %nmhwarning% +.\" +.TH ALI %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +ali \- list mail aliases +.SH SYNOPSIS +.HP 5 +.na +.B ali +.RB [ \-file +.IR aliasfile ]... +.RB [ \-list " | " \-nolist ] +.RB [ \-normalize " | " \-nonormalize ] +.RB [ \-user " | " \-nouser ] +.RB [ \-Version ] +.RB [ \-help ] +.RI [ aliases " ...]" +.ad +.SH DESCRIPTION +.B Ali +searches the named mail alias files for each of the given +.IR aliases . +It creates a list of addresses for those +.IR aliases , +and writes that list on standard output. If no arguments are given, +.B ali +outputs all alias entries. +This can be used to check the format of the alias file for validity. +.PP +By default, when an aliases expands to multiple addresses, the addresses +are separated by commas and printed on as few lines as possible. If the +.B \-list +option is specified, then when an address expands to multiple +addresses, each address will appear on a separate line. +.PP +The switch +.B \-user +directs +.B ali +to perform its processing in +an inverted fashion: instead of listing the addresses that each given +alias expands to, +.B ali +will list the aliases that expand to each +given address. If the +.B \-normalize +switch is given, +.B ali +will +try to track down the official hostname of the address. +.PP +If no +.B \-file +.I aliasfile +is given, then the default alias files, as specified by the profile entry +.RI ` Aliasfile ', +will be read. +If any alias files are given by +.B \-file +.I aliasfile +switches, these will be read instead of the default alias files. +Either the default alias files are read or the ones given at the +command line, never both. +.PP +Each +.I alias +is processed as described in +.BR mh\-alias (5). + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^/etc/passwd~^List of users +^/etc/group~^List of groups +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Aliasfile:~^For default alias files +.fi + +.SH "SEE ALSO" +mh\-alias(5) + +.SH DEFAULTS +.nf +.RB ` \-nolist ' +.RB ` \-nonormalize ' +.RB ` \-nouser ' +.fi + +.SH CONTEXT +None + +.SH BUGS +The +.B \-user +option with +.B \-nonormalize +is not entirely accurate, as it +does not replace local nicknames for hosts with their official site names. diff --git a/man/anno.man b/man/anno.man deleted file mode 100644 index f97efa5..0000000 --- a/man/anno.man +++ /dev/null @@ -1,182 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH ANNO %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -anno \- annotate messages -.SH SYNOPSIS -.HP 5 -.na -.B anno -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-component -.IR field ] -.RB [ \-inplace " | " \-noinplace ] -.RB [ \-date " | " \-nodate ] -.RB [ \-draft ] -.RB [ \-append ] -.RB [ \-list ] -.RB [ \-delete ] -.RB [ \-number -.IR [ num|all ]] -.RB [ \-preserve " | " \-nopreserve ] -.RB [ \-version ] -.RB [ \-help ] -.RB [ \-text -.IR body ] -.ad -.SH DESCRIPTION -.B Anno -manipulates header fields or -.I annotations -in messages. -Header fields consist of a field name and an optional field body -as defined by RFC-2822. -The -.B -component -option specifies the field name, and the -.B -text -option specifies the field body. -.PP -The messages are either the -.I msgs -in the named folder, or the draft if invoked with the -.B -draft -option. -.PP -Usually, annotation is performed by the commands -.BR dist , -.BR forw , -and -.BR repl , -if they are given the -.B \-anno -switch. This allows you to keep track of your distribution of, -forwarding of, and replies to a message. -.PP -By using -.BR anno , -you can perform arbitrary annotations of your own. -Each message selected will be annotated with the lines -.PP - field:\ date - field:\ body -.PP -The -.B \-nodate -switch inhibits the date annotation, leaving only the -body annotation. -.PP -By default, -.B anno -prepends the annotations to the message. -Annotations are instead appended if the -.B -append -option is specified. -.PP -If a -.B \-component -.I field -is not specified when -.B anno -is invoked, -.B anno -will prompt the user for the name of field for the annotation. -.PP -The field specified must be a valid 2822-style message field name, -which means that it may only consist of alphanumerics and dashes, -The body specified is arbitrary text. -.PP -Normally -.B anno -does the annotation inplace in order to preserve -any links to the message. You may change this by using the -.B \-noinplace -switch. -.PP -The -.B -list -option produces a listing of the field bodies for header fields with -names matching the specified component, one per line. -The listing is numbered, starting at 1, if the -.B -number -option is also used. -A tab character separates the number and the field body. -The field body is treated as if it is a file name, and only the final -path name component is listed. -The complete field body is listed if the -.B -text -option is used, the contents of the text are ignored. -.PP -The -.B -delete -option removes header fields from messages. -The first header field whose name matches the component is deleted if -no other options are specified. -If the -.B -text -option is used in conjunction with the -.B -delete -option, the first header field whose name matches the component and -whose body matches the text is deleted. -The text is treated as if it was a file name; if it begins with a -slash, the entire field body must match the text, otherwise just the -last path name component of the field body must match. -If the -.B -number -option is used in conjuction with the -.B -delete -option, header field -.I num -whose name matches the component is deleted. -The number matches that which is produced by the -.B -list -option. -The special value -.B all -can be used for the number, and causes all components that match the -name to be deleted. -.PP -By default, -.B anno -changes the last-accessed and last-modified times on annotate messages -to the time at which the annotation occurs. -.B Anno -preserves the original times if the -.B -preserve -option is used. -A matching -.B -nopreserve -option exists that allows time preservation to be turned off if enabled -in the profile. -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -dist(1), forw(1), repl(1) - -.SH DEFAULTS -.nf -.RI ` +folder "' defaults to the current folder" -.RI ` msgs "' defaults to cur" -.RB ` \-inplace ' -.RB ` \-date ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The first -message annotated will become the current message. diff --git a/man/anno.man1 b/man/anno.man1 new file mode 100644 index 0000000..07bd32c --- /dev/null +++ b/man/anno.man1 @@ -0,0 +1,236 @@ +.\" +.\" %nmhwarning% +.\" +.TH ANNO %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +anno \- annotate messages +.SH SYNOPSIS +.HP 5 +.na +.B anno +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-component +.IR field ] +.RB [ \-text +.IR body ] +.RB [ \-append ] +.RB [ \-date " | " \-nodate ] +.RB [ \-preserve " | " \-nopreserve ] +.RB [ \-Version ] +.RB [ \-help ] +.HP +.B anno +.B \-delete +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-component +.IR field ] +.RB [ \-text +.IR body ] +.RB [ \-number +.IR num " | all ] +.RB [ \-preserve " | " \-nopreserve ] +.RB [ \-Version ] +.RB [ \-help ] +.HP +.B anno +.B \-list +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-component +.IR field ] +.RB [ \-number ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Anno +manipulates header fields or +.I annotations +in messages. +Header fields consist of a field name and an optional field body +as defined by RFC-2822. +The field name may consist of alphanumerics and dashes only. +The field body may consist of arbitrary text. +.PP +Usually, annotation is performed by the commands +.BR dist , +.BR forw , +and +.BR repl , +if they are given the +.B \-anno +switch. This allows you to keep track of your redistribution of, +forwarding of, and replies to a message. +The +.B whatnow +shell uses annoations to manage attachments, too. +.PP +By using +.BR anno +manually, you can perform arbitrary annotations of your own. +.PP +.B Anno +has three operation modes: Adding, deleting and listing of header lines. + +.SS "Add mode +.PP +This is the default mode. +Historically, it had been the only mode available. +.PP +Each message selected will be annotated with the lines +.PP +.RS 5 +.nf +field:\ date +field:\ body +.fi +.RE +.PP +The +.B \-component +option specifies the field name. +If no +.B \-component +.I field +is specified, +.B anno +will prompt the user for the name of field for the annotation. +.PP +The +.B \-text +option specifies the field body. +If it is missing, only the date annotation will be added. +The +.B \-nodate +switch inhibits the date annotation, leaving only the +body annotation. +.PP +By default, +.B anno +prepends the annotations to the message. +Annotations are instead appended if the +.B \-append +option is specified. +.PP +.B Anno +always does the annotation inplace in order to preserve +any links to the message. +.PP +By default, +.B anno +changes the last-accessed and last-modified times on annotate messages +to the time at which the annotation occurs. +.B Anno +preserves the original times if the +.B \-preserve +option is used. + +.SS "Delete mode +.PP +The +.B \-delete +mode removes header fields from messages. +By default, the first header field whose name matches the component +is deleted. +.PP +The +.B \-component +option specifies the field name of headers to delete. +If no +.B \-component +.I field +is specified, +.B anno +will prompt the user for the name. +.PP +If the +.B \-text +option is used, +the first header field whose name matches the component and +whose body matches the text is deleted. +The text is treated as if it was a path name; if it begins with a +slash, the entire field body must match the text, otherwise just the +last path name component of the field body must match. +.PP +If the +.B \-number +option is used, +the +.IR n th +header field whose name matches the component is deleted. +The numbers are the same as those produced in +.B \-list +mode. +The special value `all' can be used for the number, +and causes all components that match the name to be deleted. +.PP +Either +.B \-text +or +.B \-number +may be specified, but not both at the same time. + +.SS "List mode +.PP +The +.B \-list +mode produces a listing of the field bodies for header fields with +matching component names, one per line. +If the +.B \-number +option is also used, +the listing is numbered, starting at 1. +.PP +The +.B \-component +option specifies the field name of headers to list. +If no +.B \-component +.I field +is specified, +.B anno +will prompt the user for the name. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +dist(1), forw(1), repl(1) + +.SH DEFAULTS +.nf +.RI ` +folder "' defaults to the current folder" +.RI ` msgs "' defaults to cur" +.RB ` \-date ' +.RB ` \-nopreserve ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The first +message annotated will become the current message. + +.SH BUGS +.PP +The +.B \-number +switch must appear after either the +.B \-list +or the +.B \-delete +mode switch, on the command line. +Otherwise it is not possible to determine if it takes an argument. diff --git a/man/ap.man b/man/ap.man deleted file mode 100644 index c77b39e..0000000 --- a/man/ap.man +++ /dev/null @@ -1,114 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH AP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -ap \- parse addresses 822-style -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/ap -.RB [ \-form -.IR formatfile ] -.RB [ \-format -.IR string ] -.RB [ \-normalize " | " \-nonormalize ] -.RB [ \-width -.IR columns ] -.RB [ \-version ] -.RB [ \-help ] -.I addrs -\&... -.ad -.SH DESCRIPTION -.B Ap -is a program that parses addresses according to the ARPA -Internet standard. It also understands many non\-standard formats. -It is useful for seeing how -.B nmh -will interpret an address. -.PP -The -.B ap -program treats each argument as one or more addresses, and -prints those addresses out in the official 822\-format. Hence, it is -usually best to enclose each argument in double\-quotes for the shell. -.PP -To override the output format used by -.BR ap , -the -.B \-format -.I string -or -.B \-format -.I file -switches are used. This permits individual fields of -the address to be extracted with ease. The string is simply a format -string, and the file is simply a format file. See -.BR mh\-format (5) -for the details. -.PP -In addition to the standard escapes, -.B ap -also recognizes the following additional escape: -.PP -.RS 5 -.nf -.ta \w'Escape 'u +\w'Returns 'u -.I Escape Returns Description -error string A diagnostic if the parse failed -.RE -.fi -.PP -If the -.B \-normalize -switch is given, -.B ap -will try to track down -the official hostname of the address. -.PP -Here is the default format string used by -.BR ap : -.PP -.RS 5 -%<{error}%{error}: %{text}%|%(putstr(proper{text}))%> -.RE -.PP -which says that if an error was detected, print the error, a `:', and -the address in error. Otherwise, output the 822\-proper format of -the address. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -.fi - -.SH "PROFILE COMPONENTS" -None - -.SH "SEE ALSO" -dp(8), -.I "Standard for the Format of ARPA Internet Text Messages" -(RFC\-822) - -.SH DEFAULTS -.nf -.RB ` \-format "' defaults as described above" -.RB ` \-normalize ' -.RB ` \-width "' defaults to the width of the terminal" -.fi - -.SH CONTEXT -None - -.SH BUGS -The argument to the -.B \-format -switch must be interpreted as a single token -by the shell that invokes -.BR ap . -Therefore, -one must usually place the argument to this switch inside double\-quotes. diff --git a/man/ap.man8 b/man/ap.man8 new file mode 100644 index 0000000..c96770c --- /dev/null +++ b/man/ap.man8 @@ -0,0 +1,102 @@ +.\" +.\" %nmhwarning% +.\" +.TH AP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +ap \- parse addresses 822-style +.SH SYNOPSIS +.HP 5 +.na +.B %libdir%/ap +.RB [ \-form +.IR formatfile ] +.RB [ \-normalize " | " \-nonormalize ] +.RB [ \-Version ] +.RB [ \-help ] +.I addrs +\&... +.ad +.SH DESCRIPTION +.B Ap +is a program that parses addresses according to the ARPA +Internet standard. It also understands many non\-standard formats. +It is useful for seeing how +.B nmh +will interpret an address. +.PP +The +.B ap +program treats each argument as one or more addresses, and +prints those addresses out in the official 822\-format. Hence, it is +usually best to enclose each argument in double\-quotes for the shell. +.PP +To override the output format used by +.BR ap , +the +.B \-form +.I file +switch is used. This permits individual fields of +the address to be extracted with ease. +The +.I file +is either the name of a format file or it may be +a format string directly, if prepended with an equal sign `='. +See +.BR mh\-format (5) +for the details. +.PP +In addition to the standard escapes, +.B ap +also recognizes the following additional escape: +.PP +.RS 5 +.nf +.ta \w'Escape 'u +\w'Returns 'u +.I "Escape Returns Description +error string A diagnostic if the parse failed +.RE +.fi +.PP +If the +.B \-normalize +switch is given, +.B ap +will try to track down +the official hostname of the address. +.PP +Here is the default format string used by +.BR ap : +.PP +.RS 5 +.nf +%<{error}%{error}: %{text}%|%(putstr(proper{text}))%> +.fi +.RE +.PP +which says that if an error was detected, print the error, a `:', and +the address in error. Otherwise, output the 822\-proper format of +the address. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +None + +.SH "SEE ALSO" +dp(8), +.I "Standard for the Format of ARPA Internet Text Messages" +(RFC\-822) + +.SH DEFAULTS +.nf +.RB ` \-form "' defaults as described above" +.RB ` \-normalize ' +.fi + +.SH CONTEXT +None diff --git a/man/burst.man b/man/burst.man deleted file mode 100644 index cb1e6f4..0000000 --- a/man/burst.man +++ /dev/null @@ -1,144 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH BURST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -burst \- explode digests into messages -.SH SYNOPSIS -.HP 5 -.na -.B burst -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-inplace " | " \-noinplace ] -.RB [ \-quiet " | " \-noquiet ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Burst -considers the specified messages in the named folder to be -Internet digests, and explodes them in that folder. -.PP -If -.B \-inplace -is given, each digest is replaced by the \*(lqtable -of contents\*(rq for the digest (the original digest is removed). -.B Burst -then renumbers all of the messages following the digest in the -folder to make room for each of the messages contained within the digest. -These messages are placed immediately after the digest. -.PP -If -.B \-noinplace -is given, each digest is preserved, no table of contents -is produced, and the messages contained within the digest are placed at -the end of the folder. Other messages are not tampered with in any way. -.PP -The -.B \-quiet -switch directs -.B burst -to be silent about reporting -messages that are not in digest format. -.PP -The -.B \-verbose -switch directs -.B burst -to tell the user the general -actions that it is taking to explode the digest. -.PP -It turns out that -.B burst -works equally well on forwarded messages -and blind\-carbon\-copies as on Internet digests, provided that the -former two were generated by -.B forw -or -.BR send . - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Msg\-Protect:~^To set mode when creating a new message -.fi - -.SH "SEE ALSO" -inc(1), msh(1), pack(1), -.I "Proposed Standard for Message Encapsulation" -(RFC\-934) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-noinplace ' -.RB ` \-noquiet ' -.RB ` \-noverbose ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. If -.B \-inplace -is given, then the first message burst becomes the current message. -This leaves the context ready for a -.B show -of the table of contents -of the digest, and a -.B next -to see the first message of the digest. If -.B \-noinplace -is given, then the first message extracted from the -first digest burst becomes the current message. This leaves the context -in a similar, but not identical, state to the context achieved when using -.BR \-inplace . - -.SH BUGS -The -.B burst -program enforces a limit on the number of messages which -may be -.B burst -from a single message. This number is on the order -of 1000 messages. There is usually no limit on the number of messages -which may reside in the folder after the -.BR burst ing. -.PP -Although -.B burst -uses a sophisticated algorithm to determine where -one encapsulated message ends and another begins, not all digestifying -programs use an encapsulation algorithm. In degenerate cases, this -usually results in -.B burst -finding an encapsulation boundary -prematurely and splitting a single encapsulated message into two or -more messages. These erroneous digestifying programs should be fixed. -.PP -Furthermore, any text which appears after the last encapsulated message -is not placed in a separate message by -.BR burst . -In the case of -digestified messages, this text is usually an \*(lqEnd of digest\*(rq -string. As a result of this possibly un\-friendly behavior on the -part of -.BR burst , -note that when the -.B \-inplace -option is used, -this trailing information is lost. In practice, this is not a problem -since correspondents usually place remarks in text prior to the first -encapsulated message, and this information is not lost. diff --git a/man/burst.man1 b/man/burst.man1 new file mode 100644 index 0000000..b5babf6 --- /dev/null +++ b/man/burst.man1 @@ -0,0 +1,103 @@ +.\" +.\" %nmhwarning% +.\" +.TH BURST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +burst \- explode digests into messages +.SH SYNOPSIS +.HP 5 +.na +.B burst +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Burst +considers the specified messages in the named folder to be +Internet digests, and explodes them in that folder. +.PP +The messages contained within the digest are placed at the end of the folder. +The digest is preserved. +No other messages are tampered with in any way. +.PP +The +.B \-verbose +switch directs +.B burst +to tell the user the general +actions that it is taking to explode the digest. +.PP +It turns out that +.B burst +works equally well on forwarded messages +and blind\-carbon\-copies as on Internet digests, provided that they +use RFC 934 message encapsulation. +.PP +To extract messages encapsulated with MIME, use +.BR mhstore (1). + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Msg\-Protect:~^To set mode when creating a new message +.fi + +.SH "SEE ALSO" +mhstore(1), +.I "Proposed Standard for Message Encapsulation" +(RFC\-934) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. +The first message extracted from the +first digest burst becomes the current message. + +.SH BUGS +The +.B burst +program enforces a limit on the number of messages which +may be +.B burst +from a single message. This number is on the order +of 1000 messages. There is usually no limit on the number of messages +which may reside in the folder after the +.BR burst ing. +.PP +Although +.B burst +uses a sophisticated algorithm to determine where +one encapsulated message ends and another begins, not all digestifying +programs use an encapsulation algorithm. In degenerate cases, this +usually results in +.B burst +finding an encapsulation boundary +prematurely and splitting a single encapsulated message into two or +more messages. These erroneous digestifying programs should be fixed. +.PP +Any text which appears after the last encapsulated message +is not placed in a separate message by +.BR burst . +In the case of +digestified messages, this text is usually an `End of digest' +string. diff --git a/man/comp.man b/man/comp.man deleted file mode 100644 index bfb78b3..0000000 --- a/man/comp.man +++ /dev/null @@ -1,212 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH COMP %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -comp \- compose a message -.SH SYNOPSIS -.HP 5 -.na -.B comp -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-form -.IR formfile ] -.RB [ \-use " | " \-nouse ] -.RB [ \-file -.IR file ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-editor -.IR editor ] -.RB [ \-noedit ] -.RB [ \-whatnowproc -.IR program ] -.RB [ \-nowhatnowproc ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Comp -is used to create a new message to be mailed. It copies a -message form to the draft being composed and then invokes an editor on -the draft (unless -.B \-noedit -is given, in which case the initial edit is suppressed). -.PP -The default message form contains the following elements: -.PP -.RS 5 -.nf -%components% -.fi -.RE -.PP -If a file named -.RI \*(lq components \*(rq -exists in the user's nmh directory, -it will be used instead of this form. You may specify an alternate -forms file with the switch -.B \-form -.IR formfile . -.PP -You may also start -.B comp -using the contents of an existing message -as the form. If you supply either a -.I +folder -or -.I msg -argument, that -message will be used as the message form. You may not supply both a -.B \-form -.I formfile -and a -.I +folder -or -.I msg -argument. The line of -dashes or a blank line must be left between the header and the body of -the message for the message to be identified properly when it is sent -(see -.BR send (1)). -.PP -The switch -.B \-use -directs -.B comp -to continue editing an already -started message. That is, if a -.B comp -(or -.BR dist , -.BR repl , -or -.BR forw ) -is terminated without sending the draft, the draft can -be edited again via -.RB \*(lq comp -.BR \-use \*(rq. -.PP -The -.B \-file -.I file -switch says to use the named file as the message draft. -.PP -If the draft already exists, -.B comp -will ask you as to the disposition -of the draft. A reply of -.B quit -will abort -.BR comp , -leaving the draft intact; -.B replace -will replace the existing draft with -the appropriate form; -.B list -will display the draft; -.B use -will use the draft for further composition; and -.B refile -.I +folder -will file the draft in the given folder, and give you a new draft with the -appropriate form. (The -.I +folder -argument to -.B refile -is required.) -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more information. -.PP -The -.B \-editor -.I editor -switch indicates the editor to use for the -initial edit. Upon exiting from the editor, -.B comp -will invoke the -.B whatnow -program. See -.BR whatnow (1) -for a discussion of -available options. The invocation of this program can be inhibited -by using the -.B \-nowhatnowproc -switch. (In truth of fact, it is -the -.I whatnow -program which starts the initial edit. Hence, -.B \-nowhatnowproc -will prevent any edit from occurring.) - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/components~^The standard message skeleton -^or /components~^Rather than the standard skeleton -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^Msg\-Protect:~^To set mode when creating a new message (draft) -^fileproc:~^Program to refile the message -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi - -.SH "SEE ALSO" -dist(1), forw(1), repl(1), send(1), whatnow(1), mh-profile(5) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to the current message" -.RB ` \-nodraftfolder ' -.RB ` \-nouse ' -.fi - -.SH CONTEXT -None - -.SH BUGS -If -.I whatnowproc -is -.BR whatnow , -then -.B comp -uses a built\-in -.BR whatnow , -it does not actually run the -.B whatnow -program. -Hence, if you define your own -.IR whatnowproc , -don't call it -.B whatnow -since -.B comp -won't run it. diff --git a/man/comp.man1 b/man/comp.man1 new file mode 100644 index 0000000..2f1cda0 --- /dev/null +++ b/man/comp.man1 @@ -0,0 +1,169 @@ +.\" +.\" %nmhwarning% +.\" +.TH COMP %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +comp \- compose a message +.SH SYNOPSIS +.HP 5 +.na +.B comp +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-form +.IR formfile ] +.RB [ \-use " | " \-nouse ] +.RB [ \-editor +.IR editor ] +.RB [ \-whatnowproc +.IR program ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Comp +is used to create a new message to be mailed. It copies a +message form to the draft being composed and then invokes an editor on +the draft (unless the +.B \-editor +switch with an empty string argument is given, +in which case the initial edit is suppressed). +.PP +The default message form contains the following elements: +.PP +.RS 5 +.nf +%components% +.fi +.RE +.PP +If a file named +.RI ` components ' +exists in the user's mmh directory, +it will be used instead of this form. You may specify an alternate +forms file with the switch +.B \-form +.IR formfile . +.PP +You may also start +.B comp +using the contents of an existing message +as the form. If you supply a +.I +folder +or +.I msg +argument, that +message will be used as the message form. You may not supply both a +.B \-form +.I formfile +and a +.I +folder +or +.I msg +argument. The line of +dashes or a blank line must be left between the header and the body of +the message for the message to be identified properly when it is sent +(see +.BR send (1)). +.PP +The switch +.B \-use +directs +.B comp +to continue editing an already +started message. That is, if a +.B comp +(or +.BR dist , +.BR repl , +or +.BR forw ) +is terminated without sending the draft, the draft can +be edited again via +.RB ` comp +.BR \-use '. +If +.B \-use +is given, +.I msg +is located within the draft folder. +A +.I +folder +argument is not allowed together with +.BR \-use . +.PP +If the draft already exists, +.B comp +will ask you as to the disposition +of the draft. A reply of +.B quit +will abort +.BR comp , +leaving the draft intact; +.B replace +will replace the existing draft with +the appropriate form; +.B list +will display the draft; +.B use +will use the draft for further composition; and +.B refile +.I +folder +will file the draft in the given folder, and give you a new draft with the +appropriate form. (The +.I +folder +argument to +.B refile +is required.) +.PP +Consult the +.BR mh-draft (7) +man page for more information. +.PP +The +.B \-editor +.I editor +switch indicates the editor to use for the +initial edit. Upon exiting from the editor, +.B comp +will invoke the +.B whatnow +program. See +.BR whatnow (1) +for a discussion of +available options. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/components~^The standard message skeleton +^or $HOME/.mmh/components~^Rather than the standard skeleton +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Draft\-Folder:~^To set the default draft folder +^Editor:~^To override the default editor +^Msg\-Protect:~^To set mode when creating a new message (draft) +^whatnowproc:~^Program to ask the `What now?' questions +.fi + +.SH "SEE ALSO" +dist(1), forw(1), repl(1), send(1), whatnow(1), mh-profile(5) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msg "' defaults to the current message" +.RB ` \-nouse ' +.fi + +.SH CONTEXT +None diff --git a/man/conflict.man b/man/conflict.man deleted file mode 100644 index f690596..0000000 --- a/man/conflict.man +++ /dev/null @@ -1,84 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH CONFLICT %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -conflict \- search for alias/password conflicts -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/conflict -.RB [ \-search -.IR directory ] -.RB [ \-mail -.IR name ] -.RB [ \-version ] -.RB [ \-help ] -.RI [ aliasfiles -\&...] -.ad -.SH DESCRIPTION -.B Conflict -is a program that checks to see if the interface between -.B nmh -and the transport system is in good shape -.PP -.B Conflict -also checks for maildrops in %mailspool% which do not -belong to a valid user. It assumes that no user name will start with -`.', and thus ignores files in %mailspool% which begin with `.'. It also -checks for entries in the -.BR group (5) -file which do not belong -to a valid user, and for users who do not have a valid group number. -In addition duplicate users and groups are noted. -.PP -If the -.B \-mail -.I name -switch is used, then the results will be sent -to the specified -.IR name . -Otherwise, the results are sent to the standard output. -.PP -The -.B \-search -.I directory -switch can be used to search directories -other than %mailspool% and to report anomalies in those directories. -The -.B \-search -.I directory -switch can appear more than one time in an -invocation to -.BR conflict . -.PP -.B Conflict -should be run under -.BR cron (8), -or whenever system accounting takes place. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -^/etc/passwd~^List of users -^/etc/group~^List of groups -^%bindir%/mhmail~^Program to send mail -^%mailspool%/~^Directory of mail drop -.fi - -.SH "PROFILE COMPONENTS" -None - -.SH "SEE ALSO" -mh\-alias(5) - -.SH "DEFAULTS" -.nf -.RB ` aliasfiles "' defaults to %etcdir%/MailAliases" -.fi - -.SH CONTEXT -None diff --git a/man/dist.man b/man/dist.man deleted file mode 100644 index ae7be11..0000000 --- a/man/dist.man +++ /dev/null @@ -1,238 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH DIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -dist \- redistribute a message to additional addresses -.SH SYNOPSIS -.HP 5 -.na -.B dist -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-form -.IR formfile ] -.RB [ \-annotate " | " \-noannotate ] -.RB [ \-inplace " | " \-noinplace ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-editor -.IR editor ] -.RB [ \-noedit ] -.RB [ \-whatnowproc -.IR program ] -.RB [ \-nowhatnowproc ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Dist -is similar to -.BR forw . -It prepares the specified message -for redistribution to addresses that (presumably) are not on the original -address list. -.PP -The default message form contains the following elements: -.PP -.RS 5 -.nf -%distcomps% -.fi -.RE -.PP -If a file named -.RI \*(lq distcomps \*(rq -exists in the user's nmh directory, it -will be used instead of this default form. You may specify an alternate -forms file with the switch -.B \-form -.IR formfile . -The form used will be prepended to the message being resent. -.PP -If the draft already exists, -.B dist -will ask you as to the disposition of the draft. A reply of -.B quit -will abort -.BR dist , -leaving the draft intact; -.B replace -will replace the existing draft with a blank skeleton; and -.B list -will display the draft. -.PP -Only those addresses in -.RI \*(lq Resent\-To: \*(rq, -.RI \*(lq Resent\-cc: \*(rq, -and -.RI \*(lq Resent\-Bcc: \*(rq -will be sent. Also, a -.RI \*(lq "Resent\-Fcc: folder" \*(rq -will be honored (see -.BR send (1)). -Note that with -.BR dist , -the draft should contain only -.RI \*(lq Resent\-xxx: \*(rq -fields and no body. The headers and the body of -the original message are copied to the draft when the message is sent. -Use care in constructing the headers for the redistribution. -.PP -If the -.B \-annotate -switch is given, the message being distributed will -be annotated with the lines: - - Resent:\ date - Resent:\ addrs - -where each address list contains as many lines as required. This -annotation will be done only if the message is sent directly from -.BR dist . -If the message is not sent immediately from -.BR dist , -.RB \*(lq comp -.BR \-use \*(rq -may be used to re\-edit and send the constructed -message, but the annotations won't take place. Normally annotations are -done inplace in order to preserve any links to the message. You may use -the -.B \-noinplace -switch to change this. -.PP -See -.BR comp (1) -for a description of the -.B \-editor -and -.B \-noedit -switches. Note that while in the editor, the message being resent -is available through a link named \*(lq@\*(rq (assuming the default -.IR whatnowproc ). -In addition, the actual pathname of the message is -stored in the environment variable -.BR $editalt , -and the pathname of -the folder containing the message is stored in the environment variable -.BR $mhfolder . -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more information. -.PP -Upon exiting from the editor, -.B dist -will invoke the -.B whatnow -program. See -.BR whatnow (1) -for a discussion of available options. The invocation of this -program can be inhibited by using the -.B \-nowhatnowproc -switch. (In truth of fact, it is the -.B whatnow -program which starts the initial edit. Hence, -.B \-nowhatnowproc -will prevent any edit from occurring.) - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/distcomps~^The standard message skeleton -^or /distcomps~^Rather than the standard skeleton -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^fileproc:~^Program to refile the message -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi - -.SH "SEE ALSO" -comp(1), forw(1), repl(1), send(1), whatnow(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to cur" -.RB ` \-noannotate ' -.RB ` \-nodraftfolder ' -.RB ` \-inplace ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The message -distributed will become the current message. - -.SH HISTORY -.B Dist -originally used headers of the form -.RI \*(lq Distribute\-xxx: \*(rq -instead of -.RI \*(lq Resent\-xxx: \*(rq. -In order to conform with the ARPA Internet standard, RFC\-822, the -.RI \*(lq Resent\-xxx: \*(rq -form is now used. -.B Dist -will recognize -.RI \*(lq Distribute\-xxx: \*(rq -type headers and automatically convert them to -.RI \*(lq Resent\-xxx: \*(rq. - -.SH BUGS -.B Dist -does not rigorously check the message being distributed -for adherence to the transport standard, but -.B post -called by -.B send -does. The -.B post -program will balk (and rightly so) at poorly formatted messages, and -.B dist -won't correct things for you. -.PP -If -.I whatnowproc -is -.BR whatnow , -then -.B comp -uses a built\-in -.BR whatnow , -it does not actually run the -.B whatnow -program. -Hence, if you define your own -.IR whatnowproc , -don't call it -.B whatnow -since -.B comp -won't run it. -.PP -If your current working directory is not writable, the link named -\*(lq@\*(rq is not available. diff --git a/man/dist.man1 b/man/dist.man1 new file mode 100644 index 0000000..8e27f66 --- /dev/null +++ b/man/dist.man1 @@ -0,0 +1,168 @@ +.\" +.\" %nmhwarning% +.\" +.TH DIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +dist \- redistribute a message to additional addresses +.SH SYNOPSIS +.HP 5 +.na +.B dist +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-form +.IR formfile ] +.RB [ \-annotate " | " \-noannotate ] +.RB [ \-editor +.IR editor ] +.RB [ \-whatnowproc +.IR program ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Dist +is similar to +.BR forw . +It prepares the specified message +for redistribution to addresses that (presumably) are not on the original +address list. +.PP +The default message form contains the following elements: +.PP +.RS 5 +.nf +%distcomps% +.fi +.RE +.PP +If a file named +.RI ` distcomps ' +exists in the user's mmh directory, it +will be used instead of this default form. You may specify an alternate +forms file with the switch +.B \-form +.IR formfile . +The form used will be prepended to the message being resent. +.PP +Only those addresses in +.RI ` Resent\-To: ', +.RI ` Resent\-Cc: ', +and +.RI ` Resent\-Bcc: ' +will be sent. Also, a +.RI ` "Resent\-Fcc: folder" ' +will be honored (see +.BR send (1)). +Note that with +.BR dist , +the draft should contain only +.RI ` Resent\-xxx: ' +fields and no body. The headers and the body of +the original message are copied to the draft when the message is sent. +Use care in constructing the headers for the redistribution. +.PP +If the +.B \-annotate +switch is given, the message being distributed will +be annotated with the line: + + Resent:\ date + +This annotation will be done only if the message is sent directly from +.BR dist . +If the message is not sent immediately from +.BR dist , +.RB ` comp +.BR \-use ' +may be used to re\-edit and send the constructed +message, but the annotations won't take place. Annotations are always +done inplace in order to preserve any links to the message. +.PP +See +.BR comp (1) +for a description of the +.B \-editor +switch. Note that while in the editor, the actual pathname of the +message being resent is stored in the environment variable +.BR $mhaltmsg , +and the pathname of +the folder containing the message is stored in the environment variable +.BR $mhfolder . +.PP +Consult the +.BR mh-draft (7) +man page for more information. +.PP +Upon exiting from the editor, +.B dist +will invoke the +.B whatnow +program. See +.BR whatnow (1) +for a discussion of available options. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/distcomps~^The standard message skeleton +^or $HOME/.mmh/distcomps~^Rather than the standard skeleton +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Draft\-Folder:~^To set the default draft\-folder +^Editor:~^To override the default editor +^whatnowproc:~^Program to ask the `What now?' questions +.fi + +.SH "SEE ALSO" +comp(1), forw(1), repl(1), send(1), whatnow(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msg "' defaults to cur" +.RB ` \-noannotate ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The message +distributed will become the current message. + +.SH HISTORY +.B Dist +originally used headers of the form +.RI ` Distribute\-xxx: ' +instead of +.RI ` Resent\-xxx: '. +In order to conform with the ARPA Internet standard, RFC\-822, the +.RI ` Resent\-xxx: ' +form is now used. +Since +.B mmh +.B dist +will no longer recognize and convert +.RI ` Distribute\-xxx: ' +type headers. + +.SH BUGS +.B Dist +does not rigorously check the message being distributed +for adherence to the transport standard, but +.B post +called by +.B send +does. The +.B post +program will balk (and rightly so) at poorly formatted messages, and +.B dist +won't correct things for you. diff --git a/man/dp.man b/man/dp.man deleted file mode 100644 index 363f44a..0000000 --- a/man/dp.man +++ /dev/null @@ -1,94 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH DP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -dp \- parse dates 822-style -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/dp -.RB [ \-form -.IR formatfile ] -.RB [ \-format -.IR string ] -.RB [ \-width -.IR columns ] -.RB [ \-version ] -.RB [ \-help ] -.I dates -\&... -.ad -.SH DESCRIPTION -.B Dp -is a program that parses dates according to the ARPA Internet standard. -It also understands many non\-standard formats, -such as those produced by TOPS\-20 sites and some UNIX sites using -.BR ctime (3). -It is useful for seeing how -.B nmh -will interpret a date. -.PP -The -.B dp -program treats each argument as a single date, -and prints the date out in the official 822\-format. -Hence, it is usually best to enclose each argument in double\-quotes for the -shell. -.PP -To override the output format used by -.BR dp , -the -.B \-format -.I string -or -.B \-format -.I file -switches are used. -This permits individual fields of the address to be extracted with ease. -The string is simply a format string and the file is simply a format file. -See -.BR mh\-format (5) -for the details. -.PP -Here is the default format string used by -.BR dp : -.PP -.RS 5 -%<(nodate{text})error: %{text}%|%(putstr(pretty{text}))%> -.RE -.PP -which says that if an error was detected, print the error, a `:', -and the date in error. -Otherwise, output the 822\-proper format of the date. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -None - -.SH "SEE ALSO" -ap(8), -.I "Standard for the Format of ARPA Internet Text Messages" -(RFC\-822) - -.SH DEFAULTS -.nf -.RB ` \-format "' default as described above" -.RB ` \-width "' default to the width of the terminal" -.fi - -.SH CONTEXT -None - -.SH BUGS -The argument to the -.B \-format -switch must be interpreted as a single token by the shell that invokes -.BR dp . -Therefore, one must usually place the argument to this switch inside double\-quotes. diff --git a/man/dp.man8 b/man/dp.man8 new file mode 100644 index 0000000..b19c50b --- /dev/null +++ b/man/dp.man8 @@ -0,0 +1,84 @@ +.\" +.\" %nmhwarning% +.\" +.TH DP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +dp \- parse dates 822-style +.SH SYNOPSIS +.HP 5 +.na +.B %libdir%/dp +.RB [ \-form +.IR formatfile ] +.RB [ \-Version ] +.RB [ \-help ] +.I dates +\&... +.ad +.SH DESCRIPTION +.B Dp +is a program that parses dates according to the ARPA Internet standard. +It also understands many non\-standard formats, +such as those produced by TOPS\-20 sites and some UNIX sites using +.BR ctime (3). +It is useful for seeing how +.B nmh +will interpret a date. +.PP +The +.B dp +program treats each argument as a single date, +and prints the date out in the official 822\-format. +Hence, it is usually best to enclose each argument in double\-quotes for the +shell. +.PP +To override the output format used by +.BR dp , +the +.B \-form +.I file +switch is used. +This permits individual fields of the address to be extracted with ease. +The +.I file +is either the name of a format file or +a format string directly, if prepended with an equal sign `='. +See +.BR mh\-format (5) +for the details. +.PP +Here is the default format string used by +.BR dp : +.PP +.RS 5 +.nf +%<(nodate{text})error: %{text}%|%(putstr(pretty{text}))%> +.fi +.RE +.PP +which says that if an error was detected, print the error, a `:', +and the date in error. +Otherwise, output the 822\-proper format of the date. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +None + +.SH "SEE ALSO" +ap(8), +.I "Standard for the Format of ARPA Internet Text Messages" +(RFC\-822) + +.SH DEFAULTS +.nf +.RB ` \-form "' default as described above" +.fi + +.SH CONTEXT +None diff --git a/man/flist.man b/man/flist.man deleted file mode 100644 index 66f2f85..0000000 --- a/man/flist.man +++ /dev/null @@ -1,215 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH FLIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -flist, flists \- list the number of messages in given sequence(s) -.SH SYNOPSIS -.HP 5 -.na -.B flist -.RI [ +folder1 -.RI [ +folder2 -\&...]] -.RB [ \-sequence -.I name1 -.RB [ \-sequence -.I name2 -\&...]] -.RB [ \-all " | " \-noall ] -.RB [ \-showzero " | " \-noshowzero ] -.RB [ \-recurse " | " \-norecurse ] -.RB [ \-fast " | " \-nofast ] -.RB [ \-alpha " | " \-noalpha ] -.RB [ \-version ] -.RB [ \-help ] -.PP -.HP 5 -.B flists -is equivalent to -.B flist -.B \-all -.ad -.SH DESCRIPTION -.B Flist -is used to search a list of folders and display the number -of messages in these folders that are in a given sequence or set of -sequences (for example the -.RI \*(lq unseen \*(rq -sequence). This is especially -useful if you use some mechanism such as -.B slocal -or -.B procmail -(typically in conjunction with -.BR rcvstore ) -to pre-sort your mail into different folders before you view it. -.PP -By default, the command -.B flist -will search the current folder for the given sequence or sequences (usually -.RI \*(lq unseen \*(rq). -If (possibly multiple) folders are specified on the command line with -.IR +folder , -then all these folders are searched for the given sequence(s). -.B Flist -will display for each folder searched, the number of messages in each of the -specified sequences, and the total number of messages. -.PP -The option -.B \-sequence -is used to specify the name of a sequence in -which to search for. This option may be used multiple times to specify -multiple sequences. If this is not given, then the default is to search -for all the sequences specified by the -.RI \*(lq Unseen-Sequence \*(rq -profile component. For more details about sequences, read the -.BR mh\-sequence (5) -man page. -.PP -Typically, -.B flist -will produce a line for each sequence, for every -folder that is searched, even those which do not contain any messages in -the given sequence. Specifying -.B \-noshowzero -will cause -.B flist -to print only those folder/sequence combinations such the folder has a non-zero -number of messages in the given specified sequence. -.PP -If -.B \-recurse -is given, then for each folder that is search, -.B flist -will also recursively descend into those folders to search subfolders -for the given sequence. -.PP -If -.B \-fast -is given, only the names of the folders searched will be displayed, and -.B flist -will suppress all other output. If this option is used in conjunction with -.BR \-noshowzero , -then -.B flist -will only print the names of those folders searched that contain messages in -in at least one of the specified sequences. - -.SS "Multiple Folders" -If the option -.B \-all -is given (and no folders are specified with -.IR +folder ), -then -.B flist -will search all the folders in the top -level of the users nmh directory. These folders are all preceded by -the read\-only folders, which occur as -.RI \*(lq atr\-cur\- \*(rq -entries in the user's -.B nmh -context. -.PP -An example of the output of -.B flist -.B \-all -is: -.PP -.RS 5 -.nf -/work/Mail has 5 in sequence unseen (private); out of 46 -inbox+ has 10 in sequence unseen ; out of 153 -junklist has 0 in sequence unseen ; out of 63 -postmaster has 1 in sequence unseen ; out of 3 -.fi -.RE -.PP -The \*(lq+\*(rq after -.I inbox -indicates that it is the current folder. -.PP -The \*(lqprivate\*(rq flag indicates that the given sequence for -that folder is private. See the -.BR mh\-sequence (5) -man page for details about private sequences. -.PP -If the option -.B \-all -and -.I +folder -are both specified, then -.B flist -will search this folder, and all its first level subfolders for the -given sequence. You may specify multiple folders in this way. -.PP -If -.B flist -is invoked by a name ending with \*(lqs\*(rq -(e.g. -.BR flists ), -then the switch -.B \-all -is assumed by default. -.PP -The sorting order for the listing is alphabetical (with -.BR \-alpha ), -or in a priority order defined by the -.RI \*(lq Flist-Order \*(rq -profile entry (with -.BR \-noalpha ). -Each item in the -.RI \*(lq Flist-Order \*(rq -is a folder name or a -folder name pattern that uses * to match zero or more characters. -Longer matching patterns have precedence over shorter matching patterns. -For example: -.PP -.RS 5 -.nf -Flist-Order: personal petproject mh* * admin *junk -.fi -.RE -.PP -This order puts a few interesting folders first, such as those with mail -addressed to you personally, those about a pet project, and those about -mh-related things. It places uninteresting folders at the end, and it -puts everything else in the middle in alphabetical order. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^mh-sequences:~^File that contains public sequences -^Unseen-Sequence:~^The name of the unseen message sequence -^Flist-Order:~^To sort folders by priority -.fi - -.SH "SEE ALSO" -folder(1), rcvstore(1), slocal(1), mh\-sequence(5) - -.SH DEFAULTS -.nf -.RB ` -sequence "' defaults to Unseen-Sequence profile entry" -.RB ` \-showzero ' -.RB ` \-noall ' -.RB ` \-norecurse ' -.RB ` \-noalpha ' -.RB ` \-nofast ' -.fi - -.SH CONTEXT -If -.I +folder -is given, it will become the current folder. -If multiple folders are given, the last one specified will -become the current folder. diff --git a/man/flist.man1 b/man/flist.man1 new file mode 100644 index 0000000..a2ba53a --- /dev/null +++ b/man/flist.man1 @@ -0,0 +1,215 @@ +.\" +.\" %nmhwarning% +.\" +.TH FLIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +flist, flists \- list the number of messages in given sequence(s) +.SH SYNOPSIS +.HP 5 +.na +.B flist +.RI [ +folder1 +.RI [ +folder2 +\&...]] +.RB [ \-sequence +.I name1 +.RB [ \-sequence +.I name2 +\&...]] +.RB [ \-all " | " \-noall ] +.RB [ \-showzero " | " \-noshowzero ] +.RB [ \-recurse " | " \-norecurse ] +.RB [ \-fast " | " \-nofast ] +.RB [ \-alpha " | " \-noalpha ] +.RB [ \-Version ] +.RB [ \-help ] +.PP +.HP 5 +.B flists +is equivalent to +.B flist +.B \-all +.ad +.SH DESCRIPTION +.B Flist +is used to search a list of folders and display the number +of messages in these folders that are in a given sequence or set of +sequences (for example the +.RI ` unseen ' +sequence). This is especially +useful if you use some mechanism such as +.B slocal +or +.B procmail +(typically in conjunction with +.BR rcvstore ) +to pre-sort your mail into different folders before you view it. +.PP +By default, the command +.B flist +will search the current folder for the given sequence or sequences (usually +.RI ` unseen '). +If (possibly multiple) folders are specified on the command line with +.IR +folder , +then all these folders are searched for the given sequence(s). +.B Flist +will display for each folder searched, the number of messages in each of the +specified sequences, and the total number of messages. +.PP +The option +.B \-sequence +is used to specify the name of a sequence in +which to search for. This option may be used multiple times to specify +multiple sequences. If this is not given, then the default is to search +for all the sequences specified by the +.RI ` Unseen-Sequence ' +profile component. For more details about sequences, read the +.BR mh\-sequence (7) +man page. +.PP +Typically, +.B flist +will produce a line for each sequence, for every +folder that is searched, even those which do not contain any messages in +the given sequence. Specifying +.B \-noshowzero +will cause +.B flist +to print only those folder/sequence combinations such the folder has a non-zero +number of messages in the given specified sequence. +.PP +If +.B \-recurse +is given, then for each folder that is search, +.B flist +will also recursively descend into those folders to search subfolders +for the given sequence. +.PP +If +.B \-fast +is given, only the names of the folders searched will be displayed, and +.B flist +will suppress all other output. If this option is used in conjunction with +.BR \-noshowzero , +then +.B flist +will only print the names of those folders searched that contain messages in +in at least one of the specified sequences. + +.SS "Multiple Folders" +If the option +.B \-all +is given (and no folders are specified with +.IR +folder ), +then +.B flist +will search all the folders in the top +level of the users mmh directory. These folders are all preceded by +the read\-only folders, which occur as +.RI ` atr\-cur\- ' +entries in the user's +.B mmh +context. +.PP +An example of the output of +.B flist +.B \-all +is: +.PP +.RS 5 +.nf +/work/Mail has 5 in sequence unseen (private); out of 46 +inbox+ has 10 in sequence unseen ; out of 153 +junklist has 0 in sequence unseen ; out of 63 +postmaster has 1 in sequence unseen ; out of 3 +.fi +.RE +.PP +The `+' after +.I inbox +indicates that it is the current folder. +.PP +The `private' flag indicates that the given sequence for +that folder is private. See the +.BR mh\-sequence (7) +man page for details about private sequences. +.PP +If the option +.B \-all +and +.I +folder +are both specified, then +.B flist +will search this folder, and all its first level subfolders for the +given sequence. You may specify multiple folders in this way. +.PP +If +.B flist +is invoked by a name ending with `s' +(e.g. +.BR flists ), +then the switch +.B \-all +is assumed by default. +.PP +The sorting order for the listing is alphabetical (with +.BR \-alpha ), +or in a priority order defined by the +.RI ` Flist-Order ' +profile entry (with +.BR \-noalpha ). +Each item in the +.RI ` Flist-Order ' +is a folder name or a +folder name pattern that uses * to match zero or more characters. +Longer matching patterns have precedence over shorter matching patterns. +For example: +.PP +.RS 5 +.nf +Flist-Order: personal petproject mh* * admin *junk +.fi +.RE +.PP +This order puts a few interesting folders first, such as those with mail +addressed to you personally, those about a pet project, and those about +mh-related things. It places uninteresting folders at the end, and it +puts everything else in the middle in alphabetical order. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Mh-Sequences:~^File that contains public sequences +^Unseen-Sequence:~^The name of the unseen message sequence +^Flist-Order:~^To sort folders by priority +.fi + +.SH "SEE ALSO" +folder(1), rcvstore(1), slocal(1), mh\-sequence(7) + +.SH DEFAULTS +.nf +.RB ` -sequence "' defaults to Unseen-Sequence profile entry" +.RB ` \-showzero ' +.RB ` \-noall ' +.RB ` \-norecurse ' +.RB ` \-noalpha ' +.RB ` \-nofast ' +.fi + +.SH CONTEXT +If +.I +folder +is given, it will become the current folder. +If multiple folders are given, the last one specified will +become the current folder. diff --git a/man/flists.man b/man/flists.man deleted file mode 100644 index fbc6b9b..0000000 --- a/man/flists.man +++ /dev/null @@ -1 +0,0 @@ -.so man1/flist.1 diff --git a/man/flists.man1 b/man/flists.man1 new file mode 100644 index 0000000..fbc6b9b --- /dev/null +++ b/man/flists.man1 @@ -0,0 +1 @@ +.so man1/flist.1 diff --git a/man/fmtdump.man b/man/fmtdump.man deleted file mode 100644 index 0524f01..0000000 --- a/man/fmtdump.man +++ /dev/null @@ -1,63 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH FMTDUMP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -fmtdump \- decode nmh format files -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/fmtdump -.RB [ \-form -.IR formatfile ] -.RB [ \-format -.IR string ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Fmtdump -is a program that parses an -.B nmh -format file and produces a pseudo-language listing of the how -.B nmh -interprets the file. This is useful when debugging a complicated format file. -.PP -The -.B \-format -.I string -and -.B \-form -.I formatfile -switches may be -used to specify a format string or format file to read. The string -is simply a format string and the file is simply a format file. -See -.BR mh-format (5) -for the details. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/scan.default~^The default format file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -.fi - -.SH "SEE ALSO" -mh-format(5), mh-sequences(8) - -.SH CONTEXT -None - -.SH BUGS -The output may not be useful unless you are familiar -with the internals of the mh-format subroutines. diff --git a/man/fmtdump.man8 b/man/fmtdump.man8 new file mode 100644 index 0000000..6156c39 --- /dev/null +++ b/man/fmtdump.man8 @@ -0,0 +1,53 @@ +.\" +.\" %nmhwarning% +.\" +.TH FMTDUMP %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +fmtdump \- decode nmh format files +.SH SYNOPSIS +.HP 5 +.na +.B %libdir%/fmtdump +.RB [ \-form +.IR formatfile ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Fmtdump +is a program that parses an +.B nmh +format file and produces a pseudo-language listing of the how +.B nmh +interprets the file. This is useful when debugging a complicated format file. +.PP +The +.B \-form +.I formatfile +switch may be used to specify a format file to read. +It may also be a format string directly, if prepended with an equal sign `='. +See +.BR mh-format (5) +for the details. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^%etcdir%/scan.default~^The default format file +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +.fi + +.SH "SEE ALSO" +mh-format(5), mh-sequence(7) + +.SH CONTEXT +None diff --git a/man/fnext.man b/man/fnext.man deleted file mode 100644 index 7529017..0000000 --- a/man/fnext.man +++ /dev/null @@ -1 +0,0 @@ -.so man1/new.1 diff --git a/man/fnext.man1 b/man/fnext.man1 new file mode 100644 index 0000000..7529017 --- /dev/null +++ b/man/fnext.man1 @@ -0,0 +1 @@ +.so man1/new.1 diff --git a/man/folder.man b/man/folder.man deleted file mode 100644 index 34d3fa0..0000000 --- a/man/folder.man +++ /dev/null @@ -1,317 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH FOLDER %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -folder, folders \- set/list current folder/message -.SH SYNOPSIS -.HP 5 -.na -.B folder -.RI [ +folder ] -.RI [ msg ] -.RB [ \-all " | " \-noall ] -.RB [ \-create " | " \-nocreate ] -.RB [ \-fast " | " \-nofast ] -.RB [ \-header " | " \-noheader ] -.RB [ \-recurse " | " \-norecurse ] -.RB [ \-total " | " \-nototal ] -.RB [ \-list " | " \-nolist ] -.RB [ \-push " | " \-pop ] -.RB [ \-pack " | " \-nopack ] -.RB [ \-print ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-version ] -.RB [ \-help ] -.PP -.HP 5 -.B folders -is equivalent to -.B folder -.B \-all -.ad -.SH DESCRIPTION -Since the -.B nmh -environment is the shell, it is easy to lose track -of the current folder from day to day. When -.B folder -is given the -.B \-print -switch (the default), -.B folder -will list the current folder, -the number of messages in it, the range of the messages (low\-high), -and the current message within the folder, and will flag extra files if -they exist. An example of this summary is: -.PP -.RS 5 -.nf -.ta \w'/rnd/phyl/Mail/EP 'u +\w'has ddd messages 'u +\w'(ddd\-ddd); 'u -inbox+ has \016 messages (\0\03\-\022); cur=\0\05. -.fi -.RE -.PP -If a -.I +folder -and/or -.I msg -are specified, they will become the current -folder and/or message. By comparison, when a -.I +folder -argument is given, this corresponds to a \*(lqcd\*(rq operation -in the shell; when no -.I +folder -argument is given, this corresponds roughly to a \*(lqpwd\*(rq -operation in the shell. -.PP -If the specified (or default) folder doesn't exist, the default action -is to query the user as to whether the folder should be created; when -standard input is not a tty, the answer to the query is assumed to be -\*(lqyes\*(rq. -.PP -Specifying -.B \-create -will cause -.B folder -to create new folders -without any query. (This is the easy way to create an empty folder for -use later.) Specifying -.B \-nocreate -will cause -.B folder -to exit -without creating a non-existant folder. -.\" -.\" note - this doesn't work at present -.\" If `\-noprint' is specified, -.\" a `+folder' and/or `msg' may still be specified -.\" to set the current folder and/or message, -.\" but the folder summary will not be printed. - -.SS "Multiple Folders" -Specifying -.B \-all -will produce a summary line for each top-level folder -in the user's nmh directory, sorted alphabetically. (If -.B folder -is invoked by a name ending with \*(lqs\*(rq (e.g. -.BR folders ), -.B \-all -is assumed). Specifying -.B \-recurse -with -.B \-all -will also -produce a line for all sub-folders. These folders are all preceded by -the read\-only folders, which occur as -.RI \*(lq atr\-cur\- \*(rq -entries in the user's -.B nmh -context. For example: -.PP -.RS 5 -.nf -.ta \w'/rnd/phyl/Mail/EP 'u +\w'has ddd messages 'u +\w'(ddd\-ddd); 'u -FOLDER \0\0\0\0\0\0# MESSAGES RANGE CUR (OTHERS) -/var/work/folder has \035 messages (\01\-\035); cur=23. -/usr/bugs/Mail has \082 messages (\01\-108); cur=82. -ff has \0no messages. -inbox+ has \016 messages (\03\-\022); cur=\05. -mh has \076 messages (15\-\076); cur=70. -notes has \0\02 messages (\01\-\0\02); cur=\01. -ucom has 124 messages (\01\-124); cur=\06; (others). -.ta \w'/rnd/phyl/Mail/EP has 'u - -TOTAL = 339 messages in 7 folders -.fi -.RE -.PP -The \*(lq+\*(rq after -.I inbox -indicates that it is the current folder. -The \*(lq(others)\*(rq indicates that the folder -.I ucom -has files which -aren't messages. These files may either be sub\-folders, or files that -don't belong under the nmh file naming scheme. -.PP -The header is output if either a -.B \-all -or a -.B \-header -switch is specified. It is suppressed by -.BR \-noheader . -.PP -The folder and message totals are output if either a -.B \-all -or a -.B \-total -switch is specified. It is suppressed by -.BR \-nototal . -.PP -If -.B \-fast -is given, only the folder name (or names in the case of -.BR \-all ) -will be listed. (This is faster because the folders need not -be read.) -.PP -If a -.I +folder -is given along with the -.B \-all -switch, -.B folder -will, in addition to setting the current folder, list the top\-level subfolders -for the current folder (with -.BR \-norecurse ) -or list all sub-folders under the current folder recursively (with -.BR \-recurse ). -.PP -If -.I msg -is supplied, together with -.IR +folder -or without -.BR \-all , -it will become the current message of -.IR +folder -(if it had been supplied) -or the current folder. -.PP -The -.B \-recurse -switch lists each folder recursively, so use of this -option effectively defeats the speed enhancement of the -.B \-fast -option, -since each folder must be searched for subfolders. Nevertheless, the -combination of these options is useful. -.PP -.SS "Compacting a Folder" -The -.B \-pack -switch will compress the message names in the designated -folders, removing holes in message numbering. The -.B \-verbose -switch directs -.B folder -to tell the user the general actions that it is -taking to compress the folder. -.PP -.SS "The Folder Stack" -The -.B \-push -switch directs -.B folder -to push the current folder -onto the -.IR folder\-stack , -and make the -.I +folder -argument the current folder. If -.I +folder -is not given, the current folder and the -top of the -.I folder\-stack -are exchanged. This corresponds to the -\*(lqpushd\*(rq operation in the shell. -.PP -The -.B \-pop -switch directs -.B folder -to discard the top of the -.IR folder\-stack , -after setting the current folder to that value. -No -.I +folder -argument is allowed. This corresponds to the \*(lqpopd\*(rq -operation in the shell. The -.B \-push -switch and the -.B \-pop -switch -are mutually exclusive: the last occurrence of either one overrides -any previous occurrence of the other. Both of these switches also set -.B \-list -by default. -.PP -The -.B \-list -switch directs -.B folder -to list the contents of -the -.IR folder\-stack . -No -.I +folder -argument is allowed. After a successful -.B \-push -or -.BR \-pop , -the -.B \-list -action is taken, unless a -.B \-nolist -switch follows them on the command line. This corresponds -to the \*(lqdirs\*(rq operation in the shell. The -.BR \-push , -.BR \-pop , -and -.B \-list -switches turn off -.BR \-print . - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Folder\-Protect:~^To set mode when creating a new folder -^Folder\-Stack:~^To determine the folder stack -.\" ^lsproc:~^Program to list the contents of a folder -.fi - -.SH "SEE ALSO" -refile(1), mhpath(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to none" -.RB ` \-nofast ' -.RB ` \-noheader ' -.RB ` \-nototal ' -.RB ` \-nopack ' -.RB ` \-norecurse ' -.RB ` \-noverbose ' -.RB ` \-print "' is the default if no " \-list ", " \-push ", or " \-pop " is specified" -.RB ` \-list "' is the default if " \-push ", or " \-pop " is specified" -.fi - -.SH CONTEXT -If -.I +folder -and/or -.I msg -are given, they will become the current folder and/or message. - -.SH BUGS -There is no way to restore the default behavior -(to ask the user whether to create a non-existant folder) -after -.B \-create -or -.B \-nocreate -is given. diff --git a/man/folder.man1 b/man/folder.man1 new file mode 100644 index 0000000..704809d --- /dev/null +++ b/man/folder.man1 @@ -0,0 +1,308 @@ +.\" +.\" %nmhwarning% +.\" +.TH FOLDER %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +folder, folders \- set/list current folder/message +.SH SYNOPSIS +.HP 5 +.na +.B folder +.RI [ +folder ] +.RI [ msg ] +.RB [ \-all " | " \-noall ] +.RB [ \-create " | " \-nocreate ] +.RB [ \-fast " | " \-nofast ] +.RB [ \-recurse " | " \-norecurse ] +.RB [ \-total " | " \-nototal ] +.RB [ \-list " | " \-nolist ] +.RB [ \-push " | " \-pop ] +.RB [ \-pack " | " \-nopack ] +.RB [ \-print ] +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-Version ] +.RB [ \-help ] +.PP +.HP 5 +.B folders +is equivalent to +.B folder +.B \-all +.ad +.SH DESCRIPTION +Since the +.B nmh +environment is the shell, it is easy to lose track +of the current folder from day to day. When +.B folder +is given the +.B \-print +switch (the default), +.B folder +will list the current folder, +the number of messages in it, the range of the messages (low\-high), +and the current message within the folder, and will flag extra files if +they exist. An example of this summary is: +.PP +.RS 5 +.nf +.ta \w'/rnd/phyl/Mail/EP 'u +\w'has ddd messages 'u +\w'(ddd\-ddd); 'u +inbox+ has \016 messages (\0\03\-\022); cur=\0\05 +.fi +.RE +.PP +If a +.I +folder +and/or +.I msg +are specified, they will become the current +folder and/or message. By comparison, when a +.I +folder +argument is given, this corresponds to a `cd' operation +in the shell; when no +.I +folder +argument is given, this corresponds roughly to a `pwd' +operation in the shell. +.PP +If the specified (or default) folder doesn't exist, the default action +is to query the user as to whether the folder should be created; when +standard input is not a tty, the answer to the query is assumed to be +`yes'. +.PP +Specifying +.B \-create +will cause +.B folder +to create new folders +without any query. (This is the easy way to create an empty folder for +use later.) Specifying +.B \-nocreate +will cause +.B folder +to exit +without creating a non-existant folder. +.\" +.\" note - this doesn't work at present +.\" If `\-noprint' is specified, +.\" a `+folder' and/or `msg' may still be specified +.\" to set the current folder and/or message, +.\" but the folder summary will not be printed. + +.SS "Multiple Folders" +Specifying +.B \-all +will produce a summary line for each top-level folder +in the user's mmh directory, sorted alphabetically. (If +.B folder +is invoked by a name ending with `s' (e.g. +.BR folders ), +.B \-all +is assumed). Specifying +.B \-recurse +with +.B \-all +will also +produce a line for all sub-folders. These folders are all preceded by +the read\-only folders, which occur as +.RI ` atr\-cur\- ' +entries in the user's +.B mmh +context. For example: +.PP +.RS 5 +.nf +.ta \w'/rnd/phyl/Mail/EP 'u +\w'has ddd messages 'u +\w'(ddd\-ddd); 'u +FOLDER \0\0\0\0\0\0# MESSAGES RANGE CUR (OTHERS) +/var/work/folder has \035 messages (\01\-\035); cur=23 +/usr/bugs/Mail has \082 messages (\01\-108); cur=82 +ff has \0no messages +inbox+ has \016 messages (\03\-\022); cur=\05 +mh has \076 messages (15\-\076); cur=70 +notes has \0\02 messages (\01\-\0\02); cur=\01 +ucom has 124 messages (\01\-124); cur=\06; (others) +.ta \w'/rnd/phyl/Mail/EP has 'u + +TOTAL = 339 messages in 7 folders +.fi +.RE +.PP +The `+' after +.I inbox +indicates that it is the current folder. +The `(others)' indicates that the folder +.I ucom +has files which +aren't messages. These files may either be sub\-folders, or files that +don't belong under the nmh file naming scheme. +.PP +The folder and message totals are output if either a +.B \-all +or a +.B \-total +switch is specified. It is suppressed by +.BR \-nototal . +.PP +If +.B \-fast +is given, only the folder name (or names in the case of +.BR \-all ) +will be listed. (This is faster because the folders need not +be read.) +.PP +If a +.I +folder +is given along with the +.B \-all +switch, +.B folder +will, in addition to setting the current folder, list the top\-level subfolders +for the current folder (with +.BR \-norecurse ) +or list all sub-folders under the current folder recursively (with +.BR \-recurse ). +.PP +If +.I msg +is supplied, together with +.IR +folder +or without +.BR \-all , +it will become the current message of +.IR +folder +(if it had been supplied) +or the current folder. +.PP +The +.B \-recurse +switch lists each folder recursively, so use of this +option effectively defeats the speed enhancement of the +.B \-fast +option, +since each folder must be searched for subfolders. Nevertheless, the +combination of these options is useful. +.PP +.SS "Compacting a Folder" +The +.B \-pack +switch will compress the message names in the designated +folders, removing holes in message numbering. The +.B \-verbose +switch directs +.B folder +to tell the user the general actions that it is +taking to compress the folder. +.PP +.SS "The Folder Stack" +The +.B \-push +switch directs +.B folder +to push the current folder +onto the +.IR folder\-stack , +and make the +.I +folder +argument the current folder. If +.I +folder +is not given, the current folder and the +top of the +.I folder\-stack +are exchanged. This corresponds to the +`pushd' operation in the shell. +.PP +The +.B \-pop +switch directs +.B folder +to discard the top of the +.IR folder\-stack , +after setting the current folder to that value. +No +.I +folder +argument is allowed. This corresponds to the `popd' +operation in the shell. The +.B \-push +switch and the +.B \-pop +switch +are mutually exclusive: the last occurrence of either one overrides +any previous occurrence of the other. Both of these switches also set +.B \-list +by default. +.PP +The +.B \-list +switch directs +.B folder +to list the contents of +the +.IR folder\-stack . +No +.I +folder +argument is allowed. After a successful +.B \-push +or +.BR \-pop , +the +.B \-list +action is taken, unless a +.B \-nolist +switch follows them on the command line. This corresponds +to the `dirs' operation in the shell. The +.BR \-push , +.BR \-pop , +and +.B \-list +switches turn off +.BR \-print . + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Folder\-Protect:~^To set mode when creating a new folder +^Folder\-Stack:~^To determine the folder stack +.\" ^lsproc:~^Program to list the contents of a folder +.fi + +.SH "SEE ALSO" +refile(1), mhpath(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msg "' defaults to none" +.RB ` \-nofast ' +.RB ` \-nototal ' +.RB ` \-nopack ' +.RB ` \-norecurse ' +.RB ` \-noverbose ' +.RB ` \-print "' is the default if no " \-list ", " \-push ", or " \-pop " is specified" +.RB ` \-list "' is the default if " \-push ", or " \-pop " is specified" +.fi + +.SH CONTEXT +If +.I +folder +and/or +.I msg +are given, they will become the current folder and/or message. + +.SH BUGS +There is no way to restore the default behavior +(to ask the user whether to create a non-existant folder) +after +.B \-create +or +.B \-nocreate +is given. diff --git a/man/folders.man b/man/folders.man deleted file mode 100644 index 7c3e32a..0000000 --- a/man/folders.man +++ /dev/null @@ -1 +0,0 @@ -.so man1/folder.1 diff --git a/man/folders.man1 b/man/folders.man1 new file mode 100644 index 0000000..7c3e32a --- /dev/null +++ b/man/folders.man1 @@ -0,0 +1 @@ +.so man1/folder.1 diff --git a/man/forw.man b/man/forw.man deleted file mode 100644 index 877b49b..0000000 --- a/man/forw.man +++ /dev/null @@ -1,424 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH FORW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -forw \- forward messages -.SH SYNOPSIS -.HP 5 -.na -.B forw -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-annotate " | " \-noannotate ] -.RB [ \-form -.IR formfile ] -.RB [ \-format " | " \-noformat ] -.RB [ \-filter -.IR filterfile ] -.RB [ \-inplace " | " \-noinplace ] -.RB [ \-mime " | " \-nomime ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-editor -.IR editor ] -.RB [ \-noedit ] -.RB [ \-whatnowproc -.IR program ] -.RB [ \-nowhatnowproc ] -.RB [ \-dashstuffing " | " \-nodashstuffing ] -.RB [ \-build ] -.RB [ \-file -.IR msgfile ] -.RB [ \-version ] -.RB [ \-help ] -.PP -.HP 5 -.B forw -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-digest -.IR list ] -.RB [ \-issue -.IR number ] -.RB [ \-volume -.IR number ] -[other\ switches\ for\ -.BR forw ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Forw -may be used to prepare a message containing other messages. -.PP -It constructs the new message from a forms (components) file, with a -body composed of the message(s) to be forwarded. An editor is invoked -as in -.BR comp , -and after editing is complete, the user is prompted -before the message is sent. -.PP -The default message form contains the following elements: -.PP -.RS 5 -.nf -%forwcomps% -.fi -.RE -.PP -If a file named -.RI \*(lq forwcomps \*(rq -exists in the user's nmh directory, -it will be used instead of this default form. You may also specify an -alternate forms file with the switch -.B \-form -.IR formfile . -.PP -If the draft already exists, -.B forw -will ask you as to the disposition -of the draft. A reply of -.B quit -will abort -.BR forw , -leaving the draft intact; -.B replace -will replace the existing draft with a blank skeleton; and -.B list -will display the draft. -.PP -If the -.B \-annotate -switch is given, each message being forwarded will -be annotated with the lines: -.PP -.RS 5 -.nf -Forwarded:\ date -Forwarded:\ addrs -.fi -.RE -.PP -where each address list contains as many lines as required. This -annotation will be done only if the message is sent directly from -.BR forw . -If the message is not sent immediately from -.BR forw , -.RB \*(lq comp -.BR \-use \*(rq -may be used to re\-edit and send the constructed -message, but the annotations won't take place. Normally annotations -are done inplace in order to preserve any links to the message. You may -change this by using the -.B \-noinplace -switch. -.PP -See -.BR comp (1) -for a description of the -.B \-editor -and -.B \-noedit -switches. -.PP -Although -.B forw -uses a forms (components) file to direct it how to -construct the beginning of the draft, it uses a message filter file to -direct it as to how each forwarded message should be formatted in the -body of the draft. The filter file for \fIforw\fR should be a standard -form file for -.BR mhl , -as -.B forw -will invoke -.B mhl -to filter (re\-format) the forwarded messages prior to being output to -the body of the draft. -.PP -The switches -.BR \-noformat , -.BR \-format , -and -.B \-filter -.I filterfile -specify which message filter file to use. -.PP -If -.B \-noformat -is specified (this is the default), then each forwarded -message is output into the draft exactly as it appears with no -.B mhl -filtering. -.PP -If -.B \-format -is specified, then a default message filter file is used. -This default message filter should be adequate for most users. -This default filter -.RI \*(lq mhl.forward \*(rq -is: -.PP -.RS 5 -.nf -%mhl_forward% -.fi -.RE -.PP -If a file named -.RI \*(lq mhl.forward \*(rq -exists in the user's nmh -directory, it will be used instead of this form. You may specify an -alternate message filter file with the switch -.B \-filter -.IR filterfile . -.PP -Each forwarded message is separated with an encapsulation delimiter. -By default, any dashes in the first column of the forwarded messages -will be prepended with `\-\ ' so that when received, the message is -suitable for bursting by -.BR burst . -This follows the Internet RFC\-934 guidelines. You may use the flag -.B \-nodashstuffing -in order -to suppress this form of quoting to the forwarded messages. -.PP -For users of -.BR prompter , -by specifying -.BR prompter 's -.B \-prepend -switch in the -.I \&.mh\(ruprofile -file, any commentary text is entered -before the forwarded messages. (A major win!) -.PP -To use the MIME rules for encapsulation, specify the -.B \-mime -switch. This directs -.B forw -to generate an -.B mhbuild -composition file. Note that -.B nmh -will not invoke -.B mhbuild -automatically, unless you -add this line to your -.I \&.mh\(ruprofile -file: -.PP -.RS 5 -.nf -automimeproc: 1 -.fi -.RE -.PP -Otherwise, you must specifically give the command -.PP -.RS 5 -.nf -What now? mime -.fi -.RE -.PP -prior to sending the draft. -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more information. -.PP -The -.B \-editor -.I editor -switch indicates the editor to use for the -initial edit. Upon exiting from the editor, -.B comp -will invoke the -.B whatnow -program. See -.BR whatnow (1) -for a discussion of -available options. The invocation of this program can be inhibited -by using the -.B \-nowhatnowproc -switch. (In truth of fact, it is -the -.I whatnow -program which starts the initial edit. Hence, -.B \-nowhatnowproc -will prevent any edit from occurring.) -.PP -The -.B \-build -switch is intended to be used by the Emacs mh-e interface to -.BR nmh , -and is only present if -.B nmh -was compiled with support for mh-e. It implies -.BR \-nowhatnowproc . -It causes a file /draft -to be created, containing the draft message that would normally be presented -to the user for editing. -No mail is actually sent. Note that this switch is not guaranteed to -be present or to have the same effects in future versions of -.BR nmh : -it is documented here only for completeness. -.PP -The -.B \-file -.I msgfile -switch specifies the message to be forwarded as an -exact filename rather than as an -.B nmh -folder and message number. It is -intended to be used by the -.B msh -interface to -.BR nmh . -This switch implies -.BR \-noannotate . -The forwarded message is simply -copied verbatim into the draft; the processing implied by -the -.BR \-filter , -.BR \-mime , -and -.B \-digest -switches is bypassed, and the usual leading and -trailing 'Forwarded Message' delimiters are not added. -The same caveats apply to this option as to the -.B \-build -switch. -.PP -The -.B \-digest -.IR list , -.B \-issue -.IR number , -and -.B \-volume -.I number -switches implement a digest facility for -.BR nmh . -Specifying these switches enables and/or overloads the following escapes: -.PP -.RS 5 -.nf -.ta \w'Component 'u +\w'Escape 'u +\w'Returns 'u -.I Type Escape Returns Description -component digest string Argument to `\-digest' -function cur integer Argument to `\-volume' -function msg integer Argument to `\-issue' -.fi -.RE -.PP -Consult the -.I "Advanced Features" -section of the -.B nmh -User's Manual for more information on making digests. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/forwcomps~^The standard message skeleton -^or /forwcomps~^Rather than the standard skeleton -^%etcdir%/digestcomps~^The message skeleton if `\-digest' is given -^or /digestcomps~^Rather than the standard skeleton -^%etcdir%/mhl.forward~^The standard message filter -^or /mhl.forward~^Rather than the standard filter -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^Msg\-Protect:~^To set mode when creating a new message (draft) -^fileproc:~^Program to refile the message -^mhlproc:~^Program to filter messages being forwarded -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi - -.SH "SEE ALSO" -mhbuild(1), comp(1), repl(1), send(1), whatnow(1), mh\-format(5), -.I "Proposed Standard for Message Encapsulation" -(RFC\-934) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-noannotate ' -.RB ` \-nodraftfolder ' -.RB ` \-noformat ' -.RB ` \-inplace ' -.RB ` \-dashstuffing ' -.RB ` \-nomime ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. -The first message forwarded will become the current message. - -.SH BUGS -If -.I whatnowproc -is -.BR whatnow , -then -.B forw -uses a built\-in -.BR whatnow , -it does not actually run the -.B whatnow -program. -Hence, if you define your own -.IR whatnowproc , -don't call it -.B whatnow -since -.B forw -won't run it. -.PP -When -.B forw -is told to annotate the messages it forwards, it -doesn't actually annotate them until the draft is successfully sent. -If from the -.IR whatnowproc , -you -.B push -instead of -.BR send , -it's possible to confuse -.B forw -by re\-ordering the file (e.g. by using -.RB \*(lq folder -.BR \-pack \*(rq) -before the message is successfully sent. -.B Dist -and -.B repl -don't have this problem. diff --git a/man/forw.man1 b/man/forw.man1 new file mode 100644 index 0000000..ae4f670 --- /dev/null +++ b/man/forw.man1 @@ -0,0 +1,221 @@ +.\" +.\" %nmhwarning% +.\" +.TH FORW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +forw \- forward messages +.SH SYNOPSIS +.HP 5 +.na +.B forw +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-annotate " | " \-noannotate ] +.RB [ \-form +.IR formfile ] +.RB [ \-editor +.IR editor ] +.RB [ \-whatnowproc +.IR program ] +.RB [ \-build ] +.RB [ \-Version ] +.RB [ \-help ] +.PP +.HP 5 +.B forw +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-digest +.IR list ] +.RB [ \-issue +.IR number ] +.RB [ \-volume +.IR number ] +[other\ switches\ for +.BR forw ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Forw +may be used to prepare a message containing other messages. +.PP +It constructs the new message from a forms (components) file, with a +body composed of the message(s) to be forwarded. An editor is invoked +as in +.BR comp , +and after editing is complete, the user is prompted +before the message is sent. +.PP +The default message form contains the following elements: +.PP +.RS 5 +.nf +%forwcomps% +.fi +.RE +.PP +If a file named +.RI ` forwcomps ' +exists in the user's mmh directory, +it will be used instead of this default form. You may also specify an +alternate forms file with the switch +.B \-form +.IR formfile . +.PP +If the +.B \-annotate +switch is given, each message being forwarded will +be annotated with the line: +.PP +.RS 5 +.nf +Forwarded:\ date +.fi +.RE +.PP +This annotation will be done only if the message is sent directly from +.BR forw . +If the message is not sent immediately from +.BR forw , +.RB ` comp +.BR \-use ' +may be used to re\-edit and send the constructed +message, but the annotations won't take place. Annotations +are always done inplace in order to preserve any links to the message. +.PP +See +.BR comp (1) +for a description of the +.B \-editor +switch. +.PP +.B Forw +generates an attachment header field for the messages to be forwarded. +.B Send +will care to encapsulate them using MIME rules. +.PP +To send non-MIME forwarded messages, compose a new message (e.g. with +.B comp ) +and read in the output of: +.PP +.RS 5 +mhl \-forwall \-form mhl.forward `mhpath +.I MSGS... ` +.RE +.PP +The +.B \-editor +.I editor +switch indicates the editor to use for the +initial edit. Upon exiting from the editor, +.B comp +will invoke the +.B whatnow +program. See +.BR whatnow (1) +for a discussion of +available options. +.PP +The +.B \-build +switch is intended to be used by the Emacs mh-e interface to +.BR nmh . +It causes a file `draft' in the mail storage root +to be created, containing the draft message that would normally be presented +to the user for editing. +No +.B whatnow +program is invoked. +No mail is actually sent. +.PP +The +.B \-digest +.IR list , +.B \-issue +.IR number , +and +.B \-volume +.I number +switches implement a digest facility for +.BR nmh . +Specifying these switches enables and/or overloads the following escapes: +.PP +.RS 5 +.nf +.ta \w'Component 'u +\w'Escape 'u +\w'Returns 'u +.I "Type Escape Returns Description +component digest string Argument to `\-digest' +function cur integer Argument to `\-volume' +function msg integer Argument to `\-issue' +.fi +.RE +.PP +Consult the +.I "Advanced Features" +section of the +.B nmh +User's Manual for more information on making digests. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/forwcomps~^The standard message skeleton +^or $HOME/.mmh/forwcomps~^Rather than the standard skeleton +^%etcdir%/digestcomps~^The message skeleton if `\-digest' is given +^or $HOME/.mmh/digestcomps~^Rather than the standard skeleton +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Draft\-Folder:~^To set the default draft\-folder +^Editor:~^To override the default editor +^Msg\-Protect:~^To set mode when creating a new message (draft) +^whatnowproc:~^Program to ask the `What now?' questions +.fi + +.SH "SEE ALSO" +mhbuild(1), comp(1), repl(1), send(1), whatnow(1), mh\-format(5), +.I "Proposed Standard for Message Encapsulation" +(RFC\-934) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-noannotate ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. +The first message forwarded will become the current message. + +.SH BUGS +When +.B forw +is told to annotate the messages it forwards, it +doesn't actually annotate them until the draft is successfully sent. +If from the +.IR whatnowproc , +you +.B push +instead of +.BR send , +it's possible to confuse +.B forw +by re\-ordering the file (e.g. by using +.RB ` folder +.BR \-pack ') +before the message is successfully sent. +.B Dist +and +.B repl +don't have this problem. diff --git a/man/fprev.man b/man/fprev.man deleted file mode 100644 index 7529017..0000000 --- a/man/fprev.man +++ /dev/null @@ -1 +0,0 @@ -.so man1/new.1 diff --git a/man/fprev.man1 b/man/fprev.man1 new file mode 100644 index 0000000..7529017 --- /dev/null +++ b/man/fprev.man1 @@ -0,0 +1 @@ +.so man1/new.1 diff --git a/man/inc.man b/man/inc.man deleted file mode 100644 index 540b378..0000000 --- a/man/inc.man +++ /dev/null @@ -1,338 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH INC %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -inc \- incorporate new mail -.SH SYNOPSIS -.HP 5 -.na -.B inc -.RI [ +folder ] -.RB [ \-audit -.IR audit\-file ] -.RB [ \-noaudit ] -.RB [ \-changecur " | " \-nochangecur ] -.RB [ \-form -.IR formfile ] -.RB [ \-format -.IR string ] -.RB [ \-file -.IR name ] -.RB [ \-silent " | " \-nosilent ] -.RB [ \-truncate " | " \-notruncate ] -.RB [ \-width -.IR columns ] -%nmhbeginpop% -.RB [ \-host -.IR hostname ] -.RB [ \-user -.IR username ] -.RB [ \-pack -.IR file ] -.RB [ \-nopack ] -.RB [ \-proxy -.IR command ] -.RB [ \-sasl ] -.RB [ \-saslmech -.IR mechanism ] -.RB [ \-snoop ] -%nmhendpop% -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Inc -incorporates mail from the user's incoming mail drop into -an -.B nmh -folder. -.PP -You may specify which folder to use with -.IR +folder . -If no folder is specified, then -.B inc -will use either the folder given by a (non\-empty) -.RI \*(lq Inbox \*(rq -entry in the user's profile, or the folder named -.RI \*(lq inbox \*(rq. -If the specified (or default) folder doesn't -exist, the user will be queried prior to its creation. -.PP -When the new messages are incorporated into the folder, they are assigned -numbers starting with the next highest number for the folder. As the -messages are processed, a -.B scan -listing of the new mail is produced. -.PP -If the user's profile contains a -.RI \*(lq "Msg\-Protect: nnn" \*(rq -entry, it -will be used as the protection on the newly created messages, otherwise -the -.B nmh -default of 0644 will be used. For all subsequent operations -on these messages, this initially assigned protection will be preserved. -.PP -If the switch -.B \-audit -.I audit\-file -is specified (usually as a default -switch in the profile), then -.B inc -will append a header line and a -line per message to the end of the specified audit\-file with the format: -.PP -.RS 5 -.nf -<> date - - - -.fi -.RE -.PP -This is useful for keeping track of volume and source of incoming mail. -Eventually, -.BR repl , -.BR forw , -.BR comp , -and -.B dist -may also produce audits to this (or another) file, perhaps with -.RI \*(lq Message\-Id \*(rq -information to keep an exact correspondence -history. -.RI \*(lq Audit\-file \*(rq -will be in the user's nmh directory unless a full path is specified. -.PP -.B Inc -will incorporate even improperly formatted messages into the -user's nmh folder, inserting a blank line prior to the offending component -and printing a comment identifying the bad message. -.PP -In all cases, the user's mail drop will be zeroed, unless the -.B \-notruncate -switch is given. -.PP -If the profile entry -.RI \*(lq Unseen\-Sequence \*(rq -is present and non\-empty, then -.B inc -will add each of the newly incorporated messages to -each sequence named by the profile entry. -.B Inc -will not zero each sequence prior to adding messages. -.PP -The interpretation of the -.B \-form -.IR formatfile , -.B \-format -.IR string , -and -.B \-width -.I columns -switches is the same as in -.BR scan . -.PP -By using the -.B \-file -.I name -switch, one can direct -.B inc -to incorporate messages from a file other than the user's maildrop. -Note that the name file will NOT be zeroed, unless the -.B \-truncate -switch is given. -.PP -If the environment variable -.B $MAILDROP -is set, then -.B inc -uses it as the location of the user's maildrop instead of the default -(the -.B -file -.I name -switch still overrides this, however). If this -environment variable is not set, then -.B inc -will consult the profile entry -.RI \*(lq MailDrop \*(rq -for this information. If the value found is -not absolute, then it is interpreted relative to the user's -.B nmh -directory. If the value is not found, then -.B inc -will look in the standard system location for the user's maildrop. -.PP -The -.B \-silent -switch directs -.B inc -to be quiet and not ask any questions at all. This is useful for putting -.B inc -in the background and going on to other things. -%nmhbeginpop% -.PP -.SS "Using POP" -.B inc -will normally check local mail drops for mail, as covered above. But -if the option -.RI \*(lq pophost \*(rq -is set in -.RI \*(lq mts.conf \*(rq, -or if the -.B \-host -.I hostname -switch is given, or if the -.B $MAILHOST -environment variable is set, then -.B inc -will query this POP service host for mail to incorporate. If -.B $MAILHOST -is set and -.B \-host -is specified as well, the commandline switch will override -the environment variable. -.PP -The default is for -.B inc -to assume that your account name on -the POP server is the same as your current username. To specify -a different username, use the -.B \-user -.I username -switch. -.PP -When using POP, you will normally need to type the password for -your account on the POP server, in order to retrieve your messages. -It is possible to automate this process by creating a -.RI \*(lq .netrc \*(rq -file containing your login account information for this POP server. -For each POP server, this file should have a line of the following -form. Replace the words -.IR mypopserver , -.IR mylogin , -and -.I mypassword -with your own account information. -.PP -.RS 5 -.B machine -.I mypopserver -.B login -.I mylogin -.B password -.I mypassword -.RE -.PP -This -.RI \*(lq .netrc \*(rq -file should be owned and readable only by you. -.PP -If passed the -.B \-proxy -.I command -switch, -.B inc -will use the specified command to establish the connection to the POP -server. The string -.IR %h -in the command will be substituted by the hostname to connect to. -.PP -If -.B inc -uses POP, then the -.B \-pack -.I file -switch is considered. If given, then -.B inc -simply uses the POP to -.B packf -the user's maildrop from the POP service host to the named file. This switch -is provided for those users who prefer to use -.B msh -to read their maildrops. -.PP -For debugging purposes, you may give the switch -.BR \-snoop , -which will allow you to watch the POP transaction take place -between you and the POP server. -.PP -If -.B nmh -has been compiled with SASL support, the -.B \-sasl -switch will enable -the use of SASL authentication. Depending on the SASL mechanism used, this -may require an additional password prompt from the user (but the -.RI \*(lq .netrc \*(rq -file can be used to store this password). The -.B \-saslmech -switch can be used to select a particular SASL mechanism. -.PP -If SASL authentication is successful, -.B inc -will attempt to negotiate a security layer for session encryption. -Encrypted traffic is labelled with `(encrypted)' and `(decrypted)' -when viewing the POP transaction with the -.B \-snoop -switch. -%nmhendpop% - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -^%mailspool%/$USER~^Location of mail drop -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Alternate\-Mailboxes:~^To determine the user's mailboxes -^Inbox:~^To determine the inbox, default \*(lqinbox\*(rq -^Folder\-Protect:~^To set mode when creating a new folder -^Msg\-Protect:~^To set mode when creating a new message and audit\-file -^Unseen\-Sequence:~^To name sequences denoting unseen messages -.fi - -.SH "SEE ALSO" -mhmail(1), scan(1), mh\-mail(5), post(8) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaulted by \*(lqInbox\*(rq above" -.RB ` \-noaudit ' -.RB ` \-changecur ' -.RB ` \-format "' defaulted as described above" -.RB ` \-nosilent ' -.RB ` \-truncate "' if `" \-file " name' not given, `" \-notruncate "' otherwise" -.RB ` \-width "' defaulted to the width of the terminal" -%nmhbeginpop% -.RB ` \-nopack ' -%nmhendpop% -.fi - -.SH CONTEXT -The folder into which messages are being incorporated will become the -current folder. The first message incorporated will become the current -message, unless the -.B \-nochangecur -option is specified. This leaves the context ready for a -.B show -of the first new message. - -.SH BUGS -The argument to the -.B \-format -switch must be interpreted as a single -token by the shell that invokes -.BR inc . -Therefore, one must usually place the argument to this switch inside -double\-quotes. diff --git a/man/inc.man1 b/man/inc.man1 new file mode 100644 index 0000000..415ebcb --- /dev/null +++ b/man/inc.man1 @@ -0,0 +1,201 @@ +.\" +.\" %nmhwarning% +.\" +.TH INC %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +inc \- incorporate new mail +.SH SYNOPSIS +.HP 5 +.na +.B inc +.RI [ +folder ] +.RB [ \-audit +.IR audit\-file ] +.RB [ \-noaudit ] +.RB [ \-changecur " | " \-nochangecur ] +.RB [ \-form +.IR formfile ] +.RB [ \-file +.IR name ] +.RB [ \-silent " | " \-nosilent ] +.RB [ \-truncate " | " \-notruncate ] +.RB [ \-width +.IR columns ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Inc +incorporates mail from the user's incoming mail drop into +an +.B nmh +folder. +.PP +You may specify which folder to use with +.IR +folder . +If no folder is specified, then +.B inc +will use either the folder given by a (non\-empty) +.RI ` Inbox ' +entry in the user's profile, or the folder named +.RI ` inbox '. +If the specified (or default) folder doesn't +exist, the user will (in +.B \-nosilent +mode) be queried prior to its creation. +.PP +When the new messages are incorporated into the folder, they are assigned +numbers starting with the next highest number for the folder. As the +messages are processed, a +.B scan +listing of the new mail is produced. +.PP +If the user's profile contains a +.RI ` "Msg\-Protect: nnn" ' +entry, it +will be used as the protection on the newly created messages, otherwise +the +.B nmh +default of 0644 will be used. For all subsequent operations +on these messages, this initially assigned protection will be preserved. +.PP +If the switch +.B \-audit +.I audit\-file +is specified (usually as a default +switch in the profile), then +.B inc +will append a header line and a +line per message to the end of the specified audit\-file with the format: +.PP +.RS 5 +.nf +<> date + + + +.fi +.RE +.PP +This is useful for keeping track of volume and source of incoming mail. +Eventually, +.BR repl , +.BR forw , +.BR comp , +and +.B dist +may also produce audits to this (or another) file, perhaps with +.RI ` Message\-Id ' +information to keep an exact correspondence +history. +.RI ` Audit\-file ' +will be in the current directory unless a full path is specified. +.PP +.B Inc +will incorporate even improperly formatted messages into the +user's nmh folder, inserting a blank line prior to the offending component +and printing a comment identifying the bad message. +.PP +In all cases, the user's mail drop will be zeroed, unless the +.B \-notruncate +switch is given. +.PP +If the profile entry +.RI ` Unseen\-Sequence ' +is present and non\-empty, then +.B inc +will add each of the newly incorporated messages to +each sequence named by the profile entry. +.B Inc +will not zero each sequence prior to adding messages. +.PP +The interpretation of the +.B \-form +.IR formatfile , +and +.B \-width +.I columns +switches is the same as in +.BR scan . +.PP +By using the +.B \-file +.I name +switch, one can direct +.B inc +to incorporate messages from a file other than the user's maildrop. +Note that the name file will NOT be zeroed, unless the +.B \-truncate +switch is given. +.PP +If the environment variable +.B $MAILDROP +is set, then +.B inc +uses it as the location of the user's maildrop instead of the default +(the +.B -file +.I name +switch still overrides this, however). If this +environment variable is not set, then +.B inc +will consult the profile entry +.RI ` MailDrop ' +for this information. If the value found is +not absolute, then it is interpreted relative to the user's +.B nmh +directory. If the value is not found, then +.B inc +will look in the standard system location for the user's maildrop. +.PP +The +.B \-silent +switch directs +.B inc +to be quiet and not ask any questions at all. This is useful for putting +.B inc +in the background and going on to other things. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^%mailspool%/$USER~^Location of mail drop +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Alternate\-Mailboxes:~^To determine the user's mailboxes +^Inbox:~^To determine the inbox, default `inbox' +^Folder\-Protect:~^To set mode when creating a new folder +^Msg\-Protect:~^To set mode when creating a new message and audit\-file +^Unseen\-Sequence:~^To name sequences denoting unseen messages +.fi + +.SH "SEE ALSO" +scan(1), mh\-mail(5) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaulted by `Inbox' above" +.RB ` \-noaudit ' +.RB ` \-changecur ' +.RB ` \-form "' defaulted as described above" +.RB ` \-nosilent ' +.RB ` \-truncate "' if `" \-file " name' not given, `" \-notruncate "' otherwise" +.RB ` \-width "' defaulted to the width of the terminal" +.fi + +.SH CONTEXT +The folder into which messages are being incorporated will become the +current folder. The first message incorporated will become the current +message, unless the +.B \-nochangecur +option is specified. This leaves the context ready for a +.B show +of the first new message. diff --git a/man/install-mh.man b/man/install-mh.man deleted file mode 100644 index 094ec4c..0000000 --- a/man/install-mh.man +++ /dev/null @@ -1,90 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH INSTALL-MH %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -install-mh \- initialize the nmh environment -.SH SYNOPSIS -.HP 5 -.na -.B install\-mh -.RB [ \-auto ] -.RB [ \-check ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Install\-mh -is the -.B nmh -program to create the initial setup -for a first\-time -.B nmh -user. -.B Install\-mh -lives in two places for historical reasons. -.PP -The \fB\-auto\fP option does things as automatically as possible and -makes \fBinstall\-mh\fP less chatty. -.PP -The user is asked -for the name of the directory that will be designated as the user's -.B nmh -directory. If this directory does not exist, the user is -asked if it should be created. Normally, this directory should be -under the user's home directory, and has the default name of -\fI``Mail''\fP. -.B Install\-mh -writes an initial -.I \&.mh\(ruprofile -for the user. -.PP -As with all -.B nmh -commands, -.B install\-mh -first checks for the existence of the \fB$MH\fP environment variable -since that gives the profile path if set. -If it isn't set, the -.B $HOME -environment variable is consulted to determine the user's home directory. -If -.B $HOME -is not set, then the -.I /etc/passwd -file is consulted. -.PP -When creating the users initial -.IR \&.mh\(ruprofile , -.B install\-mh -will check for the existence of a global profile -.IR %etcdir%/mh.profile . -If found, this will be used to initialize the new -.IR \&.mh\(ruprofile . -.PP -The \fB\-check\fP option can be used to check whether or not nmh has -been installed. -This can be used by other programs to determine whether or not nmh has -been installed without their having to know the internals of nmh. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mh.profile~^Used to initialize user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To set the user's nmh directory -.fi - -.SH CONTEXT -With -.BR \-auto , -the current folder is changed to -.RI \*(lq inbox \*(rq. diff --git a/man/mark.man b/man/mark.man deleted file mode 100644 index eff4bf0..0000000 --- a/man/mark.man +++ /dev/null @@ -1,202 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MARK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mark \- manipulate message sequences -.SH SYNOPSIS -.HP 5 -.na -.B mark -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-sequence -.I name -\&...] -.RB [ \-add " | " \-delete ] -.RB [ \-list ] -.RB [ \-public " | " \-nopublic ] -.RB [ \-zero " | " \-nozero ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B mark -command manipulates message sequences by adding or deleting -message numbers from folder\-specific message sequences, or by listing -those sequences and messages. -.PP -A message sequence is a keyword, just like one of the \*(lqreserved\*(rq -message names, such as \*(lqfirst\*(rq or \*(lqnext\*(rq. Unlike the -\*(lqreserved\*(rq message names, which have a fixed semantics on -a per\-folder basis, the semantics of a message sequence may be -defined, modified, and removed by the user. Message sequences are -folder\-specific, e.g., the sequence name \*(lqseen\*(rq in the context -of folder -.RI \*(lq +inbox \*(rq -need not have any relation whatsoever to the -sequence of the same name in a folder of a different name. -.PP -Three action switches direct the operation of -.BR mark . -These switches -are mutually exclusive: the last occurrence of any of them overrides -any previous occurrence of the other two. -.PP -The -.B \-add -switch tells -.B mark -to add messages to sequences or to -create a new sequence. For each sequence named via the -.B \-sequence -.I name -argument (which must occur at least once) the messages named via -.I msgs -(which defaults to \*(lqcur\*(rq if no -.I msgs -are given), are added to the -sequence. The messages to be added need not be absent from the sequence. -If the -.B \-zero -switch is specified, the sequence will be emptied prior -to adding the messages. Hence, -.B \-add -.B \-zero -means that each sequence -should be initialized to the indicated messages, while -.B \-add -.B \-nozero -means that each sequence should be appended to by the indicated messages. -.PP -The -.B \-delete -switch tells -.B mark -to delete messages from sequences, and is the dual of -.BR \-add . -For each of the named sequences, the -named messages are removed from the sequence. These messages need -not be already present in the sequence. If the -.B \-zero -switch is -specified, then all messages in the folder are added to the sequence -(first creating the sequence, if necessary) before removing the messages. -Hence, -.B \-delete -.B \-zero -means that each sequence should contain -all messages except those indicated, while -.B \-delete -.B \-nozero -means -that only the indicated messages should be removed from each sequence. -As expected, the command -.RB \*(lq mark -.B \-sequence -.I foo -.B \-delete -all\*(rq -deletes the sequence \*(lqfoo\*(rq from the current folder. -.PP -When creating or modifying sequences, you can specify the switches -.B \-public -or -.B \-nopublic -to force the new or modified sequences to be -\*(lqpublic\*(rq or \*(lqprivate\*(rq. The switch -.B \-public -indicates -that the sequences should be made \*(lqpublic\*(rq. These sequences -will then be readable by all -.B nmh -users with permission to read the relevant folders. In contrast, the -.B \-nopublic -switch indicates that the -sequences should be made \*(lqprivate\*(rq, and will only be accessible by -you. If neither of these switches is specified, then existing sequences -will maintain their current status, and new sequences will default to -\*(lqpublic\*(rq if you have write permission for the relevant folder. -Check the -.BR mh\-sequence (5) -man page for more details about the difference -between \*(lqpublic\*(rq and \*(lqprivate\*(rq sequences. -.PP -The -.B \-list -switch tells -.B mark -to list both the sequences defined -for the folder and the messages associated with those sequences. -.B Mark -will list the name of each sequence given by -.B \-sequence -.I name -and the messages associated with that sequence. If the -sequence is private, this will also be indicated. If no sequence is -specified by the -.B \-sequence -switch, then all sequences for this folder -will be listed. The -.B \-zero -switch does not affect the operation of -.BR \-list . -.PP -The current restrictions on sequences are: -.PP -.IP \(bu 2 -The name used to denote a message sequence must consist of an alphabetic -character followed by zero or more alphanumeric characters, and cannot -be one of the (reserved) message names \*(lqnew\*(rq, \*(lqfirst\*(rq, -\*(lqlast\*(rq, \*(lqall\*(rq, \*(lqnext\*(rq, or \*(lqprev\*(rq. -.PP -.IP \(bu 2 -Only a certain number of sequences may be defined for a given folder. -This number is usually limited to 26 (10 on small systems). -.PP -.IP \(bu 2 -Message ranges with user\-defined sequence names are restricted to the -form \*(lqname:n\*(rq, \*(lqname:+n\*(rq, or \*(lqname:-n\*(rq, and refer -to the first or last `n' messages of the sequence `name', respectively. -Constructs of the form \*(lqname1\-name2\*(rq are forbidden for user -defined sequences. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -flist(1), pick(1), mh-sequence(5) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` \-add "' if " \-sequence " is specified, " \-list " otherwise" -.RB ` msgs "' defaults to cur (or all if " \-list " is specified)" -.RB ` \-nozero ' - -.SH CONTEXT -If a folder is given, it will become the current folder. - -.SH "HELPFUL HINTS" -Use -.B flist -to find folders with a given sequence, and -.RB \*(lq pick -.I sequence -.BR \-list \*(rq -to enumerate those messages in the sequence (such as for -use by a shell script). diff --git a/man/mark.man1 b/man/mark.man1 new file mode 100644 index 0000000..6577f64 --- /dev/null +++ b/man/mark.man1 @@ -0,0 +1,204 @@ +.\" +.\" %nmhwarning% +.\" +.TH MARK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mark \- manipulate message sequences +.SH SYNOPSIS +.HP 5 +.na +.B mark +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-sequence +.I name +\&...] +.RB [ \-add " | " \-delete ] +.RB [ \-list ] +.RB [ \-public " | " \-nopublic ] +.RB [ \-zero " | " \-nozero ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B mark +command manipulates message sequences by adding or deleting +message numbers from folder\-specific message sequences, or by listing +those sequences and messages. +.PP +A message sequence is a keyword, just like one of the `reserved' +message names, such as `first' or `next'. Unlike the +`reserved' message names, which have a fixed semantics on +a per\-folder basis, the semantics of a message sequence may be +defined, modified, and removed by the user. Message sequences are +folder\-specific, e.g., the sequence name `seen' in the context +of folder +.RI ` +inbox ' +need not have any relation whatsoever to the +sequence of the same name in a folder of a different name. +.PP +Three action switches direct the operation of +.BR mark . +These switches +are mutually exclusive: the last occurrence of any of them overrides +any previous occurrence of the other two. +.PP +The +.B \-add +switch tells +.B mark +to add messages to sequences or to +create a new sequence. For each sequence named via the +.B \-sequence +.I name +argument (which must occur at least once) the messages named via +.I msgs +(which defaults to `cur' if no +.I msgs +are given), are added to the +sequence. The messages to be added need not be absent from the sequence. +If the +.B \-zero +switch is specified, the sequence will be emptied prior +to adding the messages. Hence, +.B \-add +.B \-zero +means that each sequence +should be initialized to the indicated messages, while +.B \-add +.B \-nozero +means that each sequence should be appended to by the indicated messages. +.PP +The +.B \-delete +switch tells +.B mark +to delete messages from sequences, and is the dual of +.BR \-add . +For each of the named sequences, the +named messages are removed from the sequence. These messages need +not be already present in the sequence. If the +.B \-zero +switch is +specified, then all messages in the folder are added to the sequence +(first creating the sequence, if necessary) before removing the messages. +Hence, +.B \-delete +.B \-zero +means that each sequence should contain +all messages except those indicated, while +.B \-delete +.B \-nozero +means +that only the indicated messages should be removed from each sequence. +As expected, the command +.RB ` mark +.B \-sequence +.I foo +.B \-delete +all' +deletes the sequence `foo' from the current folder. +.PP +When creating or modifying sequences, you can specify the switches +.B \-public +or +.B \-nopublic +to force the new or modified sequences to be +`public' or `private'. The switch +.B \-public +indicates +that the sequences should be made `public'. These sequences +will then be readable by all +.B nmh +users with permission to read the relevant folders. In contrast, the +.B \-nopublic +switch indicates that the +sequences should be made `private', and will only be accessible by +you. If neither of these switches is specified, then existing sequences +will maintain their current status, and new sequences will default to +`public' if you have write permission for the relevant folder. +Check the +.BR mh\-sequence (7) +man page for more details about the difference +between `public' and `private' sequences. +.PP +The +.B \-list +switch tells +.B mark +to list both the sequences defined +for the folder and the messages associated with those sequences. +.B Mark +will list the name of each sequence given by +.B \-sequence +.I name +and the messages associated with that sequence. If the +sequence is private, this will also be indicated. If no sequence is +specified by the +.B \-sequence +switch, then all sequences for this folder +will be listed. The +.B \-zero +switch does not affect the operation of +.BR \-list . +.PP +The current restrictions on sequences are: +.PP +.IP \(bu 2 +The name used to denote a message sequence must consist of an alphabetic +character followed by zero or more alphanumeric characters, and cannot +be one of the (reserved) message names `new', `first', +`last', `all', `next', or `prev'. +.PP +.IP \(bu 2 +Only a certain number of sequences may be defined for a given folder. +This number is usually limited to 29 (13 on small systems). (The ++internal implementation relies on bitmasks, with some bits set aside ++for internal use.) +.PP +.IP \(bu 2 +Message ranges with user\-defined sequence names are restricted to the +form `name:n', `name:+n', or `name:-n', and refer +to the first or last `n' messages of the sequence `name', respectively. +Constructs of the form `name1\-name2' are forbidden for user +defined sequences. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +flist(1), pick(1), mh-sequence(7) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` \-add "' if " \-sequence " is specified, " \-list " otherwise" +.RB ` msgs "' defaults to cur (or all if " \-list " is specified)" +.RB ` \-nozero ' + +.SH CONTEXT +If a folder is given, it will become the current folder. + +.SH "HELPFUL HINTS" +Use +.B flist +to find folders with a given sequence, and +.RB ` pick +.I sequence +.BR \-list ' +to enumerate those messages in the sequence (such as for +use by a shell script). diff --git a/man/mh-alias.man b/man/mh-alias.man deleted file mode 100644 index ad47699..0000000 --- a/man/mh-alias.man +++ /dev/null @@ -1,280 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MH-ALIAS %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mh-alias \- alias file for nmh message system -.SH SYNOPSIS -any -.B nmh -command -.SH DESCRIPTION -This describes both -.B nmh -personal alias files and -the global alias file for -.B nmh -mail delivery, the file -.PP -.RS 5 -%etcdir%/MailAliases -.RE -.PP -It does -.B not -describe aliases files used by the message transport system. -Each line of the alias file has the format: -.PP -.RS 5 -.I alias -.B : -.I address\-group -.RE -or -.RS 5 -.I alias -.B ; -.I address\-group -.RE -or -.RS 5 -.B < -.I alias\-file -.RE -or -.RS 5 -.B ; -.I comment -.RE -.PP -where: -.PP -.RS 5 -.nf -.IR address\-group " := " address\-list -.RI " | < " file -.RI " | = " UNIX\-group -.RI " | + " UNIX\-group - | * - -.IR address\-list " := " address -.RI " | " address\-list ", " address -.fi -.RE -.PP -Continuation lines in alias files end with `\\' followed by the newline -character. -.PP -.RI \*(lq Alias\-file \*(rq -and -.RI \*(lq file \*(rq -are UNIX file names. -.I UNIX\-group -is a group name (or number) from -.IR /etc/group . -An address is a \*(lqsimple\*(rq -Internet\-style address. Througout this file, case is ignored, except -for file names. -.PP -If the line starts with a `<', then the file named after the `<' is -read for more alias definitions. The reading is done recursively, so a -`<' may occur in the beginning of an alias file with the expected results. -.PP -If the -.I address\-group -starts with a `<', then the file named after the -`<' is read and its contents are added to the -.I address\-list -for the alias. -.PP -If the -.I address\-group -starts with an `=', then the file -.I /etc/group -is consulted for the UNIX\-group named after the `='. Each login name -occurring as a member of the group is added to the -.I address\-list -for the alias. -.PP -In contrast, if the -.I address\-group -starts with a `+', then the file -.I /etc/group -is consulted to determine the group\-id of the -UNIX\-group named after the `+'. Each login name occurring in the -.I /etc/passwd -file whose group\-id is indicated by this group is -added to the -.I address\-list -for the alias. -.PP -If the -.I address\-group -is simply `*', then the file -.I /etc/passwd -is consulted and all login names with a userid -greater than some magic number (usually 200) are added to the -.I address\-list -for the alias. -.PP -In match, a trailing \*(lq*\*(rq on an alias will match just about anything -appropriate. (See example below.) -.PP -An approximation of the way aliases are resolved at posting time is -(it's not really done this way): -.PP -.RS 2 -.IP 1) 3 -Build a list of all addresses from the message to be delivered, -eliminating duplicate addresses. -.PP -.IP 2) 3 -If this draft originated on the local host, then for those addresses in -the message that have no host specified, perform alias resolution. -.PP -.IP 3) 3 -For each line in the alias file, compare \*(lqalias\*(rq against all of -the existing addresses. If a match, remove the matched \*(lqalias\*(rq -from the address list, and add each new address in the address\-group to -the address list if it is not already on the list. The alias itself is -not usually output, rather the address\-group that the alias maps to is -output instead. If \*(lqalias\*(rq is terminated with a `;' instead of -a `:', then both the \*(lqalias\*(rq and the address are output in the -correct format. (This makes replies possible since -.B nmh -aliases -and personal aliases are unknown to the mail transport system.) -.RE -.PP -Since the alias file is read line by line, forward references work, but -backward references are not recognized, thus, there is no recursion. -.PP -Example Alias File: -.PP -.RS 5 -.nf -<%etcdir%/BBoardAliases -sgroup: fred, fear, freida -b-people: Blind List: bill, betty; -fred: frated@UCI -UNIX\-committee: \*(rq are defined to be \*(lqnews\*(rq. -.PP -The key thing to understand about aliasing in -.B nmh -is that aliases in -.B nmh -alias files are expanded into the headers of messages posted. -This aliasing occurs first, at posting time, without the knowledge of the -message transport system. In contrast, once the message transport system -is given a message to deliver to a list of addresses, for each address -that appears to be local, a system\-wide alias file is consulted. These -aliases are -.B NOT -expanded into the headers of messages delivered. - -.SH "HELPFUL HINTS" -To use aliasing in -.B nmh -quickly, do the following: -.PP -.RS 2 -.IP 1) 3 -In your -.IR \&.mh\(ruprofile , -choose a name for your alias file, say -.RI \*(lq aliases \*(rq, -and add the line: -.PP -.RS 5 -.nf -Aliasfile: aliases -.\" ali: \-alias aliases -.\" send: \-alias aliases -.\" whom: \-alias aliases -.fi -.RE -.PP -.IP 2) 3 -Create the file -.RI \*(lq aliases \*(rq -in your -.B nmh -directory. -.PP -.IP 3) 3 -Start adding aliases to your -.RI \*(lq aliases \*(rq -file as appropriate. -.RE - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/MailAliases~^global nmh alias file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Aliasfile:~^For a default alias file -.fi - -.SH "SEE ALSO" -ali(1), send(1), whom(1), group(5), passwd(5), conflict(8), post(8) - -.SH CONTEXT -None - -.SH BUGS -Although the forward-referencing semantics of -.B mh\-alias -files prevent recursion, the -.RI \*(lq< " alias\-file" \*(rq -command may defeat this. -Since the number of file descriptors is finite (and very limited), such -infinite recursion will terminate with a meaningless diagnostic when -all the fds are used up. -.PP -Forward references do not work correctly inside blind lists. diff --git a/man/mh-alias.man5 b/man/mh-alias.man5 new file mode 100644 index 0000000..90cb9ba --- /dev/null +++ b/man/mh-alias.man5 @@ -0,0 +1,255 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-ALIAS %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh-alias \- alias file for nmh message system +.SH SYNOPSIS +any +.B nmh +command +.SH DESCRIPTION +This describes +.B nmh +personal alias files. +It does +.B not +describe aliases files used by the message transport system. +Each line of the alias file has the format: +.PP +.RS 5 +.I alias +.B : +.I address\-group +.RE +or +.RS 5 +.I alias +.B ; +.I address\-group +.RE +or +.RS 5 +.B < +.I alias\-file +.RE +or +.RS 5 +.B ; +.I comment +.RE +.PP +where: +.PP +.RS 5 +.nf +.IR address\-group " := " address\-list +.RI " | < " file +.RI " | = " UNIX\-group +.RI " | + " UNIX\-group + | * + +.IR address\-list " := " address +.RI " | " address\-list ", " address +.fi +.RE +.PP +Continuation lines in alias files end with `\\' followed by the newline +character. +.PP +.RI ` Alias\-file ' +and +.RI ` file ' +are UNIX file names. +.I UNIX\-group +is a group name (or number) from +.IR /etc/group . +An address is a `simple' +Internet\-style address. Througout this file, case is ignored, except +for file names. +.PP +If the line starts with a `<', then the file named after the `<' is +read for more alias definitions. The reading is done recursively, so a +`<' may occur in the beginning of an alias file with the expected results. +.PP +If the +.I address\-group +starts with a `<', then the file named after the +`<' is read and its contents are added to the +.I address\-list +for the alias. +.PP +If the +.I address\-group +starts with an `=', then the file +.I /etc/group +is consulted for the UNIX\-group named after the `='. Each login name +occurring as a member of the group is added to the +.I address\-list +for the alias. +.PP +In contrast, if the +.I address\-group +starts with a `+', then the file +.I /etc/group +is consulted to determine the group\-id of the +UNIX\-group named after the `+'. Each login name occurring in the +.I /etc/passwd +file whose group\-id is indicated by this group is +added to the +.I address\-list +for the alias. +.PP +In match, a trailing `*' on an alias will match just about anything +appropriate. (See example below.) +.PP +An approximation of the way aliases are resolved at posting time is +(it's not really done this way): +.PP +.RS 2 +.IP 1) 3 +Build a list of all addresses from the message to be delivered, +eliminating duplicate addresses. +.PP +.IP 2) 3 +If this draft originated on the local host, then for those addresses in +the message that have no host specified, perform alias resolution. +.PP +.IP 3) 3 +For each line in the alias file, compare `alias' against all of +the existing addresses. If a match, remove the matched `alias' +from the address list, and add each new address in the address\-group to +the address list if it is not already on the list. The alias itself is +not usually output, rather the address\-group that the alias maps to is +output instead. If `alias' is terminated with a `;' instead of +a `:', then both the `alias' and the address are output in the +correct format. (This makes replies possible since personal +.B nmh +aliases are unknown to the mail transport system.) +.RE +.PP +Since the alias file is read line by line, forward references work, but +backward references are not recognized, thus, there is no recursion. +.PP +Example Alias File: +.PP +.RS 5 +.nf +<%etcdir%/MoreAliases +sgroup: fred, fear, freida +b-people: Blind List: bill, betty; +fred: frated@UCI +UNIX\-committee: ' are defined to be `news'. +.PP +The key thing to understand about aliasing in +.B nmh +is that aliases in +.B nmh +alias files are expanded into the headers of messages posted. +This aliasing occurs first, at posting time, without the knowledge of the +message transport system. In contrast, once the message transport system +is given a message to deliver to a list of addresses, for each address +that appears to be local, a system\-wide alias file is consulted. These +aliases are +.B NOT +expanded into the headers of messages delivered. + +.SH "HELPFUL HINTS" +To use aliasing in +.B nmh +quickly, do the following: +.PP +.RS 2 +.IP 1) 3 +In your +.IR .mmh/profile , +choose a name for your alias file, say +.RI ` aliases ', +and add the line: +.PP +.RS 5 +.nf +Aliasfile: aliases +.fi +.RE +.PP +.IP 2) 3 +Create the file +.RI ` aliases ' +in your +.B mmh +directory. +.PP +.IP 3) 3 +Start adding aliases to your +.RI ` aliases ' +file as appropriate. +.RE + +.SH FILES +None + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Aliasfile:~^For a default alias file +.fi + +.SH "SEE ALSO" +ali(1), send(1), group(5), passwd(5), post(8) + +.SH CONTEXT +None + +.SH HISTORY +An address group named `*', meaning everyone on the system, had been +supported in nmh. It is not anymore in mmh. + +.SH BUGS +Although the forward-referencing semantics of +.B mh\-alias +files prevent recursion, the +.RI `< " alias\-file" ' +command may defeat this. +Since the number of file descriptors is finite (and very limited), such +infinite recursion will terminate with a meaningless diagnostic when +all the fds are used up. +.PP +Forward references do not work correctly inside blind lists. diff --git a/man/mh-chart-gen.sh b/man/mh-chart-gen.sh new file mode 100755 index 0000000..72a2b38 --- /dev/null +++ b/man/mh-chart-gen.sh @@ -0,0 +1,33 @@ +#! /bin/sh +# +# Generates mh-chart man page from other man page source files that have a +# SYNOPSIS section. + +cat <'. -These are combined into the conditional execution construct: -.PP -.RS 5 -.nf -.RI "%< " condition " " "format-text" -.RI "%? " condition " " "format-text" - \&... -.RI "%| " "format-text" -%> -.fi -.RE -.PP -Extra white space is shown here only for clarity. These -constructs may be nested without ambiguity. They form a general -.B if\-elseif\-else\-endif -block where only one of the -format-texts -is interpreted. In other -words, `%<' is like the "if", `%?' is like the "elseif", `%|' is like -"else", and `%>' is like "endif". -.PP -A `%<' or `%?' control escape causes its condition to be evaluated. -This condition is a -.I component -or -.IR function . -For integer valued functions or components, the condition is true -if the function return or component value is non-zero, and false if zero. -For string valued functions or components, the condition is true -if the function return or component value is -a non-empty string, and false for an empty string. - -.PP -The `%?' control escape is optional, and may there may be more -than one `%?' control escape in a conditional block. -The `%|' control escape -is also optional, but may be included at most once. - -.SS "Function escapes" -Functions expecting an argument generally -require an argument of a particular type. -In addition to the number and string types, -these include: -.PP -.RS 5 -.nf -.ta +\w'Argument 'u +\w'An optional component, 'u -.I Argument Description Example Syntax -literal A literal number %(\fIfunc\fR 1234) - or string %(\fIfunc\fR text string) -comp Any component %(\fIfunc\fR\^{\fIin-reply-to\fR\^}) -date A date component %(\fIfunc\fR\^{\fIdate\fR\^}) -addr An address component %(\fIfunc\fR\^{\fIfrom\fR\^}) -expr Nothing %(\fIfunc\fR) - or a subexpression %(\fIfunc\fR\^(\fIfunc2\fR\^)) - or control escape %(\fIfunc\fR %<{\fIreply-to\fR\^}%|%{\fIfrom\fR\^}%>) -.fi -.RE -.PP -The types -.I date -and -.I addr -have the same syntax as -.IR comp , -but require that the header component be a date string, or address -string, respectively. -.PP -Most arguments not of type -.IR expr -are required. -When escapes are nested (via expr arguments), evaluation is done from inner-most to outer-most. -As noted above, for the -expr -argument type, -functions and components are written without a -leading `%'. -Control escape arguments must use a leading `%', preceded by a space. -.PP -For example, -.PP -.RS 5 -.nf -%<(mymbox{from}) To: %{to}%> -.fi -.RE -.PP -writes the value of the header component \*(lqFrom:\*(rq to the -internal register named str; then (\fImymbox\fR\^) reads str and -writes its result to the internal register named -.IR num ; -then the control escape evaluates -.IR num . -If -.IR num -is non-zero, the -string \*(lqTo:\*(rq is printed followed by the value of the -header component \*(lqTo:\*(rq. -.SS Evaluation -The evaluation of format strings is performed -by a small virtual machine. -The machine is capable of evaluating nested expressions -as described above, and in addition -has an integer register -.IR num , -and a text string register -.IR str . -When a function escape that -accepts an optional argument is processed, -and the argument is not present, the current value of either -.I num -or -.I str -is used as the argument: which register is -used depends on the function, as listed below. -.PP -Component escapes write the value of their message header in -.IR str . -Function escapes write their return value in -.I num -for functions returning integer or boolean values, and in -.I str -for functions returning string values. (The boolean type is a subset -of integers with usual values 0=false and 1=true.) Control escapes -return a boolean value, setting -.I num -to 1 if the last explicit condition -evaluated by a `%<' or `%?' control -succeeded, and 0 otherwise. -.PP -All component escapes, and those function escapes which return an -integer or string value, evaluate to their value as well as setting -.I str -or -.IR num . -Outermost escape expressions in -these forms will print -their value, but outermost escapes which return a boolean value -do not result in printed output. -.SS Functions -The function escapes may be roughly grouped into a few categories. -.PP -.RS 5 -.nf -.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u -.I Function Argument Result Description -msg integer message number -cur integer message is current (0 or 1) -unseen integer message is unseen (0 or 1) -size integer size of message -strlen integer length of \fIstr\fR -width integer output buffer size in bytes -charleft integer bytes left in output buffer -timenow integer seconds since the UNIX epoch -me string the user's mailbox -eq literal boolean \fInum\fR == \fIarg\fR -ne literal boolean \fInum\fR != \fIarg\fR -gt literal boolean \fInum\fR > \fIarg\fR -match literal boolean \fIstr\fR contains \fIarg\fR -amatch literal boolean \fIstr\fR starts with \fIarg\fR -plus literal integer \fIarg\fR plus \fInum\fR -minus literal integer \fIarg\fR minus \fInum\fR -divide literal integer \fInum\fR divided by \fIarg\fR -modulo literal integer \fInum\fR modulo \fIarg\fR -num literal integer Set \fInum\fR to \fIarg\fR. -num integer Set \fInum\fR to zero. -lit literal string Set \fIstr\fR to \fIarg\fR. -lit string Clear \fIstr\fR. -getenv literal string Set \fIstr\fR to environment value of \fIarg\fR -profile literal string Set \fIstr\fR to profile component \fIarg\fR - value -.\" dat literal int return value of dat[arg] -nonzero expr boolean \fInum\fR is non-zero -zero expr boolean \fInum\fR is zero -null expr boolean \fIstr\fR is empty -nonnull expr boolean \fIstr\fR is non-empty -void expr Set \fIstr\fR or \fInum\fR -comp comp string Set \fIstr\fR to component text -compval comp integer Set \fInum\fR to \*(lq\fBatoi\fR(\fIcomp\fR\^)\*(rq -.\" compflag comp integer Set \fInum\fR to component flags bits (internal) -.\" decodecomp comp string Set \fIstr\fR to RFC-2047 decoded component text -decode expr string decode \fIstr\fR as RFC-2047 (MIME-encoded) - component -unquote expr string remove RFC-2822 quotes from \fIstr\fR -trim expr trim trailing white-space from \fIstr\fR -putstr expr print \fIstr\fR -putstrf expr print \fIstr\fR in a fixed width -putnum expr print \fInum\fR -putnumf expr print \fInum\fR in a fixed width -.\" addtoseq literal add msg to sequence (LBL option) -nodate string integer Argument not a date string (0 or 1) -formataddr expr append \fIarg\fR to \fIstr\fR as a - (comma separated) address list -putaddr literal print \fIstr\fR address list with - \fIarg\fR as optional label; - get line width from \fInum\fR -.fi -.RE -.PP -The following functions require a date component as an argument: -.PP -.RS 5 -.nf -.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u -.I Function Argument Return Description -sec date integer seconds of the minute -min date integer minutes of the hour -hour date integer hours of the day (0-23) -wday date integer day of the week (Sun=0) -day date string day of the week (abbrev.) -weekday date string day of the week -sday date integer day of the week known? - (1=explicit,0=implicit,\-1=unknown) -mday date integer day of the month -yday date integer day of the year -mon date integer month of the year -month date string month of the year (abbrev.) -lmonth date string month of the year -year date integer year (may be > 100) -zone date integer timezone in hours -tzone date string timezone string -szone date integer timezone explicit? - (1=explicit,0=implicit,\-1=unknown) -date2local date coerce date to local timezone -date2gmt date coerce date to GMT -dst date integer daylight savings in effect? (0 or 1) -clock date integer seconds since the UNIX epoch -rclock date integer seconds prior to current time -tws date string official 822 rendering -pretty date string user-friendly rendering -.fi -.RE -.PP -These functions require an address component as an argument. -The return value of functions noted with `*' is computed from -the first address present in the header component. -.PP -.RS 5 -.nf -.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u -.I Function Argument Return Description -proper addr string official 822 rendering -friendly addr string user-friendly rendering -addr addr string mbox@host or host!mbox rendering* -pers addr string the personal name* -note addr string commentary text* -mbox addr string the local mailbox* -mymbox addr integer List has the user's address? (0 or 1) -host addr string the host domain* -nohost addr integer no host was present (0 or 1)* -type addr integer host type* (0=local,1=network, - \-1=uucp,2=unknown) -path addr string any leading host route* -ingrp addr integer address was inside a group (0 or 1)* -gname addr string name of group* -.fi -.RE -.PP -(A clarification on (\fImymbox\fR\^{\fIcomp\fR\^}) is in order. -This function checks each of the addresses in the header component -\*(lq\fIcomp\fR\*(rq against the user's mailbox name and any -.RI \*(lq Alternate-Mailboxes \*(rq. -It returns true if any address matches, -however, it also returns true if the \*(lq\fIcomp\fR\*(rq header is not -present in the message. If needed, the (\fInull\fR\^) function can be -used to explicitly test for this case.) -.SS Formatting -When a function or component escape is interpreted and the result will -be immediately printed, an optional field width can be specified to -print the field in exactly a given number of characters. For example, a -numeric escape like %4(\fIsize\fR\^) will print at most 4 digits of the -message size; overflow will be indicated by a `?' in the first position -(like `?234'). A string escape like %4(\fIme\fR\^) will print the first 4 -characters and truncate at the end. Short fields are padded at the right -with the fill character (normally, a blank). If the field width argument -begins with a leading zero, then the fill character is set to a zero. -.PP -The functions (\fIputnumf\fR\^) and (\fIputstrf\fR\^) -print their result in exactly the number of characters -specified by their leading field width argument. For example, -%06(\fIputnumf\fR\^(\fIsize\fR\^)) will print the message -size in a field six characters wide filled with leading zeros; -%14(\fIputstrf\^\fR{\fIfrom\^\fR}) will print the \*(lqFrom:\*(rq header -component in fourteen characters with trailing spaces added as needed. -For \fIputstrf\fR, using a negative value for the field width causes -right-justification of the string within the field, with padding on -the left up to the field width. -The functions (\fIputnum\fR\^) and -(\fIputstr\fR\^) are somewhat special: they print their result in the minimum number of characters -required, and ignore any leading field width argument. -.PP -The available output width is kept in an internal register; any output -past this width will be truncated. -.SS Examples -With all this in mind, -here's the default format string for -.BR scan . -It's been divided into several pieces for readability. -The first part is: -.PP -.RS -.nf -%4(msg)%<(cur)+%| %>%<{replied}\-%?{encrypted}E%| %> -.fi -.RE -.PP -which says that the message number should be printed in four digits. -If the message is the current message then a `+' else a space should -be printed; if a \*(lqReplied:\*(rq field is present then a `\-' -else if an \*(lqEncrypted:\*(rq field is present then an `E' otherwise -a space should be printed. Next: -.PP -.RS -.nf -%02(mon{date})/%02(mday{date}) -.fi -.RE -.PP -the month and date are printed in two digits (zero filled) separated by -a slash. Next, -.PP -.RS 5 -.nf -%<{date} %|*%> -.fi -.RE -.PP -If a \*(lqDate:\*(rq field was present, -then a space is printed, otherwise a `*'. -Next, -.PP -.RS 5 -.nf -%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%> -.fi -.RE -.PP -if the message is from me, and there is a \*(lqTo:\*(rq header, -print \*(lqTo:\*(rq followed by a \*(lquser-friendly\*(rq rendering of the -first address in the \*(lqTo:\*(rq field; any MIME-encoded -characters are decoded into the actual characters. -Continuing, -.PP -.RS 5 -.nf -%<(zero)%17(decode(friendly{from}))%> -.fi -.RE -.PP -if either of the above two tests failed, -then the \*(lqFrom:\*(rq address is printed -in a mime-decoded, \*(lquser-friendly\*(rq format. -And finally, -.PP -.RS 5 -.nf -%(decode{subject})%<{body}<<%{body}>>%> -.fi -.RE -.PP -the mime-decoded subject and initial body (if any) are printed. -.PP -For a more complicated example, next consider -a possible -.I replcomps -format file. -.PP -.RS 5 -.nf -%(lit)%(formataddr %<{reply-to} -.fi -.RE -.PP -This clears -.I str -and formats the \*(lqReply-To:\*(rq header -if present. If not present, the else-if clause is executed. -.PP -.RS 5 -.nf -%?{from}%?{sender}%?{return-path}%>)\\ -.fi -.RE -.PP -This formats the -\*(lqFrom:\*(rq, \*(lqSender:\*(rq and \*(lqReturn-Path:\*(rq -headers, stopping as soon as one of them is present. Next: -.PP -.RS 5 -.nf -%<(nonnull)%(void(width))%(putaddr To: )\\n%>\\ -.fi -.RE -.PP -If the \fIformataddr\fR result is non-null, it is printed as -an address (with line folding if needed) in a field \fIwidth\fR -wide with a leading label of \*(lqTo:\*(rq. -.PP -.RS 5 -.nf -%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\\ -.fi -.RE -.PP -.I str -is cleared, and the \*(lqTo:\*(rq and \*(lqCc:\*(rq headers, along with the user's -address (depending on what was specified with -the \*(lq\-cc\*(rq switch to \fIrepl\fR\^) are formatted. -.PP -.RS 5 -.nf -%<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\ -.fi -.RE -.PP -If the result is non-null, it is printed as above with a -leading label of \*(lqcc:\*(rq. -.PP -.RS 5 -.nf -%<{fcc}Fcc: %{fcc}\\n%>\\ -.fi -.RE -.PP -If a -.B \-fcc -.I folder -switch was given to -.B repl -(see -.BR repl (1) -for more details about %{\fIfcc\fR\^}), -an \*(lqFcc:\*(rq header is output. -.PP -.RS 5 -.nf -%<{subject}Subject: Re: %{subject}\\n%>\\ -.fi -.RE -.PP -If a subject component was present, -a suitable reply subject is output. -.PP -.RS 5 -.nf -%<{message-id}In-Reply-To: %{message-id}\\n%>\\ -%<{message-id}References: %<{references} %{references}%>\\ -%{message-id}\\n%> -\-\-\-\-\-\-\-\- -.fi -.RE -.PP -If a message-id component was present, an \*(lqIn-Reply-To:\*(rq header is -output including the message-id, followed by a \*(lqReferences:\*(rq -header with references, if present, and the message-id. -As with all -plain-text, the row of dashes are output as-is. -.PP -This last part is a good example for a little more elaboration. -Here's that part again in pseudo-code: -.PP -.RS 5 -.nf -.ta .5i 1i 1.5i 2i -if (comp_exists(message-id)) then - print (\*(lqIn-reply-to: \*(rq) - print (message-id.value) - print (\*(lq\\n\*(rq) -endif -if (comp_exists(message-id)) then - print (\*(lqReferences: \*(rq) - if (comp_exists(references)) then - print(references.value); - endif - print (message-id.value) - print (\*(lq\\n\*(rq) -endif -.fi -.RE -.PP -.\" (Note that this pseudocode begs the question ``why not just -.\" support this syntax?'' MH has been hacked on for a long time...) -.\".PP -One more example: Currently, -.B nmh -supports very -large message numbers, and it is not uncommon for a folder -to have far more than 10000 messages. -.\" (Indeed, the original MH -.\" tutorial document by Rose and Romine is entitled "How to -.\" process 200 messages a day and still get some real work -.\" done." The authors apparently only planned to get -.\" real work done for about 50 days per folder.) -Nontheless (as noted above) -the various scan format strings are inherited -from older MH versions, and are generally hard-coded to 4 -digits of message number before formatting problems -start to occur. -The nmh format strings can be modified to behave more sensibly with larger -message numbers: -.PP -.RS -.nf -%(void(msg))%<(gt 9999)%(msg)%|%4(msg)%> -.fi -.RE -.PP -The current message number is placed in \fInum\fP. -(Note that -.RI ( msg ) -is an int function, not a component.) -The -.RI ( gt ) -conditional -is used to test whether the message number -has 5 -or more digits. -If so, it is printed at full width: otherwise -at 4 digits. -.SH "SEE ALSO" -scan(1), repl(1), ap(8), dp(8) - -.SH CONTEXT -None diff --git a/man/mh-format.man5 b/man/mh-format.man5 new file mode 100644 index 0000000..e86e9ce --- /dev/null +++ b/man/mh-format.man5 @@ -0,0 +1,606 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-FORMAT %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh-format \- format file for nmh message system +.SH DESCRIPTION +Several +.B nmh +commands utilize either a +.I format +string or a +.I format +file during their execution. For example, +.B scan +uses a format string which directs it how to generate the scan listing +for each message; +.B repl +uses a format file which directs it +how to generate the reply to a message, and so on. +.PP +There are a few alternate scan listing formats available +in +.IR nmh/etc/scan.time , +.IR nmh/etc/scan.size , +and +.IR nmh/etc/scan.timely . +Look in +.I nmh/etc +for other +.B scan +and +.B repl +format files which may have been written at your site. +.PP +It suffices to have your local +.B nmh +expert actually write new format +commands or modify existing ones. This manual section explains how to +do that. Note: familiarity with the C +.B printf +routine is assumed. +.PP +A format string consists of ordinary text, and special multi-character +escape sequences which begin with `%'. When specifying a format +string, the usual C backslash characters are honored: `\\b', `\\f', +`\\n', `\\r', and `\\t'. Continuation lines in format files end with +`\\' followed by the newline character. + +.\" TALK ABOUT SYNTAX FIRST, THEN SEMANTICS +.SS SYNTAX +Format strings are built around +.IR "escape sequences" . +There are three types of escape sequences: header +.IR components , +built-in +.IR functions , +and flow +.IR control . +Comments may be inserted in most places where a function argument is +not expected. A comment begins with `%;' and ends with a (non-escaped) +newline. +.PP +A +.I component +escape is specified as +.RI `%{ component }', +and +exists for each header found in the message being processed. For example +.RI `%{ date }' +refers to the `Date:' field of the appropriate message. +All component escapes have a string value. Normally, component values are +compressed by converting any control characters (tab and newline included) +to spaces, then eliding any leading or multiple spaces. However, commands +may give different interpretations to some component escapes; be sure +to refer to each command's manual entry for complete details. +.PP +A +.I function +escape is specified as +.RI `%( function )'. +All functions are built-in, and most have a string or numeric value. +A function escape may have an +.IR argument . +The argument follows the function escape: separating +whitespace is discarded: +.RI `%( function " " argument )'. +.PP +In addition to literal numbers or strings, +the argument to a function escape can be another function, a component, +or a control escape. When the argument is a function or a +component, they are listed without a leading `%'. When control escapes +are used as function arguments, they written as normally, with +a leading `%'; + +.SS "Control escapes" +.PP +A +.I control +escape is one of: `%<', `%?', `%|', or `%>'. +These are combined into the conditional execution construct: +.PP +.RS 5 +.nf +.RI "%< " condition " " "format-text" +.RI "%? " condition " " "format-text" + \&... +.RI "%| " "format-text" +%> +.fi +.RE +.PP +Extra white space is shown here only for clarity. These +constructs may be nested without ambiguity. They form a general +.B if\-elseif\-else\-endif +block where only one of the +format-texts +is interpreted. In other +words, `%<' is like the "if", `%?' is like the "elseif", `%|' is like +"else", and `%>' is like "endif". +.PP +A `%<' or `%?' control escape causes its condition to be evaluated. +This condition is a +.I component +or +.IR function . +For integer valued functions or components, the condition is true +if the function return or component value is non-zero, and false if zero. +For string valued functions or components, the condition is true +if the function return or component value is +a non-empty string, and false for an empty string. + +.PP +The `%?' control escape is optional, and may there may be more +than one `%?' control escape in a conditional block. +The `%|' control escape +is also optional, but may be included at most once. + +.SS "Function escapes" +Functions expecting an argument generally +require an argument of a particular type. +In addition to the number and string types, +these include: +.PP +.RS 5 +.nf +.ta +\w'Argument 'u +\w'An optional component, 'u +.I "Argument Description Example Syntax +literal A literal number %(\fIfunc\fR 1234) + or string %(\fIfunc\fR text string) +comp Any component %(\fIfunc\fR\^{\fIin-reply-to\fR\^}) +date A date component %(\fIfunc\fR\^{\fIdate\fR\^}) +addr An address component %(\fIfunc\fR\^{\fIfrom\fR\^}) +expr Nothing %(\fIfunc\fR) + or a subexpression %(\fIfunc\fR\^(\fIfunc2\fR\^)) + or control escape %(\fIfunc\fR %<{\fIreply-to\fR\^}%|%{\fIfrom\fR\^}%>) +.fi +.RE +.PP +The types +.I date +and +.I addr +have the same syntax as +.IR comp , +but require that the header component be a date string, or address +string, respectively. +.PP +Most arguments not of type +.IR expr +are required. +When escapes are nested (via expr arguments), evaluation is done from inner-most to outer-most. +As noted above, for the +expr +argument type, +functions and components are written without a +leading `%'. +Control escape arguments must use a leading `%', preceded by a space. +.PP +For example, +.PP +.RS 5 +.nf +%<(mymbox{from}) To: %{to}%> +.fi +.RE +.PP +writes the value of the header component `From:' to the +internal register named str; then (\fImymbox\fR\^) reads str and +writes its result to the internal register named +.IR num ; +then the control escape evaluates +.IR num . +If +.IR num +is non-zero, the +string `To:' is printed followed by the value of the +header component `To:'. +.SS Evaluation +The evaluation of format strings is performed +by a small virtual machine. +The machine is capable of evaluating nested expressions +as described above, and in addition +has an integer register +.IR num , +and a text string register +.IR str . +When a function escape that +accepts an optional argument is processed, +and the argument is not present, the current value of either +.I num +or +.I str +is used as the argument: which register is +used depends on the function, as listed below. +.PP +Component escapes write the value of their message header in +.IR str . +Function escapes write their return value in +.I num +for functions returning integer or boolean values, and in +.I str +for functions returning string values. (The boolean type is a subset +of integers with usual values 0=false and 1=true.) Control escapes +return a boolean value, setting +.I num +to 1 if the last explicit condition +evaluated by a `%<' or `%?' control +succeeded, and 0 otherwise. +.PP +All component escapes, and those function escapes which return an +integer or string value, evaluate to their value as well as setting +.I str +or +.IR num . +Outermost escape expressions in +these forms will print +their value, but outermost escapes which return a boolean value +do not result in printed output. +.SS Functions +The function escapes may be roughly grouped into a few categories. +.PP +.RS 5 +.nf +.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u +.I "Function Argument Result Description +msg integer message number +cur integer message is current (0 or 1) +unseen integer message is unseen (0 or 1) +size integer size of message +strlen integer length of \fIstr\fR +width integer output buffer size in bytes +charleft integer bytes left in output buffer +timenow integer seconds since the UNIX epoch +me string the user's mailbox +eq literal boolean \fInum\fR == \fIarg\fR +ne literal boolean \fInum\fR != \fIarg\fR +gt literal boolean \fInum\fR > \fIarg\fR +match literal boolean \fIstr\fR contains \fIarg\fR +amatch literal boolean \fIstr\fR starts with \fIarg\fR +plus literal integer \fIarg\fR plus \fInum\fR +minus literal integer \fIarg\fR minus \fInum\fR +divide literal integer \fInum\fR divided by \fIarg\fR +modulo literal integer \fInum\fR modulo \fIarg\fR +num literal integer Set \fInum\fR to \fIarg\fR. +num integer Set \fInum\fR to zero. +lit literal string Set \fIstr\fR to \fIarg\fR. +lit string Clear \fIstr\fR. +getenv literal string Set \fIstr\fR to environment value of \fIarg\fR +profile literal string Set \fIstr\fR to profile component \fIarg\fR + value +.\" dat literal int return value of dat[arg] +nonzero expr boolean \fInum\fR is non-zero +zero expr boolean \fInum\fR is zero +null expr boolean \fIstr\fR is empty +nonnull expr boolean \fIstr\fR is non-empty +void expr Set \fIstr\fR or \fInum\fR +comp comp string Set \fIstr\fR to component text +compval comp integer Set \fInum\fR to `\fBatoi\fR(\fIcomp\fR\^)' +.\" compflag comp integer Set \fInum\fR to component flags bits (internal) +.\" decodecomp comp string Set \fIstr\fR to RFC-2047 decoded component text +decode expr string decode \fIstr\fR as RFC-2047 (MIME-encoded) + component +unquote expr string remove RFC-2822 quotes from \fIstr\fR +trim expr trim trailing white-space from \fIstr\fR +putstr expr print \fIstr\fR +putstrf expr print \fIstr\fR in a fixed width +putnum expr print \fInum\fR +putnumf expr print \fInum\fR in a fixed width +nodate string integer Argument not a date string (0 or 1) +formataddr expr append \fIarg\fR to \fIstr\fR as a + (comma separated) address list +putaddr literal print \fIstr\fR address list with + \fIarg\fR as optional label; + get line width from \fInum\fR +.fi +.RE +.PP +The following functions require a date component as an argument: +.PP +.RS 5 +.nf +.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u +.I "Function Argument Return Description +sec date integer seconds of the minute +min date integer minutes of the hour +hour date integer hours of the day (0-23) +wday date integer day of the week (Sun=0) +day date string day of the week (abbrev.) +weekday date string day of the week +sday date integer day of the week known? + (1=explicit,0=implicit,\-1=unknown) +mday date integer day of the month +yday date integer day of the year +mon date integer month of the year +month date string month of the year (abbrev.) +lmonth date string month of the year +year date integer year (may be > 100) +zone date integer timezone in hours +tzone date string timezone string +szone date integer timezone explicit? + (1=explicit,0=implicit,\-1=unknown) +date2local date coerce date to local timezone +date2gmt date coerce date to GMT +dst date integer daylight savings in effect? (0 or 1) +clock date integer seconds since the UNIX epoch +rclock date integer seconds prior to current time +tws date string official 822 rendering +pretty date string user-friendly rendering +.fi +.RE +.PP +These functions require an address component as an argument. +The return value of functions noted with `*' is computed from +the first address present in the header component. +.PP +.RS 5 +.nf +.ta \w'Fformataddr 'u +\w'Aboolean 'u +\w'Rboolean 'u +.I "Function Argument Return Description +proper addr string official 822 rendering +friendly addr string user-friendly rendering +addr addr string mbox@host or host!mbox rendering* +pers addr string the personal name* +note addr string commentary text* +mbox addr string the local mailbox* +mymbox addr integer List has the user's address? (0 or 1) +host addr string the host domain* +nohost addr integer no host was present (0 or 1)* +type addr integer host type* (0=local,1=network, + \-1=uucp,2=unknown) +path addr string any leading host route* +ingrp addr integer address was inside a group (0 or 1)* +gname addr string name of group* +.fi +.RE +.PP +(A clarification on (\fImymbox\fR\^{\fIcomp\fR\^}) is in order. +This function checks each of the addresses in the header component +`\fIcomp\fR' against the user's mailbox name and any +.RI ` Alternate-Mailboxes '. +It returns true if any address matches, +however, it also returns true if the `\fIcomp\fR' header is not +present in the message. If needed, the (\fInull\fR\^) function can be +used to explicitly test for this case.) +.SS Formatting +When a function or component escape is interpreted and the result will +be immediately printed, an optional field width can be specified to +print the field in exactly a given number of characters. For example, a +numeric escape like %4(\fIsize\fR\^) will print at most 4 digits of the +message size; overflow will be indicated by a `?' in the first position +(like `?234'). A string escape like %4(\fIme\fR\^) will print the first 4 +characters and truncate at the end. Short fields are padded at the right +with the fill character (normally, a blank). If the field width argument +begins with a leading zero, then the fill character is set to a zero. +.PP +The functions (\fIputnumf\fR\^) and (\fIputstrf\fR\^) +print their result in exactly the number of characters +specified by their leading field width argument. For example, +%06(\fIputnumf\fR\^(\fIsize\fR\^)) will print the message +size in a field six characters wide filled with leading zeros; +%14(\fIputstrf\^\fR{\fIfrom\^\fR}) will print the `From:' header +component in fourteen characters with trailing spaces added as needed. +For \fIputstrf\fR, using a negative value for the field width causes +right-justification of the string within the field, with padding on +the left up to the field width. +The functions (\fIputnum\fR\^) and +(\fIputstr\fR\^) are somewhat special: they print their result in the minimum number of characters +required, and ignore any leading field width argument. +.PP +The available output width is kept in an internal register; any output +past this width will be truncated. +.SS Examples +With all this in mind, +here's the default format string for +.BR scan . +It's been divided into several pieces for readability. +The first part is: +.PP +.RS +.nf +%4(msg)%<(cur)+%| %>%<{replied}\-%| %> +.fi +.RE +.PP +which says that the message number should be printed in four digits. +If the message is the current message then a `+' else a space should +be printed; if a `Replied:' field is present then a `\-' +else a space should be printed. Next: +.PP +.RS +.nf +%02(mon{date})/%02(mday{date}) +.fi +.RE +.PP +the month and date are printed in two digits (zero filled) separated by +a slash. Next, +.PP +.RS 5 +.nf +%<{date} %|*%> +.fi +.RE +.PP +If a `Date:' field was present, +then a space is printed, otherwise a `*'. +Next, +.PP +.RS 5 +.nf +%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%> +.fi +.RE +.PP +if the message is from me, and there is a `To:' header, +print `To:' followed by a `user-friendly' rendering of the +first address in the `To:' field; any MIME-encoded +characters are decoded into the actual characters. +Continuing, +.PP +.RS 5 +.nf +%<(zero)%17(decode(friendly{from}))%> +.fi +.RE +.PP +if either of the above two tests failed, +then the `From:' address is printed +in a mime-decoded, `user-friendly' format. +And finally, +.PP +.RS 5 +.nf +%(decode{subject}) +.fi +.RE +.PP +the mime-decoded subject is printed. +.PP +For a more complicated example, next consider +a possible +.I replcomps +format file. +.PP +.RS 5 +.nf +%(lit)%(formataddr %<{reply-to} +.fi +.RE +.PP +This clears +.I str +and formats the `Reply-To:' header +if present. If not present, the else-if clause is executed. +.PP +.RS 5 +.nf +%?{from}%?{sender}%?{return-path}%>)\\ +.fi +.RE +.PP +This formats the +`From:', `Sender:' and `Return-Path:' +headers, stopping as soon as one of them is present. Next: +.PP +.RS 5 +.nf +%<(nonnull)%(void(width))%(putaddr To: )\\n%>\\ +.fi +.RE +.PP +If the \fIformataddr\fR result is non-null, it is printed as +an address (with line folding if needed) in a field \fIwidth\fR +wide with a leading label of `To:'. +.PP +.RS 5 +.nf +%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\\ +.fi +.RE +.PP +.I str +is cleared, and the `To:' and `Cc:' headers, along with the user's +address (depending on what was specified with +the `\-cc' switch to \fIrepl\fR\^) are formatted. +.PP +.RS 5 +.nf +%<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\ +.fi +.RE +.PP +If the result is non-null, it is printed as above with a +leading label of `Cc:'. +.PP +.RS 5 +.nf +%<{subject}Subject: Re: %{subject}\\n%>\\ +.fi +.RE +.PP +If a subject component was present, +a suitable reply subject is output. +.PP +.RS 5 +.nf +%<{message-id}In-Reply-To: %{message-id}\\n%>\\ +%<{message-id}References: %<{references} %{references}%>\\ +%{message-id}\\n%> +\-\-\-\-\-\-\-\- +.fi +.RE +.PP +If a message-id component was present, an `In-Reply-To:' header is +output including the message-id, followed by a `References:' +header with references, if present, and the message-id. +As with all +plain-text, the row of dashes are output as-is. +.PP +This last part is a good example for a little more elaboration. +Here's that part again in pseudo-code: +.PP +.RS 5 +.nf +.ta .5i 1i 1.5i 2i +if (comp_exists(message-id)) then + print (`In-reply-to: ') + print (message-id.value) + print (`\\n') +endif +if (comp_exists(message-id)) then + print (`References: ') + if (comp_exists(references)) then + print(references.value); + endif + print (message-id.value) + print (`\\n') +endif +.fi +.RE +.PP +.\" (Note that this pseudocode begs the question ``why not just +.\" support this syntax?'' MH has been hacked on for a long time...) +.\".PP +One more example: Currently, +.B nmh +supports very +large message numbers, and it is not uncommon for a folder +to have far more than 10000 messages. +.\" (Indeed, the original MH +.\" tutorial document by Rose and Romine is entitled "How to +.\" process 200 messages a day and still get some real work +.\" done." The authors apparently only planned to get +.\" real work done for about 50 days per folder.) +Nontheless (as noted above) +the various scan format strings are inherited +from older MH versions, and are generally hard-coded to 4 +digits of message number before formatting problems +start to occur. +The nmh format strings can be modified to behave more sensibly with larger +message numbers: +.PP +.RS +.nf +%(void(msg))%<(gt 9999)%(msg)%|%4(msg)%> +.fi +.RE +.PP +The current message number is placed in \fInum\fP. +(Note that +.RI ( msg ) +is an int function, not a component.) +The +.RI ( gt ) +conditional +is used to test whether the message number +has 5 +or more digits. +If so, it is printed at full width: otherwise +at 4 digits. +.SH "SEE ALSO" +scan(1), repl(1), ap(8), dp(8) + +.SH CONTEXT +None diff --git a/man/mh-mail.man b/man/mh-mail.man deleted file mode 100644 index 2f29640..0000000 --- a/man/mh-mail.man +++ /dev/null @@ -1,277 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MH-MAIL %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mh-mail \- message format for nmh message system -.SH SYNOPSIS -any -.B nmh -command -.SH DESCRIPTION -.B nmh -processes messages in a particular format. It should be noted -that although neither Bell nor Berkeley mailers produce message files -in the format that -.B nmh -prefers, -.B nmh -can read message files in that antiquated format. -.PP -Each user possesses a mail drop box which initially receives all messages -processed by -.BR post . -.B Inc -will read from that drop -box and incorporate the new messages found there into the user's own -mail folders (typically -.RI \*(lq +inbox \*(rq). -The mail drop box consists of one or more messages. -.PP -Messages are expected to consist of lines of text. Graphics and binary -data are not handled. No data compression is accepted. All text is -clear ASCII 7-bit data. -.PP -The general \*(lqmemo\*(rq framework of RFC\-822 is used. A message -consists of a block of information in a rigid format, followed by -general text with no specified format. The rigidly formatted first -part of a message is called the header, and the free-format portion is -called the body. The header must always exist, but the body is optional. -These parts are separated by an empty line, i.e., two consecutive newline -characters. Within -.B nmh , -the header and body may be separated by a line consisting of dashes: -.PP -.RS 5 -.nf -%components% -.fi -.RE -.PP -The header is composed of one or more header items. Each header item can -be viewed as a single logical line of ASCII characters. If the text of -a header item extends across several real lines, the continuation lines -are indicated by leading spaces or tabs. -.PP -Each header item is called a component and is composed of a keyword or -name, along with associated text. The keyword begins at the left margin, -may NOT contain spaces or tabs, may not exceed 63 characters (as specified -by RFC\-822), and is terminated by a colon (`:'). Certain components -(as identified by their keywords) must follow rigidly defined formats -in their text portions. -.PP -The text for most formatted components (e.g., \*(lqDate:\*(rq and -\*(lqMessage\-Id:\*(rq) is produced automatically. The only ones entered -by the user are address fields such as \*(lqTo:\*(rq, \*(lqcc:\*(rq, -etc. Internet addresses are assigned mailbox names and host computer -specifications. The rough format is \*(lqlocal@domain\*(rq, such as -\*(lqMH@UCI\*(rq, or \*(lqMH@UCI\-ICSA.ARPA\*(rq. Multiple addresses -are separated by commas. A missing host/domain is assumed to be the -local host/domain. -.PP -As mentioned above, a blank line (or a line of dashes) signals that all -following text up to the end of the file is the body. No formatting is -expected or enforced within the body. -.PP -Following is a list of header components that are considered -meaningful to various -.B nmh -programs. -.PP -.BR Date : -.RS 5 -Added by -.BR post , -contains date and time of the message's entry -into the mail transport system. -.RE -.PP -.BR From : -.RS 5 -Added by -.BR post , -contains the address of the author or authors -(may be more than one if a \*(lqSender:\*(rq field is present). For a -standard reply (using -.BR repl , -the reply address is constructed by -checking the following headers (in this order): \*(lqMail-Reply\-To:\*(rq, -\*(lqReply\-To:\*(rq, \*(lqFrom:\*(rq, \*(lqSender:\*(rq. -.RE -.PP -.BR Mail\-Reply\-To : -.RS 5 -For a standard reply (using -.BR repl ), -the reply address is -constructed by checking the following headers (in this order): -\*(lqMail-Reply\-To:\*(rq, \*(lqReply\-To:\*(rq, \*(lqFrom:\*(rq, -\*(lqSender:\*(rq. -.RE -.PP -.BR Mail\-Followup\-To : -.RS 5 -When making a \*(lqgroup\*(rq reply (using -.B repl -.BR \-group ), -any addresses in this field will take precedence, and no other reply address -will be added to the draft. If this header is not available, then the -return addresses will be constructed from the \*(lqMail-Reply\-To:\*(rq, -or \*(lqReply\-To:\*(rq, or \*(lqFrom:\*(rq, along with adding the -addresses from the headers \*(lqTo:\*(rq, \*(lqcc:\*(rq, as well as -adding your personal address. -.RE -.PP -.BR Reply\-To : -.RS 5 -For a standard reply (using -.BR repl ), -the reply address is -constructed by checking the following headers (in this order): -\*(lqMail-Reply\-To:\*(rq, \*(lqReply\-To:\*(rq, \*(lqFrom:\*(rq, -\*(lqSender:\*(rq. -.RE -.PP -.BR Sender : -.RS 5 -Added by -.B post -in the event that the message already has a -\*(lqFrom:\*(rq line. This line contains the address of the actual -sender. -.RE -.PP -.BR To : -.RS 5 -Contains addresses of primary recipients. -.RE -.PP -.BR cc : -.RS 5 -Contains addresses of secondary recipients. -.RE -.PP -Bcc: -.RS 5 -Still more recipients. However, the \*(lqBcc:\*(rq line is not -copied onto the message as delivered, so these recipients are not -listed. -.B nmh -uses an encapsulation method for blind copies, see -.BR send . -.RE -.PP -.BR Fcc : -.RS 5 -Causes -.B post -to copy the message into the specified folder for the sender, -if the message was successfully given to the transport system. -.RE -.PP -.BR Message\-ID : -.RS 5 -A unique message identifier added by -.B post -if the -.B \-msgid -flag is set. -.RE -.PP -.BR Subject : -.RS 5 -Sender's commentary. It is displayed by -.BR scan . -.RE -.PP -.BR In\-Reply\-To : -.RS 5 -A commentary line added by -.B repl -when replying to a message. -.RE -.PP -.BR Resent\-Date : -.RS 5 -Added when redistributing a message by -.BR post . -.RE -.PP -.BR Resent\-From : -.RS 5 -Added when redistributing a message by -.BR post . -.RE -.PP -.BR Resent\-To: -.RS 5 -New recipients for a message resent by -.BR dist . -.RE -.PP -.BR Resent\-cc : -.RS 5 -Still more recipients. See \*(lqcc:\*(rq and \*(lqResent\-To:\*(rq. -.RE -.PP -.BR Resent\-Bcc : -.RS 5 -Even more recipients. See \*(lqBcc:\*(rq and \*(lqResent\-To:\*(rq. -.RE -.PP -.BR Resent\-Fcc : -.RS 5 -Copy resent message into a folder. -See \*(lqFcc:\*(rq and \*(lqResent\-To:\*(rq. -.RE -.PP -.BR Resent\-Message\-Id : -.RS 5 -A unique identifier glued on by -.B post -if the -.B \-msgid -flag is set. -See \*(lqMessage\-Id:\*(rq and \*(lqResent\-To:\*(rq. -.RE -.PP -.BR Resent : -.RS 5 -Annotation for -.B dist -under the -.B \-annotate -option. -.RE -.PP -.BR Forwarded : -.RS 5 -Annotation for -.B forw -under the -.B \-annotate -option. -.RE -.PP -.BR Replied : -.RS 5 -Annotation for -.B repl -under the -.B \-annotate -option. -.RE - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%mailspool%/$USER~^Location of mail drop -.fi - -.SH "SEE ALSO" -.I "Standard for the Format of ARPA Internet Text Messages -(RFC\-822) - -.SH CONTEXT -None diff --git a/man/mh-mail.man5 b/man/mh-mail.man5 new file mode 100644 index 0000000..a6e6677 --- /dev/null +++ b/man/mh-mail.man5 @@ -0,0 +1,280 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-MAIL %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh-mail \- message format for nmh message system +.SH SYNOPSIS +any +.B nmh +command +.SH DESCRIPTION +.B nmh +processes messages in a particular format. It should be noted +that although neither Bell nor Berkeley mailers produce message files +in the format that +.B nmh +prefers, +.B nmh +can read message files in that antiquated format. +.PP +Each user possesses a system maildrop box which initially receives all +messages delivered by the MTA. +.B Inc +will read from that maildrop +and incorporate the new messages found there into the user's own +mail folders (typically +.RI ` +inbox '). +.PP +Messages are expected to consist of lines of text. Graphics and binary +data are not directly handled. No data compression is accepted. All text is +clear ASCII 7-bit data. +.PP +The general `memo' framework of RFC\-822 is used. A message +consists of a block of information in a rigid format, followed by +general text with no specified format. The rigidly formatted first +part of a message is called the header, and the free-format portion is +called the body. The header must always exist, but the body is optional. +These parts are separated by an empty line, i.e., two consecutive newline +characters. Within +.B nmh , +the header and body may be separated by a line consisting of dashes: +.PP +.RS 5 +.nf +%components% +.fi +.RE +.PP +The header is composed of one or more header items. Each header item can +be viewed as a single logical line of ASCII characters. If the text of +a header item extends across several real lines, the continuation lines +are indicated by leading spaces or tabs. +.PP +Each header item is called a component and is composed of a keyword or +name, along with associated text. The keyword begins at the left margin, +may NOT contain spaces or tabs, may not exceed 63 characters (as specified +by RFC\-822), and is terminated by a colon (`:'). Certain components +(as identified by their keywords) must follow rigidly defined formats +in their text portions. +.PP +The text for most formatted components (e.g., `Date:' and +`Message\-Id:') is produced automatically. The only ones entered +by the user are address fields such as `To:', `Cc:', +etc. Internet addresses are assigned mailbox names and host computer +specifications. The rough format is `local@domain', such as +`bob@example.org'. Multiple addresses +are separated by commas. A missing host/domain is assumed to be the +local host/domain. +.PP +As mentioned above, a blank line (or a line of dashes) signals that all +following text up to the end of the file is the body. No formatting is +expected or enforced within the body. +.PP +Following is a list of header components that are considered +meaningful to various +.B mmh +programs. +.PP +.BR Date : +.RS 5 +Added by +.BR spost . +Contains date and time of the message's entry +into the mail transport system. +.RE +.PP +.BR From : +.RS 5 +Added by +.BR spost . +Contains the address of the author or authors +(may be more than one if a `Sender:' field is present). For a +standard reply (using +.BR repl , +the reply address is constructed by +checking the following headers (in this order): `Mail-Reply\-To:', +`Reply\-To:', `From:', `Sender:'. +.RE +.PP +.BR Mail\-Reply\-To : +.RS 5 +For a standard reply (using +.BR repl ), +the reply address is +constructed by checking the following headers (in this order): +`Mail-Reply\-To:', `Reply\-To:', `From:', +`Sender:'. +.RE +.PP +.BR Mail\-Followup\-To : +.RS 5 +When making a `group' reply (using +.B repl +.BR \-group ), +any addresses in this field will take precedence, and no other reply address +will be added to the draft. If this header is not available, then the +return addresses will be constructed from the `Mail-Reply\-To:', +or `Reply\-To:', or `From:', along with adding the +addresses from the headers `To:', `Cc:', as well as +adding your personal address. +.RE +.PP +.BR Reply\-To : +.RS 5 +For a standard reply (using +.BR repl ), +the reply address is +constructed by checking the following headers (in this order): +`Mail-Reply\-To:', `Reply\-To:', `From:', +`Sender:'. +.RE +.PP +.BR Sender : +.RS 5 +Added by +.B spost +in the event that the message already has a +`From:' line. This line contains the address of the actual +sender. +.RE +.PP +.BR To : +.RS 5 +Contains addresses of primary recipients. +.RE +.PP +.BR Cc : +.RS 5 +Contains addresses of secondary recipients. +.RE +.PP +.BR Bcc : +.RS 5 +Still more recipients. However, the `Bcc:' line is not +copied onto the message as delivered, so these recipients are not +listed. +.B mmh +uses an encapsulation method for blind copies, see +.BR send (1) +or +.BR spost (8). +.RE +.PP +.BR Fcc : +.RS 5 +Causes +.B spost +to copy the message into the specified folder for the sender, +if the message was successfully given to the transport system. +.RE +.PP +.BR Message\-ID : +.RS 5 +A unique message identifier added by the MTA. +.RE +.PP +.BR Subject : +.RS 5 +Sender's commentary. It is displayed by +.BR scan . +.RE +.PP +.BR In\-Reply\-To : +.RS 5 +A commentary line added by +.B repl +when replying to a message. +.RE +.PP +.BR Resent\-Date : +.RS 5 +Added when redistributing a message by +.BR spost . +.RE +.PP +.BR Resent\-From : +.RS 5 +Added when redistributing a message by +.BR spost . +.RE +.PP +.BR Resent\-To: +.RS 5 +New recipients for a message resent by +.BR dist . +.RE +.PP +.BR Resent\-Cc : +.RS 5 +Still more recipients. See `Cc:' and `Resent\-To:'. +.RE +.PP +.BR Resent\-Bcc : +.RS 5 +Even more recipients. See `Bcc:' and `Resent\-To:'. +.RE +.PP +.BR Resent\-Fcc : +.RS 5 +Copy resent message into a folder. +See `Fcc:' and `Resent\-To:'. +.RE +.PP +.BR Resent\-Message\-Id : +.RS 5 +A unique identifier glued on by the MTA. +See `Message\-Id:' and `Resent\-To:'. +.RE +.PP +The following non-standard header components are also meaningful to +.B mmh +tools: +.PP +.BR Attach : +.RS 5 +Annotation for +.B send +to attach the given file to the message being sent. +.RE +.PP +.BR Replied : +.RS 5 +Annotation for +.B repl +under the +.B \-annotate +option. +.RE +.PP +.BR Forwarded : +.RS 5 +Annotation for +.B forw +under the +.B \-annotate +option. +.RE +.PP +.BR Resent : +.RS 5 +Annotation for +.B dist +under the +.B \-annotate +option. +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%mailspool%/$USER~^Location of mail drop +.fi + +.SH "SEE ALSO" +.I "Standard for the Format of ARPA Internet Text Messages +(RFC\-822) + +.SH CONTEXT +None diff --git a/man/mh-profile.man b/man/mh-profile.man deleted file mode 100644 index cd47524..0000000 --- a/man/mh-profile.man +++ /dev/null @@ -1,976 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MH-PROFILE %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mh-profile \- user profile customization for nmh message handler -.SH SYNOPSIS -.I $HOME/.mh\(ruprofile -.SH DESCRIPTION -Each user of -.B nmh -is expected to have a file named -.I \&.mh\(ruprofile -in his or her home directory. This file contains -a set of user parameters used by some or all of the -.B nmh -family of programs. Each entry in the file is of the format -.PP -.RS 5 -.IR profile\-component ": " value -.RE -.PP -If the text of profile entry is long, you may extend it across several -real lines by indenting the continuation lines with leading spaces or tabs. - -.SS "Standard Profile Entries" -The possible profile components are exemplified below. The only mandatory -entry is `Path:'. The others are optional; some have default values if -they are not present. In the notation used below, (profile, default) -indicates whether the information is kept in the user's -.B nmh -profile or -.B nmh -context, and indicates what the default value is. -.PP -.BR Path : -Mail -.RS 5 -Locates -.B nmh -transactions in directory \*(lqMail\*(rq. This is the -only mandatory profile entry. (profile, no default) -.RE -.PP -.BR context : -context -.RS 5 -Declares the location of the -.B nmh -context file. This is overridden by the environment variable -.BR $MHCONTEXT . -See the -.B HISTORY -section below. -(profile, default: /context) -.RE -.PP -.BR Current\-Folder : -inbox -.RS 5 -Keeps track of the current open folder. -(context, default: folder specified by \*(lqInbox\*(rq) -.RE -.PP -.BR Inbox : -inbox -.RS 5 -Defines the name of your default inbox. -(profile, default: inbox) -.RE -.PP -.BR Previous\-Sequence : -.I pseq -.RS 5 -Names the sequence or sequences which should be defined as the `msgs' or -`msg' argument given to any -.B nmh -command. If not present or empty, -no such sequences are defined. Otherwise, for each name given, the -sequence is first zero'd and then each message is added to the sequence. -Read the -.BR mh\-sequence (5) -man page for the details about this sequence. (profile, no default) -.RE -.PP -.BR Sequence\-Negation : -not -.RS 5 -Defines the string which, when prefixed to a sequence name, negates -that sequence. Hence, \*(lqnotseen\*(rq means all those messages that -are not a member of the sequence \*(lqseen\*(rq. Read the -.BR mh\-sequence (5) -man page for the details. (profile, no default) -.RE -.PP -.BR Unseen\-Sequence : -unseen -.RS 5 -Names the sequence or sequences which should be defined as those -messages which are unread. The commands -.BR inc , -.BR rcvstore , -.BR mhshow , -and -.B show -will add or remove messages from these -sequences when they are incorporated or read. If not present or -empty, no such sequences are defined. Otherwise, each message is -added to, or removed from, each sequence name given. Read the -.BR mh\-sequence (5) -man page for the details about this sequence. -(profile, no default) -.RE -.PP -.BR mh\-sequences : -\&.mh\(rusequences -.RS 5 -The name of the file in each folder which defines public sequences. -To disable the use of public sequences, leave the value portion of this -entry blank. (profile, default: \&.mh\(rusequences) -.RE -.PP -.BI atr\- seq \- folder : -172\0178\-181\0212 -.RS 5 -Keeps track of the private sequence called \*(lqseq\*(rq in the specified -folder. Private sequences are generally used for read\-only folders. -See the -.BR mh\-sequence (5) -man page for details about private sequences. -(context, no default) -.RE -.PP -.BR Editor : -/usr/bin/vi -.RS 5 -Defines the editor to be used by the commands -.BR comp , -.BR dist , -.BR forw , -and -.BR repl . -(profile, default: %default_editor%) -.RE -.PP -.BR automimeproc : -.RS 5 -If defined and set to 1, then the -.B whatnow -program will automatically -invoke the buildmimeproc (discussed below) to process each message as a MIME -composition draft before it is sent. -(profile, no default) -.RE -.PP -.BR Msg\-Protect : -644 -.RS 5 -An octal number which defines the permission bits for new message files. -See -.BR chmod (1) -for an explanation of the octal number. -(profile, default: 0644) -.RE -.PP -.BR Folder\-Protect : -750 -.RS 5 -An octal number which defines the permission bits for new folder -directories. See -.BR chmod (1) -for an explanation of the octal number. -(profile, default: 700) -.RE -.PP -.IR program : -.I default switches -.RS 5 -Sets default switches to be used whenever the mh program -.I program -is invoked. For example, one could override the \*(lqEditor:\*(rq profile -component when replying to messages by adding a component such as: -.PP -.RS 5 -repl: \-editor /bin/ed -.RE -.PP -(profile, no defaults) -.RE -.PP -.IB lasteditor "-next:" -.I nexteditor -.RS 5 -Names \*(lqnexteditor\*(rq to be the default editor after using -\*(lqlasteditor\*(rq. This takes effect at \*(lqWhat now?\*(rq prompt -in -.BR comp , -.BR dist , -.BR forw , -and -.BR repl . -After editing -the draft with \*(lqlasteditor\*(rq, the default editor is set to be -\*(lqnexteditor\*(rq. If the user types \*(lqedit\*(rq without any -arguments to \*(lqWhat now?\*(rq, then \*(lqnexteditor\*(rq is used. -(profile, no default) -.RE -.PP -.BR bboards : -system -.RS 5 -Tells -.B bbc -which BBoards you are interested in. (profile, default: system) -.RE -.PP -.BR Folder\-Stack : -.I folders -.RS 5 -The contents of the folder-stack for the -.B folder -command. -(context, no default) -.RE -.PP -.BR mhe : -.RS 5 -If present, tells -.B inc -to compose an -.I MHE -auditfile in addition to its other tasks. -.I MHE -is Brian Reid's -.B emacs -front-end for -.BR nmh . -(profile, no default) -.RE -.PP -.BR Alternate\-Mailboxes : -mh@uci\-750a, bug-mh* -.RS 5 -Tells -.B repl -and -.B scan -which addresses are really yours. -In this way, -.B repl -knows which addresses should be included in the -reply, and -scan -knows if the message really originated from you. -Addresses must be separated by a comma, and the hostnames listed should -be the \*(lqofficial\*(rq hostnames for the mailboxes you indicate, as -local nicknames for hosts are not replaced with their official site names. -For each address, if a host is not given, then that address on any host is -considered to be you. In addition, an asterisk (`*') may appear at either -or both ends of the mailbox and host to indicate wild-card matching. -(profile, default: your user-id) -.RE -.PP -.BR Aliasfile : -aliases -.I other-alias -.RS 5 -Indicates aliases files for -.BR ali , -.BR whom , -and -.BR send . -This may be used instead of the -.B \-alias -.I file -switch. (profile, no default) -.RE -.PP -.BR Draft\-Folder : -drafts -.RS 5 -Indicates a default draft folder for -.BR comp , -.BR dist , -.BR forw , -and -.BR repl . -Read the -.BR mh\-draft (5) -man page for details. (profile, no default) -.RE -.PP -.BI digest\-issue\- list : -1 -.RS 5 -Tells -.B forw -the last issue of the last volume sent for the digest -.IR list . -(context, no default) -.RE -.PP -.BI digest\-volume\- list : -1 -.RS 5 -Tells -.B forw -the last volume sent for the digest -.IR list . -(context, no default) -.RE -.PP -.BR MailDrop : -\&.mail -.RS 5 -Tells -.B inc -your maildrop, if different from the default. This is -superseded by the environment variable -.BR $MAILDROP . -(profile, default: %mailspool%/$USER) -.RE -.PP -.BR Signature : -RAND MH System (agent: Marshall Rose) -.RS 5 -Tells -.B send -your mail signature. This is superseded by the -environment variable -.BR $SIGNATURE . -If -.B $SIGNATURE -is not set and this profile entry is not present, the \*(lqgcos\*(rq field of -the \fI/etc/passwd\fP file will be used; otherwise, on hosts where -.B nmh -was configured with the UCI option, the file -.I $HOME/.signature -is consulted. Your signature will be added to the address -.B send -puts in the \*(lqFrom:\*(rq header; do not include an address in the -signature text. (profile, no default) -.RE - -.SS "Process Profile Entries" -The following profile elements are used whenever an -.B nmh -program invokes some other program such as -.BR more . -The -.I \&.mh\(ruprofile -can be used to select alternate programs if the -user wishes. The default values are given in the examples. -.RE -.PP -.BR buildmimeproc : -%bindir%/mhbuild -.RS 5 -This is the program used by -.B whatnow -to process drafts which are MIME composition files. -.RE -.PP -.BR fileproc : -%bindir%/refile -.RS 5 -This program is used to refile or link a message to another folder. -It is used by -.B post -to file a copy of a message into a folder given -by a \*(lqFcc:\*(rq field. It is used by the draft folder facility in -.BR comp , -.BR dist , -.BR forw , -and -.B repl -to refile a draft -message into another folder. It is used to refile a draft message in -response to the -.B refile -directive at the \*(lqWhat now?\*(rq prompt. -.RE -.PP -.BR incproc : -%bindir%/inc -.RS 5 -Program called by -.B mhmail -to incorporate new mail when it -is invoked with no arguments. -.RE -.PP -.BR installproc : -%libdir%/install\-mh -.RS 5 -This program is called to initialize the environment for -new users of -.BR nmh . -.RE -.PP -.BR lproc : -%default_pager% -.RS 5 -This program is used to list the contents of a message in response -to the -.B list -directive at the \*(lqWhat now?\*(rq prompt. It is -also used by the draft folder facility in -.BR comp , -.BR dist , -.BR forw , -and -.B repl -to display the draft message. -.RE -.PP -.BR mailproc : -%bindir%/mhmail -.RS 5 -This is the program used to automatically mail various messages -and notifications. It is used by -.B conflict -when using the -.B \-mail -option. It is used by -.B send -to post failure notices. -It is used to retrieve an external-body with access-type `mail-server' -(such as when storing the body with -.BR mhstore ). -.RE -.PP -.BR mhlproc : -%libdir%/mhl -.RS 5 -This is the program used to filter messages in various ways. It -is used by -.B mhshow -to filter and display the message headers -of MIME messages. When the -.B \-format -or -.B \-filter -option is used -by -.B forw -or -.BR repl , -the -.I mhlproc -is used to filter the -message that you are forwarding, or to which you are replying. -When the -.B \-filter -option is given to -.B send -or -.BR post , -the -.I mhlproc -is used by -.B post -to filter the copy of the message -that is sent to \*(lqBcc:\*(rq recipients. -.RE -.PP -.BR moreproc : -%default_pager% -.RS 5 -This is the program used by -.B mhl -to page the -.B mhl -formatted message when displaying to a terminal. It is also the default -program used by -.B mhshow -to display message bodies (or message parts) of type text/plain. -.RE -.PP -.BR mshproc : -%bindir%/msh -.RS 5 -Currently not used. -.RE -.PP -.BR packproc : -%bindir%/packf -.RS 5 -Currently not used. -.RE -.PP -.BR postproc : -%libdir%/post -.RS 5 -This is the program used by -.BR send , -.BR mhmail , -.BR rcvdist , -and -.B viamail -(used by the -.B sendfiles -shell script) to -post a message to the mail transport system. It is also called by -.B whom -(called with the switches -.B \-whom -and -.BR \-library ) -to do address verification. -.RE -.PP -.BR rmmproc : -none -.RS 5 -This is the program used by -.B rmm -and -.B refile -to delete a message from a folder. -.RE -.PP -.BR rmfproc : -%bindir%/rmf -.RS 5 -Currently not used. -.RE -.PP -.BR sendproc : -%bindir%/send -.RS 5 -This is the program to use by -.B whatnow -to actually send the message -.RE -.PP -.BR showmimeproc : -%bindir%/mhshow -.RS 5 -This is the program used by -.B show -to process and display non-text (MIME) messages. -.RE -.PP -.BR showproc : -%libdir%/mhl -.RS 5 -This is the program used by -.B show -to filter and display text (non-MIME) messages. -.RE -.PP -.BR whatnowproc : -%bindir%/whatnow -.RS 5 -This is the program invoked by -.BR comp , -.BR forw , -.BR dist , -and -.B repl -to query about the disposition of a composed draft message. -.RE -.PP -.BR whomproc : -%bindir%/whom -.RS 5 -This is the program used by -.B whatnow -to determine to whom a message would be sent. -.RE - -.SS "Environment Variables" -The operation of -.B nmh -and its commands it also controlled by the -presence of certain environment variables. -.PP -Many of these environment variables are used internally by the -\*(lqWhat now?\*(rq interface. It's amazing all the information -that has to get passed via environment variables to make the -\*(lqWhat now?\*(rq interface look squeaky clean to the -.B nmh -user, isn't it? The reason for all this is that the -.B nmh -user -can select -.B any -program as the -.IR whatnowproc , -including -one of the standard shells. As a result, it's not possible to pass -information via an argument list. The convention is that environment -variables whose names are all upper-case are user-settable; those -whose names are lower-case only are used internally by nmh and should -not generally be set by the user. -.PP -If the -.B WHATNOW -option was set during -.B nmh -configuration, and -if this environment variable is set, then if the commands -.BR refile\ , -.BR send , -.BR show , -or -.B whom -are not given any `msgs' -arguments, then they will default to using the file indicated by -.BR mh\-draft (5). -This is useful for getting the default behavior -supplied by the default -.IR whatnowproc . -.PP -.B $MH -.RS 5 -With this environment variable, you can specify a profile -other than -.I \&.mh\(ruprofile -to be read by the -.B nmh -programs -that you invoke. If the value of -.B $MH -is not absolute, (i.e., does -not begin with a \*(lq/\*(rq), it will be presumed to start from the current -working directory. This is one of the very few exceptions in -.B nmh -where non-absolute pathnames are not considered relative to the user's -.B nmh -directory. -.RE -.PP -.B $MHCONTEXT -.RS 5 -With this environment variable, you can specify a -context other than the normal context file (as specified in -the -.B nmh -profile). As always, unless the value of -.B $MHCONTEXT -is absolute, it will be presumed to start from your -.B nmh -directory. -.RE -.PP -.B $MM_CHARSET -.RS 5 -With this environment variable, you can specify -the native character set you are using. You must be able to display -this character set on your terminal. -.PP -This variable is checked to see if a RFC-2047 header field should be -decoded (in -.BR inc , -.BR scan , -.BR mhl ). -This variable is -checked by -.B show -to see if the -.I showproc -or -.I showmimeproc -should -be called, since showmimeproc will be called if a text message uses -a character set that doesn't match -.BR $MM_CHARSET . -This variable is -checked by -.B mhshow -for matches against the charset parameter -of text contents to decide it the text content can be displayed -without modifications to your terminal. This variable is checked by -.B mhbuild -to decide what character set to specify in the charset -parameter of text contents containing 8\-bit characters. -.PP -When decoding text in such an alternate character set, -.B nmh -must be able to determine which characters are alphabetic, which -are control characters, etc. For many operating systems, this -will require enabling the support for locales (such as setting -the environment variable -.B $LC_CTYPE -to iso_8859_1). -.RE -.PP -.B $MAILDROP -.RS 5 -This variable tells -.B inc -the default maildrop. This supersedes the \*(lqMailDrop\*(rq profile entry. -.RE -.PP -.B $SIGNATURE -.RS 5 -This variable tells -.B send -and -.B post -your mail signature. This supersedes the \*(lqSignature\*(rq profile entry. -.RE -.PP -.B $HOME -.RS 5 -This variable tells all -.B nmh -programs your home directory -.RE -.PP -.B $SHELL -.RS 5 -This variable tells -.B bbl -the default shell to run -.RE -.PP -.B $TERM -.RS 5 -This variable tells -.B nmh -your terminal type. -.PP -The environment variable -.B $TERMCAP -is also consulted. In particular, -these tell -.B scan -and -.B mhl -how to clear your terminal, and how -many columns wide your terminal is. They also tell -.B mhl -how many -lines long your terminal screen is. -.RE -.PP -.B $editalt -.RS 5 -This is the alternate message. -.PP -This is set by -.B dist -and -.B repl -during edit sessions so you can -peruse the message being distributed or replied to. The message is also -available through a link called \*(lq@\*(rq in the current directory if -your current working directory and the folder the message lives in are -on the same UNIX filesystem. -.RE -.PP -.B $mhdraft -.RS 5 -This is the path to the working draft. -.PP -This is set by -.BR comp , -.BR dist , -.BR forw , -and -.B repl -to tell the -.I whatnowproc -which file to ask \*(lqWhat now?\*(rq -questions about. -.RE -.PP -.B $mhfolder -.RS 5 -This is set by -.BR dist , -.BR forw , -and -.BR repl , -if appropriate. -.RE -.PP -.B $mhaltmsg -.RS 5 -.B dist -and -.B repl -set -.B $mhaltmsg -to tell the -.I whatnowproc -about an alternate message associated with the -draft (the message being distributed or replied to). -.RE -.PP -.B $mhdist -.RS 5 -.B dist -sets -.B $mhdist -to tell the -.I whatnowproc -that message re-distribution is occurring. -.RE -.PP -.B $mheditor -.RS 5 -This is set by -.BR comp , -.BR repl , -.BR forw , -and -.B dist -to tell the -.I whatnowproc -the user's choice of -editor (unless overridden by -.BR \-noedit ). -.RE -.PP -.B $mhuse -.RS 5 -This may be set by -.BR comp . -.RE -.PP -.B $mhmessages -.RS 5 -This is set by -.BR dist , -.BR forw , -and -.B repl -if annotations are to occur. -.RE -.PP -.B $mhannotate -.RS 5 -This is set by -.BR dist , -.BR forw , -and -.B repl -if annotations are to occur. -.RE -.PP -.B $mhinplace -.RS 5 -This is set by -.BR dist , -.BR forw , -and -.B repl -if annotations are to occur. -.RE -.PP -.B $mhfolder -.RS 5 -This is the folder containing the alternate message. -.PP -This is set by -.B dist -and -.B repl -during edit sessions so you -can peruse other messages in the current folder besides the one being -distributed or replied to. The environment variable -.B $mhfolder -is also set by -.BR show , -.BR prev , -and -.B next -for use by -.BR mhl . -.RE - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^or $MH~^Rather than the standard profile -^/context~^The user context -^or $MHCONTEXT~^Rather than the standard context -^/\&.mh\(rusequences~^Public sequences for -.fi - -.SH "SEE ALSO" -nmh(1), environ(5), mh-sequence(5) - -.SH HISTORY -The -.I \&.mh\(ruprofile -contains only static information, which -.B nmh -programs will -.B NOT -update. Changes in context are made to the -.I context -file kept in the users -.B nmh -directory. -This includes, but is not limited to: the \*(lqCurrent\-Folder\*(rq entry -and all private sequence information. Public sequence information is -kept in each folder in the file determined by the \*(lqmh\-sequences\*(rq -profile entry (default is -.IR \&.mh\(rusequences ). -.PP -The -.I \&.mh\(ruprofile -may override the path of the -.I context -file, by specifying a \*(lqcontext\*(rq entry (this must be in -lower-case). If the entry is not absolute (does not start with a -\*(lq/\*(rq), then it is interpreted relative to the user's -.B nmh -directory. As a result, you can actually have more than one set of -private sequences by using different context files. - -.SH BUGS -The shell quoting conventions are not available in the -.IR \&.mh\(ruprofile . -Each token is separated by whitespace. -.PP -There is some question as to what kind of arguments should be placed -in the profile as options. In order to provide a clear answer, recall -command line semantics of all -.B nmh -programs: conflicting switches -(e.g. -.B \-header -and -.BR \-noheader ) -may occur more than one time on the -command line, with the last switch taking effect. Other arguments, such -as message sequences, filenames and folders, are always remembered on -the invocation line and are not superseded by following arguments of -the same type. Hence, it is safe to place only switches (and their -arguments) in the profile. -.PP -If one finds that an -.B nmh -program is being invoked again and again -with the same arguments, and those arguments aren't switches, then there -are a few possible solutions to this problem. The first is to create a -(soft) link in your -.I $HOME/bin -directory to the -.B nmh -program -of your choice. By giving this link a different name, you can create -a new entry in your profile and use an alternate set of defaults for -the -.B nmh -command. Similarly, you could create a small shell script -which called the -.B nmh -program of your choice with an alternate set -of invocation line switches (using links and an alternate profile entry -is preferable to this solution). -.PP -Finally, the -.B csh -user could create an alias for the command of the form: -.PP -.RS 5 -alias cmd 'cmd arg1 arg2 ...' -.RE -.PP -In this way, the user can avoid lengthy type-in to the shell, and still -give -.B nmh -commands safely. (Recall that some -.B nmh -commands -invoke others, and that in all cases, the profile is read, meaning that -aliases are disregarded beyond an initial command invocation) diff --git a/man/mh-profile.man5 b/man/mh-profile.man5 new file mode 100644 index 0000000..1499c06 --- /dev/null +++ b/man/mh-profile.man5 @@ -0,0 +1,796 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-PROFILE %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh-profile \- user profile customization for mmh message handler +.SH SYNOPSIS +.I $HOME/.mmh/profile +.br +.I $HOME/.mmh/context +.SH DESCRIPTION +Each user of +.B mmh +is expected to have a file named +.I $HOME/.mmh/profile +in his or her home directory. This file contains +a set of user parameters used by some or all of the +.B mmh +family of programs. Each entry in the file is of the format +.PP +.RS 5 +.IR Profile\-Component ": " value +.RE +.PP +If the text of profile entry is long, you may extend it across several +real lines by indenting the continuation lines with leading spaces or tabs. + +.SS "Standard Profile Entries" +The possible profile components are exemplified below. The only mandatory +entry is `Path:'. The others are optional; some have default values if +they are not present. In the notation used below, (profile, default) +indicates whether the information is kept in the user's +.B mmh +profile or +.B mmh +context, and indicates what the default value is. +.PP +.BR Path : +Mail +.RS 5 +Sets the user's mail storage to `Mail'. This is the +only mandatory profile entry. (profile, no default) +.RE +.PP +.BR Context : +context +.RS 5 +Declares the location of the +.B mmh +context file. This is overridden by the environment variable +.BR $MMHC . +See the +.B HISTORY +section below. +(profile, default: $HOME/.mmh/context) +.RE +.PP +.BR Current\-Folder : +inbox +.RS 5 +Keeps track of the current open folder. +(context, default: folder specified by `Inbox') +.RE +.PP +.BR Inbox : +inbox +.RS 5 +Defines the name of your default inbox. +(profile, default: inbox) +.RE +.PP +.BR Previous\-Sequence : +.I pseq +.RS 5 +Names the sequence or sequences which should be defined as the `msgs' or +`msg' argument given to any +.B mmh +command. If not present or empty, +no such sequences are defined. Otherwise, for each name given, the +sequence is first zero'd and then each message is added to the sequence. +Read the +.BR mh\-sequence (7) +man page for the details about this sequence. (profile, no default) +.RE +.PP +.BR Sequence\-Negation : +\&! +.RS 5 +Defines the string which, when prefixed to a sequence name, negates +that sequence. Hence, `!foo' means all those messages that +are not a member of the sequence `foo'. +To deactivate this mechanism, define Sequence\-Negation to an empty value. +Read the +.BR mh\-sequence (7) +man page for the details. (profile, default: !) +.RE +.PP +.BR Unseen\-Sequence : +u +.RS 5 +Names the sequence or sequences which shall contain any unread messages. +The commands +.BR inc , +.BR rcvstore , +and +.B show +will add or remove messages from these +sequences when they are incorporated or read. If defined with an empty +value, no such sequences are defined. Otherwise, each message is +added to, or removed from, each sequence name given. Read the +.BR mh\-sequence (7) +man page for the details about this sequence. +(profile, default: u) +.RE +.PP +.BR Mh\-Sequences : +\&.mh_sequences +.RS 5 +The name of the file in each folder which defines public sequences. +To disable the use of public sequences, leave the value portion of this +entry blank. (profile, default: \&.mh_sequences) +.RE +.PP +.BI atr\- seq \- folder : +172\0178\-181\0212 +.RS 5 +Keeps track of the private sequence called `seq' in the specified +folder. Private sequences are generally used for read\-only folders. +See the +.BR mh\-sequence (7) +man page for details about private sequences. +(context, no default) +.RE +.PP +.BR Editor : +vi +.RS 5 +Defines the editor to be used by the commands +.BR comp , +.BR dist , +.BR forw , +and +.BR repl . +This profile entry overrides the $VISUAL and $EDITOR environment variables, +but gets overridden by the $MMHEDITOR environment variabel. +(profile, default: vi) +.RE +.PP +.BR Pager : +more +.RS 5 +This is the program used by +.B mhl +to page the +.B mhl +formatted message when displaying to a terminal. It is also the default +program used by +.B show +to display message bodies (or message parts) of type text/plain. +This profile entry overrides the $PAGER environment variable, but gets +overridden by the $MMHPAGER environment variable. +(profile, default: more) +.RE +.PP +.BR Sendmail : +/usr/sbin/sendmail +.RS 5 +The path name to the +.B sendmail +program, used by +.BR spost +to send mail. +(profile, default: %sendmailpath%) +.RE +.PP +.BR Attachment-Header : +Attach +.RS 5 +The (pseudo) header in draft messages, that contains files to be attached +to the message on sending. +If you like to type a lot, name it `X-MH-Attachment'. +(profile, default: `Attach') +.RE +.PP +.BR Sign-Header : +Sign +.RS 5 +The (pseudo) header in draft messages, that requests the message to be +signed automatically by +.BR send , +using +.BR mhsign . +If you like to type a lot, name it `X-MH-Sign-This-Message'. +(profile, default: `Sign') +.RE +.PP +.BR Enc-Header : +Enc +.RS 5 +The (pseudo) header in draft messages, that requests the message to be +signed and encrypted by +.BR send , +using +.BR mhsign . +If you like to type a lot, name it `X-MH-Encrypt-This-Message'. +(profile, default: `Enc') +.RE +.PP +.BR Mime-Type-Query : +file \-b \-\-mime +.RS 5 +A command that prints the MIME type of a file. +The file name gets appended to the command line. +Note: Older GNU versions of file(1) won't generate the desired +output. GNU file-4.26, for instance, omits a required semicolon. +GNU file-5.04 is known to work. Non-GNU version likely need different +options or don't provide this function at all. Alternatively, you can use +.BR print\-mimetype , +which is part of mmh, but guesses MIME types by file name extensions only. +.RE +.PP +.BR Msg\-Protect : +0644 +.RS 5 +An octal number which defines the permission bits for new message files. +See +.BR chmod (1) +for an explanation of the octal number. +(profile, default: 0600) +.RE +.PP +.BR Folder\-Protect : +0750 +.RS 5 +An octal number which defines the permission bits for new folder +directories. See +.BR chmod (1) +for an explanation of the octal number. +(profile, default: 0700) +.RE +.PP +.IR program : +.I default switches +.RS 5 +Sets default switches to be used whenever the mmh program +.I program +is invoked. For example, one could override the `Editor:' profile +component when replying to messages by adding a component such as: +.PP +.RS 5 +repl: \-editor /bin/ed +.RE +.PP +(profile, no defaults) +.RE +.PP +.IB lasteditor "-next:" +.I nexteditor +.RS 5 +Names `nexteditor' to be the default editor after using +`lasteditor'. This takes effect at `What now?' prompt +in +.BR comp , +.BR dist , +.BR forw , +and +.BR repl . +After editing +the draft with `lasteditor', the default editor is set to be +`nexteditor'. If the user types `edit' without any +arguments to `What now?', then `nexteditor' is used. +(profile, no default) +.RE +.PP +.BR Folder\-Stack : +.I folders +.RS 5 +The contents of the folder-stack for the +.B folder +command. +(context, no default) +.RE +.PP +.BR Alternate\-Mailboxes : +mh@uci\-750a, bug-mh* +.RS 5 +Tells +.B repl +and +.B scan +which addresses are really yours. +In this way, +.B repl +knows which addresses should be included in the +reply, and +scan +knows if the message really originated from you. +Addresses must be separated by a comma, and the hostnames listed should +be the `official' hostnames for the mailboxes you indicate, as +local nicknames for hosts are not replaced with their official site names. +For each address, if a host is not given, then that address on any host is +considered to be you. In addition, an asterisk (`*') may appear at either +or both ends of the mailbox and host to indicate wild-card matching. +(profile, default: your user-id) +.RE +.PP +.BR Aliasfile : +aliases +.I other-alias +.RS 5 +Indicates aliases files for +.BR ali , +.BR send . +and +.BR spost . +(profile, no default) +.RE +.PP +.BR Draft\-Folder : +drafts +.RS 5 +Changes the default draft folder. Read the +.BR mh\-draft (7) +man page for details. (profile, default: +drafts) +.RE +.PP +.BR Trash\-Folder : +trash +.RS 5 +Changes the default folder for removed messages. Read the +.BR rmm (1) +man page for details. +(profile, default: +trash) +.RE +.PP +.BI digest\-issue\- list : +1 +.RS 5 +Tells +.B forw +the last issue of the last volume sent for the digest +.IR list . +(context, no default) +.RE +.PP +.BI digest\-volume\- list : +1 +.RS 5 +Tells +.B forw +the last volume sent for the digest +.IR list . +(context, no default) +.RE +.PP +.BR MailDrop : +\&.mail +.RS 5 +Tells +.B inc +your maildrop, if different from the default. This is +superseded by the environment variable +.BR $MAILDROP . +(profile, default: %mailspool%/$USER) +.RE +.PP +.BR Signature : +RAND MH System (agent: Marshall Rose) +.RS 5 +Tells +.B send +your mail signature. This is superseded by the +environment variable +.BR $SIGNATURE . +If +.B $SIGNATURE +is not set and this profile entry is not present, the `gcos' field of +the \fI/etc/passwd\fP file will be used. +Your signature will be added to the address +.B send +puts in the `From:' header; do not include an address in the +signature text. (profile, no default) +.RE + +.SS "Process Profile Entries" +The following profile elements are used whenever an +.B nmh +program invokes some other program such as +.BR more . +The profile can be used to select alternate programs if the +user wishes. The default values are given in the examples. +.RE +.PP +.BR listproc : +show \-file +.RS 5 +This program is used to list the contents of a message in response +to the +.B list +and +.B display +directive at the `What now?' prompt. +The absolute pathname of the message to list will be appended to +the command line given. +.RE +.PP +.BR whatnowproc : +%bindir%/whatnow +.RS 5 +This is the program invoked by +.BR comp , +.BR forw , +.BR dist , +and +.B repl +to query about the disposition of a composed draft message. +.RE + +.SS "Environment Variables" +The operation of +.B mmh +and its commands it also controlled by the +presence of certain environment variables. +.PP +Many of these environment variables are used internally by the +`What now?' interface. It's amazing all the information +that has to get passed via environment variables to make the +`What now?' interface look squeaky clean to the +.B mmh +user, isn't it? The reason for all this is that the +.B mmh +user +can select +.B any +program as the +.IR whatnowproc , +including +one of the standard shells. As a result, it's not possible to pass +information via an argument list. The convention is that environment +variables whose names are all upper-case are user-settable; those +whose names are lower-case only are used internally by mmh and should +not generally be set by the user. +.PP +If the +.B WHATNOW +option was set during +.B mmh +configuration, and +if this environment variable is set, then if the commands +.BR refile\ , +.BR send +or +.BR show +are not given any `msgs' +arguments, then they will default to using the file indicated by +.BR mh\-draft (7). +This is useful for getting the default behavior +supplied by the default +.IR whatnowproc . +.PP +.B $MMH +.RS 5 +With this environment variable, you can specify an alternative +mmh directory. Personal mmh configuration files are located relative to +the mmh directory. +Non-absolute values are relative to the home directory. +This is one of the very few exceptions in +.B mmh +where non-absolute pathnames are not considered relative to the user's +mmh directory. +.RE +.PP +.B $MMHP +.RS 5 +With this environment variable, you can specify a profile +other than +.I $HOME/.mmh/profile +to be read by the +.B mmh +programs +that you invoke. If the value of +.B $MMHP +is not absolute, it will be presumed to start from the mmh directory. +.RE +.PP +.B $MMHC +.RS 5 +With this environment variable, you can specify a +context other than the normal context file (as specified in +the profile). As always, unless the value of +.B $MMHC +is absolute, it will be presumed to start from your mmh directory. +.RE +.PP +.B $MM_CHARSET +.RS 5 +With this environment variable, you can specify +the native character set you are using. You must be able to display +this character set on your terminal. +.PP +This variable is checked to see if a RFC-2047 header field should be +decoded (in +.BR inc , +.BR scan , +.BR mhl ). +This variable is +checked by +.B show +to see if the +.I showproc +or +.I showmimeproc +should +be called, since showmimeproc will be called if a text message uses +a character set that doesn't match +.BR $MM_CHARSET . +This variable is +checked by +.B show +for matches against the charset parameter +of text contents to decide it the text content can be displayed +without modifications to your terminal. This variable is checked by +.B mhbuild +to decide what character set to specify in the charset +parameter of text contents containing 8\-bit characters. +.PP +When decoding text in such an alternate character set, +.B mmh +must be able to determine which characters are alphabetic, which +are control characters, etc. For many operating systems, this +will require enabling the support for locales (such as setting +the environment variable +.B $LC_CTYPE +to iso_8859_1). +.RE +.PP +.B $MAILDROP +.RS 5 +This variable tells +.B inc +the default maildrop. This supersedes the `MailDrop' profile entry. +.RE +.PP +.B $SIGNATURE +.RS 5 +This variable tells +.B send +and +.B post +your mail signature. This supersedes the `Signature' profile entry. +.RE +.PP +.B $HOME +.RS 5 +This variable tells all +.B mmh +programs your home directory +.RE +.PP +.B $SHELL +.RS 5 +This variable tells +.B bbl +the default shell to run +.RE +.PP +.B $MMHEDITOR +.br +.B $VISUAL +.br +.B $EDITOR +.RS 5 +These variables (in descending priority) define the default editor to use. +.RE +.PP +.B $MMHPAGER +.br +.B $PAGER +.RS 5 +These variables (in descending priority) define the default pager to use. +.RE +.PP +.B $TERM +.RS 5 +This variable tells +.B mmh +your terminal type. +.PP +The environment variable +.B $TERMCAP +is also consulted. In particular, +these tell +.B scan +and +.B mhl +how many columns wide your terminal is. They also tell +.B mhl +how many +lines long your terminal screen is. +.RE +.PP +.B $mhdraft +.RS 5 +This is the path to the working draft. +.PP +This is set by +.BR comp , +.BR dist , +.BR forw , +and +.B repl +to tell the +.I whatnowproc +which file to ask `What now?' +questions about. +.RE +.PP +.B $mhaltmsg +.RS 5 +.B dist +and +.B repl +set +.B $mhaltmsg +to tell the +.I whatnowproc +about an alternate message associated with the +draft (the message being distributed or replied to). +It is also set during edit sessions so you can peruse the +message being distributed or replied to. +This variable replaces the older +.B $editalt +variable. +There used to be a link named `@' in the working directory, pointing +to the alternate message, there is no such link anymore. +.RE +.PP +.B $mhdist +.RS 5 +.B dist +sets +.B $mhdist +to tell the +.I whatnowproc +that message re-distribution is occurring. +.RE +.PP +.B $mheditor +.RS 5 +This is set by +.BR comp , +.BR repl , +.BR forw , +and +.B dist +to tell the +.I whatnowproc +the user's choice of +editor (unless overridden by +.BR \-noedit ). +.RE +.PP +.B $mhuse +.RS 5 +This may be set by +.BR comp . +.RE +.PP +.B $mhmessages +.RS 5 +This is set by +.BR dist , +.BR forw , +and +.B repl +if annotations are to occur. +.RE +.PP +.B $mhannotate +.RS 5 +This is set by +.BR dist , +.BR forw , +and +.B repl +if annotations are to occur. +.RE +.PP +.B $mhfolder +.RS 5 +This is the folder containing the alternate message. +.PP +This is set by +.B dist +and +.B repl +during edit sessions so you +can peruse other messages in the current folder besides the one being +distributed or replied to. +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh~^The user's mmh directory +^or $MMH~^Rather than the standard mmh directory +^$HOME/.mmh/profile~^The user's profile +^or $MMHP~^Rather than the standard profile +^$HOME/.mmh/context~^The user's context +^or $MMHC~^Rather than the standard context +^/.mh_sequences~^Public sequences for +.fi + +.SH "SEE ALSO" +nmh(1), environ(5), mh-sequence(7) + +.SH HISTORY +The +.I $HOME/.mmh/profile +contains only static information, which +.B mmh +programs will +.B NOT +update. Changes in context are made to the +.I $HOME/.mmh/context +file. +This includes, but is not limited to: the `Current\-Folder' entry +and all private sequence information. Public sequence information is +kept in each folder in the file determined by the `Mh\-Sequences' +profile entry (default is +.IR \&.mh_sequences ). +.PP +The profile may override the path of the +.I context +file, by specifying a `Context' entry. +As a result, you can actually have more than one set of +private sequences by using different context files. + +.SH BUGS +The shell quoting conventions are not available in the profile. +Each token is separated by whitespace. +.PP +There is some question as to what kind of arguments should be placed +in the profile as options. In order to provide a clear answer, recall +command line semantics of all +.B mmh +programs: conflicting switches +(e.g. +.B \-header +and +.BR \-noheader ) +may occur more than one time on the +command line, with the last switch taking effect. Other arguments, such +as message sequences, filenames and folders, are always remembered on +the invocation line and are not superseded by following arguments of +the same type. Hence, it is safe to place only switches (and their +arguments) in the profile. +.PP +If one finds that an +.B mmh +program is being invoked again and again +with the same arguments, and those arguments aren't switches, then there +are a few possible solutions to this problem. The first is to create a +(soft) link in your +.I $HOME/bin +directory to the +.B mmh +program +of your choice. By giving this link a different name, you can create +a new entry in your profile and use an alternate set of defaults for +the +.B mmh +command. Similarly, you could create a small shell script +which called the +.B mmh +program of your choice with an alternate set +of invocation line switches (using links and an alternate profile entry +is preferable to this solution). +.PP +Finally, the +.B csh +user could create an alias for the command of the form: +.PP +.RS 5 +alias cmd 'cmd arg1 arg2 ...' +.RE +.PP +In this way, the user can avoid lengthy type-in to the shell, and still +give +.B mmh +commands safely. (Recall that some +.B mmh +commands +invoke others, and that in all cases, the profile is read, meaning that +aliases are disregarded beyond an initial command invocation) diff --git a/man/mh-sequence.man b/man/mh-sequence.man deleted file mode 100644 index 12fdb1c..0000000 --- a/man/mh-sequence.man +++ /dev/null @@ -1,287 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MH-SEQUENCE %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mh-sequence \- sequence specification for nmh message system -.SH SYNOPSIS -most -.B nmh -commands -.SH DESCRIPTION -A sequence (or sequence set) is a symbolic name representing a -message or collection of messages. -.B nmh -has several internally -defined sequences, as well as allowing users to define their own -sequences. - -.SS "Message Specification and Pre\-Defined Message Sequences" -Most -.B nmh -commands accept a `msg' or `msgs' specification, where -`msg' indicates one message and `msgs' indicates one or more messages. -To designate a message, you may use either its number (e.g., 1, 10, 234) -or one of these \*(lqreserved\*(rq message names: -.PP -.RS 5 -.nf -.ta +\w'\fIName\fP 'u -.I Name Description -first the first message in the folder -last the last message in the folder -cur the most recently accessed message -prev the message numerically preceding \*(lqcur\*(rq -next the message numerically following \*(lqcur\*(rq -.fi -.RE -.PP -In commands that take a `msg' argument, the default is \*(lqcur\*(rq. -As a shorthand, \*(lq\&.\*(rq is equivalent to \*(lqcur\*(rq. -.PP -For example: In a folder containing five messages numbered 5, 10, 94, 177 -and 325, \*(lqfirst\*(rq is 5 and \*(lqlast\*(rq is 325. If \*(lqcur\*(rq -is 94, then \*(lqprev\*(rq is 10 and \*(lqnext\*(rq is 177. -.PP -The word `msgs' indicates that one or more messages may be specified. -Such a specification consists of one message designation or of several -message designations separated by spaces. A message designation consists -either of a message name as defined above, or a message range. -.PP -A message range is specified as \*(lqname1\-name2\*(rq or -\*(lqname:n\*(rq, where `name', `name1' and `name2' are message names, -and `n' is an integer. -.PP -The specification \*(lqname1\-name2\*(rq designates all currently existing -messages from `name1' to `name2' inclusive. The \*(lqreserved\*(rq -message name \*(lqall\*(rq is a shorthand for the message range -\*(lqfirst\-last\*(rq. -.PP -The specification \*(lqname:n\*(rq designates up to `n' messages. -These messages start with `name' if `name' is a message number or one of -the reserved names \*(lqfirst\*(rq \*(lqcur\*(rq, or \*(lqnext\*(rq, The -messages end with `name' if `name' is \*(lqprev\*(rq or \*(lqlast\*(rq. -The interpretation of `n' may be overridden by preceding `n' with a -plus or minus sign; `+n' always means up to `n' messages starting with -`name', and `\-n' always means up to `n' messages ending with `name'. -.PP -In commands which accept a `msgs' argument, the default is either -\*(lqcur\*(rq or \*(lqall\*(rq, depending on which makes more sense -for each command (see the individual man pages for details). Repeated -specifications of the same message have the same effect as a single -specification of the message. -.PP -There is also a special \*(lqreserved\*(rq message name \*(lqnew\*(rq -which is used by the -.B mhpath -command. - -.SS "User\-Defined Message Sequences" -In addition to the \*(lqreserved\*(rq (pre-defined) message names given -above, -.B nmh -supports user-defined sequence names. User-defined -sequences allow the -.B nmh -user a tremendous amount of power in dealing -with groups of messages in the same folder by allowing the user to bind -a group of messages to a meaningful symbolic name. -.PP -The name used to denote a message sequence must consist of an alphabetic -character followed by zero or more alphanumeric characters, and can not -be one of the \*(lqreserved\*(rq message names above. After defining a -sequence, it can be used wherever an -.B nmh -command expects a `msg' or -`msgs' argument. -.PP -Some forms of message ranges are allowed with user-defined sequences. -The specification \*(lqname:n\*(rq may be used, and it designates up -to the first `n' messages (or last `n' messages for `\-n') which are -elements of the user-defined sequence `name'. -.PP -The specifications \*(lqname:next\*(rq and \*(lqname:prev\*(rq may also -be used, and they designate the next or previous message (relative to the -current message) which is an element of the user-defined sequence `name'. -The specifications \*(lqname:first\*(rq and \*(lqname:last\*(rq are -equivalent to \*(lqname:1\*(rq and \*(lqname:\-1\*(rq, respectively. The -specification \*(lqname:cur\*(rq is not allowed (use just \*(lqcur\*(rq -instead). The syntax of these message range specifications is subject -to change in the future. -.PP -User-defined sequence names are specific to each folder. They are -defined using the -.B pick -and -.B mark -commands. -.PP -.SS "Public and Private User-Defined Sequences" -There are two varieties of user-defined sequences: -public and private. Public sequences of a folder are accessible to any -.B nmh -user that can read that folder. They are kept in each folder -in the file determined by the \*(lqmh\-sequences\*(rq profile entry -(default is -.IR \&.mh\(rusequences ). -Private sequences are accessible -only to the -.B nmh -user that defined those sequences and are kept in -the user's -.B nmh -context file. -.PP -In general, the commands that create sequences (such as -.B pick -and -.BR mark ) -will create public sequences if the folder for which -the sequences are being defined is writable by the -.B nmh -user. -For most commands, this can be overridden by using the switches -.B \-public -and -.BR \-private . -But if the folder is read\-only, or if -the \*(lqmh\-sequences\*(rq profile entry is defined but empty, then -\fIprivate\fR sequences will be created instead. - -.SS "Sequence Negation" -.B Nmh -provides the ability to select all messages not elements of a -user-defined sequence. To do this, the user should define the entry -\*(lqSequence\-Negation\*(rq in the -.B nmh -profile file; its value -may be any string. This string is then used to preface an existing -user-defined sequence name. This specification then refers to those -messages not elements of the specified sequence name. For example, if -the profile entry is: -.PP -.RS 5 -Sequence\-Negation: not -.RE -.PP -then anytime an -.B nmh -command is given \*(lqnotfoo\*(rq as a `msg' or -`msgs' argument, it would substitute all messages that are not elements -of the sequence \*(lqfoo\*(rq. -.PP -Obviously, the user should beware of defining sequences with names that -begin with the value of the \*(lqSequence\-Negation\*(rq profile entry. - -.SS "The Previous Sequence" -.B Nmh -provides the ability to remember the `msgs' or `msg' argument -last given to an -.B nmh -command. The entry \*(lqPrevious\-Sequence\*(rq -should be defined in the -.B nmh -profile; its value should be a sequence -name or multiple sequence names separated by spaces. If this entry -is defined, when when an -.B nmh -command finishes, it will define the -sequence(s) named in the value of this entry to be those messages that -were specified to the command. Hence, a profile entry of -.PP -.RS 5 -Previous\-Sequence: pseq -.RE -.PP -directs any -.B nmh -command that accepts a `msg' or `msgs' argument to -define the sequence \*(lqpseq\*(rq as those messages when it finishes. -.PP -.BR Note : -there can be a performance penalty in using the -\*(lqPrevious\-Sequence\*(rq facility. If it is used, -.B all -.B nmh -programs have to write the sequence information to the -.I \&.mh\(rusequences -file for the folder each time they run. If the -\*(lqPrevious\-Sequence\*(rq profile entry is not included, only -.B pick -and -.B mark -will write to the -.B \&.mh\(rusequences -file. - -.SS "The Unseen Sequence" -Finally, many users like to indicate which messages have not been -previously seen by them. The commands -.BR inc , -.BR rcvstore , -.BR show , -.BR mhshow , -and -.B flist -honor the profile entry -\*(lqUnseen\-Sequence\*(rq to support this activity. This entry -in the -.I \&.mh\(ruprofile -should be defined as one or more sequence -names separated by spaces. If there is a value for -\*(lqUnseen\-Sequence\*(rq in the profile, then whenever new messages -are placed in a folder (using -.B inc -or -.BR rcvstore ), -the new messages will also be added to all the sequences named in this -profile entry. For example, a profile entry of -.PP -.RS 5 -Unseen\-Sequence: unseen -.RE -.PP -directs -.B inc -to add new messages to the sequence \*(lqunseen\*(rq. -Unlike the behavior of the \*(lqPrevious\-Sequence\*(rq entry in the -profile, however, the sequence(s) will -.B not -be zeroed by -.BR inc . -.PP -Similarly, whenever -.BR show , -.BR mhshow , -.BR next , -or -.B prev -displays a message, that message will be removed from -any sequences named by the \*(lqUnseen\-Sequence\*(rq entry in the -profile. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^/context~^The user context -^/\&.mh\(rusequences~^File for public sequences -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^mh-sequences:~^Name of file to store public sequences -^Sequence\-Negation:~^To designate messages not in a sequence -^Previous\-Sequence:~^The last message specification given -^Unseen\-Sequence:~^Those messages not yet seen by the user -.fi - -.SH "SEE ALSO" -flist(1), mark(1), pick(1), mh-profile(5) - -.SH DEFAULTS -None diff --git a/man/mh-sequence.man7 b/man/mh-sequence.man7 new file mode 100644 index 0000000..60568ed --- /dev/null +++ b/man/mh-sequence.man7 @@ -0,0 +1,296 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-SEQUENCE %manext7% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh-sequence \- sequence specification for nmh message system +.SH SYNOPSIS +most +.B nmh +commands +.SH DESCRIPTION +A sequence (or sequence set) is a symbolic name representing a +message or collection of messages. +.B nmh +has several internally +defined sequences, as well as allowing users to define their own +sequences. + +.SS "Message Specification and Pre\-Defined Message Sequences" +Most +.B nmh +commands accept a `msg' or `msgs' specification, where +`msg' indicates one message and `msgs' indicates one or more messages. +To designate a message, you may use either its number (e.g., 1, 10, 234) +or one of these `reserved' message names: +.PP +.RS 5 +.nf +.ta +\w'\fIName\fP 'u +.I "Name Description +first the first message in the folder +last the last message in the folder +cur the most recently accessed message +prev the message numerically preceding `cur' +next the message numerically following `cur' +.fi +.RE +.PP +In commands that take a `msg' argument, the default is `cur'. +As a shorthand, `\&.' is equivalent to `cur'. +.PP +For example: In a folder containing five messages numbered 5, 10, 94, 177 +and 325, `first' is 5 and `last' is 325. If `cur' +is 94, then `prev' is 10 and `next' is 177. +.PP +The word `msgs' indicates that one or more messages may be specified. +Such a specification consists of one message designation or of several +message designations separated by spaces. A message designation consists +either of a message name as defined above, or a message range. +.PP +A message range is specified as `name1\-name2' or +`name:n', where `name', `name1' and `name2' are message names, +and `n' is an integer. +.PP +The specification `name1\-name2' designates all currently existing +messages from `name1' to `name2' inclusive. The `reserved' +message name `all' is a shorthand for the message range +`first\-last'. +.PP +The specification `name:n' designates up to `n' messages. +These messages start with `name' if `name' is a message number or one of +the reserved names `first' `cur', or `next', The +messages end with `name' if `name' is `prev' or `last'. +The interpretation of `n' may be overridden by preceding `n' with a +plus or minus sign; `+n' always means up to `n' messages starting with +`name', and `\-n' always means up to `n' messages ending with `name'. +.PP +In commands which accept a `msgs' argument, the default is either +`cur' or `all', depending on which makes more sense +for each command (see the individual man pages for details). Repeated +specifications of the same message have the same effect as a single +specification of the message. +.PP +There is also a special `reserved' message name `new' +which is used by the +.B mhpath +command. + +.SS "User\-Defined Message Sequences" +In addition to the `reserved' (pre-defined) message names given +above, +.B nmh +supports user-defined sequence names. User-defined +sequences allow the +.B nmh +user a tremendous amount of power in dealing +with groups of messages in the same folder by allowing the user to bind +a group of messages to a meaningful symbolic name. +.PP +The name used to denote a message sequence must consist of an alphabetic +character followed by zero or more alphanumeric characters, and can not +be one of the `reserved' message names above. After defining a +sequence, it can be used wherever an +.B nmh +command expects a `msg' or +`msgs' argument. +.PP +Some forms of message ranges are allowed with user-defined sequences. +The specification `name:n' may be used, and it designates up +to the first `n' messages (or last `n' messages for `\-n') which are +elements of the user-defined sequence `name'. +.PP +The specifications `name:next' and `name:prev' may also +be used, and they designate the next or previous message (relative to the +current message) which is an element of the user-defined sequence `name'. +The specifications `name:first' and `name:last' are +equivalent to `name:1' and `name:\-1', respectively. The +specification `name:cur' is not allowed (use just `cur' +instead). The syntax of these message range specifications is subject +to change in the future. +.PP +User-defined sequence names are specific to each folder. They are +defined using the +.B pick +and +.B mark +commands. +.PP +.SS "Public and Private User-Defined Sequences" +There are two varieties of user-defined sequences: +public and private. Public sequences of a folder are accessible to any +.B nmh +user that can read that folder. They are kept in each folder +in the file determined by the `Mh\-Sequences' profile entry +(default is +.IR \&.mh_sequences ). +Private sequences are accessible +only to the +.B nmh +user that defined those sequences and are kept in +the user's +.B nmh +context file. +.PP +In general, the commands that create sequences (such as +.B pick +and +.BR mark ) +will create public sequences if the folder for which +the sequences are being defined is writable by the +.B nmh +user. +For most commands, this can be overridden by using the switches +.B \-public +and +.BR \-private . +But if the folder is read\-only, or if +the `Mh\-Sequences' profile entry is defined but empty, then +\fIprivate\fR sequences will be created instead. + +.SS "Sequence Negation" +.B Nmh +provides the ability to select all messages +.B not +elements of a user-defined sequence. +A special string is used to preface an existing user-defined +sequence name. This specification then refers to those +messages not elements of the specified sequence name. +The default negation prefix is the exlamation mark `!', +but it may be change to any string, by defining the entry +`Sequence\-Negation' in the +.B nmh +profile file. +For example, if the profile entry is: +.PP +.RS 5 +Sequence\-Negation: not +.RE +.PP +then anytime an +.B nmh +command is given `notfoo' as a `msg' or +`msgs' argument, it would substitute all messages that are not elements +of the sequence `foo'. +.PP +Obviously, the user should beware of defining sequences with names that +begin with the value of the `Sequence\-Negation' profile entry. +The default value `!' was chosen due to its similar meaning in the C +programming language, and because it cannot be part of a user-defined +sequence. But if your shell provides history expansion, +you might need to quote the exlamation mark (prefix it with a backslash). +.PP +To deactivate the negation mechanism, define Sequence\-Negation in your +profile to an empty value. + +.SS "The Previous Sequence" +.B Nmh +provides the ability to remember the `msgs' or `msg' argument +last given to an +.B nmh +command. The entry `Previous\-Sequence' +should be defined in the +.B nmh +profile; its value should be a sequence +name or multiple sequence names separated by spaces. If this entry +is defined, when an +.B nmh +command finishes, it will define the +sequence(s) named in the value of this entry to be those messages that +were specified to the command. Hence, a profile entry of +.PP +.RS 5 +Previous\-Sequence: pseq +.RE +.PP +directs any +.B nmh +command that accepts a `msg' or `msgs' argument to +define the sequence `pseq' as those messages when it finishes. +.PP +.BR Note : +there can be a performance penalty in using the +`Previous\-Sequence' facility. If it is used, +.B all +.B nmh +programs have to write the sequence information to the +.I \&.mh_sequences +file for the folder each time they run. If the +`Previous\-Sequence' profile entry is not included, only +.B pick +and +.B mark +will write to the +.B \&.mh_sequences +file. + +.SS "The Unseen Sequence" +Finally, the unseen sequence indicates which messages have not been +previously seen by the user. +The commands +.BR inc , +.BR rcvstore , +.BR show , +and +.B flist +honor the sequence. +Whenever new messages are placed in a folder (using +.B inc +or +.BR rcvstore ), +the new messages will also be added to the unseen sequence. +.RE +.PP +.BR inc , +for example, +adds new messages to the unseen sequence. +Unlike the behavior of the previous sequence, however, +the unseen sequence will +.B not +be zeroed by +.BR inc . +.PP +Similarly, whenever +.BR show , +.BR next , +or +.B prev +display a message, that message will be removed from +the unseen sequence. +.PP +The default unseen sequence is named `u'. +To change, define a `Unseen\-Sequence' entry in your profile. +It may also contain multiple sequence names, separated by spaces. +In this case, anything that applied to a single unseen sequence, +applies to multiple ones, too. +.PP +The unseen sequence mechanism is automatically activated. +To deactivate it, define the `Unseen\-Sequence' entry +in your profile with an empty value. + + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^$HOME/.mmh/context~^The user context +^/\&.mh_sequences~^File for public sequences +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Mh-Sequences:~^Name of file to store public sequences +^Sequence\-Negation:~^To designate messages not in a sequence +^Previous\-Sequence:~^The last message specification given +^Unseen\-Sequence:~^Those messages not yet seen by the user +.fi + +.SH "SEE ALSO" +flist(1), mark(1), pick(1), mh-profile(5) + +.SH DEFAULTS +None diff --git a/man/mh-tailor.man b/man/mh-tailor.man deleted file mode 100644 index 15704ee..0000000 --- a/man/mh-tailor.man +++ /dev/null @@ -1,416 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MH-TAILOR %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mh-tailor, mts.conf \- mail transport customization for nmh message handler -.SH SYNOPSIS -.I %etcdir%/mts.conf -.SH DESCRIPTION -The file -.I %etcdir%/mts.conf -defines run-time options for those -.B nmh -programs which interact (in some form) with the message transport system. -At present, these (user) programs are: -.BR ap , -.BR conflict , -.BR inc , -.BR msgchk , -.BR msh , -.BR post , -.BR rcvdist , -and -.BR rcvpack . -.PP -Each option should be given on a single line. Blank lines and lines -which begin with `#' are ignored. The options available along with -default values and a description of their meanings are listed below: -.PP -.BR mts : -.RS 5 -The mail transport method to use. The two acceptable options are -.B smtp -(which is the default), and -.BR sendmail . -.PP -If you use -.BR smtp , -this will enable a direct SMTP (simple mail transport -protocol) interface in -.BR nmh . -When sending mail, instead of passing the -message to the mail transport agent, -.B post -will open a socket connection -to the mail port on the machine specified in the -.B servers -entry. -.PP -If you use -.BR sendmail , -then -.B post -will send messages by forking a -local copy of -.BR sendmail . -Currently it will still speak SMTP with this local -copy of -.BR sendmail . -.RE -.PP -.BR localname : -.RS 5 -The hostname -.B nmh -considers local. It should typically be a fully -qualified hostname. If this is not set, depending on the version of -UNIX you're running, -.B nmh -will query the system for this value -(e.g. uname, gethostname, etc.), and attempt to fully qualify this -value. -.PP -If you are using POP to retrieve new messages, you may want to set this -value to the name of the POP server, so that outgoing message appear to -have originated on the POP server. -.RE -.PP -.BR localdomain : -.RS 5 -If this is set, a `.' followed by this string will be appended to your -hostname. -.PP -This should only be needed, if for some reason -.B nmh -is not able to -fully qualify the hostname returned by the system (e.g. uname, -gethostname, etc.). -.RE -.PP -.BR clientname : -.RS 5 -This option specifies the host name that -.B nmh -will give in the -SMTP -.B HELO -(and -.BR EHLO ) -command, when posting mail. If not -set, the default is to use the host name that -.B nmh -considers local -(see -.B localname -above). If this option is set, but empty, no -.B HELO -command will be given. -.PP -Although the -/B HELO -command is required by RFC\-821, many SMTP servers -do not require it. Early versions of -.I SendMail -will fail if the hostname -given in the -.B HELO -command is the local host. Later versions of -.I SendMail -will complain if you omit the -.B HELO -command. If you run -.IR SendMail , -find out what your system expects and set this field if needed. -.RE -.PP -.BR systemname : -.RS 5 -This option is only used for UUCP mail. It specifies the name of the -local host in the UUCP \*(lqdomain\*(rq. If not set, depending -on the version of UNIX you're running, -.B nmh -will query the system -for this value. This has no equivalent in the -.B nmh -configuration -file. -.RE -.PP -.BR mmdfldir : -%mailspool% -.RS 5 -The directory where maildrops are kept. If this option is set, but empty, -the user's home directory is used. This overrides the default value -chosen at the time of compilation. -.RE -.PP -.BR mmdflfil : -.RS 5 -The name of the maildrop file in the directory where maildrops are kept. -If this is empty, the user's login name is used. This overrides the default -value (which is empty). -.RE -.PP -.BR mmdelim1 : -\&\\001\\001\\001\\001\\n -.RS 5 -The beginning-of-message delimiter for maildrops. -.RE -.PP -.BR mmdelim2 : -\&\\001\\001\\001\\001\\n -.RS 5 -The end-of-message delimiter for maildrops. -.RE -.PP -.BR masquerade: -.RS 5 -This directive controls three different types of email address masquerading. -The three possible values, which may be specified in any combination on the -line, separated by spaces, are \*(lqdraft_from\*(rq, \*(lqmmailid\*(rq, and -\*(lqusername_extension\*(rq. -.PP -\*(lqmmailid\*(rq was the only type of masquerading in the original MH package, and -apparently stands for \*(lqmasquerade mail identification\*(rq. This type of -masquerading keys off of the GECOS field of the passwd file. When enabled, -.B nmh -will check if the user's pw_gecos field in the passwd file is of the -form: -.PP -.RS 5 -Full Name -.RE -.PP -If it is, the internal -.B nmh -routines that find the username and full name -of that user will return \*(lqfakeusername\*(rq and \*(lqFull Name\*(rq respectively. This is -useful if you want the messages you send to always appear to come from the name -of an MTA alias rather than your actual account name. For instance, many -organizations set up \*(lqFirst.Last\*(rq sendmail aliases for all users. If this is -the case, the GECOS field for each user should look like: -.PP -.RS 5 -First [Middle] Last -.RE -.PP -\*(lqusername_extension\*(rq, when specified on the \*(lqmasquerade:\*(rq line, allows a second -type of username masquerading. If the user sets the -.B $USERNAME_EXTENSION -environment variable, its value will be appended to the actual login name. For -instance, if I am \*(lqdan@company.com\*(rq, and I set -.B $USERNAME_EXTENSION -to \*(lq\-www\*(rq, my mail will appear to come from \*(lqdan\-www@company.com\*(rq. This is meant -to interact with qmail's \*(lquser\-extension\*(rq feature, where mail sent to -.IR user \- string -will be delivered to -.IR user . -Likewise, those using -versions of sendmail for which \*(lqplussed user\*(rq processing is active can set -.B $USERNAME_EXTENSION -to \*(lq+\fIstring\fR\*(rq. These MTA features are useful -because they allow one to use different email addresses in different situations -(to aid in automatic mail filtering or in determining where spammers got one's -address) while only actually having a single account. Note that -.B $USERNAME_EXTENSION -is only appended to the username when \fIpost\fR is -generating \*(lq[Resent\-]From:\*(rq lines and the SMTP envelope -\*(lqFrom:\*(rq. -.BR inc , -for instance, will not try to read from a maildrop file called \*(lqdan\-www\*(rq (to -recall the earlier example). -.PP -\*(lqdraft_from\*(rq controls the most powerful type of address masquerading. Normally, -when a user explicitly specifies a \*(lqFrom:\*(rq header in a draft, -.B nmh -uses it -rather than constructing its own. However, to discourage email forgery, the -SMTP envelope \*(lqFrom:\*(rq and a \*(lqSender:\*(rq header are set to the user's real address. -When \*(lqdraft_from\*(rq is turned on, though, the envelope \*(lqFrom:\*(rq will use the -address specified in the draft, and there will be no \*(lqSender:\*(rq header. This is -useful when a user wants to pretend to be sending mail \*(lqdirectly\*(rq from a remote -POP3 account, or when remote mail robots incorrectly use the envelope \*(lqFrom:\*(rq in -preference to the body \*(lqFrom:\*(rq (or refuse to take action when the two don't -match). Note that the MTA may still reveal the user's real identity (e.g. -.BR sendmail 's -\*(lqX\-Authentication\-Warning:\*(rq header). -.RE -.PP -.BR maildelivery : -%libdir%/maildelivery -.RS 5 -The name of the system-wide default -.I maildelivery -file. -See -.BR slocal (1) -for the details. -.RE -.PP -.BR everyone : -200 -.RS 5 -The highest user-id which should NOT receive mail addressed to -\*(lqeveryone\*(rq. -.RE -.PP -.BR noshell : -.RS 5 -If set, then each user-id greater than \*(lqeveryone\*(rq that has a -login shell equivalent to the given value (e.g., \*(lq/bin/csh\*(rq) -indicates that mail for \*(lqeveryone\*(rq should not be sent to them. -This is useful for handling admin, dummy, and guest logins. -.RE -.SS "SMTP support" -These options are only available if you set -.B mts -to -.BR smtp . -.PP -.BR hostable : -%etcdir%/hosts -.RS 5 -The exceptions file for /etc/hosts used by -.B post -to try to find -official names. The format of this file is quite simple: -.PP -.IP 1. 4 -Comments are surrounded by sharp (`#') and newline. -.IP 2. 4 -Words are surrounded by white space. -.IP 3. 4 -The first word on the line is the official name of a host. -.IP 4. 4 -All words following the official names are aliases for that host. -.RE -.PP -.BR servers : -localhost -.RS 5 -A lists of hosts and networks which to look for SMTP servers when -posting local mail. It turns out this is a major win for hosts which -don't run an message transport system. The value of -.B servers -should be one or more items. Each item is the name of a host which -is (hopefully) running a SMTP server. -.SS "SendMail" -This option is only available if you set -.B mts -to -.BR sendmail . -.PP -.BR sendmail : -%sendmailpath% -.RS 5 -The pathname to the -.B sendmail -program. -.RE -.SS "Post Office Protocol" -This option is only available if you have compiled -.B nmh -with POP support enabled (i.e., \*(lq--enable-pop\*(rq). -.PP -.BR pophost : -.RS 5 -The name of the default POP service host. If this is not set, then -.B nmh -looks in the standard maildrop areas for waiting mail, otherwise -the named POP service host is consulted. -.RE -\" .SS "BBoards Delivery" -\" This option is only available if you compiled \fInmh\fP with -\" \*(lqbbdelivery:\ on\*(rq. -\" .PP -\" .BR bbdomain : -\" .RS 5 -\" The local BBoards domain (a UCI hack). -\" .RE - -\" .SS "BBoards & The POP" -\" These options are only available if you compiled \fInmh\fP with -\" \*(lqbboards:\ pop\*(rq and \*(lqpop:\ on\*(rq. - -\" .PP -\" .BR popbbhost : -\" .RS 5 -\" The POP service host which also acts as a BBoard server. This variable -\" should be set on the POP BBoards client host. -\" .RE -\" .PP -\" .BR popbbuser : -\" .RS 5 -\" The guest account on the POP/BB service host. This should be a different -\" login ID than either the POP user or the BBoards user. (The user-id -\" \*(lqftp\*(rq is highly recommended.) This variable should be set on -\" both the POP BBoards client and service hosts. -\" .RE -\" .PP -\" .BR popbblist : -\" %etcdir%/hosts.popbb -\" .RS 5 -\" A file containing of lists of hosts that are allowed to use the POP -\" facility to access BBoards using the guest account. If this file is not -\" present, then no check is made. This variable should be set on the POP -\" BBoards service host. -\" .RE - -.SS "File Locking" -A few words on locking: -.B nmh -has several methods for creating locks -on files. When configuring -.BR nmh , -you will need to decide on the -locking style and locking directory (if any). The first controls the -method of locking, the second says where lock files should be created. -.PP -To configure -.B nmh -for kernel locking, use the \*(lq--with-locking=flock\*(rq configure option if -you want to use the -.B flock -system call; use \*(lq--with-locking=lockf\*(rq if -you want to use the -.B lockf -system call; or use \*(lq--with-locking=fcntl\*(rq -if you want to use the -.B fcntl -system call for kernel-level locking. -.PP -Instead of kernel locking, you can configure -.B nmh -to use dot locking by using \*(lq--with-locking=dot\*(rq. Dot locking -specifies that -a file should be created whose existence means \*(lqlocked\*(rq and -whose non-existence means \*(lqunlocked\*(rq. The name of this file is -constructed by appending \*(lq.lock\*(rq to the name of the file being -locked. If -.B LOCKDIR -is not specified, lock files will be created -in the directory where the file being locked resides. Otherwise, lock -files will be created in the directory specified by -.BR LOCKDIR . -.PP -Prior to installing -.BR nmh , -you should see how locking is done at -your site, and set the appropriate values. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -.fi - -.SH "PROFILE COMPONENTS" -None - -.SH "SEE ALSO" -mh\-mts(8), post(8) - -.SH DEFAULTS -As listed above diff --git a/man/mh-tailor.man5 b/man/mh-tailor.man5 new file mode 100644 index 0000000..097242b --- /dev/null +++ b/man/mh-tailor.man5 @@ -0,0 +1,64 @@ +.\" +.\" %nmhwarning% +.\" +.TH MH-TAILOR %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mh\-tailor \- obsolete man page +.SH DESCRIPTION +.B "This man page is in transition state. +.B "It's original use is gone. +.B "Eventually it will be removed. +.B "Until then, it contains information that have no better place yet. +.SS "Spost's handling of From: headers +.B spost +will send messages by forking a +local copy of +.BR sendmail . +.PP +When a user explicitly specifies a `From:' header in a draft, +.B nmh +uses it +rather than constructing its own. However, to discourage email forgery, the +SMTP envelope `From:' and a `Sender:' header are set to the user's real address. +.RE +.SS "File Locking" +A few words on locking: +.B nmh +has several methods for creating locks +on files. When configuring +.BR nmh , +you will need to decide on the +locking style and locking directory (if any). The first controls the +method of locking, the second says where lock files should be created. +.PP +To configure +.B nmh +for kernel locking, use the `--with-locking=flock' configure option if +you want to use the +.B flock +system call; use `--with-locking=lockf' if +you want to use the +.B lockf +system call; or use `--with-locking=fcntl' +if you want to use the +.B fcntl +system call for kernel-level locking. +.PP +Instead of kernel locking, you can configure +.B nmh +to use dot locking by using `--with-locking=dot'. Dot locking +specifies that +a file should be created whose existence means `locked' and +whose non-existence means `unlocked'. The name of this file is +constructed by appending `.lock' to the name of the file being +locked. If +.B LOCKDIR +is not specified, lock files will be created +in the directory where the file being locked resides. Otherwise, lock +files will be created in the directory specified by +.BR LOCKDIR . +.PP +Prior to installing +.BR nmh , +you should see how locking is done at +your site, and set the appropriate values. diff --git a/man/mhbuild.man b/man/mhbuild.man deleted file mode 100644 index b0af881..0000000 --- a/man/mhbuild.man +++ /dev/null @@ -1,688 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHBUILD %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhbuild \- translate MIME composition draft -.SH SYNOPSIS -.na -.HP 5 -.B mhbuild -.I file -.RB [ \-list " | " \-nolist ] -.RB [ \-realsize " | " \-norealsize ] -.RB [ \-headers " | " \-noheaders ] -.RB [ \-ebcdicsafe " | " \-noebcdicsafe ] -.RB [ \-rfc934mode " | " \-norfc934mode ] -.RB [ \-contentid " | " \-nocontentid ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B mhbuild -command will translate a MIME composition draft into -a valid MIME message. -.PP -.B mhbuild -creates multi-media messages as specified in RFC\-2045 -thru RFC\-2049. Currently -.B mhbuild -only supports encodings in -message bodies, and does not support the encoding of message headers as -specified in RFC\-2047. -.PP -If you specify the name of the composition file as \*(lq-\*(rq, -then -.B mhbuild -will accept the composition draft on the standard -input. If the translation of this input is successful, -.B mhbuild -will output the new MIME message to the standard output. This argument -must be the last argument on the command line. -.PP -Otherwise if the file argument to -.B mhbuild -is the name of a valid -composition file, and the translation is successful, -.B mhbuild -will replace the original file with the new MIME message. It will rename -the original file to start with the \*(lq,\*(rq character and end with the -string \*(lq.orig\*(rq, e.g., if you are editing the file \*(lqdraft\*(rq, -it will be renamed to \*(lq,draft.orig\*(rq. This allows you to easily -recover the -.B mhbuild -input file. -.SS "Listing the Contents" -The -.B \-list -switch tells -.B mhbuild -to list the table of contents associated with the MIME message that is created. -.PP -The -.B \-headers -switch indicates -that a one-line banner should be displayed above the listing. The -.B \-realsize -switch tells -.B mhbuild -to evaluate the \*(lqnative\*(rq -(decoded) format of each content prior to listing. This provides an -accurate count at the expense of a small delay. If the -.B \-verbose -switch -is present, then the listing will show any \*(lqextra\*(rq information -that is present in the message, such as comments in the -\*(lqContent-Type\*(rq header. -.SS "Translating the Composition File" -.B mhbuild -is essentially a filter to aid in the composition of MIME -messages. -.B mhbuild -will convert an -.B mhbuild -\*(lqcomposition file\*(rq -into a valid MIME message. A -.B mhbuild -\*(lqcomposition file\*(rq -is just a file containing plain text that is interspersed -with various -.B mhbuild -directives. When this file is processed -by -.BR mhbuild , -the various directives will be expanded to the -appropriate content, and will be encoded according to the MIME standards. -The resulting MIME message can then be sent by electronic mail. -.PP -The formal syntax for a -.B mhbuild -composition file is defined at the -end of this document, but the ideas behind this format are not complex. -Basically, the body contains one or more contents. A content consists of -either a directive, indicated with a \*(lq#\*(rq as the first character -of a line; or, plaintext (one or more lines of text). The continuation -character, \*(lq\\\*(lq, may be used to enter a single directive on more -than one line, e.g., -.PP -.RS 5 -.nf -#image/png \\ - /home/foobar/junk/picture.png -.fi -.RE -.PP -There are four kinds of directives: \*(lqtype\*(rq directives, which -name the type and subtype of the content; \*(lqexternal-type\*(rq -directives, which also name the type and subtype of the content; the -\*(lqmessage\*(rq directive (#forw), which is used to forward one or -more messages; and, the \*(lqbegin\*(rq directive (#begin), which is -used to create a multipart content. -.PP -The \*(lqtype\*(rq directive is used to directly specify the type and -subtype of a content. You may only specify discrete types in this manner -(can't specify the types multipart or message with this directive). -You may optionally specify the name of a file containing the contents -in \*(lqnative\*(rq (decoded) format. If this filename starts with the -\*(lq|\*(rq character, then it represents a command to execute whose -output is captured accordingly. -For example, -.PP -.RS 5 -.nf -#audio/basic |raw2audio -F < /usr/lib/sound/giggle.au -.fi -.RE -.PP -If a filename is not given, -.B mhbuild -will look for information in the -user's profile to determine how the different contents should be composed. -This is accomplished by consulting a composition string, and executing -it under -.BR /bin/sh , -with the standard output set to the content. -If the -.B \-verbose -switch is given, -.B mhbuild -will echo any commands that are used to create contents in this way. -.PP -The composition string may contain the following escapes: -.PP -.RS 5 -.nf -.ta \w'%P 'u -%a Insert parameters from directive -%f Insert filename containing content -%F %f, and stdout is not re-directed -%s Insert content subtype -%% Insert character % -.fi -.RE -.PP -First, -.B mhbuild -will look for an entry of the form: -.PP -.RS 5 -mhbuild-compose-/ -.RE -.PP -to determine the command to use to compose the content. If this isn't -found, -.B mhbuild -will look for an entry of the form: -.PP -.RS 5 -mhbuild-compose- -.RE -.PP -to determine the composition command. If this isn't found, -.B mhbuild -will complain. -.PP -An example entry might be: -.PP -.RS 5 -mhbuild-compose-audio/basic: record | raw2audio -F -.RE -.PP -Because commands like these will vary, depending on the display -environment used for login, composition strings for different -contents should probably be put in the file specified by the -.B $MHBUILD -environment variable, instead of directly in your -user profile. -.PP -The \*(lqexternal-type\*(rq directives are used to provide a MIME -reference to a content, rather than enclosing the contents itself -(for instance, by specifying an ftp site). Hence, instead of -providing a filename as with the type directives, external-parameters -are supplied. These look like regular parameters, so they must be -separated accordingly. For example, -.PP -.RS 5 -.nf -#@application/octet-stream; \\ - type=tar; \\ - conversions=compress \\ - [this is the nmh distribution] \\ - {application; filename="nmh.tar.gz"} \\ - name="nmh.tar.gz"; \\ - directory="/pub/nmh"; \\ - site="ftp.math.gatech.edu"; \\ - access-type=anon-ftp; \\ - mode="image" -.fi -.RE -.PP -You must give a description string to separate the content parameters -from the external-parameters (although this string may be empty). -This description string is specified by enclosing it within -\*(lq[]\*(rq. A disposition string, to appear in a -\*(lqContent-Disposition\*(rq header, may appear in the optional -\*(lq{}\*(rq. -.PP -These parameters are of the form: -.PP -.RS 5 -.nf -.ta \w'access-type= 'u -access-type= usually \fIanon-ftp\fR or \fImail-server\fR -name= filename -permission= read-only or read-write -site= hostname -directory= directoryname (optional) -mode= usually \fIascii\fR or \fIimage\fR (optional) -size= number of octets -server= mailbox -subject= subject to send -body= command to send for retrieval -.fi -.RE -.PP -The \*(lqmessage\*(rq directive (#forw) is used to specify a message or -group of messages to include. You may optionally specify the name of -the folder and which messages are to be forwarded. If a folder is not -given, it defaults to the current folder. Similarly, if a message is not -given, it defaults to the current message. Hence, the message directive -is similar to the -.B forw -command, except that the former uses -the MIME rules for encapsulation rather than those specified in RFC\-934. -For example, -.PP -.RS 5 -.nf -#forw +inbox 42 43 99 -.fi -.RE -.PP -If you include a single message, it will be included directly as a content -of type \*(lqmessage/rfc822\*(rq. If you include more than one message, -then -.B mhbuild -will add a content of type \*(lqmultipart/digest\*(rq -and include each message as a subpart of this content. -.PP -If you are using this directive to include more than one message, you -may use the -.B \-rfc934mode -switch. This switch will indicate that -.B mhbuild -should attempt to utilize the MIME encapsulation rules -in such a way that the \*(lqmultipart/digest\*(rq that is created -is (mostly) compatible with the encapsulation specified in RFC\-934. -If given, then RFC\-934 compliant user-agents should be able to burst the -message on reception\0--\0providing that the messages being encapsulated -do not contain encapsulated messages themselves. The drawback of this -approach is that the encapsulations are generated by placing an extra -newline at the end of the body of each message. -.PP -The \*(lqbegin\*(rq directive is used to create a multipart content. -When using the \*(lqbegin\*(rq directive, you must specify at least one -content between the begin and end pairs. -.PP -.RS 5 -.nf -#begin -This will be a multipart with only one part. -#end -.fi -.RE -.PP -If you use multiple directives in a composition draft, -.B mhbuild -will -automatically encapsulate them inside a multipart content. Therefore the -\*(lqbegin\*(rq directive is only necessary if you wish to use nested -multiparts, or create a multipart message containing only one part. -.PP -For all of these directives, the user may include a brief description -of the content between the \*(lq[\*(rq character and the \*(lq]\*(rq -character. This description will be copied into the -\*(lqContent-Description\*(rq header when the directive is processed. -.PP -.RS 5 -.nf -#forw [important mail from Bob] +bob 1 2 3 4 5 -.fi -.RE -.PP -Similarly, a disposition string may optionally be provided between -\*(lq{\*(rq and \*(lq}\*(rq characters; it will be copied into the -\*(lqContent-Disposition\*(rq header when the directive is processed. -If a disposition string is provided that does not contain a filename -parameter, and a filename is provided in the directive, it will be -added to the \*(lqContent-Disposition\*(rq header. For example, the -following directive: -.PP -.RS 5 -.nf -#text/plain; charset=iso-8859-1 <>{attachment} /tmp/summary.txt -.fi -.RE -.PP -creates these message part headers: -.PP -.RS 5 -.nf -Content-Type: text/plain; charset="iso-8859-1" -Content-Disposition: attachment; filename="summary.txt" -.fi -.RE -.PP -By default, -.B mhbuild -will generate a unique \*(lqContent-ID:\*(rq for each directive, -corresponding to each message part; however, the user may override -this by defining the ID using the \*(lq<\*(rq and \*(lq>\*(rq -characters. The -.B \-nocontentid -switch suppresses creation of all \*(lqContent-ID:\*(rq headers, -even in the top level of the message. -.PP -In addition to the various directives, plaintext can be present. -Plaintext is gathered, until a directive is found or the draft is -exhausted, and this is made to form a text content. If the plaintext -must contain a \*(lq#\*(rq at the beginning of a line, simply double it, -e.g., -.PP -.RS 5 -##when sent, this line will start with only one # -.RE -.PP -If you want to end the plaintext prior to a directive, e.g., to have two -plaintext contents adjacent, simply insert a line containing a single -\*(lq#\*(rq character, e.g., -.PP -.RS 5 -.nf -this is the first content -# -and this is the second -.fi -.RE -.PP -Finally, if the plaintext starts with a line of the form: -.PP -.RS 5 -Content-Description: text -.RE -.PP -then this will be used to describe the plaintext content. -You MUST follow this line with a blank line before starting -your text. -.PP -By default, plaintext is captured as a text/plain content. You can -override this by starting the plaintext with \*(lq#<\*(rq followed by -a content-type specification. For example, e.g., -.PP -.RS 5 -.nf -#" ] - [ "[" description "]" ] - [ "{" disposition "}" ] - [ filename ] - EOL - - | "#@" type "/" subtype - 0*(";" attribute "=" value) - [ "(" comment ")" ] - [ "<" id ">" ] - [ "[" description "]" ] - [ "{" disposition "}" ] - external-parameters - EOL - - | "#forw" - [ "<" id ">" ] - [ "[" description "]" ] - [ "{" disposition "}" ] - [ "+"folder ] [ 0*msg ] - EOL - - | "#begin" - [ "<" id ">" ] - [ "[" description "]" ] - [ "{" disposition "}" ] - [ "alternative" - | "parallel" - | something-else ] - EOL - 1*body - "#end" EOL - -plaintext ::= [ "Content-Description:" - description EOL EOL ] - 1*line - [ "#" EOL ] - - | "#<" type "/" subtype - 0*(";" attribute "=" value) - [ "(" comment ")" ] - [ "[" description "]" ] - [ "{" disposition "}" ] - EOL - 1*line - [ "#" EOL ] - -line ::= "##" text EOL - -- interpreted as "#"text EOL - | text EOL -.fi -.RE -.PP - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^$MHBUILD~^Additional profile entries -^%etcdir%/mhn.defaults~^System default MIME profile entries -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^mhbuild-compose-*~^Template for composing contents -.fi - -.SH "SEE ALSO" -mhlist(1), mhshow(1), mhstore(1), -.br -.I "Proposed Standard for Message Encapsulation" -(RFC\-934), -.br -.I "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies" -(RFC\-2045), -.br -.I "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types" -(RFC\-2046), -.br -.I "Multipurpose Internet Mail Extensions (MIME) Part Three: Message Header Extensions for Non-ASCII Text" -(RFC\-2047), -.br -.I "Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures" -(RFC\-2048), -.br -.I "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples" -(RFC\-2049) - -.SH DEFAULTS -.nf -.RB ` \-headers ' -.RB ` \-realsize ' -.RB ` \-norfc934mode ' -.RB ` \-contentid ' -.RB ` \-nocheck ' -.RB ` \-noebcdicsafe ' -.RB ` \-noverbose ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The last -message selected will become the current message. diff --git a/man/mhbuild.man1 b/man/mhbuild.man1 new file mode 100644 index 0000000..62d01be --- /dev/null +++ b/man/mhbuild.man1 @@ -0,0 +1,516 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHBUILD %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhbuild \- translate MIME composition draft +.SH SYNOPSIS +.na +.HP 5 +.B mhbuild +.I file +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B mhbuild +command will translate a MIME composition draft into +a valid MIME message. +.PP +.B mhbuild +creates multi-media messages as specified in RFC\-2045 +thru RFC\-2049. Currently +.B mhbuild +only supports encodings in +message bodies, and does not support the encoding of message headers as +specified in RFC\-2047. +.PP +If you specify the name of the composition file as `-', +then +.B mhbuild +will accept the composition draft on the standard +input. If the translation of this input is successful, +.B mhbuild +will output the new MIME message to the standard output. This argument +must be the last argument on the command line. +.PP +Otherwise if the file argument to +.B mhbuild +is the name of a valid +composition file, and the translation is successful, +.B mhbuild +will replace the original file with the new MIME message. +It will preserve the original file under the same name with `.orig' +appended. +E.g., if you are editing the file `draft', its original contents +it will be preserved as `draft.orig'. This allows you to easily +recover the +.B mhbuild +input file. +.SS "Translating the Composition File" +.B mhbuild +is essentially a filter to aid in the composition of MIME +messages. +.B mhbuild +will convert an +.B mhbuild +`composition file' +into a valid MIME message. A +.B mhbuild +`composition file' +is just a file containing plain text that is interspersed +with various +.B mhbuild +directives. When this file is processed +by +.BR mhbuild , +the various directives will be expanded to the +appropriate content, and will be encoded according to the MIME standards. +The resulting MIME message can then be sent by electronic mail. +.PP +The formal syntax for a +.B mhbuild +composition file is defined at the +end of this document, but the ideas behind this format are not complex. +Basically, the body contains one or more contents. A content consists of +either a directive, indicated with a `#' as the first character +of a line; or, plaintext (one or more lines of text). The continuation +character, `\\`, may be used to enter a single directive on more +than one line, e.g., +.PP +.RS 5 +.nf +#image/png \\ + /home/foobar/junk/picture.png +.fi +.RE +.PP +There are three kinds of directives: +`type', +`message' (#forw), +and `begin' (#begin). +.PP +.B "(1) The `type' directive +is used to directly specify the type and +subtype of a content. You may only specify discrete types in this manner +(can't specify the types multipart or message with this directive). +You may optionally specify the name of a file containing the contents +in `native' (decoded) format. If this filename starts with the +`|' character, then it represents a command to execute whose +output is captured accordingly. +For example, +.PP +.RS 5 +.nf +#audio/basic |raw2audio -F < /usr/lib/sound/giggle.au +.fi +.RE +.PP +If a filename is not given, +.B mhbuild +will look for information in the +user's profile to determine how the different contents should be composed. +This is accomplished by consulting a composition string, and executing +it under +.BR /bin/sh , +with the standard output set to the content. +If the +.B \-verbose +switch is given, +.B mhbuild +will echo any commands that are used to create contents in this way. +.PP +The composition string may contain the following escapes: +.PP +.RS 5 +.nf +.ta \w'%P 'u +%a Insert parameters from directive +%f Insert filename containing content +%F %f, and stdout is not re-directed +%s Insert content subtype +%% Insert character % +.fi +.RE +.PP +First, +.B mhbuild +will look for an entry of the form: +.PP +.RS 5 +mhbuild-compose-/ +.RE +.PP +to determine the command to use to compose the content. If this isn't +found, +.B mhbuild +will look for an entry of the form: +.PP +.RS 5 +mhbuild-compose- +.RE +.PP +to determine the composition command. If this isn't found, +.B mhbuild +will complain. +.PP +An example entry might be: +.PP +.RS 5 +mhbuild-compose-audio/basic: record | raw2audio -F +.RE +.PP +Because commands like these will vary, depending on the display +environment used for login, composition strings for different +contents should probably be put in the file specified by the +.B $MHBUILD +environment variable, instead of directly in your +user profile. +.PP +.B "(2) The `message' directive (#forw) +is used to specify a message or +group of messages to include. You may optionally specify the name of +the folder and which messages are to be forwarded. If a folder is not +given, it defaults to the current folder. Similarly, if a message is not +given, it defaults to the current message. The message directive +is used by +.BR forw . +.PP +For example, +.PP +.RS 5 +.nf +#forw +inbox 42 43 99 +.fi +.RE +.PP +If you include a single message, it will be included directly as a content +of type `message/rfc822'. If you include more than one message, +then +.B mhbuild +will add a content of type `multipart/digest' +and include each message as a subpart of this content. +.PP +.B "(3) The `begin' directive +is used to create a multipart content. +When using the `begin' directive, you must specify at least one +content between the begin and end pairs. +.PP +.RS 5 +.nf +#begin +This will be a multipart with only one part. +#end +.fi +.RE +.PP +If you use multiple directives in a composition draft, +.B mhbuild +will +automatically encapsulate them inside a multipart content. Therefore the +`begin' directive is only necessary if you wish to use nested +multiparts, or create a multipart message containing only one part. +.PP +For all of these directives, the user may include a brief description +of the content between the `[' character and the `]' +character. This description will be copied into the +`Content-Description' header when the directive is processed. +.PP +.RS 5 +.nf +#forw [important mail from Bob] +bob 1 2 3 4 5 +.fi +.RE +.PP +Similarly, a disposition string may optionally be provided between +`{' and `}' characters; it will be copied into the +`Content-Disposition' header when the directive is processed. +If a disposition string is provided that does not contain a filename +parameter, and a filename is provided in the directive, it will be +added to the `Content-Disposition' header. For example, the +following directive: +.PP +.RS 5 +.nf +#text/plain; charset=iso-8859-1 <>{attachment} /tmp/summary.txt +.fi +.RE +.PP +creates these message part headers: +.PP +.RS 5 +.nf +Content-Type: text/plain; charset="iso-8859-1" +Content-Disposition: attachment; filename="summary.txt" +.fi +.RE +.PP +By default, +.B mhbuild +will generate a unique `Content-ID:' for each directive, +corresponding to each message part; however, the user may override +this by defining the ID using the `<' and `>' +characters. +.PP +In addition to the various directives, plaintext can be present. +Plaintext is gathered, until a directive is found or the draft is +exhausted, and this is made to form a text content. If the plaintext +must contain a `#' at the beginning of a line, simply double it, +e.g., +.PP +.RS 5 +##when sent, this line will start with only one # +.RE +.PP +If you want to end the plaintext prior to a directive, e.g., to have two +plaintext contents adjacent, simply insert a line containing a single +`#' character, e.g., +.PP +.RS 5 +.nf +this is the first content +# +and this is the second +.fi +.RE +.PP +Finally, if the plaintext starts with a line of the form: +.PP +.RS 5 +Content-Description: text +.RE +.PP +then this will be used to describe the plaintext content. +You MUST follow this line with a blank line before starting +your text. +.PP +By default, plaintext is captured as a text/plain content. You can +override this by starting the plaintext with `#<' followed by +a content-type specification. For example, e.g., +.PP +.RS 5 +.nf +#" ] + [ "[" description "]" ] + [ "{" disposition "}" ] + [ filename ] + EOL + + | "#forw" + [ "<" id ">" ] + [ "[" description "]" ] + [ "{" disposition "}" ] + [ "+"folder ] [ 0*msg ] + EOL + + | "#begin" + [ "<" id ">" ] + [ "[" description "]" ] + [ "{" disposition "}" ] + [ "alternative" + | "parallel" + | something-else ] + EOL + 1*body + "#end" EOL + +plaintext ::= [ "Content-Description:" + description EOL EOL ] + 1*line + [ "#" EOL ] + + | "#<" type "/" subtype + 0*(";" attribute "=" value) + [ "(" comment ")" ] + [ "[" description "]" ] + [ "{" disposition "}" ] + EOL + 1*line + [ "#" EOL ] + +line ::= "##" text EOL + -- interpreted as "#"text EOL + | text EOL +.fi +.RE +.PP + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^$MHBUILD~^Additional profile entries +^%etcdir%/mhn.defaults~^System default MIME profile entries +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^mhbuild-compose-*~^Template for composing contents +.fi + +.SH "SEE ALSO" +mhlist(1), show(1), mhstore(1), forw(1), +.br +.I "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies" +(RFC\-2045), +.br +.I "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types" +(RFC\-2046), +.br +.I "Multipurpose Internet Mail Extensions (MIME) Part Three: Message Header Extensions for Non-ASCII Text" +(RFC\-2047), +.br +.I "Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures" +(RFC\-2048), +.br +.I "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples" +(RFC\-2049) + +.SH DEFAULTS +.nf +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The last +message selected will become the current message. + +.SH BUGS +Outlook 2002 won't display attachments that have a Content-ID header. +This is a bug in Outlook 2002, not in +.BR mhbuild . +To workaround it, invoke \fIe mhbuild\fP manually at the Whatnow prompt +and edit the draft again thereafter, removing the Content-ID headers. +Then send it. +There used to be a +.B \-nocontentid +switch to prevent Content-ID headers to be inserted, but as it was considerd +wrong to complicate all other MUAs instead of forcing the developers and users +of broken MUAs to fix or change their software, it was removed. diff --git a/man/mhl.man b/man/mhl.man deleted file mode 100644 index f8546c3..0000000 --- a/man/mhl.man +++ /dev/null @@ -1,353 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhl \- produce formatted listings of nmh messages -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/mhl -.RB [ \-bell " | " \-nobell ] -.RB [ \-clear " | " \-noclear ] -.RB [ \-folder -.IR +folder ] -.RB [ \-form -.IR formfile ] -.RB [ \-length -.IR lines ] -.RB [ \-width -.IR columns ] -.RB [ \-moreproc -.IR program ] -.RB [ \-nomoreproc ] -.RI [ files -.IR \&... ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Mhl -is an -.B nmh -command for filtering and/or displaying text -messages. It is the default method of displaying text messages for -.B nmh -(it is the default -.IR showproc ). -.PP -As with -.BR more , -each of the messages specified as arguments (or -the standard input) will be output. If more than one message file is -specified, the user will be prompted prior to each one, and a -or will begin the output, with clearing the screen (if -appropriate), and (usually CTRL\-D) suppressing the screen clear. -An (usually CTRL\-C) will abort the current message output, -prompting for the next message (if there is one), and a (usually -CTRL-\\) will terminate the program (without core dump). -.PP -The -.B \-bell -option tells -.B mhl -to ring the terminal's bell at the -end of each page, while the -.B \-clear -option tells -.B mhl -to clear the -screen at the end of each page (or output a formfeed after each message). -Both of these switches (and their inverse counterparts) take effect only -if the profile entry -.I moreproc -is defined but empty, and -.B mhl -is outputting to a terminal. If the -.I moreproc -entry is defined and -non-empty, and -.B mhl -is outputting to a terminal, then -.B mhl -will -cause the -.I moreproc -to be placed between the terminal and -.B mhl -and the switches are ignored. Furthermore, if the -.B \-clear -switch is -used and \fImhl's\fR output is directed to a terminal, then -.B mhl -will consult the -.B $TERM -and -.B $TERMCAP -environment variables -to determine the user's terminal type in order to find out how to clear -the screen. If the -.B \-clear -switch is used and -.BR mhl 's -output is -not directed to a terminal (e.g., a pipe or a file), then -.B mhl -will -send a formfeed after each message. -.PP -To override the default -.I moreproc -and the profile entry, use the -.B \-moreproc -.I program -switch. Note that -.B mhl -will never start a -.I moreproc -if invoked on a hardcopy terminal. -.PP -The -.B \-length -.I length -and -.B \-width -.I width -switches set the screen -length and width, respectively. These default to the values indicated by -.BR $TERMCAP , -if appropriate, otherwise they default to 40 and 80, respectively. -.PP -The default format file used by -.B mhl -is called -.RI \*(lq mhl.format \*(rq. -.B mhl -will first search for this file in the user's -.B nmh -directory, and will then search in the directory -.IR %etcdir% . -This default -can be changed by using the -.B \-form -.I formatfile -switch. -.PP -Finally, the -.B \-folder -.I +folder -switch sets the -.B nmh -folder name, -which is used for the \*(lqmessagename:\*(rq field described below. The -environment variable -.B $mhfolder -is consulted for the default value, -which -.BR show , -.BR next , -and -.B prev -initialize appropriately. -.PP -.B Mhl -operates in two phases: 1) read and parse the format file, and -2) process each message (file). During phase 1, an internal description -of the format is produced as a structured list. In phase 2, this list -is walked for each message, outputting message information under the -format constraints from the format file. -.PP -The format file can contain information controlling screen clearing, -screen size, wrap\-around control, transparent text, component ordering, -and component formatting. Also, a list of components to ignore may be -specified, and a couple of \*(lqspecial\*(rq components are defined -to provide added functionality. Message output will be in the order -specified by the order in the format file. -.PP -Each line of a format file has one of the following forms: -.PP -.RS 5 -.nf -;comment -:cleartext -variable[,variable...] -component:[variable,...] -.fi -.RE -.PP -.IP \(bu 4 -A line beginning with a `;' is a comment, and is ignored. -.IP \(bu 4 -A line beginning with a `:' is clear text, and is output exactly as is. -.IP \(bu 4 -A line containing only a `:' produces a blank line in the output. -.IP \(bu 4 -A line beginning with \*(lqcomponent:\*(rq defines the format for the specified -component, -.IP \(bu 4 -Remaining lines define the global environment. -.PP -For example, the line: -.PP -.RS 5 -width=80,length=40,clearscreen,overflowtext="***",overflowoffset=5 -.RE -.PP -defines the screen size to be 80 columns by 40 rows, specifies that the -screen should be cleared prior to each page, that the overflow indentation -is 5, and that overflow text should be flagged with \*(lq***\*(rq. -.PP -Following are all of the current variables and their arguments. If they -follow a component, they apply only to that component, otherwise, their -affect is global. Since the whole format is parsed before any output -processing, the last global switch setting for a variable applies to -the whole message if that variable is used in a global context (i.e., -bell, clearscreen, width, length). -.PP -.RS 5 -.nf -.ta \w'noclearscreen 'u +\w'integer/G 'u -.I variable type semantics -width integer screen width or component width -length integer screen length or component length -offset integer positions to indent \*(lqcomponent: \*(rq -overflowtext string text to use at the beginning of an - overflow line -overflowoffset integer positions to indent overflow lines -compwidth integer positions to indent component text - after the first line is output -uppercase flag output text of this component in all - upper case -nouppercase flag don't uppercase -clearscreen flag/G clear the screen prior to each page -noclearscreen flag/G don't clearscreen -bell flag/G ring the bell at the end of each page -nobell flag/G don't bell -component string/L name to use instead of \*(lqcomponent\*(rq for - this component -nocomponent flag don't output \*(lqcomponent: \*(rq for this - component -center flag center component on line (works for - one\-line components only) -nocenter flag don't center -leftadjust flag strip off leading whitespace on each - line of text -noleftadjust flag don't leftadjust -compress flag change newlines in text to spaces -nocompress flag don't compress -split flag don't combine multiple fields into - a single field -nosplit flag combine multiple fields into - a single field -newline flag print newline at end of components - (this is the default) -nonewline flag don't print newline at end of components -formatfield string format string for this component - (see below) -decode flag decode text as RFC-2047 encoded - header field -addrfield flag field contains addresses -datefield flag field contains dates -.fi -.RE -.PP -To specify the value of integer\-valued and string\-valued variables, -follow their name with an equals\-sign and the value. Integer\-valued -variables are given decimal values, while string\-valued variables -are given arbitrary text bracketed by double\-quotes. If a value is -suffixed by \*(lq/G\*(rq or \*(lq/L\*(rq, then its value is useful in -a global\-only or local\-only context (respectively). -.PP -A line of the form: -.PP -.RS 5 -ignores=component,... -.RE -.PP -specifies a list of components which are never output. -.PP -The component \*(lqMessageName\*(rq (case\-insensitive) will output the -actual message name (file name) preceded by the folder name if one is -specified or found in the environment. The format is identical to that -produced by the -.B \-header -option to -.BR show . -.PP -The component \*(lqExtras\*(rq will output all of the components of the -message which were not matched by explicit components, or included in -the ignore list. If this component is not specified, an ignore list is -not needed since all non\-specified components will be ignored. -.PP -If \*(lqnocomponent\*(rq is NOT specified, then the component name will -be output as it appears in the format file. -.PP -The default format file is: -.PP -.RS 5 -.nf -%mhl_format% -.fi -.RE -.PP -The variable \*(lqformatfield\*(rq specifies a format string (see -.BR mh\-format (5)). -The flag variables \*(lqaddrfield\*(rq and -\*(lqdatefield\*(rq (which are mutually exclusive), tell -.B mhl -to interpret the escapes in the format string as either addresses or -dates, respectively. -.PP -By default, -.B mhl -does not apply any formatting string to fields -containing address or dates (see -.BR mh\-mail (5) -for a list of these -fields). Note that this results in faster operation since -.B mhl -must parse both addresses and dates in order to apply a format string -to them. If desired, -.B mhl -can be given a default format string for -either address or date fields (but not both). To do this, on a global -line specify: either the flag addrfield or datefield, along with the -appropriate formatfield variable string. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mhl.format~^The message template -^or /mhl.format~^Rather than the standard template -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^moreproc:~^Program to use as interactive front\-end -.fi - -.SH "SEE ALSO" -show(1), ap(8), dp(8) - -.SH DEFAULTS -.nf -.RB ` \-bell ' -.RB ` \-noclear ' -.RB ` \-length 40 ' -.RB ` \-width 80 ' -.fi - -.SH CONTEXT -None - -.SH BUGS -There should be some way to pass `bell' and `clear' information to the -front\-end. -.PP -The \*(lqnonewline\*(rq option interacts badly with \*(lqcompress\*(rq -and \*(lqsplit\*(rq. diff --git a/man/mhl.man1 b/man/mhl.man1 new file mode 100644 index 0000000..37577f8 --- /dev/null +++ b/man/mhl.man1 @@ -0,0 +1,247 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhl \- produce formatted listings of nmh messages +.SH SYNOPSIS +.HP 5 +.na +.B mhl +.RB [ \-form +.IR formfile ] +.RB [ \-width +.IR columns ] +.RI [ files +.IR \&... ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Mhl +is an +.B nmh +command for filtering and/or displaying text +messages. It is the default method of displaying text messages for +.B nmh +(it is the default +.IR showproc ). +.PP +The +.B \-width +.I width +switch sets the screen width. This defaults to the value indicated by +.BR $TERMCAP , +if appropriate, otherwise it defaults to 80. +.PP +The default format file used by +.B mhl +is called +.RI ` mhl.format '. +.B mhl +will first search for this file in the user's +.B mmh +directory, and will then search in the directory +.IR %etcdir% . +This default +can be changed by using the +.B \-form +.I formatfile +switch. +Note: In contrast to any other +.B mmh +tool, the +.B \-form +switch does only take file names, but no format strings with a prepended +equal sign `='. +.PP +.B Mhl +operates in two phases: 1) read and parse the format file, and +2) process each message (file). During phase 1, an internal description +of the format is produced as a structured list. In phase 2, this list +is walked for each message, outputting message information under the +format constraints from the format file. +.PP +The format file can contain information controlling +screen size, wrap\-around control, transparent text, component ordering, +and component formatting. Also, a list of components to ignore may be +specified, and a couple of `special' components are defined +to provide added functionality. Message output will be in the order +specified by the order in the format file. +.PP +Each line of a format file has one of the following forms: +.PP +.RS 5 +.nf +;comment +:cleartext +variable[,variable...] +component:[variable,...] +.fi +.RE +.PP +.IP \(bu 4 +A line beginning with a `;' is a comment, and is ignored. +.IP \(bu 4 +A line beginning with a `:' is clear text, and is output exactly as is. +.IP \(bu 4 +A line containing only a `:' produces a blank line in the output. +.IP \(bu 4 +A line beginning with `component:' defines the format for the specified +component, +.IP \(bu 4 +Remaining lines define the global environment. +.PP +For example, the line: +.PP +.RS 5 +width=80,overflowtext="***",overflowoffset=5 +.RE +.PP +defines the screen size to be 80 columns by 40 rows, specifies that the +overflow indentation +is 5, and that overflow text should be flagged with `***'. +.PP +Following are all of the current variables and their arguments. If they +follow a component, they apply only to that component, otherwise, their +affect is global. Since the whole format is parsed before any output +processing, the last global switch setting for a variable applies to +the whole message if that variable is used in a global context (i.e., +width). +.PP +.RS 5 +.nf +.ta \w'xxxxxxxxxxxxx 'u +\w'integer/G 'u +.I "variable type semantics +width integer screen width or component width +length integer component length +offset integer positions to indent `component: ' +overflowtext string text to use at the beginning of an + overflow line +overflowoffset integer positions to indent overflow lines +compwidth integer positions to indent component text + after the first line is output +uppercase flag output text of this component in all + upper case +nouppercase flag don't uppercase +component string/L name to use instead of `component' for + this component +nocomponent flag don't output `component: ' for this + component +center flag center component on line (works for + one\-line components only) +nocenter flag don't center +leftadjust flag strip off leading whitespace on each + line of text +noleftadjust flag don't leftadjust +compress flag change newlines in text to spaces +nocompress flag don't compress +split flag don't combine multiple fields into + a single field +nosplit flag combine multiple fields into + a single field +newline flag print newline at end of components + (this is the default) +nonewline flag don't print newline at end of components +formatfield string format string for this component + (see below) +decode flag decode text as RFC-2047 encoded + header field +addrfield flag field contains addresses +datefield flag field contains dates +.fi +.RE +.PP +To specify the value of integer\-valued and string\-valued variables, +follow their name with an equals\-sign and the value. Integer\-valued +variables are given decimal values, while string\-valued variables +are given arbitrary text bracketed by double\-quotes. If a value is +suffixed by `/G' or `/L', then its value is useful in +a global\-only or local\-only context (respectively). +.PP +A line of the form: +.PP +.RS 5 +ignores=component,... +.RE +.PP +specifies a list of components which are never output. +.PP +The component `MessageName' (case\-insensitive) will output the +message file name as a one-line header, similar to +.BR show . +E.g. ``(Message 42)'' +.PP +The component `Extras' will output all of the components of the +message which were not matched by explicit components, or included in +the ignore list. If this component is not specified, an ignore list is +not needed since all non\-specified components will be ignored. +.PP +If `nocomponent' is NOT specified, then the component name will +be output as it appears in the format file. +.PP +The default format file is: +.PP +.RS 5 +.nf +%mhl_format% +.fi +.RE +.PP +The variable `formatfield' specifies a format string (see +.BR mh\-format (5)). +The flag variables `addrfield' and +`datefield' (which are mutually exclusive), tell +.B mhl +to interpret the escapes in the format string as either addresses or +dates, respectively. +.PP +By default, +.B mhl +does not apply any formatting string to fields +containing address or dates (see +.BR mh\-mail (5) +for a list of these +fields). Note that this results in faster operation since +.B mhl +must parse both addresses and dates in order to apply a format string +to them. If desired, +.B mhl +can be given a default format string for +either address or date fields (but not both). To do this, on a global +line specify: either the flag addrfield or datefield, along with the +appropriate formatfield variable string. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/mhl.format~^The message template +^or $HOME/.mmh/mhl.format~^Rather than the standard template +^$HOME/.mh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +none + +.SH "SEE ALSO" +show(1), ap(8), dp(8) + +.SH DEFAULTS +.nf +.RB ` \-width \ 80' +.fi + +.SH CONTEXT +None + +.SH BUGS +In contrast to any other +.B mmh +tool, the +.B \-form +switch does only take file names, but no format strings with a prepended +equal sign `='. +.PP +The `nonewline' option interacts badly with `compress' +and `split'. diff --git a/man/mhlist.man b/man/mhlist.man deleted file mode 100644 index f0ef31a..0000000 --- a/man/mhlist.man +++ /dev/null @@ -1,189 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHLIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhlist \- list information about MIME messages -.SH SYNOPSIS -.HP 5 -.na -.B mhlist -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-file -.IR file ] -.RB [ \-part -.IR number ] -\&... -.RB [ \-type -.IR content ] -\&... -.RB [ \-headers " | " \-noheaders ] -.RB [ \-realsize " | " \-norealsize ] -.RB [ \-rcache -.IR policy ] -.RB [ \-wcache -.IR policy ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B mhlist -command allows you to list information (essentially -a table of contents) about the various parts of a collection of -MIME (multi-media) messages. -.PP -.B mhlist -manipulates MIME (multi-media messages) as specified -in RFC\-2045 thru RFC\-2049 (See -.BR mhbuild (1)). -.PP -The -.B \-headers -switch indicates that a one-line banner should be -displayed above the listing. -.PP -The -.B \-realsize -switch tells -.B mhlist -to evaluate the -\*(lqnative\*(rq (decoded) format of each content prior to listing. -This provides an accurate count at the expense of a small delay. -.PP -If the -.B \-verbose -switch is present, then the listing will show -any \*(lqextra\*(rq information that is present in the message, -such as comments in the \*(lqContent-Type\*(rq header. -.PP -The option -.B \-file -.I file -directs -.B mhlist -to use the specified -file as the source message, rather than a message from a folder. -If you specify this file as \*(lq-\*(rq, then -.B mhlist -will -accept the source message on the standard input. Note that the -file, or input from standard input should be a validly formatted -message, just like any other -.B nmh -message. It should -.B NOT -be in mail drop format (to convert a file in mail drop format to -a folder of -.B nmh -messages, see -.BR inc (1)). -.PP -By default, -.B mhlist -will list information about the entire -message (all of its parts). By using the -.B \-part -and -.B \-type -switches, you may limit the scope of this command to particular -subparts (of a multipart content) and/or particular content types. -.PP -A part specification consists of a series of numbers separated by dots. -For example, in a multipart content containing three parts, these -would be named as 1, 2, and 3, respectively. If part 2 was also a -multipart content containing two parts, these would be named as 2.1 and -2.2, respectively. Note that the -.B \-part -switch is effective for only -messages containing a multipart content. If a message has some other -kind of content, or if the part is itself another multipart content, the -.B \-part -switch will not prevent the content from being acted upon. -.PP -A content specification consists of a content type and a subtype. -The initial list of \*(lqstandard\*(rq content types and subtypes can -be found in RFC\-2046. -.PP -A list of commonly used contents is briefly reproduced here: -.PP -.RS 5 -.nf -.ta \w'application 'u -Type Subtypes ----- -------- -text plain, enriched -multipart mixed, alternative, digest, parallel -message rfc822, partial, external-body -application octet-stream, postscript -image jpeg, gif, png -audio basic -video mpeg -.fi -.RE -.PP -A legal MIME message must contain a subtype specification. -.PP -To specify a content, regardless of its subtype, just use the -name of the content, e.g., \*(lqaudio\*(rq. To specify a specific -subtype, separate the two with a slash, e.g., \*(lqaudio/basic\*(rq. -Note that regardless of the values given to the -.B \-type -switch, a -multipart content (of any subtype listed above) is always acted upon. -Further note that if the -.B \-type -switch is used, and it is desirable to -act on a message/external-body content, then the -.B \-type -switch must -be used twice: once for message/external-body and once for the content -externally referenced. -.SS "Checking the Contents" -The -.B \-check -switch tells -.B mhlist -to check each content for an -integrity checksum. If a content has such a checksum (specified as a -Content-MD5 header field), then -.B mhlist -will attempt to verify the -integrity of the content. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -mhbuild(1), mhshow(1), mhstore(1), sendfiles(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-nocheck ' -.RB ` \-headers ' -.RB ` \-realsize ' -.RB ` \-rcache ask ' -.RB ` \-wcache ask ' -.RB ` \-noverbose ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The last -message selected will become the current message. diff --git a/man/mhlist.man1 b/man/mhlist.man1 new file mode 100644 index 0000000..e0724b2 --- /dev/null +++ b/man/mhlist.man1 @@ -0,0 +1,150 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHLIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhlist \- list information about MIME messages +.SH SYNOPSIS +.HP 5 +.na +.B mhlist +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-file +.IR file ] +.RB [ \-part +.IR number ] +\&... +.RB [ \-type +.IR content ] +\&... +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B mhlist +command allows you to list information (essentially +a table of contents) about the various parts of a collection of +MIME (multi-media) messages. +.PP +.B mhlist +manipulates MIME (multi-media messages) as specified +in RFC\-2045 thru RFC\-2049 (See +.BR mhbuild (1)). +.PP +A one-line banner is displayed above the listing. +The size of the +`native' (decoded) format of each content is evaluated. +This provides an accurate count at the expense of a small delay. +If the +.B \-verbose +switch is present, then the listing will show +any `extra' information that is present in the message, +such as comments in the `Content-Type' header. +.PP +The option +.B \-file +.I file +directs +.B mhlist +to use the specified +file as the source message, rather than a message from a folder. +If you specify this file as `-', then +.B mhlist +will +accept the source message on the standard input. Note that the +file, or input from standard input should be a validly formatted +message, just like any other +.B nmh +message. It should +.B NOT +be in mail drop format (to convert a file in mail drop format to +a folder of +.B nmh +messages, see +.BR inc (1)). +.PP +By default, +.B mhlist +will list information about the entire +message (all of its parts). By using the +.B \-part +and +.B \-type +switches, you may limit the scope of this command to particular +subparts (of a multipart content) and/or particular content types. +.PP +A part specification consists of a series of numbers separated by dots. +For example, in a multipart content containing three parts, these +would be named as 1, 2, and 3, respectively. If part 2 was also a +multipart content containing two parts, these would be named as 2.1 and +2.2, respectively. Note that the +.B \-part +switch is effective for only +messages containing a multipart content. If a message has some other +kind of content, or if the part is itself another multipart content, the +.B \-part +switch will not prevent the content from being acted upon. +.PP +A content specification consists of a content type and a subtype. +The initial list of `standard' content types and subtypes can +be found in RFC\-2046. +.PP +A list of commonly used contents is briefly reproduced here: +.PP +.RS 5 +.nf +.ta \w'application 'u +Type Subtypes +---- -------- +text plain, enriched +multipart mixed, alternative, digest, parallel +message rfc822, partial, external-body +application octet-stream, postscript +image jpeg, gif, png +audio basic +video mpeg +.fi +.RE +.PP +A legal MIME message must contain a subtype specification. +.PP +To specify a content, regardless of its subtype, just use the +name of the content, e.g., `audio'. To specify a specific +subtype, separate the two with a slash, e.g., `audio/basic'. +Note that regardless of the values given to the +.B \-type +switch, a +multipart content (of any subtype listed above) is always acted upon. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +mhbuild(1), show(1), mhstore(1), sendfiles(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The last +message selected will become the current message. diff --git a/man/mhmail.man b/man/mhmail.man deleted file mode 100644 index 6e3cf13..0000000 --- a/man/mhmail.man +++ /dev/null @@ -1,116 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHMAIL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhmail \- send or read mail -.SH SYNOPSIS -.HP 5 -.na -.B mhmail -.RI [ addrs -\&...] -.RB [ \-body -.IR text ] -.RB [ \-cc -.I addrs -\&...] -.RB [ \-from -.IR addr ] -.RB [ \-subject -.IR subject ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B mhmail -is intended as a replacement for the standard Berkeley -mail program -.RB ( mail -or -.BR mailx ), -which is compatible with -.BR nmh . -This program is intended for the use of programs such as -.BR cron , -which expect to send mail automatically to various -users. It is also used by various -.B nmh -commands to mail various -error notifications. Although -.B mhmail -can be used interactively, -it is recommended that -.B comp -and -.B send -be used instead to send messages. -.PP -When invoked without arguments, it simply invokes -.B inc -to incorporate new messages from the user's maildrop. When one or more users -is specified, a message is read from the standard input and spooled to -a temporary file. -.B mhmail -then invokes -.B post -with the -name of the temporary file as its argument to deliver the message to -the specified user. -.PP -The -.B \-subject -.I subject -switch can be used to specify the -\*(lqSubject:\*(rq field of the message. -.PP -By default, -.B mhmail -will read the message to be sent from the -standard input. You can specify the text of the message at the command -line with the -.B \-body -.I text -switch. If the standard input has zero -length, -.B mhmail -will not send the message. You can use the switch -.B \-body -\*(lq\*(rq to force an empty message. -.PP -Normally, addresses appearing as arguments are put in the \*(lqTo:\*(rq -field. If the -.B \-cc -switch is used, all addresses following it are -placed in the \*(lqcc:\*(rq field. -.PP -By using -.B \-from -.IR addr , -you can specify the \*(lqFrom:\*(rq header of -the draft. Naturally, -.B post -will fill\-in the \*(lqSender:\*(rq -header correctly. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%bindir%/inc~^Program to incorporate maildrop into folder -^%libdir%/post~^Program to deliver a message -^/tmp/mhmail*~^Temporary copy of message -.fi - -.SH "SEE ALSO" -inc(1), post(8) - -.SH DEFAULTS -None - -.SH CONTEXT -If -.B inc -is invoked, then -.BR inc 's -context changes occur. diff --git a/man/mhmail.man1 b/man/mhmail.man1 new file mode 100644 index 0000000..b2381c1 --- /dev/null +++ b/man/mhmail.man1 @@ -0,0 +1,142 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHMAIL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhmail \- send mail +.SH SYNOPSIS +.HP 5 +.na +.B mhmail +.IR addrs ... +.RB [ \-cc +.IR addrs ...] +.RB [ \-from +.IR addr ] +.RB [ \-subject +.IR subject ] +.RB [ \-bodytext +.IR text ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B mhmail +is inspired by the standard Berkeley mail program +.RB ( mail +or +.BR mailx ). +It should not be seen as a drop-in replacement for these programs, +but rather as a more convenient alternative to +.B comp +for non-interactive use. +For interactive use, +.B comp +and +.B send +are recommended over +.BR mhmail . +.PP +When one or more addresses +are specified, a message is read from the standard input and spooled to +a temporary file. +.B mhmail +then invokes +.B spost +to deliver the message. +.PP +.B mhmail +can not be used for mal reading. Use +.BR inc , +.BR scan , +.B show +instead. +.PP +The +.B \-subject +.I subject +switch can be used to specify the +`Subject:' field of the message. +.PP +By default, +.B mhmail +will read the message to be sent from the +standard input. +The message is terminated by either end-of-file or by a single period +alone on a line. This is compatible to +.B mail +and +.BR mailx . +Alternatively, you can specify the text of the message at the command +line with the +.B \-bodytext +.I text +switch. +.PP +If the standard input has zero length, +.B mhmail +will not send the message. You can use +.B \-bodytext +"" to force an empty message. +.PP +Normally, addresses appearing as arguments are put in the `To:' +field. If the +.B \-cc +switch is used, all addresses following it are +placed in the `Cc:' field. +.PP +By using +.B \-from +.IR addr , +you can specify the `From:' header of +the draft. Naturally, +.B post +will fill\-in the `Sender:' +header correctly. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/BigFileName 'u +^/tmp/mhmail*~^Temporary copy of message +.fi + +.SH "SEE ALSO" +inc(1), scan(1), show(1), post(8) + +.SH DEFAULTS +None + +.SH CONTEXT +None + +.SH HISTORY +.B mhmail +was intended as a replacement for the standard Berkeley +mail program +.RB ( mail +or +.BR mailx ), +which is compatible with +.BR nmh . +This program was intended for the use of programs such as +.BR cron , +which expect to send mail automatically to various +addresses. It was also used by various +.B nmh +commands to mail various +error notifications. +.PP +When invoked without arguments, it had simply invokes +.B inc +to incorporate new messages from the user's maildrop. + +.SH BUGS +.B mhmail +should no longer try to replace +.BR mailx , +but become a mail sending front-end to +.B comp +or +.BR send , +which is more convenient in some situations. diff --git a/man/mhn.man b/man/mhn.man deleted file mode 100644 index fc682ef..0000000 --- a/man/mhn.man +++ /dev/null @@ -1,54 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHN %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhn \- display/list/store/cache MIME messages -.SH SYNOPSIS -.HP 5 -.na -.B mhn -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-file -.IR file ] -.RB [ \-part -.IR number ] -\&... -.RB [ \-type -.IR content ] -\&... -.RB [ \-show " | " \-noshow ] -.RB [ \-list " | " \-nolist ] -.RB [ \-store " | " \-nostore ] -.RB [ \-cache " | " \-nocache ] -.RB [ \-headers " | " \-noheaders ] -.RB [ \-realsize " | " \-norealsize ] -.RB [ \-serialonly " | " \-noserialonly ] -.RB [ \-form -.IR formfile ] -.RB [ \-pause " | " \-nopause ] -.RB [ \-auto " | " \-noauto ] -.RB [ \-rcache -.IR policy ] -.RB [ \-wcache -.IR policy ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-version ] -.RB [ \-help ] -.PP -.HP 5 -.B mhn -.B \-build -.I file -.RB [ \-ebcdicsafe " | " \-noebcdicsafe ] -.RB [ \-rfc934mode " | " \-norfc934mode ] -.ad -.SH DESCRIPTION -.B MHN SHOULD BE CONSIDERED DEPRECATED. IT IS RETAINED FOR THE PURPOSE -.B OF BACKWARD COMPATIBILITY, BUT EVERYONE SHOULD MIGRATE TO USING THE -.B COMMANDS MHSHOW, MHSTORE, AND MHLIST. CHECK THE INDIVIDUAL MAN PAGES -.B FOR DETAILS. - -.SH "SEE ALSO" -mhbuild(1), mhl(1), sendfiles(1) diff --git a/man/mhparam.man b/man/mhparam.man deleted file mode 100644 index ba00fc6..0000000 --- a/man/mhparam.man +++ /dev/null @@ -1,113 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHPARAM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhparam \- print nmh profile and context components -.SH SYNOPSIS -.na -.B mhparam -.RI [ components ] -.RB [ \-all ] -.RB [ \-component " | " \-nocomponent ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B mhparam -writes the value of the specified profile component to the -standard output separated by newlines. If the profile component is not -present, the default value (or nothing if there is no default) is printed. -.PP -If the switch -.B \-component -is given, then the component name is displayed -along with the profile components value. This can be disabled with the -switch -.BR \-nocomponent . -.PP -If more than one component is specified in the -.I components -list, then -the switch -.B \-component -is on by default. If only one component is -specified, then the switch -.B \-nocomponent -is on by default. -.PP -If -.B \-all -is specified, then all components in the nmh profile are -displayed and other arguments are ignored. -.PP -Examples: -.PP -.RS 5 -.nf -.ta \w'AliasFile:'u+2n -% mhparam path -Mail - -% mhparam mhlproc -%libdir%/mhl - -% mhparam \-component path -Path: Mail - -% mhparam AliasFile rmmproc -AliasFile: aliases -rmmproc: rmmproc - -% mhparam \-nocomponent AliasFile rmmproc -aliases -rmmproc - -% mhparam path nonexistent context -Path: Mail -context: context -.fi -.RE -.PP -.B mhparam -is also useful in back\-quoted operations: -.PP -.RS 5 -.nf -% fgrep cornell.edu `mhpath +`/`mhparam aliasfile` -.fi - -.SH "EXIT STATUS" -.B mhparam -returns the number of components that were not found. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/.mh_profile~^The user profile -^or $MH~^Rather than the standard profile -^/context~^The user context -^or $MHCONTEXT~^Rather than the standard context -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^context:~^To determine the context file -.fi - -.SH "SEE ALSO" -mh-profile(5) - -.SH DEFAULTS -.nf -.RB ` \-nocomponent "' if only one component is specified" -.RB ` \-component "' if more than one component is specified" -.RB ` components "' defaults to none" -.fi - -.SH CONTEXT -None diff --git a/man/mhparam.man1 b/man/mhparam.man1 new file mode 100644 index 0000000..11a1346 --- /dev/null +++ b/man/mhparam.man1 @@ -0,0 +1,120 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHPARAM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhparam \- print nmh profile and context components +.SH SYNOPSIS +.HP 5 +.na +.B mhparam +.RI [ components ] +.RB [ \-all ] +.RB [ \-component " | " \-nocomponent ] +.RB [ \-debug ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B mhparam +writes the value of the specified profile component to the +standard output separated by newlines. If the profile component is not +present, the default value (or nothing if there is no default) is printed. +.PP +If the switch +.B \-component +is given, then the component name is displayed +along with the profile components value. This can be disabled with the +switch +.BR \-nocomponent . +.PP +If more than one component is specified in the +.I components +list, then +the switch +.B \-component +is on by default. If only one component is +specified, then the switch +.B \-nocomponent +is on by default. +.PP +If +.B \-all +is specified, then all components in the mmh profile and context +(including comments) are displayed and other arguments are ignored. +.PP +If +.B \-debug +is specified, then a defined set of internal profile entries are +displayed. +.PP +Examples: +.PP +.RS 5 +.nf +.ta \w'LongEntry:'u+2n +% mhparam path +Mail + +% mhparam editor +vi + +% mhparam \-component Path +Path: Mail + +% mhparam AliasFile sendmail +AliasFile: aliases +sendmail: /usr/sbin/sendmail + +% mhparam \-nocomponent AliasFile sendmail +aliases +/usr/sbin/sendmail + +% mhparam path nonexistent context +Path: Mail +context: context +.fi +.RE +.PP +.B mhparam +is also useful in back\-quoted operations: +.PP +.RS 5 +.nf +% fgrep cornell.edu `mhpath +`/`mhparam aliasfile` +.fi + +.SH "EXIT STATUS" +.B mhparam +returns the number of components that were not found. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^or $MMHP~^Rather than the standard profile +^$HOME/.mmh/context~^The user context +^or $MMHC~^Rather than the standard context +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Context:~^To determine the context file +.fi + +.SH "SEE ALSO" +mh-profile(5) + +.SH DEFAULTS +.nf +.RB ` \-nocomponent "' if only one component is specified" +.RB ` \-component "' if more than one component is specified" +.RB ` components "' defaults to none" +.fi + +.SH CONTEXT +None diff --git a/man/mhpath.man b/man/mhpath.man deleted file mode 100644 index e04c4a3..0000000 --- a/man/mhpath.man +++ /dev/null @@ -1,171 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHPATH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhpath \- print full pathnames of nmh messages and folders -.SH SYNOPSIS -.HP 5 -.na -.B mhpath -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B mhpath -expands and sorts the message list `msgs' and writes the full -pathnames of the messages to the standard output separated by newlines. -If no `msgs' are specified, -.B mhpath -outputs the current mail folder's pathname -instead. If the only argument is `+', your -.B nmh -\*(lqPath\*(rq is output; this can be useful in shell scripts. -.PP -Contrasted with other -.B nmh -commands, a message argument to -.B mhpath -may often be intended for writing. Because of this: -.PP -.IP 1) 4 -the name \*(lqnew\*(rq has been added to -.BR mhpath 's -list of -reserved message names (the others are \*(lqfirst\*(rq, \*(lqlast\*(rq, -\*(lqprev\*(rq, \*(lqnext\*(rq, \*(lqcur\*(rq, and \*(lqall\*(rq). -The new message is equivalent to the message after the last message -in a folder (and equivalent to 1 in a folder without messages). -The \*(lqnew\*(rq message may not be used as part of a message range. -.IP 2) 4 -Within a message list, the following designations may refer to messages -that do not exist: a single numeric message name, the single message name -\*(lqcur\*(rq, and (obviously) the single message name \*(lqnew\*(rq. -All other message designations must refer to at least one existing -message, if the folder contains messages. -.IP 3) 4 -An empty folder is not in itself an error. -.PP -Message numbers greater than the highest existing message in a folder -as part of a range designation are replaced with the next free message -number. -.PP -Examples: The current folder foo contains messages 3 5 6. -Cur is 4. -.PP -.RS 5 -.nf -% mhpath -/r/phyl/Mail/foo - -% mhpath all -/r/phyl/Mail/foo/3 -/r/phyl/Mail/foo/5 -/r/phyl/Mail/foo/6 - -% mhpath 2001 -/r/phyl/Mail/foo/7 - -% mhpath 1\-2001 -/r/phyl/Mail/foo/3 -/r/phyl/Mail/foo/5 -/r/phyl/Mail/foo/6 - -% mhpath new -/r/phyl/Mail/foo/7 - -% mhpath last new -/r/phyl/Mail/foo/6 -/r/phyl/Mail/foo/7 - -% mhpath last\-new -bad message list \*(lqlast\-new\*(rq. - -% mhpath cur -/r/phyl/Mail/foo/4 - -% mhpath 1\-2 -no messages in range \*(lq1\-2\*(rq. - -% mhpath first:2 -/r/phyl/Mail/foo/3 -/r/phyl/Mail/foo/5 - -% mhpath 1 2 -/r/phyl/Mail/foo/1 -/r/phyl/Mail/foo/2 -.fi -.RE -.PP -.B mhpath -is also useful in back\-quoted operations: -.PP -.RS 5 -.nf -% cd `mhpath +inbox` - -% echo `mhpath +` -/r/phyl/Mail -.fi -.RE -.PP - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -folder(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to none" -.fi - -.SH CONTEXT -None - -.SH BUGS -Like all -.B nmh -commands, -.B mhpath -expands and sorts -.RI [ msgs ]. -So don't -expect -.PP -.RS 5 -.nf -mv `mhpath 501 500` -.fi -.RE -.PP -to move 501 to 500. -Quite the reverse. But -.PP -.RS 5 -.nf -mv `mhpath 501` `mhpath 500` -.fi -.RE -.PP -will do the trick. -.PP -Out of range message 0 is treated far more severely than large out of -range message numbers. diff --git a/man/mhpath.man1 b/man/mhpath.man1 new file mode 100644 index 0000000..1c35fcd --- /dev/null +++ b/man/mhpath.man1 @@ -0,0 +1,170 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHPATH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhpath \- print full pathnames of nmh messages and folders +.SH SYNOPSIS +.HP 5 +.na +.B mhpath +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B mhpath +expands and sorts the message list `msgs' and writes the full +pathnames of the messages to the standard output separated by newlines. +If no `msgs' are specified, +.B mhpath +outputs the current mail folder's pathname +instead. If the only argument is `+', your mail storage location +(`Path') is output; this can be useful in shell scripts. +.PP +Contrasted with other +.B nmh +commands, a message argument to +.B mhpath +may often be intended for writing. Because of this: +.PP +.IP 1) 4 +the name `new' has been added to +.BR mhpath 's +list of +reserved message names (the others are `first', `last', +`prev', `next', `cur', and `all'). +The new message is equivalent to the message after the last message +in a folder (and equivalent to 1 in a folder without messages). +The `new' message may not be used as part of a message range. +.IP 2) 4 +Within a message list, the following designations may refer to messages +that do not exist: a single numeric message name, the single message name +`cur', and (obviously) the single message name `new'. +All other message designations must refer to at least one existing +message, if the folder contains messages. +.IP 3) 4 +An empty folder is not in itself an error. +.PP +Message numbers greater than the highest existing message in a folder +as part of a range designation are replaced with the next free message +number. +.PP +Examples: The current folder foo contains messages 3 5 6. +Cur is 4. +.PP +.RS 5 +.nf +% mhpath +/r/phyl/Mail/foo + +% mhpath all +/r/phyl/Mail/foo/3 +/r/phyl/Mail/foo/5 +/r/phyl/Mail/foo/6 + +% mhpath 2001 +/r/phyl/Mail/foo/7 + +% mhpath 1\-2001 +/r/phyl/Mail/foo/3 +/r/phyl/Mail/foo/5 +/r/phyl/Mail/foo/6 + +% mhpath new +/r/phyl/Mail/foo/7 + +% mhpath last new +/r/phyl/Mail/foo/6 +/r/phyl/Mail/foo/7 + +% mhpath last\-new +bad message list `last\-new'. + +% mhpath cur +/r/phyl/Mail/foo/4 + +% mhpath 1\-2 +no messages in range `1\-2'. + +% mhpath first:2 +/r/phyl/Mail/foo/3 +/r/phyl/Mail/foo/5 + +% mhpath 1 2 +/r/phyl/Mail/foo/1 +/r/phyl/Mail/foo/2 +.fi +.RE +.PP +.B mhpath +is also useful in back\-quoted operations: +.PP +.RS 5 +.nf +% cd `mhpath +inbox` + +% echo `mhpath +` +/r/phyl/Mail +.fi +.RE +.PP + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +folder(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to none" +.fi + +.SH CONTEXT +None + +.SH BUGS +Like all +.B nmh +commands, +.B mhpath +expands and sorts +.RI [ msgs ]. +So don't +expect +.PP +.RS 5 +.nf +mv `mhpath 501 500` +.fi +.RE +.PP +to move 501 to 500. +Quite the reverse. But +.PP +.RS 5 +.nf +mv `mhpath 501` `mhpath 500` +.fi +.RE +.PP +will do the trick. +.PP +Out of range message 0 is treated far more severely than large out of +range message numbers. diff --git a/man/mhpgp.man1 b/man/mhpgp.man1 new file mode 100644 index 0000000..7d5af3b --- /dev/null +++ b/man/mhpgp.man1 @@ -0,0 +1,63 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHPGP %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhpgp \- check PGP signatures and decrypt PGP messages using gnupg +.SH SYNOPSIS +.HP 5 +.na +.B mhpgp +.RB [ \-write ] +.RI [ msg ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B mhpgp +is a script to simplify verifying and decrypting PGP messages, +using gnupg. +.PP +.B mhpgp +can handle signatures and encryption in MIME and plain (non-MIME) format. +Signed messages are verified. +Encrypted messages are displayed with +.B show +in decrypted form, the signature is verified as well. +.PP +With the +.B \-write +switch, the decrypted message is stored into the current folder. +.PP +If no +.I msg +is given, the current message is used. +.PP +Trailing blanks are stripped from the lines before signature verification, +because non are expected to be present as RFC 3156 requests: +.PP +.RS 5 +[...] implementations MUST make sure that no trailing +whitespace is present after the MIME encoding has been applied. +.RE +.PP +If there is trailing whitespace, it was likely added mistakenly +during mail transfer. + +.SH FILES +None + +.SH "PROFILE COMPONENTS" +None + +.SH "SEE ALSO" +mhsign(1), gpg(1) + +.SH DEFAULTS +None + +.SH CONTEXT +None + +.SH BUGS +None diff --git a/man/mhshow.man b/man/mhshow.man deleted file mode 100644 index 27ebd95..0000000 --- a/man/mhshow.man +++ /dev/null @@ -1,605 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHSHOW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhshow \- display MIME messages -.SH SYNOPSIS -.HP 5 -.na -.B mhshow -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-file -.IR file ] -.RB [ \-part -.IR number ] -\&... -.RB [ \-type -.IR content ] -\&... -.RB [ \-serialonly " | " \-noserialonly ] -.RB [ \-pause " | " \-nopause ] -.RB [ \-form -.IR formfile ] -.RB [ \-rcache -.IR policy ] -.RB [ \-wcache -.IR policy ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B mhshow -command display contents of a MIME (multi-media) -message or collection of messages. -.PP -.B mhshow -manipulates multi-media messages as specified in -RFC\-2045 thru RFC\-2049. Currently -.B mhshow -only supports -encodings in message bodies, and does not support the encoding of -message headers as specified in RFC\-2047. -.PP -By default -.B mhshow -will display all parts of a multipart -message. By using the -.B \-part -and -.B \-type -switches, you may -limit the scope of -.B mhshow -to particular subparts (of a -multipart content) and/or particular content types. -.PP -The option -.B \-file -.I file -directs -.B mhshow -to use the specified file as -the source message, rather than a message from a folder. If you specify -this file as \*(lq-\*(rq, then -.B mhshow -will accept the source message -on the standard input. Note that the file, or input from standard input -should be a validly formatted message, just like any other -.B nmh -message. It should -.B NOT -be in mail drop format (to convert a file in -mail drop format to a folder of -.B nmh -messages, see -.BR inc (1)). -.PP -A part specification consists of a series of numbers separated by dots. -For example, in a multipart content containing three parts, these -would be named as 1, 2, and 3, respectively. If part 2 was also a -multipart content containing two parts, these would be named as 2.1 and -2.2, respectively. Note that the -.B \-part -switch is effective for only -messages containing a multipart content. If a message has some other -kind of content, or if the part is itself another multipart content, the -.B \-part -switch will not prevent the content from being acted upon. -.PP -A content specification consists of a content type and a subtype. -The initial list of \*(lqstandard\*(rq content types and subtypes can -be found in RFC\-2046. -.PP -A list of commonly used contents is briefly reproduced here: -.PP -.RS 5 -.nf -.ta \w'application 'u -Type Subtypes ----- -------- -text plain, enriched -multipart mixed, alternative, digest, parallel -message rfc822, partial, external-body -application octet-stream, postscript -image jpeg, gif, png -audio basic -video mpeg -.fi -.RE -.PP -A legal MIME message must contain a subtype specification. -.PP -To specify a content, regardless of its subtype, just use the -name of the content, e.g., \*(lqaudio\*(rq. To specify a specific -subtype, separate the two with a slash, e.g., \*(lqaudio/basic\*(rq. -Note that regardless of the values given to the `\-type' switch, a -multipart content (of any subtype listed above) is always acted upon. -Further note that if the `\-type' switch is used, and it is desirable to -act on a message/external-body content, then the `\-type' switch must -be used twice: once for message/external-body and once for the content -externally referenced. -.SS "Unseen Sequence" -If the profile entry \*(lqUnseen\-Sequence\*(rq is present and -non\-empty, then -.B mhshow -will remove each of the messages shown -from each sequence named by the profile entry. -.SS "Checking the Contents" -The -.B \-check -switch tells -.B mhshow -to check each content for an -integrity checksum. If a content has such a checksum (specified as a -Content-MD5 header field), then -.B mhshow -will attempt to verify the -integrity of the content. -.SS "Showing the Contents" -The headers of each message are displayed with the -.I mhlproc -(usually -.BR mhl ), -using the standard format file -.IR mhl.headers . -You may specify an alternate format file with the -.B \-form -.I formfile -switch. If the format file -.I mhl.null -is specified, then the display -of the message headers is suppressed. -.PP -Next, the contents are extracted from the message and are stored in -a temporary file. Usually, the name of the temporary file is the -word \*(lqmhshow\*(rq followed by a string of characters. Occasionally, -the method used to display a content (described next), requires that -the file end in a specific suffix. For example, the -.B soffice -command (part of the StarOffice package) can be used to display -Microsoft Word content, but it uses the suffix to determine how to display -the file. If no suffix is present, the file is not correctly loaded. -Similarily, older versions of the -.B gs -command append a \*(lq.ps\*(rq suffix to -the filename if one was missing. As a result, these cannot be used to read -the default temporary file. -.PP -To get around this, your profile can contain lines of the form: -.PP -.RS 5 -mhshow-suffix-/: -.RE -.PP -or -.PP -.RS 5 -mhshow-suffix-: -.RE -.PP -to specify a suffix which can be automatically added to the temporary -file created for a specific content type. For example, the following -lines might appear in your profile: -.PP -.RS 5 -.nf -mhshow-suffix-text: .txt -mhshow-suffix-application/msword: .doc -mhshow-suffix-application/PostScript: .ps -.fi -.RE -.PP -to automatically append a suffix to the temporary files. -.PP -The method used to display the different contents in the messages bodies -will be determined by a \*(lqdisplay string\*(rq. To find the display -string, -.B mhshow -will first search your profile for an entry of the form: -.PP -.RS 5 -mhshow-show-/ -.RE -.PP -to determine the display string. If this isn't found, -.B mhshow -will search for an entry of the form: -.PP -.RS 5 -mhshow-show- -.RE -.PP -to determine the display string. -.PP -If a display string is found, any escapes (given below) will be expanded. -The result will be executed under -\*(lq/bin/sh\*(rq, with the standard input -set to the content. -.PP -The display string may contain the following escapes: -.PP -.RS 5 -.nf -.ta \w'%F 'u -%a Insert parameters from Content-Type field -%e exclusive execution -%f Insert filename containing content -%F %e, %f, and stdin is terminal not content -%l display listing prior to displaying content -%p %l, and ask for confirmation -%s Insert content subtype -%d Insert content description -%% Insert the character % -.fi -.RE -.PP -For those display strings containing the e- or F-escape, -.B mhshow -will -execute at most one of these at any given time. Although the F-escape -expands to be the filename containing the content, the e-escape has no -expansion as far as the shell is concerned. -.PP -When the p-escape prompts for confirmation, typing INTR (usually -control-C) will tell -.B mhshow -not to display that content. -The p-escape can be disabled by specifying the switch -.BR \-nopause . -Further, when -.B mhshow -is display a content, typing QUIT (usually -control-\\) will tell -.B mhshow -to wrap things up immediately. -.PP -Note that if the content being displayed is multipart, but not one of -the subtypes listed above, then the f- and F-escapes expand to multiple -filenames, one for each subordinate content. Further, stdin is not -redirected from the terminal to the content. -.PP -If a display string is not found, -.B mhshow -has several default values: -.PP -.RS 5 -.nf -mhshow-show-text/plain: %pmoreproc '%F' -mhshow-show-message/rfc822: %pshow -file '%F' -.fi -.RE -.PP -If a subtype of type text doesn't have a profile entry, it will be -treated as text/plain. -.PP -.B mhshow -has default methods for handling multipart messages of subtype -mixed, alternative, parallel, and digest. Any unknown subtype of type -multipart (without a profile entry), will be treated as multipart/mixed. -.PP -If none of these apply, then -.B mhshow -will check to see if the message -has an application/octet-stream content with parameter \*(lqtype=tar\*(rq. -If so, -.B mhshow -will use an appropriate command. If not, -.B mhshow -will complain. -.PP -Example entries might be: -.PP -.RS 5 -.nf -mhshow-show-audio/basic: raw2audio 2>/dev/null | play -mhshow-show-image: xv '%f' -mhshow-show-application/PostScript: lpr -Pps -.fi -.RE -.PP -Note that when using the f- or F-escape, it's a good idea to use -single-quotes around the escape. This prevents misinterpretation by -the shell of any funny characters that might be present in the filename. -.PP -Finally, -.B mhshow -will process each message serially\0--\0it won't start -showing the next message until all the commands executed to display the -current message have terminated. In the case of a multipart content -(of any subtype listed above), the content contains advice indicating if -the parts should be displayed serially or in parallel. Because this may -cause confusion, particularly on uni-window displays, the -.B \-serialonly -switch can be given to tell -.B mhshow -to never display parts in parallel. -.SS "Showing Alternate Character Sets" -Because a content of type text might be in a non-ASCII character -set, when -.B mhshow -encounters a \*(lqcharset\*(rq parameter for -this content, it checks if your terminal can display this character -set natively. -.B mhn -checks this by examining the the environment -variable -.BR $MM_CHARSET . -If the value of this environment variable is equal -to the value of the charset parameter, then -.B mhshow -assumes it can -display this content without any additional setup. If this environment -variable is not set, -.B mhshow -will assume a value of \*(lqUS-ASCII\*(rq. -If the character set cannot be displayed natively, then -.B mhshow -will look for an entry of the form: -.PP -.RS 5 -mhshow-charset- -.RE -.PP -which should contain a command creating an environment to render -the character set. This command string should containing a single -\*(lq%s\*(rq, which will be filled-in with the command to display the -content. -.PP -Example entries might be: -.PP -.RS 5 -mhshow-charset-iso-8859-1: xterm -fn '-*-*-medium-r-normal-*-*-120-*-*-c-*-iso8859-*' -e %s -.RE -.PP -or -.PP -.RS 5 -mhshow-charset-iso-8859-1: '%s' -.RE -.PP -The first example tells -.B mhshow -to start -.B xterm -and load the -appropriate character set for that message content. The second example -tells -.B mhshow -that your pager (or other program handling that content -type) can handle that character set, and that no special processing is -needed beforehand. -.PP -Note that many pagers strip off the high-order bit or have problems -displaying text with the high-order bit set. However, the pager -.B less -has support for single-octet character sets. The source -to -.B less -is available on many ftp sites carrying free software. -In order to view messages sent in the ISO-8859-1 character set using -.BR less , -.PP -put these lines in your -.I \&.login -file: -.PP -.RS 5 -.nf -setenv LESSCHARSET latin1 -setenv LESS "-f" -.fi -.RE -.PP -The first line tells -.B less -to use the ISO-8859-1 definition for -determining whether a character is \*(lqnormal\*(rq, \*(lqcontrol\*(lq, -or \*(lqbinary\*(rq. The second line tells -.B less -not to warn you -if it encounters a file that has non-ASCII characters. Then, simply -set the -.I moreproc -profile entry to -.BR less , -and it will get -called automatically. (To handle other single-octet character sets, -look at the -.BR less (1) -manual entry for information about the -.B $LESSCHARDEF -environment variable.) -.SS "Messages of Type message/partial" -.B mhshow -cannot directly display messages of type partial. -You must reassemble them first into a normal message using -.BR mhstore . -Check the man page for -.BR mhstore (1) -for details. -.SS "External Access" -For contents of type message/external-body, -.B mhshow -supports these access-types: -.PP -.IP \(bu 4 -afs -.IP \(bu 4 -anon-ftp -.IP \(bu 4 -ftp -.IP \(bu 4 -local-file -.IP \(bu 4 -mail-server -.PP -For the \*(lqanon-ftp\*(rq and \*(lqftp\*(rq access types, -.B mhshow -will look for the \*(lqnmh-access-ftp\*(rq -profile entry, e.g., -.PP -.RS 5 -nmh-access-ftp: myftp.sh -.RE -.PP -to determine the pathname of a program to perform the FTP retrieval. -.PP -This program is invoked with these arguments: -.PP -.RS 5 -.nf -domain name of FTP-site -username -password -remote directory -remote filename -local filename -\*(lqascii\*(rq or \*(lqbinary\*(rq -.fi -.RE -.PP -The program should terminate with an exit status of zero if the -retrieval is successful, and a non-zero exit status otherwise. -.PP -If this entry is not provided, then -.B mhshow -will use a simple -built-in FTP client to perform the retrieval. -.SS "The Content Cache" -When -.B mhshow -encounters an external content containing a -\*(lqContent-ID:\*(rq field, and if the content allows caching, then -depending on the caching behavior of -.BR mhshow , -the content might be read from or written to a cache. -.PP -The caching behavior of -.B mhshow -is controlled with the -.B \-rcache -and -.B \-wcache -switches, which define the policy for reading from, -and writing to, the cache, respectively. One of four policies may be -specified: \*(lqpublic\*(rq, indicating that -.B mhshow -should make use -of a publically-accessible content cache; \*(lqprivate\*(rq, indicating -that -.B mhshow -should make use of the user's private content cache; -\*(lqnever\*(rq, indicating that -.B mhshow -should never make use of -caching; and, \*(lqask\*(rq, indicating that -.B mhshow -should ask the user. -.PP -There are two directories where contents may be cached: the profile entry -\*(lqnmh-cache\*(rq names a directory containing world-readable contents, and, -the profile entry \*(lqnmh-private-cache\*(rq names a directory containing -private contents. The former should be an absolute (rooted) directory -name. -.PP -For example, -.PP -.RS 5 -nmh-cache: /tmp -.RE -.PP -might be used if you didn't care that the cache got wiped after each -reboot of the system. The latter is interpreted relative to the user's -nmh directory, if not rooted, e.g., -.PP -.RS 5 -nmh-private-cache: .cache -.RE -.PP -(which is the default value). -.SS "User Environment" -Because the display environment in which -.B mhshow -operates may vary for -different machines, -.B mhshow -will look for the environment variable -.BR $MHSHOW . -If present, this specifies the name of an additional -user profile which should be read. Hence, when a user logs in on a -particular display device, this environment variable should be set to -refer to a file containing definitions useful for the given display device. -Normally, only entries that deal with the methods to display different -content type and subtypes -.PP -.RS 5 -.nf -mhshow-show-/ -mhshow-show- -.fi -.RE -.PP -need be present in this additional profile. Finally, -.B mhshow -will attempt to consult one other additional user profile, -e.g., -.PP -.RS 5 -%etcdir%/mhn.defaults -.RE -.PP -which is created automatically during -.B nmh -installation. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^$MHSHOW~^Additional profile entries -^%etcdir%/mhn.defaults~^System default MIME profile entries -^%etcdir%/mhl.headers~^The headers template -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Unseen\-Sequence:~^To name sequences denoting unseen messages -^mhlproc:~^Default program to display message headers -^nmh-access-ftp:~^Program to retrieve contents via FTP -^nmh-cache~^Public directory to store cached external contents -^nmh-private-cache~^Personal directory to store cached external contents -^mhshow-charset-~^Template for environment to render character sets -^mhshow-show-*~^Template for displaying contents -^moreproc:~^Default program to display text/plain content -.fi - -.SH "SEE ALSO" -mhbuild(1), mhl(1), mhlist(1), mhstore(1), sendfiles(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-nocheck ' -.RB ` \-form mhl.headers ' -.RB ` \-pause ' -.RB ` \-rcache ask ' -.RB ` \-realsize ' -.RB ` \-noserialonly ' -.RB ` \-noverbose ' -.RB ` \-wcache ask ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The last -message selected will become the current message. diff --git a/man/mhsign.man1 b/man/mhsign.man1 new file mode 100644 index 0000000..3999152 --- /dev/null +++ b/man/mhsign.man1 @@ -0,0 +1,105 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHSIGN %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhsign \- sign or encrypt a message with gnupg +.SH SYNOPSIS +.HP 5 +.na +.B mhsign +.RB [ \-encrypt ] +.RB [ \-mime ] +.I file +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B mhsign +is a script to simplify signing and encrypting, using gnupg. +.PP +.B mhsign +is normally invoked automatically by +.BR send . +When used directly, the source file, typically an MH draft file, +is replaced by the signed or encrypted message. +To permit recovery from mistakes, +a backup copy of the original file is saved, under the same name +with `.orig' appended. +.PP +The following options are recognized: +.TP +.B \-encrypt +Encrypt to recipients, in addition to signing. +The message will also be encrypted to the signing key. +.TP +.B \-mime +Use the PGP/MIME standard for signing and encrypting. +This is automatic if the message is already a multipart MIME message. +Otherwise the default is to sign/encrypt in the old-fashioned +non-MIME manner, for compatibility with older software. +.QP +When a message is signed but not encrypted, using the PGP/MIME +formatting, any line beginning with ``From '' will be indented, and any +trailing spaces will be removed from lines in the message body. +This is to ensure maximum compatibility. +Where trailing blanks are important (sending patches, for example), +it would be wise to use quoted-printable or other MIME encoding +for that component. +.PP +The signing key is automatically determinded by gnupg, +unless the the profile entry +.IR Pgpkey +defines it. +The environment variable +.IR MMHPGPKEY +has highest precedence and can be used to overrule the key uid temporarily. +.PP +For encryption, the public keys of the recipients are taken from +the gnupg keyring. +To handle exceptions, e.g. recipient addresses that do not +match the key uid in the keyring, a file named +.I pgpkeys +may be used. +It should be located either in the gnupg directory (normally $HOME/.gnupg) +or in the mmh directory (normally $HOME/.mmh). +If both files exist, the one in the gnupg directory takes precedence. +.PP +A sample +.I pgpkeys +file: +.sp +.RS 5 +.nf +0x88888888 john@nowhere.example.org +e5fda812 meillo@marmaro.de +.fi +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.gnupg/pgpkeys~^Pubkey exceptions for encrypting +^$HOME/.mmh/pgpkeys~^... alternative location +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Pgpkey:~^To determine the user's signing key +.fi + +.SH "SEE ALSO" +whom(1), send(1), mhpgp(1), gpg(1) + +.SH DEFAULTS +None + +.SH CONTEXT +None + +.SH BUGS +None diff --git a/man/mhstore.man b/man/mhstore.man deleted file mode 100644 index af05bf2..0000000 --- a/man/mhstore.man +++ /dev/null @@ -1,479 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MHSTORE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -mhstore \- store contents of MIME messages into files -.SH SYNOPSIS -.HP 5 -.na -.B mhstore -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-file -.IR file ] -.RB [ \-part -.IR number ] -\&... -.RB [ \-type -.IR content ] -\&... -.RB [ \-auto " | " \-noauto ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-rcache -.IR policy ] -.RB [ \-wcache -.IR policy ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B mhstore -command allows you to store the contents of a -collection of MIME (multi-media) messages into files or other -messages. -.PP -.B mhstore -manipulates multi-media messages as specified in -RFC\-2045 thru RFC\-2049. -.PP -By default, -.B mhstore -will store all the parts of each message. -Each part will be store in a separate file. The header fields of -the message are not stored. By using the -.B \-part -and -.B \-type -switches, you may limit the scope of -.B mhstore -to particular -subparts (of a multipart content) and/or particular content types. -.PP -The option -.B \-file -.I file -directs -.B mhstore -to use the specified -file as the source message, rather than a message from a folder. -If you specify this file as \*(lq-\*(rq, then -.B mhstore -will -accept the source message on the standard input. Note that the -file, or input from standard input should be a validly formatted -message, just like any other -.B nmh -message. It should -.B NOT -be in mail drop format (to convert a file in mail drop format to -a folder of -.B nmh -messages, see -.BR inc (1)). -.PP -A part specification consists of a series of numbers separated by -dots. For example, in a multipart content containing three parts, -these would be named as 1, 2, and 3, respectively. If part 2 was -also a multipart content containing two parts, these would be named -as 2.1 and 2.2, respectively. Note that the -.B \-part -switch is -effective for only messages containing a multipart content. If a -message has some other kind of content, or if the part is itself -another multipart content, the -.B \-part -switch will not prevent -the content from being acted upon. -.PP -A content specification consists of a content type and a subtype. -The initial list of \*(lqstandard\*(rq content types and subtypes -can be found in RFC\-2046. -.PP -A list of commonly used contents is briefly reproduced here: -.PP -.RS 5 -.nf -.ta \w'application 'u -Type Subtypes ----- -------- -text plain, enriched -multipart mixed, alternative, digest, parallel -message rfc822, partial, external-body -application octet-stream, postscript -image jpeg, gif, png -audio basic -video mpeg -.fi -.RE -.PP -A legal MIME message must contain a subtype specification. -.PP -To specify a content, regardless of its subtype, just use the name -of the content, e.g., \*(lqaudio\*(rq. To specify a specific -subtype, separate the two with a slash, e.g., \*(lqaudio/basic\*(rq. -Note that regardless of the values given to the -.B \-type -switch, -a multipart content (of any subtype listed above) is always acted -upon. Further note that if the -.B \-type -switch is used, and it is -desirable to act on a message/external-body content, then the -.B \-type -switch must be used twice: once for message/external-body -and once for the content externally referenced. -.SS "Checking the Contents" -The -.B \-check -switch tells -.B mhstore -to check each content for -an integrity checksum. If a content has such a checksum (specified -as a Content-MD5 header field), then -.B mhstore -will attempt to -verify the integrity of the content. -.SS "Storing the Contents" -The -.B mhstore -will store the contents of the named messages in -\*(lqnative\*(rq (decoded) format. Two things must be determined: -the directory to store the content, and the filenames. Files are -written in the directory given by the \*(lqnmh-storage\*(rq profile -entry, e.g., -.PP -.RS 5 -nmh-storage: /tmp -.RE -.PP -If this entry isn't present, -the current working directory is used. -.PP -If the -.B \-auto -switch is given, then -.B mhstore -will check if -the message contains information indicating the filename that should -be used to store the content. This information should be specified -as the attribute \*(lqname=filename\*(rq in the \*(lqContent-Type\*(rq header -for the content you are storing. For security reasons, this filename -will be ignored if it begins with the character '/', '.', '|', or '!', -or if it contains the character '%'. For the sake of security, -this switch is not the default, and it is recommended that you do -NOT put the -.B \-auto -switch in your -.I \&.mh\(ruprofile -file. -.PP -If the -.B \-auto -switch is not given (or is being ignored for security -reasons) then -.B mhstore -will look in the user's profile for a -\*(lqformatting string\*(rq to determine how the different contents -should be stored. First, -.B mhstore -will look for an entry of -the form: -.PP -.RS 5 -mhstore-store-/ -.RE -.PP -to determine the formatting string. If this isn't found, -.B mhstore -will look for an entry of the form: -.PP -.RS 5 -mhstore-store- -.RE -.PP -to determine the formatting string. -.PP -If the formatting string starts with a \*(lq+\*(rq character, then -content is stored in the named folder. A formatting string consisting -solely of a \*(lq+\*(rq character is interpreted to be the current -folder. -.PP -If the formatting string consists solely of a \*(lq-\*(rq character, -then the content is sent to the standard output. -.PP -If the formatting string starts with a '|', then the display string -will represent a command for -.B mhstore -to execute which should -ultimately store the content. The content will be passed to the -standard input of the command. Before the command is executed, -.B mhstore -will change to the appropriate directory, and any -escapes (given below) in the display string will be expanded. -.PP -Otherwise the formatting string will represent a pathname in which -to store the content. If the formatting string starts with a '/', -then the content will be stored in the full path given, else the -file name will be relative to the value of \*(lqnmh-storage\*(rq or -the current working directory. Any escapes (given below) will be -expanded, except for the a-escape. -.PP -A command or pathname formatting string may contain the following -escapes. If the content isn't part of a multipart (of any subtype -listed above) content, the p-escapes are ignored. -.PP -.RS 5 -.nf -.ta \w'%P 'u -%a Parameters from Content-type (only valid with command) -%m Insert message number -%P Insert part number with leading dot -%p Insert part number without leading dot -%t Insert content type -%s Insert content subtype -%% Insert character % -.fi -.RE -.PP -If no formatting string is found, -.B mhstore -will check to see -if the content is application/octet-stream with parameter -\*(lqtype=tar\*(rq. If so, -.B mhstore -will choose an appropriate -filename. If the content is not application/octet-stream, then -.B mhstore -will check to see if the content is a message. If -so, -.B mhstore -will use the value \*(lq+\*(rq. As a last resort, -.B mhstore -will use the value \*(lq%m%P.%s\*(rq. -.PP -Example profile entries might be: -.PP -.RS 5 -.nf -mhstore-store-text: %m%P.txt -mhstore-store-text: +inbox -mhstore-store-message/partial: + -mhstore-store-audio/basic: | raw2audio -e ulaw -s 8000 -c 1 > %m%P.au -mhstore-store-image/jpeg: %m%P.jpg -mhstore-store-application/PostScript: %m%P.ps -.fi -.RE -.PP -.SS "Reassembling Messages of Type message/partial" -.B mhstore -is also able to reassemble messages that have been -split into multiple messages of type \*(lqmessage/partial\*(rq. -.PP -When asked to store a content containing a partial message, -.B mhstore -will try to locate all of the portions and combine -them accordingly. The default is to store the combined parts as -a new message in the current folder, although this can be changed -using formatting strings as discussed above. Thus, if someone has -sent you a message in several parts (such as the output from -.BR sendfiles ), -you can easily reassemble them all into a single -message in the following fashion: -.PP -.RS 5 -.nf -% mhlist 5-8 - msg part type/subtype size description - 5 message/partial 47K part 1 of 4 - 6 message/partial 47K part 2 of 4 - 7 message/partial 47K part 3 of 4 - 8 message/partial 18K part 4 of 4 -% mhstore 5-8 -reassembling partials 5,6,7,8 to folder inbox as message 9 -% mhlist -verbose 9 - msg part type/subtype size description - 9 application/octet-stream 118K - (extract with uncompress | tar xvpf -) - type=tar - conversions=compress -.fi -.RE -.PP -This will store exactly one message, containing the sum of the -parts. It doesn't matter whether the partials are specified in -order, since -.B mhstore -will sort the partials, so that they -are combined in the correct order. But if -.B mhstore -can not -locate every partial necessary to reassemble the message, it will -not store anything. -.SS "External Access" -For contents of type message/external-body, -\fImhstore\fR supports these access-types: -.PP -.IP \(bu 4 -afs -.IP \(bu 4 -anon-ftp -.IP \(bu 4 -ftp -.IP \(bu 4 -local-file -.IP \(bu 4 -mail-server -.PP -For the \*(lqanon-ftp\*(rq and \*(lqftp\*(rq access types, -.B mhstore -will look for the \*(lqnmh-access-ftp\*(rq -profile entry, e.g., -.PP -.RS 5 -nmh-access-ftp: myftp.sh -.RE -.PP -to determine the pathname of a program to perform the FTP retrieval. -This program is invoked with these arguments: -.PP -.RS 5 -.nf -domain name of FTP-site -username -password -remote directory -remote filename -local filename -\*(lqascii\*(rq or \*(lqbinary\*(rq -.fi -.RE -.PP -The program should terminate with an exit status of zero if the -retrieval is successful, and a non-zero exit status otherwise. -.PP -If this entry is not provided, then -.B mhstore -will use a simple -built-in FTP client to perform the retrieval. -.SS "The Content Cache" -When -.B mhstore -encounters an external content containing a -\*(lqContent-ID:\*(rq field, and if the content allows caching, then -depending on the caching behavior of -.BR mhstore , -the content might be read from or written to a cache. -.PP -The caching behavior of -.B mhstore -is controlled with the -.B \-rcache -and -.B \-wcache -switches, which define the policy for reading from, -and writing to, the cache, respectively. One of four policies may be -specified: \*(lqpublic\*(rq, indicating that -.B mhstore -should make use -of a publically-accessible content cache; \*(lqprivate\*(rq, indicating -that -.B mhstore -should make use of the user's private content cache; -\*(lqnever\*(rq, indicating that -.B mhstore -should never make use of -caching; and, \*(lqask\*(rq, indicating that -.B mhstore -should ask the user. -.PP -There are two directories where contents may be cached: the profile entry -\*(lqnmh-cache\*(rq names a directory containing world-readable contents, and, -the profile entry \*(lqnmh-private-cache\*(rq names a directory containing -private contents. The former should be an absolute (rooted) directory -name. -.PP -For example, -.PP -.RS 5 -nmh-cache: /tmp -.RE -.PP -might be used if you didn't care that the cache got wiped after each -reboot of the system. The latter is interpreted relative to the user's -nmh directory, if not rooted, e.g., -.PP -.RS 5 -nmh-private-cache: .cache -.RE -.PP -(which is the default value). -.SS "User Environment" -Because the display environment in which -.B mhstore -operates may vary for -different machines, -.B mhstore -will look for the environment variable -.BR $MHSTORE . -If present, this specifies the name of an additional -user profile which should be read. Hence, when a user logs in on a -particular machine, this environment variable should be set to -refer to a file containing definitions useful for that machine. -Finally, -.B mhstore -will attempt to consult one other additional -user profile, e.g., -.PP -.RS 5 -%etcdir%/mhn.defaults -.RE -.PP -which is created automatically during -.B nmh -installation. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^$MHSTORE~^Additional profile entries -^%etcdir%/mhn.defaults~^System default MIME profile entries -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^nmh-access-ftp:~^Program to retrieve contents via FTP -^nmh-cache~^Public directory to store cached external contents -^nmh-private-cache~^Personal directory to store cached external contents -^nmh-storage~^Directory to store contents -^mhstore-store-*~^Template for storing contents -.fi - -.SH "SEE ALSO" -mhbuild(1), mhlist(1), mhshow(1), sendfiles(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-noauto ' -.RB ` \-nocheck ' -.RB ` \-rcache ask ' -.RB ` \-wcache ask ' -.RB ` \-noverbose ' - -.SH CONTEXT -If a folder is given, it will become the current folder. The last -message selected will become the current message. - -.SH BUGS -Partial messages contained within a multipart content are not reassembled. diff --git a/man/mhstore.man1 b/man/mhstore.man1 new file mode 100644 index 0000000..8445a5f --- /dev/null +++ b/man/mhstore.man1 @@ -0,0 +1,353 @@ +.\" +.\" %nmhwarning% +.\" +.TH MHSTORE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mhstore \- store contents of MIME messages into files +.SH SYNOPSIS +.HP 5 +.na +.B mhstore +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-file +.IR file ] +.RB [ \-part +.IR number ] +\&... +.RB [ \-type +.IR content ] +\&... +.RB [ \-auto " | " \-noauto ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B mhstore +command allows you to store the contents of a +collection of MIME (multi-media) messages into files or other +messages. +.PP +.B mhstore +manipulates multi-media messages as specified in +RFC\-2045 thru RFC\-2049. +.PP +By default, +.B mhstore +will store all the parts of each message. +Each part will be store in a separate file. The header fields of +the message are not stored. By using the +.B \-part +and +.B \-type +switches, you may limit the scope of +.B mhstore +to particular +subparts (of a multipart content) and/or particular content types. +.PP +The option +.B \-file +.I file +directs +.B mhstore +to use the specified +file as the source message, rather than a message from a folder. +If you specify this file as `-', then +.B mhstore +will +accept the source message on the standard input. Note that the +file, or input from standard input should be a validly formatted +message, just like any other +.B nmh +message. It should +.B NOT +be in mail drop format (to convert a file in mail drop format to +a folder of +.B nmh +messages, see +.BR inc (1)). +.PP +A part specification consists of a series of numbers separated by +dots. For example, in a multipart content containing three parts, +these would be named as 1, 2, and 3, respectively. If part 2 was +also a multipart content containing two parts, these would be named +as 2.1 and 2.2, respectively. Note that the +.B \-part +switch is +effective for only messages containing a multipart content. If a +message has some other kind of content, or if the part is itself +another multipart content, the +.B \-part +switch will not prevent +the content from being acted upon. +.PP +A content specification consists of a content type and a subtype. +The initial list of `standard' content types and subtypes +can be found in RFC\-2046. +.PP +A list of commonly used contents is briefly reproduced here: +.PP +.RS 5 +.nf +.ta \w'application 'u +Type Subtypes +---- -------- +text plain, enriched +multipart mixed, alternative, digest, parallel +message rfc822, partial, external-body +application octet-stream, postscript +image jpeg, gif, png +audio basic +video mpeg +.fi +.RE +.PP +A legal MIME message must contain a subtype specification. +.PP +To specify a content, regardless of its subtype, just use the name +of the content, e.g., `audio'. To specify a specific +subtype, separate the two with a slash, e.g., `audio/basic'. +Note that regardless of the values given to the +.B \-type +switch, +a multipart content (of any subtype listed above) is always acted +upon. +.SS "Storing the Contents" +The +.B mhstore +will store the contents of the named messages in +`native' (decoded) format. Two things must be determined: +the directory to store the content, and the filenames. +.PP +By default (or if the +.B \-auto +switch is given), +.B mhstore +uses filename information, contained in the message, if available. +(This information should be specified +as the attribute `name=filename' in the `Content-Type' header +for the content you are storing.) +Only the basename of this filename is considered. +If it begins with the character '.', '|', or '!', +or if it contains the character '%', automatic naming won't happen for +security reasons. (See below for the fall-back.) +.PP +Files are +written in the directory given by the `nmh-storage' profile +entry, e.g., +.PP +.RS 5 +nmh-storage: /tmp +.RE +.PP +(Note that `nmh-storage' is relative to the folder that contains +the message.) +If this entry isn't present, +the current working directory is used. +Attachments will get stored in either the `nmh-storage' or the current working +directory \(en in no case elsewhere. +Existing files get silently overwritten. +.PP +If the +.B \-noauto +switch is given (or a filename is being ignored for security reasons) then +.B mhstore +will look in the user's profile for a +`formatting string' to determine how the different contents +should be stored. First, +.B mhstore +will look for an entry of +the form: +.PP +.RS 5 +mhstore-store-/ +.RE +.PP +to determine the formatting string. If this isn't found, +.B mhstore +will look for an entry of the form: +.PP +.RS 5 +mhstore-store- +.RE +.PP +to determine the formatting string. +.PP +If the formatting string starts with a `+' character, then +content is stored in the named folder. A formatting string consisting +solely of a `+' character is interpreted to be the current +folder. +.PP +If the formatting string consists solely of a `\-' character, +then the content is sent to the standard output. +.PP +If the formatting string starts with a '|', then the display string +will represent a command for +.B mhstore +to execute which should +ultimately store the content. The content will be passed to the +standard input of the command. Before the command is executed, +.B mhstore +will change to the appropriate directory, and any +escapes (given below) in the display string will be expanded. +.PP +Otherwise the formatting string will represent a pathname in which +to store the content. If the formatting string starts with a '/', +then the content will be stored in the full path given, else the +file name will be relative to either the value of `nmh-storage', +if set, or the current working directory. +Existing files get silently overwritten. +.PP +A command or pathname formatting string may contain the following +escapes. If the content isn't part of a multipart (of any subtype +listed above) content, the p-escapes are ignored. +.PP +.RS 5 +.nf +.ta \w'%P 'u +%a Parameters from Content-type (only valid with command) +%m Insert message number +%P Insert part number with leading dot +%p Insert part number without leading dot +%t Insert content type +%s Insert content subtype +%% Insert character % +.fi +.RE +.PP +If no formatting string is found, +.B mhstore +will check to see if the content is a message. If +so, +.B mhstore +will use the value `+'. As a last resort, +.B mhstore +will use the value `%m%P.%s'. +.PP +Example profile entries might be: +.PP +.RS 5 +.nf +mhstore-store-text: %m%P.txt +mhstore-store-text: +inbox +mhstore-store-message/partial: + +mhstore-store-audio/basic: | raw2audio -e ulaw -s 8000 -c 1 > %m%P.au +mhstore-store-image/jpeg: %m%P.jpg +mhstore-store-application/PostScript: %m%P.ps +.fi +.RE +.PP +.SS "Reassembling Messages of Type message/partial" +.B mhstore +is also able to reassemble messages that have been +split into multiple messages of type `message/partial'. +.PP +When asked to store a content containing a partial message, +.B mhstore +will try to locate all of the portions and combine +them accordingly. The default is to store the combined parts as +a new message in the current folder, although this can be changed +using formatting strings as discussed above. Thus, if someone has +sent you a message in several parts (such as the output from +.BR sendfiles ), +you can easily reassemble them all into a single +message in the following fashion: +.PP +.RS 5 +.nf +% mhlist 5-8 + msg part type/subtype size description + 5 message/partial 47K part 1 of 4 + 6 message/partial 47K part 2 of 4 + 7 message/partial 47K part 3 of 4 + 8 message/partial 18K part 4 of 4 +% mhstore 5-8 +reassembling partials 5,6,7,8 to folder inbox as message 9 +% mhlist 9 + msg part type/subtype size description + 9 application/octet-stream 118K + (extract with uncompress | tar xvpf -) + type=tar + conversions=compress +.fi +.RE +.PP +This will store exactly one message, containing the sum of the +parts. It doesn't matter whether the partials are specified in +order, since +.B mhstore +will sort the partials, so that they +are combined in the correct order. But if +.B mhstore +can not +locate every partial necessary to reassemble the message, it will +not store anything. +.RE +.SS "External Access" +.B Mhstore +does not automatically retrieve message/external-body parts (anymore), +but prints the relevant information to enable the user to retrieve +the files manually. +.SS "User Environment" +Because the display environment in which +.B mhstore +operates may vary for +different machines, +.B mhstore +will look for the environment variable +.BR $MHSTORE . +If present, this specifies the name of an additional +user profile which should be read. Hence, when a user logs in on a +particular machine, this environment variable should be set to +refer to a file containing definitions useful for that machine. +Finally, +.B mhstore +will attempt to consult one other additional +user profile, e.g., +.PP +.RS 5 +%etcdir%/mhn.defaults +.RE +.PP +which is created automatically during +.B nmh +installation. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^$MHSTORE~^Additional profile entries +^%etcdir%/mhn.defaults~^System default MIME profile entries +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^nmh-storage~^Directory to store contents +^mhstore-store-*~^Template for storing contents +.fi + +.SH "SEE ALSO" +mhbuild(1), mhlist(1), show(1), sendfiles(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-auto ' + +.SH CONTEXT +If a folder is given, it will become the current folder. The last +message selected will become the current message. + +.SH BUGS +Partial messages contained within a multipart content are not reassembled. +.PP +Existing files get silently overwritten. diff --git a/man/mmh-intro.man7 b/man/mmh-intro.man7 new file mode 100644 index 0000000..e9d0f13 --- /dev/null +++ b/man/mmh-intro.man7 @@ -0,0 +1,291 @@ +.\" +.\" %nmhwarning% +.\" +.TH NMH %manext7% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mmh \- Introduction to the Modern MH message system +.SH DESCRIPTION +.B mmh +is a powerful message handling system, based on +.BR nmh , +which in turn bases on MH, the Rand Corporation's Message Handler. +.PP +Rather than +being a single comprehensive program, +.B mmh +consists of a collection +of fairly simple single-purpose programs to send, retrieve, organize, +and manipulate messages. +.PP +Unlike most other mail clients, +.B mmh +is not a closed system which +must be explicitly run, then exited when you wish to return to the shell. +Instead, you may freely intersperse +.B mmh +commands with other shell commands, +allowing you to read and answer your mail while you +search for a file or run programs as needed +to find the answer to someone's question before answering their mail. +.PP +The rest of this manual entry is a quick tutorial which will teach you +the basics of +.BR mmh . +You should read the manual entries for the +individual programs for complete documentation. +.PP +To get started using +.BR mmh , +put the directory +.I %bindir% +on your +.BR $PATH . +This is best done in one of the files: +.IR \&.profile , +.IR \&.login , +.IR \&.bashrc , +or +.I \&.cshrc +in your home directory. (Check the +manual entry for the shell you use, in case you don't know how to +do this.) Run the +.B mmh +command. If you've never used +.B mmh +before, it will create the necessary default files and directories after +asking you if you wish it to do so. +.PP +.B inc +moves mail from your system maildrop into your +.B mmh +`+inbox' folder, converting it to the MH format (one file per message). +It prints one line for each message it +processes, containing the date, from and subject fields. +It leaves the first message it processes as your current message. +You'll need to run +.B inc +each time you wish to incorporate new mail into your +.B mmh +mail storage. +.PP +.B scan +prints a list of the messages in your current folder. +.PP +The commands: +.BR show , +.BR next , +and +.B prev +are used to read +specific messages from the current folder. +.B show +displays the +current message, or a specific message, which may be specified by its +number, which you pass as an argument to +.BR show . +.B next +and +.B prev +display, respectively, the message numerically after or before +the current message. In all cases, the message displayed becomes the +current message. If there is no current message, +.B show +may be +called with an argument, or +.B next +may be used to advance to the +first message. +.PP +.B rmm +(remove message) deletes the current message. It may be called +with message numbers passed as arguments, to delete specific messages. +.PP +.B repl +is used to respond to the current message (by default). +It places you in the editor with a prototype response form. +After completing your response, type +.B l +to +.B list +(review) it, or +.B s +to +.B send +it. +.PP +.B comp +allows you to compose a message by putting you in the editor +on a prototype message form, and then lets you send it. +.PP +All the +.B mmh +commands may be run with the single argument: +.BR \-help , +which causes them to print a list of the arguments they may be invoked +with and then exit. +.PP +Commands which take a message number as an argument +.RB ( scan , +.BR show , +.BR repl , +\&...) also take one of the letters: `f', +`p', `c', `n', or `l' to indicate +(respectively) the first, previous, current, next, or last message in +the current folder (assuming they are defined). + +Commands which take a range of message numbers +.RB ( rmm , +.BR scan , +.BR show , +\&...) also take any of the abbreviations: +.PP +.RS 5 +.IP \fI\fR\-\fI\fR 15 +Indicates all messages in the range to , inclusive. The range must be nonempty. +.IP \fI\fR:+\fIN\fR 15 +.IP \fI\fR:\-\fIN\fR 15 +Up to +.I N +messages beginning with (or ending with) message +.IR num . +.I Num +may be any of the pre-defined symbols: +.IR f , +.IR p , +.IR c , +.I n +or +.IR l . +.IP f:\fIN\fR 15 +.IP p:\fIN\fR 15 +.IP n:\fIN\fR 15 +.IP l:\fIN\fR 15 +The first, previous, next or last +messages, if they exist. +.RE +.PP +There are many other possibilities such as creating multiple folders +for different topics, and automatically refiling messages according to +subject, source, destination, or content. These are beyond the scope +of this manual entry. +.PP +Following is a list of all the +.B mmh +commands: +.PP +.RS 5 +.fc ^ ~ +.nf +.ta 1.5i +^ali(1)~^\- list mail aliases +^anno(1)~^\- annotate messages +^burst(1)~^\- explode digests into messages +^comp(1)~^\- compose a message +^dist(1)~^\- redistribute a message to additional addresses +^flist(1)~^\- list folders with messages in given sequence(s) +^flists(1)~^\- list all folders with messages in given sequence(s) +^folder(1)~^\- set/list current folder/message +^folders(1)~^\- list all folders +^forw(1)~^\- forward messages +^inc(1)~^\- incorporate new mail +^mark(1)~^\- mark messages +^mhbuild(1)~^\- translate MIME composition draft +^mhl(1)~^\- produce formatted listings of mmh messages +^mhlist(1)~^\- list information about content of MIME messages +^mhmail(1)~^\- send mail (mailx replacement) +^mhparam(1)~^\- print mmh profile components +^mhpath(1)~^\- print full pathnames of mmh messages and folders +^mhpgp(1)~^\- verify and decrypt a message with gnupg +^mhsign(1)~^\- sign or encrypt a message with gnupg +^mhstore(1)~^\- store contents of MIME messages into files +^mmh(1)~^\- initialize the mmh environment +^next(1)~^\- show the next message +^packf(1)~^\- pack a folder into mbox format +^pick(1)~^\- select messages by content +^prev(1)~^\- show the previous message +^prompter(1)~^\- prompting editor front end +^rcvdist(1)~^\- asynchronously redistribute new mail +^rcvpack(1)~^\- asynchronously append a message to an mbox file +^rcvstore(1)~^\- asynchronously incorporate new mail +^refile(1)~^\- file messages in other folders +^repl(1)~^\- reply to a message +^rmf(1)~^\- remove folder +^rmm(1)~^\- remove messages +^scan(1)~^\- produce a one line per message scan listing +^send(1)~^\- send a message +^sendfiles(1)~^\- send multiple files and directories in MIME message +^show(1)~^\- display MIME messages +^slocal(1)~^\- asynchronously filter and deliver new mail +^sortm(1)~^\- sort messages +^whatnow(1)~^\- prompting front\-end for send +^whom(1)~^\- list recipients of a message +.sp +^ap(8)~^\- parse addresses 822\-style +^dp(8)~^\- parse dates 822\-style +^fmtdump(8)~^\- decode \fImmh\fP format files +^post(8)~^\- deliver a message +.fi +.RE +.PP +The following man pages describe file formats and concepts: +.PP +.RS 5 +.fc ^ ~ +.nf +.ta 1.5i +^mh\-alias(5)~^\- alias file for mmh message system +^mh\-format(5)~^\- format file for mmh message system +^mh\-mail(5)~^\- message format for mmh message system +^mh\-profile(5)~^\- user customization for mmh message system +^mh\-tailor(5)~^\- mail transport customization for mmh message system +.sp +^mmh(7)~^\- introduction to the mmh message system +^mh\-draft(7)~^\- draft folder facility +^mh\-sequence(7)~^\- sequence specification for mmh message system +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%bindir%~^contains \fImmh\fR commands +^%etcdir%~^contains \fImmh\fR format files +^%libdir%~^contains \fImmh\fR library commands +^$HOME/.mmh~^The user's mmh directory +^$HOME/.mmh/profile~^The user's profile +^$HOME/.mmh/context~^The user's context +^$HOME/Mail~^Default location of the user's mail storage +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'LongName 'u +^Path:~^Location of the user's mail storage +.fi + +.SH HISTORY +.B mmh +is an experimental version of +.BR nmh , +the New Mail Handler. +Its name ``mmh'' stands for ``meillo's mail handler''. + +.SH BUGS +If you encounter problems with an +.B mmh +program, please report them. +When doing this, include the version information, which you can obtain +by invoking the program with the +.B \-Version +switch. +.PP +Send bug reports, comments, and suggestions to +.I "markus schnalke +or to +.IR . + +.SH "SEE ALSO" +mmh(1) +mh-chart(1) diff --git a/man/mmh.man1 b/man/mmh.man1 new file mode 100644 index 0000000..0069435 --- /dev/null +++ b/man/mmh.man1 @@ -0,0 +1,76 @@ +.\" +.\" %nmhwarning% +.\" +.TH MMH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mmh \- initialize the mmh environment +.SH SYNOPSIS +.HP 5 +.na +.B mmh +.RB [ \-check ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.PP +The command +.B mmh +creates the initial setup for a first\-time +.B mmh +user. +.PP +.B (For an introduction to the mmh system, see mmh\-intro(7).) +.PP +First, the mmh directory +.I $HOME/.mmh +is created. +.PP +Then the user is asked to name a directory that will be designated +as the user's mail storage. +If this directory does not exist, the user is +asked if it should be created. Normally, this directory should be +under the user's home directory. The default is \fI$HOME/Mail\fP. +.PP +Afterwards, +.B mmh +writes an initial +.I $HOME/.mmh/profile +for the user, containing only the path to the mail storage. +If the profile is already present, the user is asked to edit it. +.PP +The \fB\-c\fP option can be used to check whether or not mmh has +been installed. This can be used by other programs +without having knowledge about the internals of mmh. + +.SH "ENVIRONMENT VARIABLES" +.fc ^ ~ +.nf +.ta \w'VeryLongName 'u +^$MMH~^Overrides the user's mmh directory path +^$MMHP~^Overrides the user's profile path +.fi + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh~^The user's mmh directory +^$HOME/.mmh/profile~^The user's profile +^$HOME/.mmh/context~^The user's context +^$HOME/Mail~^The user's mail storage +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To set the user's mail storage +.fi + +.SH CONTEXT +None + +.SH "SEE ALSO" +mmh\-intro(7) diff --git a/man/mmhwrap.man1 b/man/mmhwrap.man1 new file mode 100644 index 0000000..1bec9c8 --- /dev/null +++ b/man/mmhwrap.man1 @@ -0,0 +1,79 @@ +.\" +.\" %nmhwarning% +.\" +.TH MMHWRAP %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +mmhwrap \- invoke mmh commands if they are not in $PATH +.SH SYNOPSIS +.HP 5 +.na +.B mmhwrap +.I command +.RI [ options ...] +.ad +.SH DESCRIPTION +.PP +Use +.B mmhwrap +if you want to invoke mmh programs without adding the mmh bindir +into $PATH, or if you want to install +.B nmh +and +.B mmh +both. +As their tools are equally named (but incompatibe) you can only +have one of both tool chests accessible through $PATH. +Use the wrapper to access +.B mmh +tools, if you have the +.B nmh +tools in your $PATH (first). +.PP +Copy +.B mmhwrap +into a directory that's part of $PATH, likely $HOME/bin or /usr/local/bin. +You likely want to rename +.B mmhwrap +to something shorter, like `m' for instance: +.PP +.RS 5 +.nf +cp %libdir%/mmhwrap $HOME/bin/m +chmod +x $HOME/bin/m +.fi +.RE +.PP +Then use it this way: +.PP +.RS 5 +.nf +% m folder +inbox+ has 162 messages (1\-177); cur=131; (others). + +% m scan \-help +Usage: scan [+folder] [msgs] [switches] + switches are: + \-form formatfile + \-width columns + \-(file) file + \-Version + \-help + +% m scan f + 1 2012\-02\-13 To: meillo laber blubb + +% m refile l +foo +.fi +.RE + +.SH FILES +None + +.SH "PROFILE COMPONENTS" +None + +.SH CONTEXT +None + +.SH "SEE ALSO" +mmh\-intro(7) diff --git a/man/msgchk.man b/man/msgchk.man deleted file mode 100644 index 55d4a18..0000000 --- a/man/msgchk.man +++ /dev/null @@ -1,183 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MSGCHK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -msgchk \- check for messages -.SH SYNOPSIS -.HP 5 -.na -.B msgchk -.RB [ \-date " | " \-nodate ] -.RB [ \-notify -all/mail/nomail ] -.RB [ \-nonotify -all/mail/nomail ] -%nmhbeginpop% -.RB [ \-host -.IR hostname ] -.RB [ \-user -.IR username ] -.RB [ \-sasl ] -.RB [ \-saslmech -.IR mechanism ] -.RB [ \-snoop ] -%nmhendpop% -.RI [ users -\&... ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B msgchk -program checks all known mail drops for mail waiting -for you. For those drops which have mail for you, -.B msgchk -will -indicate if it believes that you have seen the mail in question before. -.PP -The -.B \-notify -.I type -switch indicates under what circumstances -.B msgchk -should produce a message. The default is -.B \-notify -.I all -which says that -.B msgchk -should always report the status of the -users maildrop. Other values for `type' include `mail' which says that -.B msgchk -should report the status of waiting mail; and, `nomail' -which says that -.B msgchk -should report the status of empty maildrops. -The -.B \-nonotify -.I type -switch has the inverted sense, so -.B \-nonotify -.I all -directs -.B msgchk -to never report the status of -maildrops. This is useful if the user wishes to check -.BR msgchk 's -exit status. A non\-zero exit status indicates that mail was -.B not -waiting for at least one of the indicated users. -.PP -If -.B msgchk -produces output, then the -.B \-date -switch directs -.B msgchk -to print out the last date mail was read, if this can -be determined. -%nmhbeginpop% - -.SS "Using POP" -.B msgchk -will normally check all the local mail drops, but if -the option \*(lqpophost:\*(rq is set in the mts configuration file -\*(lqmts.conf\*(rq, or if the -.B \-host -.I hostname -switch is given, -.B msgchk -will query this POP service host as to the status of -mail waiting. -.PP -The default is for -.B msgchk -to assume that your account name -on the POP server is the same as your current username. To specify -a different username, use the `\-user\ username' switch. -.PP -When using POP, you will normally need to type the password for -your account on the POP server, in order to retrieve your messages. -It is possible to automate this process by creating a -.RI \*(lq \&.netrc \*(rq -file containing your login account information for this POP server. -For each POP server, this file should have a line of the following -form. Replace the words -.IR mypopserver , -.IR mylogin , -and -.I mypassword -with -your own account information. -.PP -.RS 5 -machine -.I mypopserver -login -.I mylogin -password -.I mypassword -.RE -.PP -This -.RI \*(lq \&.netrc \*(rq -file should be owned and readable only by you. -.PP -For debugging purposes, there is also a switch -.BR \-snoop , -which will -allow you to watch the POP transaction take place between you and the -POP server. -.PP -If -.B nmh -has been compiled with SASL support, the -.B \-sasl -switch will enable -the use of SASL authentication. Depending on the SASL mechanism used, this -may require an additional password prompt from the user (but the -.RI \*(lq \&.netrc \*(rq -file can be used to store this password). The -.B \-saslmech -switch can be used to select a particular SASL mechanism. -.PP -If SASL authentication is successful, -.B inc -will attempt to negotiate -a security layer for session encryption. Encrypted traffic is labelled -with `(encrypted)' and `(decrypted)' when viewing the POP transaction -with the -.B \-snoop -switch. -%nmhendpop% - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -^%mailspool%/$USER~^Location of mail drop -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -None -.fi - -.SH "SEE ALSO" -inc(1) - -.SH DEFAULTS -.nf -.RB ` user "' defaults to the current user" -.RB ` \-date ' -.RB ` "\-notify\ all" ' -.fi - -.SH CONTEXT -None diff --git a/man/msh.man b/man/msh.man deleted file mode 100644 index 93d0282..0000000 --- a/man/msh.man +++ /dev/null @@ -1,355 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH MSH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -msh \- nmh shell (and BBoard reader) -.SH SYNOPSIS -.HP 5 -.na -.B msh -.RB [ \-prompt -.IR string ] -.RB [ \-scan " | " \-noscan ] -.RB [ \-topcur " | " \-notopcur ] -.RI [ file ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B msh -is an interactive program that implements a subset of the normal -.B nmh -commands operating on a single file in -.BR packf 'd format. -That is, -.B msh -is used to read a file that contains a number -of messages, as opposed to the standard -.B nmh -style of reading -a number of files, each file being a separate message in a folder. -.BR msh 's -chief advantage is that the normal -.B nmh -style does not -allow a file to have more than one message in it. Hence, -.B msh -is -ideal for reading BBoards, as these files are delivered by the -transport system in this format. In addition, -.B msh -can be used on -other files, such as message archives which have been -.BR pack ed -(see -.BR packf (1)). -Finally, -.B msh -is an excellent -.B nmh -tutor. -As the only commands available to the user are -.B nmh -commands, this -allows -.B nmh -beginners to concentrate on how commands to -.B nmh -are formed and (more or less) what they mean. -.PP -When invoked, -.B msh -reads the named file, and enters a command loop. -The user may type most of the normal -.B nmh -commands. The syntax and -semantics of these commands typed to -.B msh -are identical to their -.B nmh -counterparts. In cases where the nature of -.B msh -would be -inconsistent (e.g., specifying a -.I +folder -with some commands), -.B msh -will duly inform the user. The commands that -.B msh -currently supports -(in some slightly modified or restricted forms) are: -.PP -.RS 5 -.nf -ali -burst -comp -dist -folder -forw -inc -mark -mhmail -mhn -msgchk -next -packf -pick -prev -refile -repl -rmm -scan -send -show -sortm -whatnow -whom -.fi -.RE -.PP -In addition, -.B msh -has a -.B help -command which gives a -brief overview. To terminate -.BR msh , -type CTRL\-D, or use the -.B quit -command. If -.B msh -is being invoked from -.BR bbc , -then typing CTRL\-D will also tell -.B bbc -to exit as well, while -using the -.B quit -command will return control to -.BR bbc , -and -.B bbc -will continue examining the list of BBoards that it is scanning. -.PP -If the file is writable and has been modified, then using -.B quit -will query the user if the file should be updated. -.PP -The -.B \-prompt -.I string -switch sets the prompting string for -.BR msh . -.PP -You may wish to use an alternate -.B nmh -profile for the commands that -.B msh -executes; see -.BR mh-profile (5) -for details about the -.B $MH -environment variable. -.PP -When invoked from -.BR bbc , -two special features are enabled: -First, the -.B \-scan -switch directs -.B msh -to do a -.RB \*(lq scan -.BR unseen \*(rq -on start\-up if new items are present in the BBoard. This feature is -best used from -.BR bbc , -which correctly sets the stage. Second, the -.B mark -command in -.B msh -acts specially when you are reading a -BBoard, since -.B msh -will consult the sequence \*(lqunseen\*(rq in -determining what messages you have actually read. When -.B msh -exits, -it reports this information to -.BR bbc . -In addition, if you give the -.B mark -command with no arguments, -.B msh -will interpret it as -.RB \*(lq mark -.B \-sequence -.B unseen -.B \-delete -.B \-nozero -.BR all \*(rq -Hence, to discard -all of the messages in the current BBoard you're reading, just use the -.B mark -command with no arguments. -.PP -Normally, the -.B exit -command is identical to the -.B quit -command in -.BR msh . -When run under -.B bbc -however, -.B exit -directs -.B msh -to mark all messages as seen and then -.BR quit . -For speedy type\-in, this command is often abbreviated as just -.BR qe . -.PP -When invoked from -.BR vmh , -another special feature is enabled: -The `topcur' switch directs -.B msh -to have the current message -\*(lqtrack\*(rq the top line of the -.B vmh -scan window. Normally, -.B msh -has the current message \*(lqtrack\*(rq the center of the window -(under -.BR \-notopcur , -which is the default). -.PP -.B msh -supports an output redirection facility. Commands may be -followed by one of -.PP -.RS 5 -.nf -.ta \w'| \fIcommand\fR 'u -^> \fIfile\fR~^write output to \fIfile\fR -^>> \fIfile\fR~^append output to \fIfile\fR -^| \fIcommand\fR~^pipe output to UNIX \fIcommand\fR -.fi -.RE -.PP -If -.I file -starts with a \*(lq\~\*(rq (tilde), then a -.BR csh \-like -expansion -takes place. Note that -.I command -is interpreted by -.BR sh . -Also note that -.B msh -does NOT support history substitutions, variable -substitutions, or alias substitutions. -.PP -When parsing commands to the left of any redirection symbol, -.B msh -will honor `\\' (back\-slash) as the quote next\-character symbol, and -`\*(lq' (double\-quote) as quote\-word delimiters. All other input tokens -are separated by whitespace (spaces and tabs). - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Msg\-Protect:~^To set mode when creating a new `file' -^fileproc:~^Program to file messages -^showproc:~^Program to show messages -.fi - -.SH "SEE ALSO" -bbc(1) - -.SH DEFAULTS -.nf -.RB ` file "' defaults to \*(lq./msgbox\*(rq" -.RB ` "\-prompt\ (msh)\ "' -.RB ` \-noscan ' -.RB ` \-notopcur ' -.fi - -.SH CONTEXT -None - -.SH BUGS -The argument to the -.B \-prompt -switch must be interpreted as a single -token by the shell that invokes -.BR msh . -Therefore, one must usually -place the argument to this switch inside double\-quotes. -.PP -There is a strict limit of messages per file in -.BR packf 'd -format which -.B msh -can handle. Usually, this limit is 1000 messages. -.PP -Please remember that -.B msh -is not the C\-Shell, and that a lot of -the nice facilities provided by the latter are not present in the former. -.PP -In particular, -.B msh -does not understand back\-quoting, so the only -effective way to use -.B pick -inside -.B msh -is to always use the -.B \-seq -.I select -switch. Clever users of -.B nmh -will put the line -.P -.RS 5 -pick:\0\-seq\0select\0\-list -.RE -.PP -in their -.I \&.mh\(ruprofile -file so that -.B pick -works equally well from both the shell and -.BR msh . -.PP -.B sortm -always uses -.B \-noverbose -and if -.B \-textfield -.I field -is used, -.B \-limit -.IR 0 . -.PP -The -.B msh -program inherits most (if not all) of the bugs from the -.B nmh -commands it implements. diff --git a/man/mts.conf.man b/man/mts.conf.man deleted file mode 100644 index 9d534fd..0000000 --- a/man/mts.conf.man +++ /dev/null @@ -1 +0,0 @@ -.so man5/mh-tailor.5 diff --git a/man/new.man b/man/new.man deleted file mode 100644 index 5be7983..0000000 --- a/man/new.man +++ /dev/null @@ -1,109 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH NEW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] - -.SH NAME -new \- report on folders with new messages -.PP -fnext \- set current folder to next folder with new messages -.PP -fprev \- set current folder to previous folder with new messages -.PP -unseen \- scan new messages in all folders with new messages - -.SH SYNOPSIS -.HP 5 -.na -.B new -.RI [ sequences ] -.RB [ \-mode -.IR mode ] -.RB [ \-folders -.IR foldersfile ] -.RB [ \-version ] -.RB [ \-help ] -.PP -.HP 5 -.B fnext -is equivalent to -.B new \-mode fnext -.PP -.HP 5 -.B fprev -is equivalent to -.B new \-mode fprev -.PP -.HP 5 -.B unseen -is equivalent to -.B new \-mode unseen -.ad - -.SH DESCRIPTION -.B New -in its default mode produces a one\-line\-per\-folder listing of all -folders containing messages in the listed -.IR sequences -or in the sequences listed in the profile entry -.RI \*(lq Unseen-Sequence \*(rq. -Each line contains the folder, the number of messages in the desired -sequences, and the message lists from the .mh_sequences file. For example: -.PP -.RS 5 -.nf -foo 11.* 40\-50 -bar 380. 760\-772 824\-828 - total 391. -.fi -.RE -.PP -The `*' on foo indicates that it is the current folder. The last line shows -the total number of messages in the desired sequences. -.PP -.B New -crawls the folder hierarchy recursively to find all folders, and prints them -in lexicographic order. Override this behavior by providing -.IR foldersfile -containing the pre-sorted list of folders -.B new -should check, one per line. -.PP -In -.B fnext -and -.B fprev -modes, -.B new -instead changes to the next or previous matching folder, respectively. -.PP -In -.B unseen -mode, -.B new -executes -.B scan sequences -for each matching folder. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Unseen-Sequence:~^The name of the unseen message sequence -.fi - -.SH "SEE ALSO" -scan(1), mh\-format(5) - -.SH HISTORY -Based on Luke Mewburn's new (http://www.mewburn.net/luke/src/new). diff --git a/man/new.man1 b/man/new.man1 new file mode 100644 index 0000000..d92016e --- /dev/null +++ b/man/new.man1 @@ -0,0 +1,109 @@ +.\" +.\" %nmhwarning% +.\" +.TH NEW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] + +.SH NAME +new \- report on folders with new messages +.PP +fnext \- set current folder to next folder with new messages +.PP +fprev \- set current folder to previous folder with new messages +.PP +unseen \- scan new messages in all folders with new messages + +.SH SYNOPSIS +.HP 5 +.na +.B new +.RI [ sequences ] +.RB [ \-mode +.IR mode ] +.RB [ \-folders +.IR foldersfile ] +.RB [ \-Version ] +.RB [ \-help ] +.PP +.HP 5 +.B fnext +is equivalent to +.B new \-mode fnext +.PP +.HP 5 +.B fprev +is equivalent to +.B new \-mode fprev +.PP +.HP 5 +.B unseen +is equivalent to +.B new \-mode unseen +.ad + +.SH DESCRIPTION +.B New +in its default mode produces a one\-line\-per\-folder listing of all +folders containing messages in the listed +.IR sequences +or in the sequences listed in the profile entry +.RI ` Unseen-Sequence '. +Each line contains the folder, the number of messages in the desired +sequences, and the message lists from the .mh_sequences file. For example: +.PP +.RS 5 +.nf +foo 11.* 40\-50 +bar 380. 760\-772 824\-828 + total 391. +.fi +.RE +.PP +The `*' on foo indicates that it is the current folder. The last line shows +the total number of messages in the desired sequences. +.PP +.B New +crawls the folder hierarchy recursively to find all folders, and prints them +in lexicographic order. Override this behavior by providing +.IR foldersfile +containing the pre-sorted list of folders +.B new +should check, one per line. +.PP +In +.B fnext +and +.B fprev +modes, +.B new +instead changes to the next or previous matching folder, respectively. +.PP +In +.B unseen +mode, +.B new +executes +.B scan sequences +for each matching folder. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Unseen-Sequence:~^The name of the unseen message sequence +.fi + +.SH "SEE ALSO" +scan(1), mh\-format(5) + +.SH HISTORY +Based on Luke Mewburn's new (http://www.mewburn.net/luke/src/new). diff --git a/man/next.man b/man/next.man deleted file mode 100644 index eecc044..0000000 --- a/man/next.man +++ /dev/null @@ -1,94 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH NEXT %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -next \- show the next message -.SH SYNOPSIS -.HP 5 -.na -.B next -.RI [ +folder ] -.RB [\-showproc -.IR program ] -.RB [ \-showmimeproc -.IR program ] -.RB [ \-header " | " \-noheader ] -.RB [ \-checkmime " | " \-nocheckmime ] -[switches\ for -.I showproc -or -.IR showmimeproc ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Next -performs a -.B show -on the next message in the specified -(or current) folder. Like -.BR show , -it passes any switches on to -the program -.I showproc -or -.IR showmimeproc , -which is called to list -the message. This command is almost exactly equivalent to -.RB \*(lq show -.BR next \*(rq. -Consult the manual entry for -.BR show (1) -for all the -details. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^showproc:~^Program to show non-MIME messages -^showmimeproc:~^Program to show MIME messages -.fi - -.SH "SEE ALSO" -show(1), prev(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` \-checkmime ' -.RB ` \-header ' - -.SH CONTEXT -If a folder is specified, it will become the current folder. The message -that is shown (i.e., the next message in sequence) will become the -current message. - -.SH BUGS -.B next -is really a link to the -.B show -program. As a result, if -you make a link to -.B next -and that link is not called -.BR next , -your link will act like -.B show -instead. To circumvent this, add a -profile\-entry for the link to your -.B nmh -profile and add the argument -.I next -to the entry. diff --git a/man/next.man1 b/man/next.man1 new file mode 100644 index 0000000..b756c04 --- /dev/null +++ b/man/next.man1 @@ -0,0 +1 @@ +.so man1/show.1 diff --git a/man/nmh.man b/man/nmh.man deleted file mode 100644 index 46fd8fb..0000000 --- a/man/nmh.man +++ /dev/null @@ -1,298 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH NMH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -nmh \- new MH message system -.SH SYNOPSIS -any -.B nmh -command -.SH DESCRIPTION -.B nmh -is the name of a powerful message handling system. Rather than -being a single comprehensive program, -.B nmh -consists of a collection -of fairly simple single-purpose programs to send, retrieve, save, -and manipulate messages. -.PP -Unlike most mail clients in UNIX, -.B nmh -is not a closed system which -must be explicitly run, then exited when you wish to return to the shell. -You may freely intersperse -.B nmh -commands with other shell commands, -allowing you to read and answer your mail while you have (for example) -a compilation running, or search for a file or run programs as needed -to find the answer to someone's question before answering their mail. -.PP -The rest of this manual entry is a quick tutorial which will teach you -the basics of -.BR nmh . -You should read the manual entries for the -individual programs for complete documentation. -.PP -To get started using -.BR nmh , -put the directory -.I %bindir% -on your -.BR $PATH . -This is best done in one of the files: -.IR \&.profile , -.IR \&.login , -.IR \&.bashrc , -or -.I \&.cshrc -in your home directory. (Check the -manual entry for the shell you use, in case you don't know how to -do this.) Run the -.B install-mh -command. If you've never used -.B nmh -before, it will create the necessary default files and directories after -asking you if you wish it to do so. -.PP -.B inc -moves mail from your system maildrop into your -.B nmh -`+inbox' folder, breaking it up into separate files and converting it -to -.B nmh -format as it goes. It prints one line for each message it -processes, containing the from field, the subject field and as much of -the first line of the message as will fit. It leaves the first message -it processes as your current message. You'll need to run -.B inc -each -time you wish to incorporate new mail into your -.B nmh -file. -.PP -.B scan -.B prints a list of the messages in your current folder. -.PP -The commands: -.BR show , -.BR next , -and -.B prev -are used to read -specific messages from the current folder. -.B show -displays the -current message, or a specific message, which may be specified by its -number, which you pass as an argument to -.BR show . -.B next -and -.B prev -display, respectively, the message numerically after or before -the current message. In all cases, the message displayed becomes the -current message. If there is no current message, -.B show -may be -called with an argument, or -.B next -may be used to advance to the -first message. -.PP -.B rmm -(remove message) deletes the current message. It may be called -with message numbers passed as arguments, to delete specific messages. -.PP -.B repl -is used to respond to the current message (by default). -It places you in the editor with a prototype response form. While you're -in the editor, you may peruse the item you're responding to by reading -the file -.IR @ . -After completing your response, type -.B l -to -.B list -(review) it, or -.B s -to -.B send -it. -.PP -.B comp -allows you to compose a message by putting you in the editor -on a prototype message form, and then lets you send it. -.PP -All the -.B nmh -commands may be run with the single argument: -.BR \-help , -which causes them to print a list of the arguments they may be invoked -with and then exit. -.PP -All the -.B nmh -commands may be run with the single argument: -.BR \-version , -which cause them to print the version number of the -.B nmh -distribution, and then exit. -.PP -Commands which take a message number as an argument ( -.BR scan , -.BR show , -.BR repl , -\&...) also take one of the words: \*(lqfirst\*(rq, -\*(lqprev\*(rq, \*(lqcur\*(rq, \*(lqnext\*(rq, or \*(lqlast\*(rq to indicate -(respectively) the first, previous, current, next, or last message in -the current folder (assuming they are defined). - -Commands which take a range of message numbers ( -.BR rmm , -.BR scan , -.BR show , -\&...) also take any of the abbreviations: -.PP -.RS 5 -.IP \fI\fR\-\fI\fR 15 -Indicates all messages in the range to , inclusive. The range must be nonempty. -.IP \fI\fR:+\fIN\fR 15 -.IP \fI\fR:\-\fIN\fR 15 -Up to -.I N -messages beginning with (or ending with) message -.IR num . -.I Num -may be any of the pre-defined symbols: -.IR first , -.IR prev , -.IR cur , -.I next -or -.IR last . -.IP first:\fIN\fR 15 -.IP prev:\fIN\fR 15 -.IP next:\fIN\fR 15 -.IP last:\fIN\fR 15 -The first, previous, next or last -messages, if they exist. -.RE -.PP -There are many other possibilities such as creating multiple folders -for different topics, and automatically refiling messages according to -subject, source, destination, or content. These are beyond the scope -of this manual entry. -.PP -Following is a list of all the -.B nmh -commands: -.PP -.RS 5 -.fc ^ ~ -.nf -.ta 1.5i -^ali(1)~^\- list mail aliases -^anno(1)~^\- annotate messages -^burst(1)~^\- explode digests into messages -^comp(1)~^\- compose a message -^dist(1)~^\- redistribute a message to additional addresses -^flist(1)~^\- list folders with messages in given sequence(s) -^flists(1)~^\- list all folders with messages in given sequence(s) -^folder(1)~^\- set/list current folder/message -^folders(1)~^\- list all folders -^forw(1)~^\- forward messages -^inc(1)~^\- incorporate new mail -^mark(1)~^\- mark messages -^mhbuild(1)~^\- translate MIME composition draft -^mhl(1)~^\- produce formatted listings of nmh messages -^mhlist(1)~^\- list information about content of MIME messages -^mhmail(1)~^\- send or read mail -^mhn(1)~^\- display/list/store/cache MIME messages -^mhparam(1)~^\- print nmh profile components -^mhpath(1)~^\- print full pathnames of nmh messages and folders -^mhshow(1)~^\- display MIME messages -^mhstore(1)~^\- store contents of MIME messages into files -^msgchk(1)~^\- check for messages -^msh(1)~^\- nmh shell(and BBoard reader) -^next(1)~^\- show the next message -^packf(1)~^\- compress a folder into a single file -^pick(1)~^\- select messages by content -^prev(1)~^\- show the previous message -^prompter(1)~^\- prompting editor front end -^rcvdist(1)~^\- asynchronously redistribute new mail -^rcvpack(1)~^\- append message to file -^rcvstore(1)~^\- asynchronously incorporate new mail -^rcvtty(1)~^\- report new mail -^refile(1)~^\- file messages in other folders -^repl(1)~^\- reply to a message -^rmf(1)~^\- remove folder -^rmm(1)~^\- remove messages -^scan(1)~^\- produce a one line per message scan listing -^send(1)~^\- send a message -^sendfiles(1)~^\- send multiple files and directories in MIME message -^show(1)~^\- show(display) messages -^slocal(1)~^\- asynchronously filter and deliver new mail -^sortm(1)~^\- sort messages -^whatnow(1)~^\- prompting front\-end for send -^whom(1)~^\- report to whom a message would go -.sp -^mh\-alias(5)~^\- alias file for nmh message system -^mh\-draft(5)~^\- draft folder facility -^mh\-format(5)~^\- format file for nmh message system -^mh\-mail(5)~^\- message format for nmh message system -^mh\-profile(5)~^\- user customization for nmh message system -^mh\-sequence(5)~^\- sequence specification for nmh message system -^mh\-tailor(5)~^\- mail transport customization for nmh message system -.sp -^ap(8)~^\- parse addresses 822\-style -^conflict(8)~^\- search for alias/password conflicts -^dp(8)~^\- parse dates 822\-style -^fmtdump(8)~^\- decode \fInmh\fP format files -^install\-mh(8)~^\- initialize the nmh environment -^post(8)~^\- deliver a message -.fi -.RE - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%bindir%~^contains \fInmh\fR commands -^%etcdir%~^contains \fInmh\fR format files -^%libdir%~^contains \fInmh\fR library commands -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -.fi - -.SH BUGS -If problems are encountered with an -.B nmh -program, the problems should -be reported to the local maintainers of -.BR nmh . -When doing this, the -name of the program should be reported, along with the version information -for the program. -.br -To find out what version of an -.B nmh -program is being run, invoke -the program with the -.B \-version -switch. This information includes -the version of -.BR nmh , -the host it was generated on, and the date the -program was loaded. -.PP -Send bug reports and suggestions to -.IR nmh-workers@nongnu.org . -.SH "SEE ALSO" -mh-chart(1) diff --git a/man/packf.man b/man/packf.man deleted file mode 100644 index fd32b3a..0000000 --- a/man/packf.man +++ /dev/null @@ -1,92 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH PACKF %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -packf \- pack messages in nmh folder into a single file -.SH SYNOPSIS -.HP 5 -.na -.B packf -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-file -.IR name ] -.RB [ \-mbox ] -.RB [ \-mmdf ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Packf -will pack copies of messages from a folder, into a single -file. -.PP -If the -.B \-mbox -switch is given (the default), then the messages are -separated using mbox (uucp) style delimiters. This is the format used -by most mail clients (elm, mailx, etc.). -.PP -If the -.B \-mmdf -switch is given, then the messages are separated by -mmdf style delimiters. Each message in the file is separated by four -CTRL\-A's and a newline. -.PP -You may specify the name of the file in which to use with the -.B \-file -.I name -switch. If you do not specify the name of the file, it -will default to -.RI \*(lq msgbox \*(rq. -.PP -If the given file name points to an existing file, then the specified -messages will be appended to the end of the file, otherwise the file -will be created and the messages appended. -.PP -.B packf -makes an mbox-style delimiter by examining the first line -of the message. If the first line is a \*(lqReturn-Path\*(rq -field, its address and the current date and time are used. Otherwise, -if the first line has an \*(lqX-Envelope-From\*(rq field, its -contents (which should already be in the correct format) are used. -Otherwise, a dummy address and the current date and time are used. -.PP -Messages that are packed by -.B packf -can be unpacked using -.BR inc . - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^\&.msgbox\&.map~^A binary index of the file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Msg\-Protect:~^To set mode when creating a new `file' -.fi - -.SH "SEE ALSO" -inc(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to all" -.RB ` \-mbox ' -.RB ` "\-file ./msgbox" ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The first -message packed will become the current message. diff --git a/man/packf.man1 b/man/packf.man1 new file mode 100644 index 0000000..c07204a --- /dev/null +++ b/man/packf.man1 @@ -0,0 +1,61 @@ +.\" +.\" %nmhwarning% +.\" +.TH PACKF %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +packf \- pack messages in nmh folder into a single mbox file +.SH SYNOPSIS +.HP 5 +.na +.B packf +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Packf +will pack copies of messages from a folder, into mbox format and +print it to the standard output. +.PP +.B packf +makes an mbox-style delimiter by examining the first line +of the message. If the first line is a `Return-Path' +field, its address and the current date and time are used. Otherwise, +if the first line has an `X-Envelope-From' field, its +contents (which should already be in the correct format) are used. +Otherwise, a dummy address and the current date and time are used. +.PP +Messages that are packed by +.B packf +can be unpacked using +.BR inc . + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +inc(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to all" +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The first +message packed will become the current message. diff --git a/man/pick.man b/man/pick.man deleted file mode 100644 index 1a1b0ff..0000000 --- a/man/pick.man +++ /dev/null @@ -1,419 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH PICK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -pick \- search for messages by content -.SH SYNOPSIS -.HP 5 -.na -.B pick -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-and -\&...] -.RB [ \-or -\&...] -.RB [ \-not -\&...] -.RB [ \-lbrace -\&... -.BR \-rbrace ] -.RB [ \-\|\-component -.IR pattern ] -.RB [ \-cc -.IR pattern ] -.RB [ \-date -.IR pattern ] -.RB [ \-from -.IR pattern ] -.RB [ \-search -.IR pattern ] -.RB [ \-subject -.IR pattern ] -.RB [ \-to -.IR pattern ] -.RB [ \-after -.IR date ] -.RB [ \-before -.IR date ] -.RB [ \-datefield -.IR field ] -.RB [ \-sequence -.I name -\&...] -.RB [ \-public " | " \-nopublic ] -.RB [ \-zero " | " \-nozero ] -.RB [ \-list " | " \-nolist ] -.RB [ \-version ] -.RB [ \-help ] -.PP -typical usage: -.PP -.RS 5 -.nf -scan\0`pick\0\-from\0jones` -pick\0\-to\0holloway\0\-sequence\0select -show\0`pick\0\-before\0friday` -.fi -.RE -.ad -.SH DESCRIPTION -.B Pick -searches within a folder for messages with the specified -contents, and then identifies those messages. Two types of search -primitives are available: pattern matching and date constraint -operations. -.PP -A modified -.BR grep (1) -is used to perform the matching, so the -full regular expression (see -.BR ed (1)) -facility is available -within -.IR pattern . -With -.BR \-search , -.I pattern -is used directly, and with the others, the grep pattern constructed is: -.PP -.RS 5 -`component[ \\t]*:\&.*pattern' -.RE -.PP -This means that the pattern specified for a -.B \-search -will be found -everywhere in the message, including the header and the body, while -the other pattern matching requests are limited to the single specified -component. The expression -.PP -.RS 5 -`\-\|\-component\ pattern' -.RE -.PP -is a shorthand for specifying -.PP -.RS 5 -`\-search \*(lqcomponent[ \\t]*:\&.*pattern\*(rq\ ' -.RE -.PP -It is used to pick a component which is not one of \*(lqTo:\*(rq, -\*(lqcc:\*(rq, \*(lqDate:\*(rq, \*(lqFrom:\*(rq, or \*(lqSubject:\*(rq. -An example is -.RB \*(lq "pick\0\-\|\-reply\-to\0pooh" \*(rq. -.PP -Pattern matching is performed on a per\-line basis. Within the header -of the message, each component is treated as one long line, but in the -body, each line is separate. Lower\-case letters in the search pattern -will match either lower or upper case in the message, while upper case -will match only upper case. -.PP -Note that since the -.B \-date -switch is a pattern matching operation (as -described above), to find messages sent on a certain date the pattern -string must match the text of the \*(lqDate:\*(rq field of the message. -.PP -Independent of any pattern matching operations requested, the switches -.B \-after -.I date -or -.B \-before -.I date -may also be used to introduce date/time -constraints on all of the messages. By default, the \*(lqDate:\*(rq -field is consulted, but if another date yielding field (such as -\*(lqBB\-Posted:\*(rq or \*(lqDelivery\-Date:\*(rq) should be used, the -.B \-datefield -.I field -switch may be used. -.PP -With -.B \-before -and -.BR \-after , -.B pick -will actually parse the date -fields in each of the messages specified in `msgs' and compare them -to the date/time specified. If -.B \-after -is given, then only those -messages whose \*(lqDate:\*(rq field value is chronologically after the -date specified will be considered. The -.B \-before -switch specifies the -complimentary action. -.PP -Both the -.B \-after -and -.B \-before -switches take legal 822\-style date -specifications as arguments. -.B Pick -will default certain missing -fields so that the entire date need not be specified. These fields -are (in order of defaulting): timezone, time and timezone, date, date -and timezone. All defaults are taken from the current date, time, -and timezone. -.PP -In addition to 822\-style dates, -.B pick -will also recognize any of -the days of the week (\*(lqsunday\*(rq, \*(lqmonday\*(rq, and so on), -and the special dates \*(lqtoday\*(rq, \*(lqyesterday\*(rq (24 hours -ago), and \*(lqtomorrow\*(rq (24 hours from now). All days of the -week are judged to refer to a day in the past (e.g., telling \fIpick\fR -\*(lqsaturday\*(rq on a \*(lqtuesday\*(rq means \*(lqlast\ saturday\*(rq -not \*(lqthis\ saturday\*(rq). -.PP -Finally, in addition to these special specifications, -.B pick -will -also honor a specification of the form \*(lq\-dd\*(rq, which means -\*(lqdd days ago\*(rq. -.PP -.B Pick -supports complex boolean operations on the searching primitives -with the -.BR \-and , -.BR \-or , -.BR \-not , -and -.B \-lbrace -.B \&... -.B \-rbrace -switches. -For example, -.PP -.RS 5 -.nf -pick\0\-after\0yesterday\0\-and - \-lbrace\0\-from\0freida\0\-or\0\-from\0fear\0\-rbrace -.fi -.RE -.PP -identifies messages recently sent by \*(lqfrieda\*(rq or \*(lqfear\*(rq. -.PP -The matching primitives take precedence over the -.B \-not -switch, which in turn takes precedence over -.B \-and -which in turn takes precedence -over -.BR \-or . -To override the default precedence, the -.B \-lbrace -and -.B \-rbrace -switches are provided, which act just like opening and closing -parentheses in logical expressions. -.PP -If no search criteria are given, all the messages specified on the -command line are selected (this defaults to \*(lqall\*(rq). -.PP -Once the search has been performed, if the -.B \-list -switch is given, the -message numbers of the selected messages are written to the standard -output separated by newlines. This is -.B extremely -useful for -quickly generating arguments for other -.B nmh -programs by using the -\*(lqbackquoting\*(rq syntax of the shell. For example, the command -.PP -.RS 5 -scan\0`pick\0+todo\0\-after\0\*(lq31 Mar 83 0123 PST\*(rq` -.RE -.PP -says to -.B scan -those messages in the indicated folder which meet the -appropriate criterion. Note that since -.BR pick 's -context changes -are written out prior to -.BR scan 's -invocation, you need not give -the folder argument to -.B scan -as well. -.PP -The -.B \-sequence -.I name -switch may be given once for each sequence the user wishes to define. -For each sequence named, that sequence will be defined to mean exactly -those messages selected by -.BR pick . -For example, -.PP -.RS 5 -pick\0\-from\0frated\0\-seq\0fred -.RE -.PP -defines a new message sequence for the current folder called -\*(lqfred\*(rq which contains exactly those messages that were selected. -.PP -By default, -.B pick -will zero the sequence before adding it. This -action can be disabled with the -.B \-nozero -switch, which means that the -messages selected by -.B pick -will be added to the sequence, if it -already exists, and any messages already a part of that sequence will -remain so. -.PP -The -.B \-public -and -.B \-nopublic -switches are used by -.B pick -in the -same way -.B mark -uses them. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -mark(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to all" -.RB ` "\-datefield date" ' -.RB ` \-zero ' -.RB ` \-list "' is the default if no `\-sequence', `\-nolist' otherwise" -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. - -.SH HISTORY -In previous versions of -.BR MH , -the -.B pick -command would -.BR show , -.BR scan , -or -.B refile -the selected messages. This was rather -\*(lqinverted logic\*(rq from the UNIX point of view, so -.B pick -was changed to define sequences and output those sequences. Hence, -.B pick -can be used to generate the arguments for all other -.B MH -commands, instead of giving -.B pick -endless switches for invoking those commands -itself. -.PP -Also, previous versions of -.B pick -balked if you didn't specify -a search string or a date/time constraint. The current version does -not, and merely matches the messages you specify. This lets you type -something like: -.PP -.RS 5 -show\0`pick\0last:20\0\-seq\0fear` -.RE -.PP -instead of typing -.PP -.RS 5 -.nf -mark\0\-add\0\-nozero\0\-seq\0fear\0last:20 -show\0fear -.fi -.RE -.PP -Finally, timezones used to be ignored when comparing dates: they aren't -any more. - -.SH "HELPFUL HINTS" -Use -.RB \*(lq "pick sequence \-list" \*(rq -to enumerate the messages in a sequence -(such as for use by a shell script). - -.SH BUGS -The argument to the -.B \-after -and -.B \-before -switches must be interpreted -as a single token by the shell that invokes -.BR pick . -Therefore, one -must usually place the argument to this switch inside double\-quotes. -Furthermore, any occurrence of -.B \-datefield -must occur prior to the -.B \-after -or -.B \-before -switch it applies to. -.PP -If -.B pick -is used in a back\-quoted operation, such as -.PP -.RS 5 -scan\0`pick\0\-from\0jones` -.RE -.PP -and -.B pick -selects no messages (e.g., no messages are from -\*(lqjones\*(rq), then the shell will still run the outer command (e.g., -.BR scan ). -Since no messages were matched, -.B pick -produced -no output, and the argument given to the outer command as a result of -backquoting -.B pick -is empty. In the case of -.B nmh -programs, -the outer command now acts as if the default `msg' or `msgs' should be -used (e.g., \*(lqall\*(rq in the case of -.BR scan ). -To prevent this -unexpected behavior, if -.B \-list -was given, and if its standard output is not a tty, then -.B pick -outputs the illegal message number \*(lq0\*(rq -when it fails. This lets the outer command fail gracefully as well. -.PP -The pattern syntax \*(lq[l-r]\*(rq is not supported; each letter to be -matched must be included within the square brackets. diff --git a/man/pick.man1 b/man/pick.man1 new file mode 100644 index 0000000..2f06a22 --- /dev/null +++ b/man/pick.man1 @@ -0,0 +1,411 @@ +.\" +.\" %nmhwarning% +.\" +.TH PICK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +pick \- search for messages by content +.SH SYNOPSIS +.HP 5 +.na +.B pick +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-and +\&...] +.RB [ \-or +\&...] +.RB [ \-not +\&...] +.RB [ \-lbrace +\&... +.BR \-rbrace ] +.RB [ \-\|\-component +.IR pattern ] +.RB [ \-cc +.IR pattern ] +.RB [ \-date +.IR pattern ] +.RB [ \-from +.IR pattern ] +.RB [ \-search +.IR pattern ] +.RB [ \-subject +.IR pattern ] +.RB [ \-to +.IR pattern ] +.RB [ \-after +.IR date ] +.RB [ \-before +.IR date ] +.RB [ \-datefield +.IR field ] +.RB [ \-sequence +.I name +\&...] +.RB [ \-public " | " \-nopublic ] +.RB [ \-zero " | " \-nozero ] +.RB [ \-list " | " \-nolist ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.PP +typical usage: +.PP +.RS 5 +.nf +scan\0`pick\0\-from\0jones` +pick\0\-to\0holloway\0\-sequence\0select +show\0`pick\0\-before\0friday` +.fi +.RE +.ad +.SH DESCRIPTION +.B Pick +searches within a folder for messages with the specified +contents, and then identifies those messages. Two types of search +primitives are available: pattern matching and date constraint +operations. +.PP +A modified +.BR grep (1) +is used to perform the matching, so the +full regular expression (see +.BR ed (1)) +facility is available +within +.IR pattern . +With +.BR \-search , +.I pattern +is used directly, and with the others, the grep pattern constructed is: +.PP +.RS 5 +`component[ \\t]*:\&.*pattern' +.RE +.PP +This means that the pattern specified for a +.B \-search +will be found +everywhere in the message, including the header and the body, while +the other pattern matching requests are limited to the single specified +component. The expression +.PP +.RS 5 +`\-\|\-component\ pattern' +.RE +.PP +is a shorthand for specifying +.PP +.RS 5 +`\-search `component[ \\t]*:\&.*pattern'\ ' +.RE +.PP +It is used to pick a component which is not one of `To:', +`Cc:', `Date:', `From:', or `Subject:'. +An example is +.RB ` "pick\0\-\|\-reply\-to\0pooh" '. +.PP +Pattern matching is performed on a per\-line basis. Within the header +of the message, each component is treated as one long line, but in the +body, each line is separate. Lower\-case letters in the search pattern +will match either lower or upper case in the message, while upper case +will match only upper case. +.PP +Note that since the +.B \-date +switch is a pattern matching operation (as +described above), to find messages sent on a certain date the pattern +string must match the text of the `Date:' field of the message. +.PP +Independent of any pattern matching operations requested, the switches +.B \-after +.I date +or +.B \-before +.I date +may also be used to introduce date/time +constraints on all of the messages. By default, the `Date:' +field is consulted, but if another date yielding field (such as +`BB\-Posted:' or `Delivery\-Date:') should be used, the +.B \-datefield +.I field +switch may be used. +.PP +With +.B \-before +and +.BR \-after , +.B pick +will actually parse the date +fields in each of the messages specified in `msgs' and compare them +to the date/time specified. If +.B \-after +is given, then only those +messages whose `Date:' field value is chronologically after the +date specified will be considered. The +.B \-before +switch specifies the +complimentary action. +.PP +Both the +.B \-after +and +.B \-before +switches take legal 822\-style date +specifications as arguments. +.B Pick +will default certain missing +fields so that the entire date need not be specified. These fields +are (in order of defaulting): timezone, time and timezone, date, date +and timezone. All defaults are taken from the current date, time, +and timezone. +.PP +In addition to 822\-style dates, +.B pick +will also recognize any of +the days of the week (`sunday', `monday', and so on), +and the special dates `today', `yesterday' (24 hours +ago), and `tomorrow' (24 hours from now). All days of the +week are judged to refer to a day in the past (e.g., telling \fIpick\fR +`saturday' on a `tuesday' means `last\ saturday' +not `this\ saturday'). +.PP +Finally, in addition to these special specifications, +.B pick +will +also honor a specification of the form `\-dd', which means +`dd days ago'. +.PP +.B Pick +supports complex boolean operations on the searching primitives +with the +.BR \-and , +.BR \-or , +.BR \-not , +and +.B \-lbrace +.B \&... +.B \-rbrace +switches. +For example, +.PP +.RS 5 +.nf +pick\0\-after\0yesterday\0\-and + \-lbrace\0\-from\0freida\0\-or\0\-from\0fear\0\-rbrace +.fi +.RE +.PP +identifies messages recently sent by `frieda' or `fear'. +.PP +The matching primitives take precedence over the +.B \-not +switch, which in turn takes precedence over +.B \-and +which in turn takes precedence +over +.BR \-or . +To override the default precedence, the +.B \-lbrace +and +.B \-rbrace +switches are provided, which act just like opening and closing +parentheses in logical expressions. +.PP +If no search criteria are given, all the messages specified on the +command line are selected (this defaults to `all'). +.PP +Once the search has been performed, if the +.B \-list +switch is given, the +message numbers of the selected messages are written to the standard +output separated by newlines. This is +.B extremely +useful for +quickly generating arguments for other +.B nmh +programs by using the +`backquoting' syntax of the shell. For example, the command +.PP +.RS 5 +scan\0`pick\0+todo\0\-after\0`31 Mar 83 0123 PST'` +.RE +.PP +says to +.B scan +those messages in the indicated folder which meet the +appropriate criterion. Note that since +.BR pick 's +context changes +are written out prior to +.BR scan 's +invocation, you need not give +the folder argument to +.B scan +as well. +.PP +The +.B \-sequence +.I name +switch may be given once for each sequence the user wishes to define. +For each sequence named, that sequence will be defined to mean exactly +those messages selected by +.BR pick . +For example, +.PP +.RS 5 +pick\0\-from\0frated\0\-seq\0fred +.RE +.PP +defines a new message sequence for the current folder called +`fred' which contains exactly those messages that were selected. +.PP +By default, +.B pick +will zero the sequence before adding it. This +action can be disabled with the +.B \-nozero +switch, which means that the +messages selected by +.B pick +will be added to the sequence, if it +already exists, and any messages already a part of that sequence will +remain so. +.PP +The +.B \-public +and +.B \-nopublic +switches are used by +.B pick +in the +same way +.B mark +uses them. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +mark(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to all" +.RB ` "\-datefield date" ' +.RB ` \-zero ' +.RB ` \-list "' is the default if no `\-sequence', `\-nolist' otherwise" +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. + +.SH HISTORY +In previous versions of +.BR MH , +the +.B pick +command would +.BR show , +.BR scan , +or +.B refile +the selected messages. This was rather +`inverted logic' from the UNIX point of view, so +.B pick +was changed to define sequences and output those sequences. Hence, +.B pick +can be used to generate the arguments for all other +.B MH +commands, instead of giving +.B pick +endless switches for invoking those commands +itself. +.PP +Also, previous versions of +.B pick +balked if you didn't specify +a search string or a date/time constraint. The current version does +not, and merely matches the messages you specify. This lets you type +something like: +.PP +.RS 5 +show\0`pick\0last:20\0\-seq\0fear` +.RE +.PP +instead of typing +.PP +.RS 5 +.nf +mark\0\-add\0\-nozero\0\-seq\0fear\0last:20 +show\0fear +.fi +.RE +.PP +Finally, timezones used to be ignored when comparing dates: they aren't +any more. + +.SH "HELPFUL HINTS" +Use +.RB ` "pick sequence \-list" ' +to enumerate the messages in a sequence +(such as for use by a shell script). + +.SH BUGS +Any occurrence of +.B \-datefield +must occur prior to the +.B \-after +or +.B \-before +switch it applies to. +.PP +If +.B pick +is used in a back\-quoted operation, such as +.PP +.RS 5 +scan\0`pick\0\-from\0jones` +.RE +.PP +and +.B pick +selects no messages (e.g., no messages are from +`jones'), then the shell will still run the outer command (e.g., +.BR scan ). +Since no messages were matched, +.B pick +produced +no output, and the argument given to the outer command as a result of +backquoting +.B pick +is empty. In the case of +.B nmh +programs, +the outer command now acts as if the default `msg' or `msgs' should be +used (e.g., `all' in the case of +.BR scan ). +To prevent this +unexpected behavior, if +.B \-list +was given, and if its standard output is not a tty, then +.B pick +outputs the illegal message number `0' +when it fails. This lets the outer command fail gracefully as well. +.PP +The pattern syntax `[l-r]' is not supported; each letter to be +matched must be included within the square brackets. diff --git a/man/post.man b/man/post.man deleted file mode 100644 index b6e395e..0000000 --- a/man/post.man +++ /dev/null @@ -1,269 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH POST %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -post \- deliver a message -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/post -.RB [ \-alias -.IR aliasfile ] -.RB [ \-filter -.IR filterfile ] -.RB [ \-nofilter ] -.RB [ \-format " | " \-noformat ] -.RB [ \-mime " | " \-nomime ] -.RB [ \-msgid " | " \-nomsgid ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-watch " | " \-nowatch ] -.RB [ \-width -.IR columns ] -.RB [ \-sasl ] -.RB [ \-saslmech -.IR mechanism ] -.RB [ \-user -.IR username ] -.I file -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Post -is the default program called by -.B send -to deliver -the message in -.I file -to local and remote users. In fact, most of -the features attributed to -.B send -in its manual page are performed by -.BR post , -with -.B send -acting as a relatively simple preprocessor. -Thus, it is -.B post -which parses the various header fields, appends -\*(lqFrom:\*(rq and \*(lqDate:\*(rq lines, and interacts with the mail transport system. -.B Post -will not normally be called directly by the user. -.PP -.B Post -searches the \*(lqTo:\*(rq, \*(lqcc:\*(rq, \*(lqBcc:\*(rq, -\*(lqFcc:\*(rq, and \*(lqResent\-xxx:\*(rq header lines of the specified -message for destination addresses, checks these addresses for validity, -and formats them so as to conform to ARPAnet Internet Message Format -protocol, unless the -.B \-noformat -flag is set. This will normally cause -\*(lq@\fIlocal\-site\fR\*(rq to be appended to each local destination -address, as well as any local return addresses. The -.B \-width -.I columns -switch can be used to indicate the preferred length of the header -components that contain addresses. -.PP -If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for -delivery, and the \*(lqBcc:\*(rq field will be removed from the message -sent to sighted recipients. The blind recipients will receive an entirely -new message with a minimal set of headers. Included in the body of the -message will be a copy of the message sent to the sighted recipients. -If -.B \-filter -.I filterfile -is specified, then this copy is filtered -(re\-formatted) by -.B mhl -prior to being sent to the blind recipients. -Alternately, if the -.B \-mime -switch is given, then -.B post -will use -the MIME rules for encapsulation. -.PP -The -.B \-alias -.I aliasfile -switch can be used to specify a file that post -should take aliases from. More than one file can be specified, each -being preceded with -.BR \-alias . -In any event, the primary alias file is -read first. -.PP -The -.B \-msgid -switch indicates that a \*(lqMessage\-ID:\*(rq or -\*(lqResent\-Message\-ID:\*(rq field should be added to the header. -.PP -The -.B \-verbose -switch indicates that the user should be informed of -each step of the posting/filing process. -.PP -The -.B \-watch -switch indicates that the user would like to watch the -transport system's handling of the message (e.g., local and \*(lqfast\*(rq -delivery). -.PP -Under normal circumstances, -.B post -constructs the \*(lqFrom:\*(rq line of the -message from the user's login name, the full name from the GECOS field of the -passwd file, and the fully\-qualified name of the local machine (or the -value of -\*(lqlocalname\*(rq in -.IR mts.conf , -if set). An example is \*(lqFrom: Dan Harkless -\*(rq. There are four ways to override these values, -however. Note that they apply equally to \*(lqResent\-From:\*(rq lines in messages sent -with -.BR dist . -.PP -The first way is GECOS\-based username masquerading. If the \*(lqmasquerade:\*(rq line -in -.I mts.conf -contains \*(lqmmailid\*(rq, this processing is activated. If a user's GECOS -field in the passwd file is of the form \*(lqFull Name \*(rq then \*(lqfakename\*(rq -will be used in place of the real username. For instance, a GECOS field of \*(lqDan -Harkless \*(rq would result in \*(lqFrom: Dan Harkless -\*(rq. Naturally if you were doing something like -this you'd want to set up an MTA alias (e.g. in /etc/aliases) from, for -instance, \*(lqDan.Harkless\*(rq to \*(lqdan\*(rq. -.PP -The second way to override default construction of \*(lqFrom:\*(rq is to set the -.B $SIGNATURE -environment variable. This variable overrides the full name -from the GECOS field, even if GECOS\-based masquerading is being done. This -processing is always active, and does not need to be enabled from -.IR mts.conf . -.PP -The third way is controlled by the \*(lquser_extension\*(rq value of \*(lqmasquerade:\*(rq line -of -.IR mts.conf . -When that's turned on, setting the -.B $USERNAME_EXTENSION -environment variable will result in its value being appended the user's login -name. For instance, if I set -.B $USERNAME_EXTENSION -to \*(lq+www\*(rq, my \*(lqFrom:\*(rq -line will contain \*(lqDan Harkless \*(rq (or -\*(lqDan.Harkless+www\*(rq if I'm using mmailid masquerading as well). Recent versions -of -.B sendmail -automatically deliver all mail sent to -.IR user + string -to -.IR user . -.B qmail -has a similar feature which uses '\-' as the delimiter by -default, but can use other characters as well. -.PP -The fourth method of address masquerading is to specify a \*(lqFrom:\*(rq line manually -in the message draft. It will be used as provided (after alias substitution), -but normally, to discourage email forgery, the user's -.B real -address will be -used in the SMTP envelope \*(lqFrom:\*(rq and in a \*(lqSender:\*(rq header. However, if the -\*(lqmasquerade:\*(rq line of -.I mts.conf -contains \*(lqdraft_from\*(rq, the SMTP envelope \*(lqFrom:\*(rq -will use the address given in the draft \*(lqFrom:\*(rq, and there will be no \*(lqSender:\*(rq -header. This is useful in pretending to send mail \*(lqdirectly\*(rq from a remote POP3 -account, or when remote email robots give improper precedence to the envelope -\*(lqFrom:\*(rq. Note that your MTA may still reveal your real identity (e.g. -.BR sendmail 's -\*(lqX\-Authentication\-Warning:\*(rq header). -.PP -If nmh is using the SMTP MTA, the -.B \-server -and the -.B \-port -switches can be used to override the default mail server (defined by the -.RI servers -entry in -.I %etcdir%/mts.conf -). -.PP -If -.B nmh -has been compiled with SASL support, the -.B \-sasl -switch will enable -the use of SASL authentication with the SMTP MTA. Depending on the -SASL mechanism used, this may require an additional password prompt from the -user (but the -.RI \*(lq \&.netrc \*(rq -file can be used to store this password). -.B \-saslmech -switch can be used to select a particular SASL mechanism, -and the the -.B \-user -switch can be used to select a authorization userid -to provide to SASL other than the default. -.PP -If SASL authentication is successful, -.BR nmh -will attempt to negotiate a security layer for session encryption. -Encrypted data is labelled with `(sasl-encrypted)' and `(sasl-decrypted)' when -viewing the SMTP transaction with the -.B \-snoop -switch. -.PP -If -.B nmh -has been compiled with TLS support, the -.B \-tls -switch will require the negotiation of TLS support when connecting to the -SMTP MTA. Encrypted data is labelled with `(tls-encrypted)' and -`(tls-decrypted)' when viewing the SMTP transction with the -.B \-snoop -switch. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -^%etcdir%/MailAliases~^global nmh alias file -^%bindir%/refile~^Program to process Fcc:s -^%libdir%/mhl~^Program to process Bcc:s -.fi - -.SH "PROFILE COMPONENTS" -.B post -does -.B NOT -consult the user's -.I \&.mh\(ruprofile - -.SH "SEE ALSO" -mhmail(1), send(1), mh\-mail(5), mh\-alias(5), mh\-tailor(5), -.I "Standard for the Format of ARPA Internet Text Messages" -(RFC\-822) - -.SH DEFAULTS -.nf -.RB ` \-alias "' defaults to %etcdir%/MailAliases" -.RB ` \-format ' -.RB ` \-nomime ' -.RB ` \-nomsgid ' -.RB ` \-noverbose ' -.RB ` \-nowatch ' -.RB ` "\-width\ 72" ' -.RB ` \-nofilter ' -.fi - -.SH CONTEXT -None - -.SH BUGS -\*(lqReply\-To:\*(rq fields are allowed to have groups in them according -to the 822 specification, but -.B post -won't let you use them. diff --git a/man/prev.man b/man/prev.man deleted file mode 100644 index 6ef0b8e..0000000 --- a/man/prev.man +++ /dev/null @@ -1,93 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH PREV %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -prev \- show the previous message -.SH SYNOPSIS -.HP 5 -.na -.B prev -.RI [ +folder ] -.RB [\-showproc -.IR program ] -.RB [ \-showmimeproc -.IR program ] -.RB [ \-header " | " \-noheader ] -.RB [ \-checkmime " | " \-nocheckmime ] -[switches\ for -.I showproc -or -.IR showmimeproc ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Prev -performs a -.B show -on the previous message in the specified -(or current) folder. Like -.BR show , -it passes any switches on to -the program named by -.I showproc -or -.IR showmimeproc , -which is called -to list the message. This command is almost exactly equivalent to -.RB \*(lq "show prev" \*(rq. -Consult the manual entry for -.BR show (1) -for all the details. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^showproc:~^Program to show non-MIME messages -^showmimeproc:~^Program to show MIME messages -.fi - -.SH "SEE ALSO" -show(1), next(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` \-checkmime ' -.RB ` \-header ' -.fi - -.SH CONTEXT -If a folder is specified, it will become the current folder. The message -that is shown (i.e., the previous message in sequence) will become the -current message. - -.SH BUGS -.B prev -is really a link to the -.B show -program. As a result, if -you make a link to -.B prev -and that link is not called -.BR prev , -your link will act like -.B show -instead. To circumvent this, add a -profile\-entry for the link to your -.B nmh -profile and add the argument -.B prev -to the entry. diff --git a/man/prev.man1 b/man/prev.man1 new file mode 100644 index 0000000..b756c04 --- /dev/null +++ b/man/prev.man1 @@ -0,0 +1 @@ +.so man1/show.1 diff --git a/man/prompter.man b/man/prompter.man deleted file mode 100644 index 623abba..0000000 --- a/man/prompter.man +++ /dev/null @@ -1,195 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH PROMPTER %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -prompter \- prompting editor front-end for nmh -.SH SYNOPSIS -.HP 5 -.na -.B prompter -.RB [ \-erase -.IR chr ] -.RB [ \-kill -.IR chr ] -.RB [ \-prepend " | " \-noprepend ] -.RB [ \-rapid " | " \-norapid ] -.RB [ \-doteof " | " \-nodoteof ] -.I file -.RB [ \-version ] -.RB [ \-help ] -.fi -.SH DESCRIPTION -.B Prompter -is an editor front\-end for -.B nmh -which allows rapid -composition of messages. This program is not normally invoked directly by -users but takes the place of an editor and acts as an editor front\-end. -It operates on an RFC\-822 style message draft skeleton specified by -.IR file , -normally provided by the -.B nmh -commands -.BR comp , -.BR dist , -.BR forw , -or -.BR repl . -.PP -.B Prompter -is particularly useful when composing messages over slow -network or modem lines. It is an -.B nmh program in that it can have -its own profile entry with switches, but it is not invoked directly by -the user. The commands -.BR comp , -.BR dist , -.BR forw , -and -.B repl -invoke -.B prompter as an editor, either when invoked with -.B \-editor -.IR prompter , -or by the profile entry \*(lqEditor:\ prompter\*(rq, -or when given the command -.B edit -.B prompter -at the \*(lqWhat now?\*(rq prompt. -.PP -For each empty component -.B prompter finds in the draft, the user -is prompted for a response; A will cause the whole component -to be left out. Otherwise, a `\\' preceding a will continue -the response on the next line, allowing for multiline components. -Continuation lines -.B must -begin with a space or tab. -.PP -Each non\-empty component is copied to the draft and displayed on the -terminal. -.PP -The start of the message body is denoted by a blank line or a line -of dashes. If the body is non\-empty, the prompt, which isn't written -to the file, is -.PP -.RS 5 ---------Enter additional text -.RE -.PP -or (if -.B \-prepend -was given) -.PP -.RS 5 ---------Enter initial text -.RE -.PP -Message\-body typing is terminated with an end\-of\-file (usually -CTRL\-D). With the -.B \-doteof -switch, a period on a line all by itself -also signifies end\-of\-file. At this point control is returned to -the calling program, where the user is asked \*(lqWhat now?\*(rq. -See -.B whatnow (1) -for the valid options to this query. -.PP -By using the -.B \-prepend -switch, the user can add type\-in to the -beginning of the message body and have the rest of the body follow. -This is useful for the -.B forw -command. -.PP -By using the -.B \-rapid -switch, if the draft already contains text in -the message\-body, it is not displayed on the user's terminal. This is -useful for low\-speed terminals. -.PP -The line editing characters for kill and erase may be specified by the -user via the arguments -.B \-kill -.I chr -and -.B \-erase -.IR chr , -where -.I chr -may be a character; or `\\nnn', where \*(lqnnn\*(rq is the octal value for -the character. -.PP -An interrupt (usually CTRL\-C) during component typing will abort -.B prompter -and the -.B nmh -command that invoked it. An interrupt -during message\-body typing is equivalent to CTRL\-D, for historical -reasons. This means that -.B prompter -should finish up and exit. -.PP -The first non\-flag argument to -.B prompter is taken as the name of -the draft file, and subsequent non\-flag arguments are ignored. -.\" (\fIRepl\fR invokes editors with two file arguments: -.\" the draft file name and the replied\-to message file name.) - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^/tmp/prompter*~^Temporary copy of message -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -prompter\-next: To name the editor to be used on exit from .B prompter -^Msg\-Protect:~^To set mode when creating a new draft -.fi - -.SH "SEE ALSO" -comp(1), dist(1), forw(1), repl(1), whatnow(1) - -.SH DEFAULTS -.nf -.RB ` \-prepend ' -.RB ` \-norapid ' -.RB ` \-nodoteof ' -.fi - -.SH CONTEXT -None - -.SH "HELPFUL HINTS" -The -.B \-rapid -option is particularly useful with -.BR forw , -and -.B \-noprepend -is useful with -.B comp -.BR \-use . -.PP -The user may wish to link -.B prompter under several names (e.g., -\*(lqrapid\*(rq) and give appropriate switches in the profile entries -under these names (e.g., \*(lqrapid: -rapid\*(rq). This facilitates -invoking prompter differently for different -.B nmh -commands (e.g., -\*(lqforw: -editor rapid\*(rq). - -.SH BUGS -.B Prompter -uses -.BR stdio (3), -so it will lose if you edit files with nulls in them. diff --git a/man/prompter.man1 b/man/prompter.man1 new file mode 100644 index 0000000..4d701c6 --- /dev/null +++ b/man/prompter.man1 @@ -0,0 +1,214 @@ +.\" +.\" %nmhwarning% +.\" +.TH PROMPTER %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +prompter \- prompting editor front-end for mmh +.SH SYNOPSIS +.HP 5 +.na +.B prompter +.RB [ \-prepend " | " \-noprepend ] +.RB [ \-rapid " | " \-norapid ] +.RB [ \-body " | " \-nobody ] +.I file +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Prompter +is an editor front-end for +.B mmh +which allows rapid +composition of messages. This program is not normally invoked directly by +users but takes the place of an editor and acts as an editor front-end. +It operates on an RFC-822 style message draft skeleton specified by +.IR file , +normally provided by the +.B mmh +commands +.BR comp , +.BR dist , +.BR forw , +or +.BR repl . +.PP +.B Prompter +is particularly useful when composing messages over slow +network or modem lines. It is hardly invoked directly by +the user. The commands +.BR comp , +.BR dist , +.BR forw , +and +.B repl +invoke +.B prompter +as an editor, either when invoked with +.B \-editor +.IR prompter , +or by the profile entry `Editor:\ prompter', +or when given the command +.B edit prompter +at the `What now?' prompt. +.PP +For each empty component +.B prompter +finds in the draft, the user +is prompted for a response. An empty response will cause the whole component +to be left out. Otherwise, a `\\' preceding the Newline will continue +the response on the next line, allowing for multiline components. +Continuation lines +.B must +begin with a space or tab. +.PP +Each non-empty component is copied to the draft and displayed on the +terminal. +.PP +The start of the message body is denoted by a blank line or a line +of dashes. +Unless +.B \-nobody +is specified, the user is queried to enter the message body. +If the body of the draft is non-empty, the typed-in text will be prepended +or appended to the existing body, depending on the +.B \-prepend +and +.B \-noprepend +switches. +In these cases, the prompt (which isn't written to the file) is +.PP +.RS 5 +\-\-\-\-\-\-\-\-Enter additional text +.RE +.PP +or (if +.B \-prepend +was given) +.PP +.RS 5 +\-\-\-\-\-\-\-\-Enter initial text +.RE +.PP +Message-body typing is terminated with an end-of-file (usually +CTRL-D). +At this point control is returned to +the calling program, where the user is asked `What now?'. +See +.B whatnow (1) +for the valid options to this query. +.PP +By using the +.B \-nobody +switch, the user is only queried to fill in header fields, but not to enter +any body text. +Note, that the +.BR \-body and \-nobody +switches had already existed already in +.B nmh +in undocumented/hidden form, +but with a slightly different meaning. +Back then, +.B "prompter \-nobody +would change the draft to have an empty body, +by ignoring any existing body and not querying the user for body text. +.PP +By using the +.B \-prepend +switch, the user can add type-in to the +beginning of the message body and have the rest of the body follow. +With +.B \-noprepend +the typed-in text is appended to the message body. +.PP +By using the +.B \-rapid +switch, if the draft already contains text in +the message-body, it is not displayed on the user's terminal. This is +useful for low-speed terminals. +.PP +An interrupt (usually CTRL-C) during component typing will abort +.B prompter +and the +.B mmh +command that invoked it. An interrupt +during message-body typing is equivalent to CTRL-D, for historical +reasons and to avoid losing the typed-in message text. This means that +.B prompter +should finish up and exit, usually putting the user back to the +Whatnow prompt. +.PP +The first non-flag argument to +.B prompter +is taken as the name of +the draft file, and subsequent non-flag arguments are ignored. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^/tmp/prompter*~^Temporary copy of message +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +prompter\-next: The editor to be used on exit from \fBprompter\fP +^Msg\-Protect:~^To set mode when creating a new draft +.fi + +.SH "SEE ALSO" +comp(1), dist(1), forw(1), repl(1), whatnow(1) + +.SH DEFAULTS +.nf +.RB ` \-body ' +.RB ` \-prepend ' +.RB ` \-norapid ' +.fi + +.SH CONTEXT +None + +.SH "HELPFUL HINTS" +The +.B \-noprepend +switch is particularly useful with +.B comp +.BR \-use . +.PP +The user may wish to link +.B prompter +under several names (e.g., +`rapid') and give appropriate switches in the profile entries +under these names (e.g., `rapid: -rapid'). This facilitates +invoking prompter differently for different +.B mmh +commands (e.g., +`forw: -editor rapid'). +.PP +Former +.B mutt +users might find it useful to create a shell script +.B hprompter +containing: +.PP +.RS 5 +.nf +prompter \-nobody \-rapid "$1" +vi "$1" +.fi +.RE +.LP +and use that as the default editor for +.B comp +by adding a profile entry like: +.PP +.RS 5 +.nf +comp: \-editor hprompter +.fi +.RE diff --git a/man/rcvdist.man b/man/rcvdist.man deleted file mode 100644 index f24ea8e..0000000 --- a/man/rcvdist.man +++ /dev/null @@ -1,82 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RCVDIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rcvdist \- asynchronously redistribute new mail -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/rcvdist -.RB [ \-form -.IR formfile ] -[switches\ for -.IR postproc ] -.I address1 -\&... -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B rcvdist -program will accept a message on its standard input -and resend a copy of this message to all of the addresses listed on its -command line. -.PP -When a message is redistributed with the -.B rcvdist -command, the -format of the Resent-xxx header fields is controlled by the forms files -.RI \*(lq rcvdistcomps \*(rq. -If a file named -.RI \*(lq rcvdistcomps \*(rq -exists in the user's nmh -directory, it will be used instead of the default one. You may specify -an alternate forms file with the switch -.B \-form -.IR formfile . -.PP -The -.RI \*(lq rcvdistcomps \*(rq -file uses the format string facility described in -.BR mh\-format (5). -In addition to the standard format escapes, -.B rcvdist -also recognizes the following additional -.I component -escape: -.PP -.RS 5 -.nf -.ta \w'Dtimenow 'u +\w'Returns 'u -.I Escape Returns Description -addresses string the addresses to distribute to -.fi -.RE -.PP -By default, -.B rcvdist -uses the program -.B post -to do the actual -delivery of the message, although this can be changed by defining the -.I postproc -profile component. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/rcvdistcomps~^Default message skeleton -^or /rcvdistcomps~^Rather than standard message skeleton -^%etcdir%/mts.conf~^nmh mts configuration file -^$HOME/\&.maildelivery~^The file controlling local delivery -^%etcdir%/maildelivery~^Rather than the standard file -.fi - -.SH "SEE ALSO" -rcvpack(1), rcvstore(1), rcvtty(1), mh\-format(5), slocal(1) - -.SH BUGS -Only two return codes are meaningful, others should be. diff --git a/man/rcvdist.man1 b/man/rcvdist.man1 new file mode 100644 index 0000000..33ec5b6 --- /dev/null +++ b/man/rcvdist.man1 @@ -0,0 +1,75 @@ +.\" +.\" %nmhwarning% +.\" +.TH RCVDIST %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +rcvdist \- asynchronously redistribute new mail +.SH SYNOPSIS +.HP 5 +.na +.B rcvdist +.RB [ \-form +.IR formfile ] +[switches\ for +.BR spost ] +.IR RECIPIENT ... +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B rcvdist +program will accept a message on its standard input +and resend a copy of this message to all of the addresses listed on its +command line. +.PP +When a message is redistributed with the +.B rcvdist +command, the +format of the Resent-xxx header fields is controlled by the forms files +.RI ` rcvdistcomps '. +If a file named +.RI ` rcvdistcomps ' +exists in the user's mmh +directory, it will be used instead of the default one. You may specify +an alternate forms file with the switch +.B \-form +.IR formfile . +.PP +The +.RI ` rcvdistcomps ' +file uses the format string facility described in +.BR mh\-format (5). +In addition to the standard format escapes, +.B rcvdist +also recognizes the following additional +.I component +escape: +.PP +.RS 5 +.nf +.ta \w'Dtimenow 'u +\w'Returns 'u +.I "Escape Returns Description +addresses string the addresses to distribute to +.fi +.RE +.PP +.B rcvdist +uses the program +.B spost +to do the actual +delivery of the message. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/rcvdistcomps~^Default message skeleton +^or $HOME/.mmh/rcvdistcomps~^Rather than standard message skeleton +.fi + +.SH "SEE ALSO" +rcvpack(1), rcvstore(1), mh\-format(5), slocal(1) + +.SH BUGS +Only two return codes are meaningful, others should be. diff --git a/man/rcvpack.man b/man/rcvpack.man deleted file mode 100644 index 26ba263..0000000 --- a/man/rcvpack.man +++ /dev/null @@ -1,58 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RCVPACK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rcvpack \- append message to file -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/rcvpack -.I file -.RB [ \-mbox ] -.RB [ \-mmdf ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B rcvpack -program will append a copy of the message to the file -listed on its command line. -.PP -If the -.B \-mbox -switch is given (the default), then the messages are -separated using mbox (uucp) style delimiters. This is the format used -by most mail clients (elm, mailx, etc.). -.PP -If the -.B \-mmdf -switch is given, then the messages are separated by -mmdf style delimiters. Each message in the file is separated by four -CTRL\-A's and a newline. -.PP -.B rcvpack -will correctly lock and unlock the file to serialize -access to the file, when running multiple copies of -.B rcvpack . -.PP -In general, its use is obsoleted by the -.B file -action of -.BR slocal , -although it might still have occasional uses in various -shell scripts. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -.fi - -.SH "SEE ALSO" -rcvdist(1), rcvstore(1), rcvtty(1), slocal(1) - -.SH BUGS -Only two return codes are meaningful, others should be. diff --git a/man/rcvpack.man1 b/man/rcvpack.man1 new file mode 100644 index 0000000..e444709 --- /dev/null +++ b/man/rcvpack.man1 @@ -0,0 +1,53 @@ +.\" +.\" %nmhwarning% +.\" +.TH RCVPACK %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +rcvpack \- append message to mbox file +.SH SYNOPSIS +.HP 5 +.na +.B rcvpack +.RI [ file ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +The +.B rcvpack +program will read a message on standard in, convert it and +append it to the mbox file listed on the command line. +.PP +The RFC 822 message is converted to the mbox format. +This is the format used by most mail clients (elm, mailx, etc.). +For the nitpickers: It's the mboxo format. +.PP +.B rcvpack +will correctly lock and unlock the file to serialize +access to the file, when running multiple copies of +.B rcvpack . +.PP +If no +.I file +argument is given, the converted message is printed to standard out. +No locking will be done in this case. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +.fi + +.SH "SEE ALSO" +rcvdist(1), rcvstore(1), slocal(1), packf(1) + +.SH HISTORY +Some people say that this tool would be obsoleted by the +.B file +action of +.BR slocal , +although it might still have occasional uses in various +shell scripts. + +.SH BUGS +Only two return codes are meaningful, others should be. diff --git a/man/rcvstore.man b/man/rcvstore.man deleted file mode 100644 index 010e238..0000000 --- a/man/rcvstore.man +++ /dev/null @@ -1,144 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RCVSTORE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rcvstore \- asynchronously incorporate mail into a folder -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/rcvstore -.RI [ +folder ] -.RB [ \-create " | " \-nocreate ] -.RB [ \-unseen " | " \-nounseen ] -.RB [ \-zero " | " \-nozero ] -.RB [ \-sequence -.I name -\&...] -.RB [ \-public " | " \-nopublic ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Rcvstore -incorporates a message from the standard input into an -.B nmh -folder. This command is typically used in conjunction with -mail filtering programs such as -.B slocal -and -.BR procmail , -to filter your mail into different folders. -.PP -You may specify which folder to use with -.IR +folder . -If no folder is specified, -.B rcvstore -will use the folder given by a non\-empty -\*(lqInbox:\*(rq entry in the user's profile, else it will use the folder -named \*(lqinbox\*(rq. -.PP -If the switch -.B \-create -is given (it is the default) and if the specified -(or default) folder does not exist, then it will be created. You may -disable this with the -.B \-nocreate -option. In this case -.B rcvstore -will exit if the specified folder does not exist. -.PP -When the new message is incorporated into the folder, it is assigned -the next highest number for that folder. -.PP -.B Rcvstore -will incorporate anything except zero length messages -into the user's -.B nmh -folder. It will not change the message in any -way. -.PP -If the user's profile contains a \*(lqMsg\-Protect: nnn\*(rq entry, it -will be used as the protection on the newly created message, otherwise -the -.B nmh -default of 0644 will be used. For all subsequent operations -on this message, this initially assigned protection will be preserved. -.PP -If the switch -.B \-unseen -is given (it is on by default), and if the -profile entry \*(lqUnseen\-Sequence\*(rq is present and non\-empty, then -.B rcvstore -will add the newly incorporated message to each sequence -named by this profile entry. You may use the switch -.B \-nounseen -to disable this. These sequences will not be zero'ed by -.B rcvstore -prior to adding the new message. -.PP -Furthermore, the incoming message may be added to additional sequences -as they arrive by the use of the -.B \-sequence -switch. As with the -commands -.B pick -and -.BR mark , -you may also use the switches -.B \-zero -and -.B \-nozero -to specify whether to zero old sequences or not. -Similarly, use of the -.B \-public -and -.B \-nopublic -switches may be used -to force these sequences to be public or private sequences. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Folder\-Protect:~^To set mode when creating a new folder -^Inbox:~^To find the default inbox -^Msg\-Protect:~^To set mode when creating a new message -^Unseen\-Sequence:~^To name sequences denoting unseen messages -.fi - -.SH "SEE ALSO" -rcvdist(1), rcvpack(1), rcvtty(1), mh\-sequence(5) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to \*(lqInbox\*(rq profile entry" -.RB ` \-create ' -.RB ` \-unseen ' -.RB ` \-nozero ' -.fi - -.SH CONTEXT -No context changes will be attempted, with the exception of -sequence manipulation. - -.SH BUGS -If you use the \*(lqUnseen\-Sequence\*(rq profile entry, -.B rcvstore -could try to update the context while another -.B nmh -process -is also trying to do so. This can cause the context to become -corrupted. To avoid this, do not use -.B rcvstore -if you use the -\*(lqUnseen\-Sequence\*(rq profile entry. diff --git a/man/rcvstore.man1 b/man/rcvstore.man1 new file mode 100644 index 0000000..c9c64b9 --- /dev/null +++ b/man/rcvstore.man1 @@ -0,0 +1,144 @@ +.\" +.\" %nmhwarning% +.\" +.TH RCVSTORE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +rcvstore \- asynchronously incorporate mail into a folder +.SH SYNOPSIS +.HP 5 +.na +.B rcvstore +.RI [ +folder ] +.RB [ \-create " | " \-nocreate ] +.RB [ \-unseen " | " \-nounseen ] +.RB [ \-zero " | " \-nozero ] +.RB [ \-sequence +.I name +\&...] +.RB [ \-public " | " \-nopublic ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Rcvstore +incorporates a message from the standard input into an +.B nmh +folder. This command is typically used in conjunction with +mail filtering programs such as +.B slocal +and +.BR procmail , +to filter your mail into different folders. +.PP +You may specify which folder to use with +.IR +folder . +If no folder is specified, +.B rcvstore +will use the folder given by a non\-empty +`Inbox:' entry in the user's profile, else it will use the folder +named `inbox'. +.PP +If the switch +.B \-create +is given (it is the default) and if the specified +(or default) folder does not exist, then it will be created. You may +disable this with the +.B \-nocreate +option. In this case +.B rcvstore +will exit if the specified folder does not exist. +.PP +When the new message is incorporated into the folder, it is assigned +the next highest number for that folder. +.PP +.B Rcvstore +will incorporate anything except zero length messages +into the user's +.B nmh +folder. It will not change the message in any +way. +.PP +If the user's profile contains a `Msg\-Protect: nnn' entry, it +will be used as the protection on the newly created message, otherwise +the +.B nmh +default of 0644 will be used. For all subsequent operations +on this message, this initially assigned protection will be preserved. +.PP +If the switch +.B \-unseen +is given (it is on by default), and if the +profile entry `Unseen\-Sequence' is present and non\-empty, then +.B rcvstore +will add the newly incorporated message to each sequence +named by this profile entry. You may use the switch +.B \-nounseen +to disable this. These sequences will not be zero'ed by +.B rcvstore +prior to adding the new message. +.PP +Furthermore, the incoming message may be added to additional sequences +as they arrive by the use of the +.B \-sequence +switch. As with the +commands +.B pick +and +.BR mark , +you may also use the switches +.B \-zero +and +.B \-nozero +to specify whether to zero old sequences or not. +Similarly, use of the +.B \-public +and +.B \-nopublic +switches may be used +to force these sequences to be public or private sequences. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Folder\-Protect:~^To set mode when creating a new folder +^Inbox:~^To find the default inbox +^Msg\-Protect:~^To set mode when creating a new message +^Unseen\-Sequence:~^To name sequences denoting unseen messages +.fi + +.SH "SEE ALSO" +rcvdist(1), rcvpack(1), mh\-sequence(7) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to `Inbox' profile entry" +.RB ` \-create ' +.RB ` \-unseen ' +.RB ` \-nozero ' +.fi + +.SH CONTEXT +No context changes will be attempted, with the exception of +sequence manipulation. + +.SH BUGS +If you use the `Unseen\-Sequence' profile entry, +.B rcvstore +could try to update the context while another +.B nmh +process +is also trying to do so. This can cause the context to become +corrupted. To avoid this, do not use +.B rcvstore +if you use the +`Unseen\-Sequence' profile entry. diff --git a/man/rcvtty.man b/man/rcvtty.man deleted file mode 100644 index f098b21..0000000 --- a/man/rcvtty.man +++ /dev/null @@ -1,125 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RCVTTY %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rcvtty \- report new mail -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/rcvtty -.RI [ command ] -.RB [ \-form -.IR formatfile ] -.RB [ \-format -.IR string ] -.RB [ \-width -.IR columns ] -.RB [ \-bell " | " \-nobell ] -.RB [ \-newline " | " \-nonewline ] -.RB [ \-biff ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -The -.B rcvtty -can be used to report new mail. It is used primarily -in conjunction with mail filtering agents such as -.B slocal -or -.BR procmail . -.PP -The -.B rcvtty -program executes the named command with the message as -its standard input, and writes the resulting output on your terminal. -.PP -Alternately, if no command is specified (or is bogus), then -.B rcvtty -will instead write a one\-line scan listing. The default output format -of this scan listing may be overridden by using either the -.B \-form -.I formatfile -or -.B \-format -.I string -option, similar to the -equivalent options for -.B scan -and -.BR inc . -See -.BR mh\-format (5) -for details. -.PP -A newline is output before the message output, and the terminal bell is -rung after the output. The -.B \-nonewline -and -.B \-nobell -options will -inhibit these functions. -.PP -The switch -.B \-width -.I columns -may be given to specify the width of -the scan line. The default is to use the width of the terminal. -.PP -In addition to the standard format escapes described in -.BR mh\-format (5), -.B rcvtty -also recognizes the following additional -.I component -escapes: -.PP -.RS 5 -.nf -.ta \w'Dtimenow 'u +\w'Returns 'u -Escape Returns Description -body string the (compressed) first part of the body -dtimenow date the current date -folder string the name of the current folder -.fi -.RE -.PP -By default, -.B rcvtty -will send its output to every terminal on the -local machine that is owned by current user, and that has given write -permission as granted by the command -.BR mesg (1). -If the option -.B \-biff -is given, then -.B rcvtty -will obey the notification status -set by the command -.BR biff (1) -instead. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -^$HOME/\&.maildelivery~^The file controlling local delivery -^%etcdir%/maildelivery~^Rather than the standard file -.fi - -.SH CONTEXT -None - -.SH DEFAULTS -.nf -.RB ` \-width "' defaults to the width of the terminal" -.RB ` \-newline ' -.RB ` \-bell ' -.fi - -.SH "SEE ALSO" -rcvdist(1), rcvpack(1), rcvstore(1), mh\-format(5), slocal(1) - -.SH BUGS -Only two return codes are meaningful, others should be. diff --git a/man/refile.man b/man/refile.man deleted file mode 100644 index 4b55fe1..0000000 --- a/man/refile.man +++ /dev/null @@ -1,233 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH REFILE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -refile \- file message in other folders -.SH SYNOPSIS -.HP 5 -.na -.B refile -.RI [ msgs ] -.RB [ \-draft ] -.RB [ \-link " | " \-nolink ] -.RB [ \-preserve " | " \-nopreserve ] -.RB [ \-unlink " | " \-nounlink ] -.RB [ \-src -.IR +folder ] -.RB [ \-file -.IR file ] -.RB [ \-rmmproc -.IR program ] -.RB [ \-normmproc ] -.I +folder1 -\&... -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Refile -moves (see -.BR mv (1)) -or links (see -.BR ln (1)) -messages -from a source folder into one or more destination folders. -.PP -If you think of a message as a sheet of paper, this operation is not -unlike filing the sheet of paper (or copies) in file cabinet folders. -When a message is filed, it is linked into the destination folder(s) -if possible, and is copied otherwise. As long as the destination -folders are all on the same file system, multiple filing causes little -storage overhead. This facility provides a good way to cross\-file or -multiply\-index messages. For example, if a message is received from -Jones about the ARPA Map Project, the command -.PP -.RS 5 -refile\0cur\0+jones\0+Map -.RE -.PP -would allow the message to be found in either of the two folders `jones' -or `Map'. -.PP -You may specify the source folder using -.B \-src -.IR +folder . -If this is -not given, the current folder is used by default. If no message is -specified, then `cur' is used by default. -.PP -The option -.B \-file -.I file -directs -.B refile -to use the specified file -as the source message to be filed, rather than a message from a folder. -Note that the file should be a validly formatted message, just like -any other -.B nmh -message. It should -.B NOT -be in mail drop format -(to convert a file in mail drop format to a folder of -.B nmh -messages, -see -.BR inc (1)). -.PP -If a destination folder doesn't exist, -.B refile -will ask if you want -to create it. A negative response will abort the file operation. If the -standard input for -.B refile -is -.B not -a tty, then -.B refile -will not ask any questions and will proceed as if the user answered -\*(lqyes\*(rq to all questions. -.PP -The option -.B \-link -preserves the source folder copy of the message (i.e., -it does a -.BR ln (1) -rather than a -.BR mv (1)), -whereas, -.B \-nolink -(the default) deletes the filed messages from the source folder. -.PP -Normally when a message is refiled, for each destination folder it -is assigned the number which is one above the current highest message -number in that folder. Use of the -.B \-preserv -switch will override -this message renaming, and try to preserve the number of the message. -If a conflict for a particular folder occurs when using the -.B \-preserve -switch, then -.B refile -will use the next available message number -which is above the message number you wish to preserve. -.PP -If -.B \-link -is not specified (or -.B \-nolink -is specified), the filed -messages will be removed from the source folder. The default is to -remove these messages by renaming them with a site-dependent prefix -(usually a comma). Such files will then need to be removed in some -manner after a certain amount of time. Many sites arrange for -.B cron -to remove these files once a day, so check with your -system administrator. -.PP -Alternately, if you wish for -.B refile -to really remove the files -representing these messages from the source folder, you can use the -.B -unlink -switch (not to be confused with the -.B \-link -switch). But -messages removed by this method cannot be later recovered. -.PP -If you prefer a more sophisticated method of `removing' the messages -from the source folder, you can define the -.B rmmproc -profile -component. For example, you can add a profile component such as -.PP -.RS 5 -rmmproc: /home/coleman/bin/rmm_msgs -.RE -.PP -then -.B refile -will instead call the named program or script to -handle the message files. -.PP -The user may specify -.B \-rmmproc -.I program -on the command line to -override this profile specification. The -.B \-normmproc -option forces -the message files to be deleted by renaming or unlinking them as -described above. -.PP -The -.B \-draft -switch tells -.B refile -to file the /draft. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Folder\-Protect:~^To set mode when creating a new folder -^rmmproc:~^Program to delete the message -.fi - -.SH "SEE ALSO" -folder(1), rmf(1), rmm(1) - -.SH DEFAULTS -.nf -.RB ` "\-src\ +folder" "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-nolink ' -.RB ` \-nounlink ' -.RB ` \-nopreserve ' -.fi - -.SH CONTEXT -If -.B \-src -.I +folder -is given, it will become the current folder. -If neither -.B \-link -nor `all' is specified, the current message in the -source folder will be set to the last message specified; otherwise, the -current message won't be changed. -.PP -If the \*(lqPrevious\-Sequence\*(rq profile entry is set, in addition to defining -the named sequences from the source folder, -.B refile -will also define -those sequences for the destination folders. See -.B mh\-sequence (5) -for information concerning the previous sequence. - -.SH BUGS -Since -.B refile -uses your -.I rmmproc -to delete the message, -the -.I rmmproc -must -.B NOT -call -.B refile -without specifying -.BR \-normmproc , -or you will create an infinite loop. diff --git a/man/refile.man1 b/man/refile.man1 new file mode 100644 index 0000000..3bc85f7 --- /dev/null +++ b/man/refile.man1 @@ -0,0 +1,144 @@ +.\" +.\" %nmhwarning% +.\" +.TH REFILE %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +refile \- file message in other folders +.SH SYNOPSIS +.HP 5 +.na +.B refile +.RI [ msgs ] +.RB [ \-link " | " \-nolink ] +.RB [ \-src +.IR +folder ] +.RB [ \-file +.IR file ] +.I +folder1 +\&... +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Refile +moves (see +.BR mv (1)) +or links (see +.BR ln (1)) +messages +from a source folder into one or more destination folders. +.PP +If you think of a message as a sheet of paper, this operation is not +unlike filing the sheet of paper (or copies) in file cabinet folders. +When a message is filed, it is linked into the destination folder(s) +if possible, and is copied otherwise. As long as the destination +folders are all on the same file system, multiple filing causes little +storage overhead. This facility provides a good way to cross\-file or +multiply\-index messages. For example, if a message is received from +Jones about the ARPA Map Project, the command +.PP +.RS 5 +refile\0cur\0+jones\0+Map +.RE +.PP +would allow the message to be found in either of the two folders `jones' +or `Map'. +.PP +You may specify the source folder using +.B \-src +.IR +folder . +If this is +not given, the current folder is used by default. If no message is +specified, then `cur' is used by default. +.PP +The option +.B \-file +.I file +directs +.B refile +to use the specified file +as the source message to be filed, rather than a message from a folder. +Note that the file should be a validly formatted message, just like +any other +.B nmh +message. It should +.B NOT +be in mail drop format +(to convert a file in mail drop format to a folder of +.B nmh +messages, +see +.BR inc (1)). +.PP +If a destination folder doesn't exist, +.B refile +will ask if you want +to create it. A negative response will abort the file operation. If the +standard input for +.B refile +is +.B not +a tty, then +.B refile +will not ask any questions and will proceed as if the user answered +`yes' to all questions. +.PP +The option +.B \-link +preserves the source folder copy of the message (i.e., +it does a +.BR ln (1) +rather than a +.BR mv (1)), +whereas, +.B \-nolink +(the default) deletes the filed messages from the source folder. +No backups are kept, because the contents don't vanish. +They are only moved to a new location. +To restore: refile the other way. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Folder\-Protect:~^To set mode when creating a new folder +.fi + +.SH "SEE ALSO" +folder(1), rmf(1), rmm(1) + +.SH DEFAULTS +.nf +.RB ` "\-src\ +folder" "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-nolink ' +.fi + +.SH CONTEXT +If +.B \-src +.I +folder +is given, it will become the current folder. +If +.B \-link +is specified, the current message in the +source folder will be set to the last message specified; otherwise, the +current message won't be changed. +.PP +If the `Previous\-Sequence' profile entry is set, in addition to defining +the named sequences from the source folder, +.B refile +will also define +those sequences for the destination folders. See +.B mh\-sequence (7) +for information concerning the previous sequence. diff --git a/man/repl.man b/man/repl.man deleted file mode 100644 index 9f2f489..0000000 --- a/man/repl.man +++ /dev/null @@ -1,545 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH REPL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -repl \- reply to a message -.SH SYNOPSIS -.HP 5 -.na -.B repl -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-annotate " | " \-noannotate ] -.RB [ \-group " | " \-nogroup ] -.RB [ \-cc -all/to/cc/me] -.RB [ \-nocc -all/to/cc/me] -.RB [ \-query " | " \-noquery ] -.RB [ \-form -.IR formfile ] -.RB [ \-format " | " \-noformat ] -.RB [ \-filter -.IR filterfile ] -.RB [ \-inplace " | " \-noinplace ] -.RB [ \-mime " | " \-nomime ] -.RB [ \-fcc -.IR +folder ] -.RB [ \-width -.IR columns ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-editor -.IR editor ] -.RB [ \-noedit ] -.RB [ \-whatnowproc -.IR program ] -.RB [ \-nowhatnowproc ] -.RB [ \-build ] -.RB [ \-file -.IR msgfile ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Repl -may be used to produce a reply to an existing message. -.PP -In its simplest form (with no arguments), -.B repl -will set up a -message\-form skeleton in reply to the current message in the current -folder, and invoke the whatnow shell. -.PP -In order to construct the message draft of the reply, -.B repl -uses -a reply template to guide its actions. A reply template is simply a -.B mhl -format file (see -.BR mh\-format (5) -for details). -.PP -If the switch -.B \-nogroup -is given (it is on by default), then -.B repl -will use the standard forms file \*(lqreplcomps\*(rq. This will construct -a draft message that is intended to be sent only to the author of the -message to which you are replying. If a file named \*(lqreplcomps\*(rq -exists in the user's -.B nmh -directory, it will be used instead of this -default forms file. -.PP -The default reply template \*(lqreplcomps\*(rq will direct -.B repl -to construct the reply message draft as follows: -.PP -.RS 5 -.nf -To: or or -cc: and and -Fcc: {fcc switch} or +outbox -Subject: Re: -In\-Reply\-To: -References: -Comments: In\-Reply\-To or or -.ti +3 -message dated --------- -.fi -.RE -.PP -where field names enclosed in angle brackets (<\ >) indicate the -contents of the named field from the message to which the reply is -being made. -.PP -By default, the \*(lqcc:\*(rq field is empty. You may selectively add -addresses to this default with the -.B \-cc -.I type -switch. This switch takes an -argument ( -.IR all / to / cc / me ) -which specifies who gets added to the default -\*(lqcc:\*(rq list of the reply. You may give this switch multiple times (with -different arguments) if you wish to add multiple types of addresses. -.PP -If the switch -.B \-group -is given, then -.B repl -will use the the -standard forms file \*(lqreplgroupcomps\*(rq. This will construct a -draft message that is intended as a group or followup reply. If a file -named \*(lqreplgroupcomps\*(rq exists in the user's nmh directory, it -will be used instead of this default forms file. -.PP -The default group reply template \*(lqreplgroupcomps\*(rq will direct -.B repl -to construct the reply message draft as follows: -.PP -.RS 5 -.nf -To: -Subject: Re: -In\-Reply\-To: Message from of . -.ti +\w'In\-Reply\-To: 'u - --------- -.fi -.RE -.PP -or if the field is not available: -.PP -.RS 5 -.nf -To: or or -cc: and and -Subject: Re: -In\-Reply\-To: Message from of . -.ti +\w'In\-Reply\-To: 'u - --------- -.fi -.RE -.PP -By default, the \*(lqcc:\*(rq contains all the addresses shown. You may -selectively remove addresses from this default with the -.B \-nocc -.I type -switch. -This switch takes an argument ( -.IR all / to / cc / me ) -which specifies who gets removed -from the default \*(lqcc:\*(rq list of the reply. You may give this switch -multiple times (with different arguments) if you wish to remove multiple types -of addresses. -.PP -In any case, you may specify an alternate forms file with the switch -.B \-form -.IR formfile . -.PP -The -.B \-query -switch modifies the action of -.B \-nocc -.I type -switch by -interactively asking you if each address that normally would be placed in -the \*(lqTo:\*(rq and \*(lqcc:\*(rq list should actually be sent a copy. -This is useful for special\-purpose replies. Note that the position of -the -.B \-cc -and -.B \-nocc -switches, like all other switches which take a -positive and negative form, is important. -.PP -Lines beginning with the fields \*(lqTo:\*(rq, \*(lqcc:\*(rq, and -\*(rqBcc:\*(rq will be standardized and have duplicate addresses removed. -In addition, the -.B \-width -.I columns -switch will guide -.BR repl 's -formatting of these fields. -.PP -If the draft already exists, -.B repl -will ask you as to the disposition -of the draft. A reply of -.B quit -will abort -.BR repl , -leaving the -draft intact; -.B replace -will replace the existing draft with a blank -skeleton; and -.B list -will display the draft. -.PP -See -.BR comp (1) -for a description of the -.B \-editor -and -.B \-noedit -switches. Note that while in the editor, the message being replied -to is available through a link named \*(lq@\*(rq (assuming the default -.IR whatnowproc ). -In addition, the actual pathname of the message is -stored in the environment variable -.BR $editalt , -and the pathname of -the folder containing the message is stored in the environment variable -.BR $mhfolder . -.PP -Although -.B repl -uses a forms file to direct it how to construct -the beginning of the draft, it uses a message filter file to direct -it as to how the message to which you are replying should be filtered -(re\-formatted) in the body of the draft. The filter file for -.B repl -should be a standard form file for -.BR mhl , -as -.B repl -will invoke -.B mhl -to format the message to which you are replying. -.PP -The switches -.BR \-noformat , -.BR \-format , -and -.B \-filter -.I filterfile -specify -which message filter file to use. -.PP -If the switch -.B \-noformat -is given (it is the default), then the message -to which you are replying is not included in the body of the draft. -.PP -If the switch -.B \-format -is given, then a default message filter file -is used. This default message filter should be adequate for most users. -This default filter -.RI \*(lq mhl.reply \*(rq -is: -.PP -.RS 5 -.nf -%mhl_reply% -.fi -.RE -.PP -which outputs each line of the body of the message prefaced with the -\*(lq>\*(rq character and a space. -.PP -If a file named -.RI \*(lq mhl.reply \*(rq -exists in the user's -.B nmh -directory, -it will be used instead of this form. You may specify an alternate -message filter file with the switch -.B \-filter -.IR filterfile . -.PP -Other reply filters are commonly used, such as: -.PP -.RS 5 -.nf -: -body:nocomponent,compwidth=9,offset=9 -.fi -.RE -.PP -which says to output a blank line and then the body of the message -being replied\-to, indented by one tab\-stop. Another popular format -is: -.PP -.RS 5 -.nf -message-id:nocomponent,\|nonewline,\\ -formatfield=\*(lqIn message %{text},\ \*(rq -from:nocomponent,\|formatfield=\*(lq%(decode(friendly{text})) writes:\*(rq -body:component=\*(lq>\*(rq,\|overflowtext=\*(lq>\*(rq,\|overflowoffset=0 -.fi -.RE -.PP -This message filter file cites the Message-ID and author of the message -being replied\-to, and then outputs each line of the body prefaced with -the \*(lq>\*(rq character. -.PP -To use the MIME rules for encapsulation, specify the -.B \-mime -switch. -This directs -.B repl -to generate an -.B mhbuild -composition file. -Note that -.B nmh -will not invoke -.B mhbuild -automatically, unless you -add this line to your -.I \&.mh\(ruprofile -file: -.PP -.RS 5 -automimeproc: 1 -.RE -.PP -Otherwise, you must specifically give the command -.PP -.RS 5 -What now? mime -.RE -.PP -prior to sending the draft. -.PP -If the -.B \-annotate -switch is given, the message being replied\-to will -be annotated with the lines -.PP -.RS 5 -Replied:\ date -Replied:\ addrs -.RE -.PP -where the address list contains one line for each addressee. -The annotation will be done only if the message is sent directly from -.BR repl . -If the message is not sent immediately from -.BR repl , -.RB \*(lq "comp\ \-use" \*(rq -may be used to re\-edit and send the constructed -message, but the annotations won't take place. Normally annotations are -done inplace in order to preserve any links to the message. You may use -the -.B \-noinplace -switch to change this. -.PP -Although the default template specifies that a copy of the reply will be -put in -the folder 'outbox', -if the -.B \-fcc -.I +folder -switch is given it will override the default value. -More than one folder, each preceded by -.B \-fcc -can -be named. -.PP -In addition to the standard -.BR mh\-format (5) -escapes, -.B repl -also recognizes the following additional -.I component -escape: -.PP -.RS 5 -.nf -.ta \w'Escape 'u +\w'Returns 'u -.I Escape Returns Description -fcc string Any folders specified with `\-fcc\ folder' -.fi -.RE -.PP -To avoid reiteration, -.B repl -strips any leading `Re: ' strings from -the -.I subject -component. -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke -the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more -information. -.PP -Upon exiting from the editor, -.B repl -will invoke the -.B whatnow -program. See -.BR whatnow (1) -for a discussion of available -options. The invocation of this program can be inhibited by using the -.B \-nowhatnowproc -switch. (In truth of fact, it is the -.B whatnow -program which starts the initial edit. Hence, -.B \-nowhatnowproc -will -prevent any edit from occurring.) -.PP -The -.B \-build -switch is intended to be used by the Emacs mh-e interface -to -.BR nmh , -and is only present if -.B nmh -was compiled with support -for mh-e. It implies -.BR \-nowhatnowproc . -It causes a file -.I /reply -to be created, containing the draft message that would normally be presented -to the user for editing. -No mail is actually sent. Note that this switch is not guaranteed to -be present or to have the same effects in future versions of -.BR nmh : -it is documented here only for completeness. -.PP -The -.B \-file -.I msgfile -switch specifies the message to be replied to as an -exact filename rather than as an -.B nmh -folder and message number. It is -intended to be used by the -.B msh -interface to -.BR nmh . -The same caveats apply to this option as to the -.B \-build -switch. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/replcomps~^The standard reply template -^or /replcomps~^Rather than the standard template -^%etcdir%/replgroupcomps~^The standard `reply -group' template -^or /replgroupcomps~^Rather than the standard template -^%etcdir%/mhl.reply~^The standard message filter -^or /mhl.reply~^Rather than the standard filter -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Alternate\-Mailboxes:~^To determine the user's mailboxes -^Current\-Folder:~^To find the default current folder -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^Msg\-Protect:~^To set mode when creating a new message (draft) -^fileproc:~^Program to refile the message -^mhlproc:~^Program to filter message being replied\-to -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi - -.SH "SEE ALSO" -mhbuild(1), comp(1), forw(1), send(1), whatnow(1), mh\-format(5) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to cur" -.RB ` \-nogroup ' -.RB ` "\-nocc\ all" "' with `\-nogroup', `\-cc\ all' with `\-group'" -.RB ` \-noannotate ' -.RB ` \-nodraftfolder ' -.RB ` \-noformat ' -.RB ` \-inplace ' -.RB ` \-nomime ' -.RB ` \-noquery ' -.RB ` "\-width\ 72" ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The message -replied\-to will become the current message. - -.SH BUGS -If any addresses occur in the reply template, addresses in the template -that do not contain hosts are defaulted incorrectly. Instead of using -the localhost for the default, -.B repl -uses the sender's host. -Moral of the story: if you're going to include addresses in a reply -template, include the host portion of the address. -.PP -The -.B \-width -.I columns -switch is only used to do address-folding; other -headers are not line\-wrapped. -.PP -If -.I whatnowproc -is -.BR whatnow , -then -.B repl -uses a built\-in -.BR whatnow , -it does not actually run the -.B whatnow -program. -Hence, if you define your own -.IR whatnowproc , -don't call it -.B whatnow -since -.B repl -won't run it. -.PP -If your current working directory is not writable, the link named -\*(lq@\*(rq is not available. diff --git a/man/repl.man1 b/man/repl.man1 new file mode 100644 index 0000000..26fd094 --- /dev/null +++ b/man/repl.man1 @@ -0,0 +1,405 @@ +.\" +.\" %nmhwarning% +.\" +.TH REPL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +repl \- reply to a message +.SH SYNOPSIS +.HP 5 +.na +.B repl +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-annotate " | " \-noannotate ] +.RB [ \-group " | " \-nogroup ] +.RB [ \-cc +all/to/cc/me] +.RB [ \-nocc +all/to/cc/me] +.RB [ \-query " | " \-noquery ] +.RB [ \-form +.IR formfile ] +.RB [ \-filter +.IR filterfile +.RB " | " \-nofilter ] +.RB [ \-mime " | " \-nomime ] +.RB [ \-editor +.IR editor ] +.RB [ \-whatnowproc +.IR program ] +.RB [ \-build ] +.RB [ \-file +.IR msgfile ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Repl +may be used to produce a reply to an existing message. +.PP +In its simplest form (with no arguments), +.B repl +will set up a +message\-form skeleton in reply to the current message in the current +folder, and invoke the whatnow shell. +.PP +In order to construct the message draft of the reply, +.B repl +uses +a reply template to guide its actions. A reply template is simply a +.B mhl +format file (see +.BR mh\-format (5) +for details). +.PP +If the switch +.B \-nogroup +is given (it is on by default), then +.B repl +will use the standard forms file `replcomps'. This will construct +a draft message that is intended to be sent only to the author of the +message to which you are replying. If a file named `replcomps' +exists in the user's +.B mmh +directory, it will be used instead of this +default forms file. +.PP +The default reply template `replcomps' will direct +.B repl +to construct the reply message draft as follows: +.PP +.RS 5 +.nf +To: or or +Cc: and and +Fcc: +sent +Subject: Re: +In\-Reply\-To: +References: +Comments: In\-Reply\-To or or +.ti +3 +message dated +-------- +.fi +.RE +.PP +where field names enclosed in angle brackets (<\ >) indicate the +contents of the named field from the message to which the reply is +being made. +.PP +By default, the `Cc:' field is empty. You may selectively add +addresses to this default with the +.B \-cc +.I type +switch. This switch takes an +argument ( +.IR all / to / cc / me ) +which specifies who gets added to the default +`Cc:' list of the reply. You may give this switch multiple times (with +different arguments) if you wish to add multiple types of addresses. +.PP +If the switch +.B \-group +is given, then +.B repl +will use the the +standard forms file `replgroupcomps'. This will construct a +draft message that is intended as a group or followup reply. If a file +named `replgroupcomps' exists in the user's mmh directory, it +will be used instead of this default forms file. +.PP +The default group reply template `replgroupcomps' will direct +.B repl +to construct the reply message draft as follows: +.PP +.RS 5 +.nf +To: +Subject: Re: +In\-Reply\-To: Message from of . +.ti +\w'In\-Reply\-To: 'u + +-------- +.fi +.RE +.PP +or if the field is not available: +.PP +.RS 5 +.nf +To: or or +Cc: and and +Subject: Re: +In\-Reply\-To: Message from of . +.ti +\w'In\-Reply\-To: 'u + +-------- +.fi +.RE +.PP +By default, the `Cc:' contains all the addresses shown. You may +selectively remove addresses from this default with the +.B \-nocc +.I type +switch. +This switch takes an argument ( +.IR all / to / cc / me ) +which specifies who gets removed +from the default `Cc:' list of the reply. You may give this switch +multiple times (with different arguments) if you wish to remove multiple types +of addresses. +.PP +In any case, you may specify an alternate forms file with the switch +.B \-form +.IR formfile . +.PP +The +.B \-query +switch modifies the action of +.B \-nocc +.I type +switch by +interactively asking you if each address that normally would be placed in +the `To:' and `Cc:' list should actually be sent a copy. +This is useful for special\-purpose replies. Note that the position of +the +.B \-cc +and +.B \-nocc +switches, like all other switches which take a +positive and negative form, is important. +.PP +Lines beginning with the fields `To:', `Cc:', and +'Bcc:' will be standardized and have duplicate addresses removed. +In addition, these fields will be wrapped at a reasonable length. +.PP +See +.BR comp (1) +for a description of the +.B \-editor +switch. Note that while in the editor, +the actual pathname of the message being replied to is +stored in the environment variable +.BR $mhaltmsg , +and the pathname of +the folder containing the message is stored in the environment variable +.BR $mhfolder . +.PP +Although +.B repl +uses a forms file to direct it how to construct +the beginning of the draft, it uses a message filter file to direct +it as to how the message to which you are replying should be filtered +(re\-formatted) in the body of the draft. The filter file for +.B repl +should be a standard form file for +.BR mhl , +as +.B repl +will invoke +.B mhl +to format the message to which you are replying. +.PP +By default, the original message gets filtered +through a default message filter file and then included into the draft body +as quotation. +This should be adequate for most users. +This default filter +.RI ` mhl.reply ' +is: +.PP +.RS 5 +.nf +%mhl_reply% +.fi +.RE +.PP +which outputs each line of the body of the message prefaced with the +`>' character and a space. +If a file named +.RI ` mhl.reply ' +exists in the user's +.B mmh +directory, +it will be used instead of this form. +.PP +You may specify an alternate message filter file with the switch +.B \-filter +.IR filterfile . +.PP +Other reply filters are commonly used, such as: +.PP +.RS 5 +.nf +: +body:nocomponent,compwidth=9,offset=9 +.fi +.RE +.PP +which says to output a blank line and then the body of the message +being replied\-to, indented by one tab\-stop. Another popular format +is: +.PP +.RS 5 +.nf +message-id:nocomponent,\|nonewline,\\ +formatfield=`In message %{text},\ ' +from:nocomponent,\|formatfield=`%(decode(friendly{text})) writes:' +body:component=`>',\|overflowtext=`>',\|overflowoffset=0 +.fi +.RE +.PP +This message filter file cites the Message-ID and author of the message +being replied\-to, and then outputs each line of the body prefaced with +the `>' character. +.PP +If the switch +.B \-nofilter +is given, then the message +to which you are replying will not be formated and thus not included in +the body of the draft. +(It may be added as MIME attachment with +.B \-mime +though.) +.PP +To MIME-attach the original message, specify the +.B \-mime +switch. +Note: In mmh, the \-mime switch is unrelated to +the \-filter and \-nofilter switches. +It is therefore possible to have the original message quoted in the body +.B and +attached as MIME part. +However, using the \-mime switch is discouraged. +It may get removed in the future. +.PP +If the +.B \-annotate +switch is given, the message being replied\-to will +be annotated with the line: +.PP +.RS 5 +.nf +Replied:\ date +.fi +.RE +.PP +The annotation will be done only if the message is sent directly from +.BR repl . +If the message is not sent immediately from +.BR repl , +.RB ` "comp\ \-use" ' +may be used to re\-edit and send the constructed +message, but the annotations won't take place. Annotations are always +done inplace in order to preserve any links to the message. +.PP +The default template specifies that a copy of the reply will be +put in +the folder 'sent'. +.PP +To avoid reiteration, +.B repl +strips any leading `Re: ' strings from +the +.I subject +component. +.PP +Consult the +.BR mh-draft (7) +man page for more +information. +.PP +Upon exiting from the editor, +.B repl +will invoke the +.B whatnow +program. See +.BR whatnow (1) +for a discussion of available +options. +.PP +The +.B \-build +switch is intended to be used by the Emacs mh-e interface +to +.BR nmh . +It causes a file +.I reply (in the mail storage root) +to be created, containing the draft message that would normally be presented +to the user for editing. +No +.B whatnow +programm is invoked. +No mail is actually sent. +.PP +The +.B \-file +.I msgfile +switch specifies the message to be replied to as an +exact filename rather than as an +.B nmh +folder and message number. It is +intended to be used by the +.B msh +interface to +.BR nmh . +The same caveats apply to this option as to the +.B \-build +switch. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^%etcdir%/replcomps~^The standard reply template +^or $HOME/.mmh/replcomps~^Rather than the standard template +^%etcdir%/replgroupcomps~^The standard `reply -group' template +^or $HOME/.mmh/replgroupcomps~^Rather than the standard template +^%etcdir%/mhl.reply~^The standard message filter +^or $HOME/.mmh/mhl.reply~^Rather than the standard filter +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Alternate\-Mailboxes:~^To determine the user's mailboxes +^Current\-Folder:~^To find the default current folder +^Draft\-Folder:~^To set the default draft\-folder +^Editor:~^To override the default editor +^Msg\-Protect:~^To set mode when creating a new message (draft) +^whatnowproc:~^Program to ask the `What now?' questions +.fi + +.SH "SEE ALSO" +mhbuild(1), comp(1), forw(1), send(1), whatnow(1), mh\-format(5) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msg "' defaults to cur" +.RB ` \-nogroup ' +.RB ` "\-nocc\ all" "' with `\-nogroup', `\-cc\ all' with `\-group'" +.RB ` \-noannotate ' +.RB ` \-nomime ' +.RB ` \-noquery ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The message +replied\-to will become the current message. + +.SH BUGS +If any addresses occur in the reply template, addresses in the template +that do not contain hosts are defaulted incorrectly. Instead of using +the localhost for the default, +.B repl +uses the sender's host. +Moral of the story: if you're going to include addresses in a reply +template, include the host portion of the address. +.PP +The quotation of the original message does not get transfer-decoded, yet. diff --git a/man/rmf.man b/man/rmf.man deleted file mode 100644 index 047db5a..0000000 --- a/man/rmf.man +++ /dev/null @@ -1,100 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RMF %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rmf \- remove an nmh folder -.SH SYNOPSIS -.HP 5 -.na -.B rmf -.RI [ +folder ] -.RB [ \-interactive " | " \-nointeractive ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Rmf -removes all of the messages (files) within the specified -(or default) folder, and then removes the folder (directory) itself. -.PP -If there are any files within the folder which are not a part of -.BR nmh , -they will -.B not -be removed, and an error will be produced. -If the folder is given explicitly or the -.B \-nointeractive -option is -given, then the folder will be removed without confirmation. Otherwise, -the user will be asked for confirmation. If -.B rmf -can't find the -current folder, for some reason, the folder to be removed defaults to -`+inbox' (unless overridden by user's profile entry \*(lqInbox\*(rq) -with confirmation. -.PP -If the folder being removed is a subfolder, the parent folder will become -the new current folder, and -.B rmf -will produce a message telling the -user this has happened. This provides an easy mechanism for selecting -a set of messages, operating on the list, then removing the list and -returning to the current folder from which the list was extracted. -.PP -If -.B rmf -s used on a read\-only folder, it will delete all the -(private) sequences -(i.e., -.RI \*(lqatr\- seq \- folder \*(rq -entries) for this folder -from your context without affecting the folder itself. -.PP -.B Rmf -irreversibly deletes messages that don't have other links, so -use it with caution. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Inbox:~^To find the default inbox -.fi - -.SH "SEE ALSO" -rmm(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder, usually with confirmation" -.RB ` \-interactive "' if +folder' not given, `\-nointeractive' otherwise" -.fi - -.SH CONTEXT -.B Rmf -will set the current folder to the parent folder if a -subfolder is removed; or if the current folder is removed, it will make -\*(lqinbox\*(rq current. Otherwise, it doesn't change the current folder -or message. - -.SH BUGS -Although intuitively one would suspect that -.B rmf -works recursively, -it does not. Hence if you have a sub\-folder within a folder, in order -to -.B rmf -the parent, you must first -.B rmf -each of the children. diff --git a/man/rmf.man1 b/man/rmf.man1 new file mode 100644 index 0000000..7dccb69 --- /dev/null +++ b/man/rmf.man1 @@ -0,0 +1,100 @@ +.\" +.\" %nmhwarning% +.\" +.TH RMF %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +rmf \- remove an nmh folder +.SH SYNOPSIS +.HP 5 +.na +.B rmf +.RI [ +folder ] +.RB [ \-interactive " | " \-nointeractive ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Rmf +removes all of the messages (files) within the specified +(or default) folder, and then removes the folder (directory) itself. +.PP +If there are any files within the folder which are not a part of +.BR nmh , +they will +.B not +be removed, and an error will be produced. +If the folder is given explicitly or the +.B \-nointeractive +option is +given, then the folder will be removed without confirmation. Otherwise, +the user will be asked for confirmation. If +.B rmf +can't find the +current folder, for some reason, the folder to be removed defaults to +`+inbox' (unless overridden by user's profile entry `Inbox') +with confirmation. +.PP +If the folder being removed is a subfolder, the parent folder will become +the new current folder, and +.B rmf +will produce a message telling the +user this has happened. This provides an easy mechanism for selecting +a set of messages, operating on the list, then removing the list and +returning to the current folder from which the list was extracted. +.PP +If +.B rmf +s used on a read\-only folder, it will delete all the +(private) sequences +(i.e., +.RI `atr\- seq \- folder ' +entries) for this folder +from your context without affecting the folder itself. +.PP +.B Rmf +irreversibly deletes messages that don't have other links, so +use it with caution. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Inbox:~^To find the default inbox +.fi + +.SH "SEE ALSO" +rmm(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder, usually with confirmation" +.RB ` \-interactive "' if +folder' not given, `\-nointeractive' otherwise" +.fi + +.SH CONTEXT +.B Rmf +will set the current folder to the parent folder if a +subfolder is removed; or if the current folder is removed, it will make +`inbox' current. Otherwise, it doesn't change the current folder +or message. + +.SH BUGS +Although intuitively one would suspect that +.B rmf +works recursively, +it does not. Hence if you have a sub\-folder within a folder, in order +to +.B rmf +the parent, you must first +.B rmf +each of the children. diff --git a/man/rmm.man b/man/rmm.man deleted file mode 100644 index 0f8b5ce..0000000 --- a/man/rmm.man +++ /dev/null @@ -1,119 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH RMM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -rmm \- remove messages -.SH SYNOPSIS -.HP 5 -.na -.B rmm -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-unlink " | " \-nounlink ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -By default, -.B rmm -will remove the specified messages by renaming -the message files with preceding commas. Such files will then need to -be removed in some manner after a certain amount of time. Many sites -arrange for -.B cron -to remove these files once a day, so check -with your system administrator. -.PP -Alternately, if you wish for -.B rmm -to really remove the files -representing these messages, you can use the -.B \-unlink -switch. But -messages removed by this method cannot be later recovered. -.PP -If you prefer a more sophisticated method of `removing' messages, you -can define the -.I rmmproc -profile component. For example, you can -add a profile component such as -.PP -.RS 5 -rmmproc: /home/foouser/bin/rmm_msgs -.RE -.PP -then instead of simply renaming the message file, -.B rmm -will call -the named program or script to handle the files that represent the -messages to be deleted. -.PP -Some users of -.B csh -prefer the following: -.PP -.RS 5 -alias rmm 'refile +d' -.RE -.PP -where folder `+d' is a folder for deleted messages, and -.PP -.RS 5 -alias mexp 'rm `mhpath +d all`' -.RE -.PP -is used to \*(lqexpunge\*(rq deleted messages. -.PP -The current message is not changed by -.BR rmm , -so a -.B next - will -advance to the next message in the folder as expected. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^rmmproc:~^Program to delete the message -.fi - -.SH "SEE ALSO" -refile(1), rmf(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` -nounlink ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. - -.SH BUGS -Since -.B refile -uses your -.I rmmproc -to delete the message, -the -.I rmmproc -must -.B NOT -call -.B refile -without specifying -.BR \-normmproc , -or you will create an infinte loop. diff --git a/man/rmm.man1 b/man/rmm.man1 new file mode 100644 index 0000000..07d6cc3 --- /dev/null +++ b/man/rmm.man1 @@ -0,0 +1,72 @@ +.\" +.\" %nmhwarning% +.\" +.TH RMM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +rmm \- remove messages +.SH SYNOPSIS +.HP 5 +.na +.B rmm +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-unlink " | " \-nounlink ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +By default, +.B rmm +will remove the specified messages by refiling them to the trash folder +`+trash'. The contents of this folder will then need to +be removed after a certain amount of time. +.PP +Alternately, if you wish for +.B rmm +to really remove the files +representing these messages, you can use the +.B \-unlink +switch. But +messages removed by this method cannot be later recovered. +.PP +.RS 5 +rmm \-unlink +trash a +.RE +.PP +can be used to expunge deleted messages. +.PP +The current message is not changed by +.BR rmm , +so a +.B next + will +advance to the next message in the folder as expected. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +refile(1), rmf(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-nounlink ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. diff --git a/man/scan.man b/man/scan.man deleted file mode 100644 index fb72ac3..0000000 --- a/man/scan.man +++ /dev/null @@ -1,259 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SCAN %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -scan \- produce a one line per message scan listing -.SH SYNOPSIS -.HP 5 -.na -.B scan -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-clear " | " \-noclear ] -.RB [ \-form -.IR formatfile ] -.RB [ \-format -.IR string ] -.RB [ \-header " | " \-noheader ] -.RB [ \-width -.IR columns ] -.RB [ \-reverse " | " \-noreverse ] -.RB [ \-file -.IR filename ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Scan -produces a one\-line\-per\-message listing of the specified -folder or messages. Each -.B scan -line contains the message number -(name), the date, the \*(lqFrom:\*(rq field, the \*(lqSubject\*(rq field, -and, if room allows, some of the body of the message. For example: -.PP -.RS 5 -.nf -.ta \w'15+- 'u +\w'07/\|05x 'u +\w'Dcrocker 'u -15+ 10/\|05 crocker nned\0\0<>\*(rq if the body is sufficiently short. -.B Scan -actually reads each of the specified messages and parses them to extract -the desired fields. During parsing, appropriate error messages will be -produced if there are format errors in any of the messages. -.PP -By default, -.B scan -will decode RFC-2047 (MIME) encoding in -these scan listings. -.B Scan -will only decode these fields if your -terminal can natively display the character set used in the encoding. -You should set the MM_CHARSET environment variable to your native -character set, if it is not US-ASCII. See the mh-profile(5) man -page for details about this environment variable. -.PP -The switch -.BR \-reverse , -makes -.B scan -list the messages in reverse -order. -.PP -The -.B \-file -.I filename -switch allows the user to obtain a -.B scan -listing of a maildrop file as produced by -.BR packf . -This listing -includes every message in the file (you can't scan individual messages). -The switch -.B \-reverse -is ignored with this option. -.PP -The switch -.B \-width -.I columns -may be used to specify the width of -the scan line. The default is to use the width of the terminal. -.PP -The -.B \-header -switch produces a header line prior to the -.B scan -listing. Currently, the name of the folder and the current date and -time are output (see the -.B HISTORY -section for more information). -.PP -If the -.B \-clear -switch is used and -.BR scan 's -output is directed -to a terminal, then -.B scan -will consult the environment variables -.B $TERM -and -.B $TERMCAP -to determine your terminal type in order -to find out how to clear the screen prior to exiting. If the -.B \-clear -switch is used and -.BR scan 's -output is not directed to a terminal -(e.g., a pipe or a file), then -.B scan -will send a formfeed prior -to exiting. -.PP -For example, the command: -.PP -.RS 5 -(scan \-clear \-header; show all \-show pr \-f) | lpr -.RE -.PP -produces a scan listing of the current folder, followed by a formfeed, -followed by a formatted listing of all messages in the folder, one -per page. Omitting -.RB \*(lq "\-show\ pr\ \-f" \*(rq -will cause the messages to be -concatenated, separated by a one\-line header and two blank lines. -.PP -To override the output format used by -.BR scan , -the -.B \-format -.I string -or -.B \-form -.I file -switches are used. This permits individual fields of -the scan listing to be extracted with ease. The string is simply a format -string and the file is simply a format file. See -.BR mh\-format (5) -for the details. -.PP -In addition to the standard -.BR mh\-format (5) -escapes, -.B scan -also recognizes the following additional -.I component -escapes: -.PP -.RS 5 -.nf -.ta \w'Dtimenow 'u +\w'Returns 'u -.I Escape Returns Description -body string the (compressed) first part of the body -dtimenow date the current date -folder string the name of the current folder -.fi -.RE -.PP -If no date header is present in the message, the -.I function -escapes -which operate on -.RB { date } -will return values for the date of last -modification of the message file itself. This feature is handy for -scanning a draft folder, as message drafts usually aren't allowed -to have dates in them. -.PP -.B scan -will update the -.B nmh -context prior to starting the listing, -so interrupting a long -.B scan -listing preserves the new context. -.B nmh -purists hate this idea. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Alternate\-Mailboxes:~^To determine the user's mailboxes -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -inc(1), pick(1), show(1), mh\-format(5) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to all" -.RB ` \-format "' defaulted as described above" -.RB ` \-noheader ' -.RB ` \-width "' defaulted to the width of the terminal" -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. - -.SH HISTORY -Prior to using the format string mechanism, -.B \-header -used to generate -a heading saying what each column in the listing was. Format strings -prevent this from happening. - -.SH BUGS -The argument to the -.B \-format -switch must be interpreted as a single -token by the shell that invokes -.BR scan . -Therefore, one must usually -place the argument to this switch inside double\-quotes. -.PP -The value of each -.I component -escape is set by -.B scan -to the -contents of the first message header -.B scan -encounters with the -corresponding component name; any following headers with the same -component name are ignored. diff --git a/man/scan.man1 b/man/scan.man1 new file mode 100644 index 0000000..997ade2 --- /dev/null +++ b/man/scan.man1 @@ -0,0 +1,191 @@ +.\" +.\" %nmhwarning% +.\" +.TH SCAN %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +scan \- produce a one line per message scan listing +.SH SYNOPSIS +.HP 5 +.na +.B scan +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-form +.IR formatfile ] +.RB [ \-width +.IR columns ] +.RB [ \-file +.IR filename ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Scan +produces a one\-line\-per\-message listing of the specified +folder or messages. Each +.B scan +line contains the message number +(name), the date, the `From:' field and the `Subject' field. +For example: +.PP +.RS 5 +.nf +.ta \w'15+- 'u +\w'07/\|05x 'u +\w'Dcrocker 'u +15+ 10/\|05 crocker nned +16\- 10/\|05 crocker message id format +18 10/\|06 brien Re: Exit status from mkdir +19 10/\|07*brien `scan' listing format in nmh +.fi +.RE +.PP +The `+' on message 15 indicates that it is the current message. +.PP +The `\-' on message 16 indicates that it has been replied to, as indicated +by a `Replied:' component (produced by the +.B \-annotate +switch +to the +.B repl +command). +.PP +The `*' on message 19 indicates that no `Date:' header was +present. The time of last modification of the message is given instead. +.PP +.B Scan +actually reads each of the specified messages and parses them to extract +the desired fields. During parsing, appropriate error messages will be +produced if there are format errors in any of the messages. +.PP +By default, +.B scan +will decode RFC-2047 (MIME) encoding in +these scan listings. +.B Scan +will only decode these fields if your +terminal can natively display the character set used in the encoding. +You should set the MM_CHARSET environment variable to your native +character set, if it is not US-ASCII. See the mh-profile(5) man +page for details about this environment variable. +.PP +The +.B \-file +.I filename +switch allows the user to obtain a +.B scan +listing of a maildrop file as produced by +.BR packf . +This listing +includes every message in the file (you can't scan individual messages). +.PP +The switch +.B \-width +.I columns +may be used to specify the width of +the scan line. The default is to use the width of the terminal. +.PP +The command: +.PP +.RS 5 +(scan | pr ; show a \-showproc pr) | lpr +.RE +.PP +produces a scan listing of the current folder, +followed by a formatted listing of all messages in the folder, one +per page. Omitting +.RB ` "\-showproc\ pr" ' +will cause the messages to be +concatenated, separated by a one\-line header and two blank lines. +.PP +To override the output format used by +.BR scan , +the +.B \-form +.I file +switch is used. This permits individual fields of +the scan listing to be extracted with ease. +.I file +is either the name of a format file or a format string directly, +if prepended with an equal sign `='. +See +.BR mh\-format (5) +for the details. +.PP +In addition to the standard +.BR mh\-format (5) +escapes, +.B scan +also recognizes the following additional +.I component +escapes: +.PP +.RS 5 +.nf +.ta \w'Dtimenow 'u +\w'Returns 'u +.I "Escape Returns Description +dtimenow date the current date +folder string the name of the current folder +.fi +.RE +.PP +If no date header is present in the message, the +.I function +escapes +which operate on +.RB { date } +will return values for the date of last +modification of the message file itself. This feature is handy for +scanning a draft folder, as message drafts usually aren't allowed +to have dates in them. +.PP +.B scan +will update the +.B mmh +context prior to starting the listing, +so interrupting a long +.B scan +listing preserves the new context. +.B nmh +purists hate this idea. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Alternate\-Mailboxes:~^To determine the user's mailboxes +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +inc(1), pick(1), show(1), mh\-format(5) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to all" +.RB ` \-form "' defaulted as described above" +.RB ` \-width "' defaulted to the width of the terminal" +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. + +.SH BUGS +The value of each +.I component +escape is set by +.B scan +to the +contents of the first message header +.B scan +encounters with the +corresponding component name; any following headers with the same +component name are ignored. diff --git a/man/send.man b/man/send.man deleted file mode 100644 index e75583e..0000000 --- a/man/send.man +++ /dev/null @@ -1,430 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SEND %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -send \- send a message -.SH SYNOPSIS -.HP 5 -.na -.B send -.RB [ \-alias -.IR aliasfile ] -.RB [ \-draft ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-filter -.IR filterfile ] -.RB [ \-nofilter ] -.RB [ \-format " | " \-noformat ] -.RB [ \-forward " | " \-noforward ] -.RB [ \-mime " | " \-nomime ] -.RB [ \-msgid " | " \-nomsgid ] -.RB [ \-push " | " \-nopush ] -.RB [ \-split -.IR seconds ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-watch " | " \-nowatch ] -.RB [ \-server -.IR servername ] -.RB [ \-port -.IR port-name/number ] -.RB [ \-sasl ] -.RB [ \-saslmech -.IR mechanism ] -.RB [ \-user -.IR username ] -.RB [ \-width -.IR columns ] -.RB [ file -\&...] -.RB [ \-version ] -.RB [ \-help ] -.RB [ \-attach -.IR header-field-name ] -.RB [ \-attachformat -.IR 0 " | " 1 " | " 2 ] -.ad -.SH DESCRIPTION -.B Send -will cause each of the specified files to be delivered -to each of the destinations in the \*(lqTo:\*(rq, \*(lqcc:\*(rq, -\*(lqBcc:\*(rq, \*(lqDcc:\*(rq, and \*(lqFcc:\*(rq fields of the message. If -.B send -is re\-distributing a message, as invoked from -.BR dist , -then the -corresponding \*(lqResent\-xxx\*(rq fields are examined instead. -.PP -By default, -.B send -uses the program -.B post -to do the actual -delivery of the messages, although this can be changed by defining the -.I postproc -profile component. Most of the features attributed to -.B send -are actually performed by -.BR post . - -.PP -If a -.I header-field-name -is supplied using the -.B -attach -option, the draft is scanned for a header whose field name matches the -supplied -.IR header-field-name . -The draft is converted to a MIME message if one or more matches are found. -This conversion occurs before all other processing. -.PP -The first part of the MIME message is the draft body if that body contains -any non-blank characters. -The body of each header field whose name matches the -.I header-field-name -is interpreted as a file name, and each file named is included as a separate -part in the MIME message. -.PP -For file names with dot suffixes, the context is scanned for a -.I mhshow-suffix- -entry for that suffix. -The content-type for the part is taken from that context entry if a match is -found. -If no match is found or the file does not have a dot suffix, the content-type -is text/plain if the file contains only ASCII characters or application/octet-stream -if it contains characters outside of the ASCII range. -.PP -Each part contains a name attribute that is the last component of the path name. -A -.I x-unix-mode -attribute containing the file mode accompanies each part. -Finally, a description attribute is generated by running the -.I file -command on the file. -.PP -The -.B -attachformat -option specifies the MIME header field formats: a value of -.B 0, -the default, -includes the -.I x-unix-mode -attribute as noted above. A value of -.B 1 -suppresses both that and the \*(lqContent-Description\*(rq header, and -adds a \*(lqContent-Disposition\*(rq header. A value of -.B 2 -adds the file -.I modification-date -parameter to the \*(lqContent-Disposition\*(rq header. You can -specify one value in your profile, and override it for individual -messages at the -.I whatnow -prompt. -.PP -Here are example message part headers, for an attachment, for each of the -.B -attachformat -values: -.PP -.nf --attachformat 0: -Content-Type: text/plain; name="VERSION"; x-unix-mode="0644"; - charset="us-ascii" -Content-Description: ASCII text - --attachformat 1: -Content-Type: text/plain; name="VERSION"; charset="us-ascii" -Content-Disposition: attachment; filename="VERSION" - --attachformat 2: -Content-Type: text/plain; name="VERSION"; charset="us-ascii" -Content-Disposition: attachment; filename="VERSION"; modification-date="Mon, 19 Dec 2005 22:39:51 -0600" -.fi -.PP -If -.B \-push -is specified, -.B send -will detach itself from the user's -terminal and perform its actions in the background. If -.BR push 'd -and the draft can't be sent, then an error message will be sent (using -the mailproc) back to the user. If -.B \-forward -is given, then a copy -of the draft will be attached to this failure notice. Using -.B \-push -differs from putting -.B send -in the background because the output is -trapped and analyzed by -.BR nmh . -.PP -If -.B \-verbose -is specified, -.B send -will indicate the interactions -occurring with the transport system, prior to actual delivery. -If -.B \-watch -is specified -.B send -will monitor the delivery of local -and network mail. Hence, by specifying both switches, a large detail -of information can be gathered about each step of the message's entry -into the transport system. -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke -the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more -information. -.PP -If -.B \-split -is specified, -.B send -will split the draft into one -or more partial messages prior to sending. This makes use of the -MIME features in -.BR nmh . -Note however that if -.B send -is -invoked under -.BR dist , -then this switch is ignored\0--\0it makes -no sense to redistribute a message in this fashion. Sometimes you want -.B send -to pause after posting a partial message. This is usually -the case when you are running -.B sendmail -and expect to generate a -lot of partial messages. The argument to -.B \-split -tells it how long -to pause between postings. -.PP -.B Send -with no -.I file -argument will query whether the draft -is the intended file, whereas -.B \-draft -will suppress this question. -Once the transport system has successfully accepted custody of the -message, the file will be renamed with a leading comma, which allows -it to be retrieved until the next draft message is sent. If there are -errors in the formatting of the message, -.B send -will abort with a -(hopefully) helpful error message. -.PP -If a \*(lqBcc:\*(rq field is encountered, its addresses will be used for -delivery, and the \*(lqBcc:\*(rq field will be removed from the message -sent to sighted recipients. The blind recipients will receive an entirely -new message with a minimal set of headers. Included in the body of the -message will be a copy of the message sent to the sighted recipients. -.PP -If a \*(lqDcc:\*(rq field is encountered, its addresses will be used for -delivery, and the \*(lqDcc:\*(rq field will be removed from the message. The -blind recipients will receive the same message sent to the sighted -recipients. *WARNING* Recipients listed in the \*(lqDcc:\*(rq field receive no -explicit indication that they have received a \*(lqblind copy\*(rq. -This can cause blind recipients to -inadvertently reply to all of the sighted recipients of the -original message, revealing that they received a blind copy. -On the other hand, since a normal reply to a message sent -via a \*(lqBcc:\*(rq field -will generate a reply only to the sender of the original message, -it takes extra effort in most mailers to reply to the included -message, and so would usually only be done deliberately, rather -than by accident. -.PP -If -.B \-filter -.I filterfile -is specified, then this copy is filtered -(re\-formatted) by -.B mhl -prior to being sent to the blind recipients. -Alternately, if you specify the -.B -mime -switch, then -.B send -will -use the MIME rules for encapsulation. -.PP -Prior to sending the message, the fields \*(lqFrom:\ user@local\*(rq, -and \*(lqDate:\ now\*(rq will be appended to the headers in the message. -If the environment variable -.B $SIGNATURE -is set, then its value -is used as your personal name when constructing the \*(lqFrom:\*(rq -line of the message. If this environment variable is not set, then -.B send -will consult the profile entry \*(lqSignature\*(rq for -this information. -If -.B \-msgid -is specified, then a \*(lqMessage\-ID:\*(rq field will also -be added to the message. -.PP -If -.B send -is re\-distributing a message (when invoked by -.BR dist ), -then \*(lqResent\-\*(rq will be prepended to each of these -fields: \*(lqFrom:\*(rq, \*(lqDate:\*(rq, and \*(lqMessage\-ID:\*(rq. -If the message already contains a \*(lqFrom:\*(rq field, then a -\*(lqSender: user@local\*(rq field will be added as well. (An already -existing \*(lqSender:\*(rq field is an error!) -.PP -By using the -.B \-format -switch, each of the entries in the \*(lqTo:\*(rq -and \*(lqcc:\*(rq fields will be replaced with \*(lqstandard\*(rq -format entries. This standard format is designed to be usable by all -of the message handlers on the various systems around the Internet. -If -.B \-noformat -is given, then headers are output exactly as they appear -in the message draft. -.PP -If an \*(lqFcc:\ folder\*(rq is encountered, the message will be copied -to the specified folder for the sender in the format in which it will -appear to any non\-Bcc receivers of the message. That is, it will have -the appended fields and field reformatting. The \*(lqFcc:\*(rq fields -will be removed from all outgoing copies of the message. -.PP -By using the -.B \-width -.I columns -switch, the user can direct -.B send -as to how long it should make header lines containing addresses. -.PP -If nmh is using the SMTP MTA, the -.B \-server -and the -.B \-port -switches can be used to override the default mail server (defined by the -.RI servers -entry in -.I %etcdir%/mts.conf -). -.PP -If -.B nmh -has been compiled with SASL support, the -.B \-sasl -switch will enable -the use of SASL authentication with the SMTP MTA. Depending on the -SASL mechanism used, this may require an additional password prompt from the -user (but the -.RI \*(lq \&.netrc \*(rq -file can be used to store this password). -.B \-saslmech -switch can be used to select a particular SASL mechanism, -and the the -.B \-user -switch can be used to select a authorization userid -to provide to SASL other than the default. -.PP -If SASL authentication is successful, -.BR nmh -will attempt to negotiate a security layer for session encryption. -Encrypted data is labelled with `(encrypted)' and `(decrypted)' when -viewing the SMTP transaction with the -.B \-snoop -switch. -.PP -If -.B nmh -has been compiled with TLS support, the -.B \-tls -switch will require the negotiation of TLS support when connecting to the -SMTP MTA. Encrypted data is labelled with `(tls-encrypted)' and -`(tls-decrypted)' when viewing the SMTP transction with the -.B \-snoop -switch. -.PP -The files specified by the profile entry \*(lqAliasfile:\*(rq and any -additional alias files given by the -.B \-alias -.I aliasfile -switch will be -read (more than one file, each preceded by -.BR \-alias , -can be named). -See -.BR mh\-alias (5) -for more information. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Draft\-Folder:~^To find the default draft\-folder -^Aliasfile:~^For a default alias file -^Signature:~^To determine the user's mail signature -^mailproc:~^Program to post failure notices -^postproc:~^Program to post the message -.fi - -.SH "SEE ALSO" -comp(1), dist(1), forw(1), repl(1), mh\-alias(5), post(8) - -.SH DEFAULTS -.nf -.RB ` file "' defaults to /draft" -.RB ` \-alias "' defaults to %etcdir%/MailAliases" -.RB ` \-nodraftfolder ' -.RB ` \-nofilter ' -.RB ` \-format ' -.RB ` \-forward ' -.RB ` \-nomime ' -.RB ` \-nomsgid ' -.RB ` \-nopush ' -.RB ` \-noverbose ' -.RB ` \-nowatch ' -.RB ` "\-width\ 72" ' -.RB ` "\-attachformat\ 0" ' -.fi - -.SH CONTEXT -None - -.SH BUGS -Under some configurations, it is not possible to monitor the mail delivery -transaction; -.B \-watch -is a no-op on those systems. -.PP -Using -.B \-split -.I 0 -doesn't work correctly. diff --git a/man/send.man1 b/man/send.man1 new file mode 100644 index 0000000..34c4a22 --- /dev/null +++ b/man/send.man1 @@ -0,0 +1,179 @@ +.\" +.\" %nmhwarning% +.\" +.TH SEND %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +send \- send a message +.SH SYNOPSIS +.HP 5 +.na +.B send +.RB [ \-verbose " | " \-noverbose ] +.RB [ msg +\&...] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Send +will cause each of the specified messages to be delivered +to each of the destinations in the `To:', `Cc:', +`Bcc:', `Dcc:', and `Fcc:' fields of the message. If +.B send +is re\-distributing a message, as invoked from +.BR dist , +then the +corresponding `Resent\-xxx' fields are examined instead. +.PP +.B send +uses the program +.B spost +to do the actual delivery of the messages. +Most of the features attributed to +.B send +are actually performed by +.BR spost . +.PP +The draft is scanned for attachment header fields. +Their name defaults to ``Attach'', but may be changed by the value of the +.I Attachment-Header +profile entry. +If such header fields are found, or the body contains non-ASCII characters, +the message is converted to a MIME message. +This conversion occurs before all other processing. +.PP +The first part of the MIME message is the draft body if the body is non-empty. +The body of each attachment header field is interpreted as a file name, +and each file named is included as a separate part in the MIME message. +.PP +The MIME type of each file is determined by the MIME type query program, +as defined by the +.I Mime-Type-Query +profile entry. +Mmh distributes the program +.BR print-mimetype , +in case no better alternative is available on the system. +.PP +The last component of the path name is taken as the name of the MIME parts. +A message part header for an attachment might be: +.PP +.nf +Content-Type: text/plain; name="VERSION"; charset="us-ascii" +Content-Description: VERSION +Content-Disposition: attachment; filename="VERSION" +.fi +.PP +If +.B \-verbose +is specified, +.B send +will request verbose information of the transport system. +.PP +.B Send +with no +.I msg +argument will send the current message in the draft folder. +.B Send +always takes messages from the draft folder. +(But, a +.I +folder +argument might be added in the future.) +Consult the +.BR mh-draft (7) +man page for more information. +.PP +Once the transport system has successfully accepted custody of the +message, the message will be moved into the trash folder. +If there are errors in the formatting of the message, +.B send +will abort with a +(hopefully) helpful error message. +.PP +If a `Bcc:' field is encountered, its addresses will be used for +delivery, and the `Bcc:' field will be removed from the message +sent to sighted recipients. The blind recipients will receive an entirely +new message with a minimal set of headers. Included in the body of the +message will be a copy of the message sent to the sighted recipients. +.PP +If a `Dcc:' field is encountered, its addresses will be used for +delivery, and the `Dcc:' field will be removed from the message. The +blind recipients will receive the same message sent to the sighted +recipients. *WARNING* Recipients listed in the `Dcc:' field receive no +explicit indication that they have received a `blind copy'. +This can cause blind recipients to +inadvertently reply to all of the sighted recipients of the +original message, revealing that they received a blind copy. +On the other hand, since a normal reply to a message sent +via a `Bcc:' field +will generate a reply only to the sender of the original message, +it takes extra effort in most mailers to reply to the included +message, and so would usually only be done deliberately, rather +than by accident. +.PP +Prior to sending the message, the fields `From:\ user@local', +and `Date:\ now' will be appended to the headers in the message. +If the environment variable +.B $SIGNATURE +is set, then its value +is used as your personal name when constructing the `From:' +line of the message. If this environment variable is not set, then +.B send +will consult the profile entry `Signature' for +this information. +.PP +If +.B send +is re\-distributing a message (when invoked by +.BR dist ), +then `Resent\-' will be prepended to each of these +fields: `From:', `Date:', and `Message\-ID:'. +If the message already contains a `From:' field, then a +`Sender: user@local' field will be added as well. (An already +existing `Sender:' field is an error!) +.PP +If an `Fcc:\ folder' is encountered, the message will be copied +to the specified folder for the sender in the format in which it will +appear to any non\-Bcc receivers of the message. That is, it will have +the appended fields and field reformatting. The `Fcc:' fields +will be removed from all outgoing copies of the message. +.PP +The files specified by the profile entry `Aliasfile:' will be read. +See +.BR mh\-alias (5) +for more information. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Draft\-Folder:~^To set the default draft\-folder +^Aliasfile:~^For a default alias file +^Signature:~^To determine the user's mail signature +^Attachment\-Header:~^To set the name of the attachment header field +^Mime\-Type\-Query:~^Program to determine the MIME types of files +.fi + +.SH "SEE ALSO" +comp(1), dist(1), forw(1), repl(1), mh\-alias(5), spost(8) + +.SH DEFAULTS +.nf +.RB ` msg "' defaults to the current message in the draft folder" +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +None + +.SH BUGS +None diff --git a/man/sendfiles.man b/man/sendfiles.man deleted file mode 100644 index 76b793a..0000000 --- a/man/sendfiles.man +++ /dev/null @@ -1,162 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SENDFILES %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -sendfiles \- send multiple files via a MIME message -.SH SYNOPSIS -.HP -.na -.B sendfiles -.RB [ delay ] -.I mailpath -.I subject -.I file1 -.RI [ file2 -\&...] -.ad -.SH DESCRIPTION -The shell script -.BR sendfiles , -is used to send a collection -of files and directories via electronic mail. -.PP -.RS 5 -sendfiles mailpath \*(lqsubject\*(rq files\0... -.RE -.PP -.B sendfiles -will archive the files and directories you name -with the -.B tar -command, and then mail the compressed -archive to the \*(lqmailpath\*(rq with the given \*(lqsubject\*(rq. -The archive -will be automatically split up into as many messages as necessary -in order to get past most mailers. -.PP -Sometimes you want -.B sendfiles -to pause after posting a partial -message. This is usually the case when you are running -.B sendmail -and expect to generate a lot of partial messages. If the first -argument given to -.B sendfiles -starts with a dash, then it is -interpreted as the number of seconds to pause in between postings, -e.g., -.PP -.RS 5 -sendfiles -30 mailpath \*(lqsubject\*(rq files\0... -.RE -.PP -will pause 30 seconds in between each posting. -.PP -.SS "Extracting the Received Files" -When these messages are received, invoke -.B mhstore -once for -the list of messages. The default is for -.B mhstore -to store -the combined parts as a new message in the current folder, although -this can be changed using storage formatting strings. You can then -use -.B mhlist -to find out what's inside; possibly followed by -.B mhstore -again to write the archive to a file where you can -subsequently uncompress and untar it. For instance: -.PP -.RS 5 -.nf -% mhlist 5-8 - msg part type/subtype size description - 5 message/partial 47K part 1 of 4 - 6 message/partial 47K part 2 of 4 - 7 message/partial 47K part 3 of 4 - 8 message/partial 18K part 4 of 4 -% mhstore 5-8 -reassembling partials 5,6,7,8 to folder inbox as message 9 -% mhlist -verbose 9 - msg part type/subtype size description - 9 application/octet-stream 118K - (extract with uncompress | tar xvpf -) - type=tar - conversions=compress -% mhstore 9 -% uncompress < 9.tar.Z | tar xvpf - -.fi -.RE -.PP -Alternately, by using the -.B \-auto -switch, -.B mhstore -will automatically do the extraction for you: -.PP -.RS 5 -.nf -% mhlist 5-8 - msg part type/subtype size description - 5 message/partial 47K part 1 of 4 - 6 message/partial 47K part 2 of 4 - 7 message/partial 47K part 3 of 4 - 8 message/partial 18K part 4 of 4 -% mhstore 5-8 -reassembling partials 5,6,7,8 to folder inbox as message 9 -% mhlist -verbose 9 - msg part type/subtype size description - 9 application/octet-stream 118K - (extract with uncompress | tar xvpf -) - type=tar - conversions=compress -% mhstore -auto 9 --- tar listing appears here as files are extracted -.fi -.RE -.PP -As the second -.B tar -listing is generated, the files are extracted. -A prudent user will never put -.B \-auto -in the -.I \&.mh\(ruprofile -file. The correct procedure is to first use -.B mhlist -to find out what will be extracted. Then -.B mhstore -can be invoked with -.B \-auto -to perform the extraction. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -mhbuild(1), mhlist(1), mhshow(1), mhstore(1). -.I "Proposed Standard for Message Encapsulation" -(RFC\-934) - -.SH DEFAULTS -.nf -.RB ` \-noverbose ' -.fi - -.SH CONTEXT -None diff --git a/man/sendfiles.man1 b/man/sendfiles.man1 new file mode 100644 index 0000000..434be09 --- /dev/null +++ b/man/sendfiles.man1 @@ -0,0 +1,57 @@ +.\" +.\" %nmhwarning% +.\" +.TH SENDFILES %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +sendfiles \- send multiple files in a MIME message +.SH SYNOPSIS +.HP 5 +.na +.B sendfiles +.I recipient +.I subject +.IR file ... +.ad +.SH DESCRIPTION +The program +.BR sendfiles , +is used to send a collection +of files via electronic mail. +.B sendfiles +will mail the files in one message with the given `subject' +to the `recipient'. +Take care not to generate too large messages, as there usually are +size limits enforced by the MTAs. +.PP +To extract received files, use +.B mhstore . + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/FileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +None + +.SH "SEE ALSO" +send(1), mhlist(1), mhstore(1). + +.SH CONTEXT +None + +.SH HISTORY +.PP +This is a new and simpler version of +.B sendfiles , +which directly invokes +.B send . +The old one had invoked +.B viamail . +The old version had been able to send whole directories, by automatically +tarballing them. This new version is not able to do so. +The old man page had described some kind of automatical splitting of +large content into `message/partial' parts. However, it appears as if this +had been removed earlier, only its documentation remained. diff --git a/man/show.man b/man/show.man deleted file mode 100644 index bdca14f..0000000 --- a/man/show.man +++ /dev/null @@ -1,282 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SHOW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -show \- show (display) messages -.SH SYNOPSIS -.HP 5 -.na -.B show -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-draft ] -.RB [\-showproc -.IR program ] -.RB [ \-showmimeproc -.IR program ] -.RB [ \-header " | " \-noheader ] -.RB [ \-checkmime " | " \-nocheckmime ] -[switches\ for -.I showproc -or -.IR showmimeproc ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Show -lists each of the specified messages to the standard output -(typically, the terminal). -.PP -By default, text (non-MIME) messages are filtered and displayed by -the -.B nmh -command -.BR mhl . -This command will display text -messages in a nice, uniform format. It also allows you to configure -the format of the displayed messages and which headers fields are -shown. See the -.BR mhl (1) -manual page for the details about this -command. This default can be changed by defining the -.I showproc -profile component. Any switches not recognized by -.B show -are -passed along to that program. To override the default and the -.I showproc -profile component, use the -.B \-showproc -.I program -switch. For example, -.B \-showproc -.I more -will cause the -.B more -program to list the messages with no reformatting. Normally, this -program is specified as the -.I showproc -in the user's -.IR \&.mh\(ruprofile , -rather than using a command line switch. -.PP -By default, non-text messages (MIME messages with multi-media -contents) are processed and displayed by the -.B nmh -command -.BR mhshow . -See the -.BR mhshow (1) -manual page for details -about this command. This default can changed by defining the -.I showmimeproc -profile component. Any switches not recognized -by -.B show -are passed along to that program. To override this -default and the -.B showmimeproc -profile component, use the -.B \-showmimeproc -.I program -switch. -.PP -Note that in some cases, -.B show -may invoke the -.I showmimeproc -even for textual contents. This will happen for text messages that -specify a transfer encoding (such as MIME quoted-printable or -base64) or specify a character set that -.B show -doesn't believe -can be displayed natively. The environment variable -.B $MM_CHARSET -should be set to the terminal's native character set to avoid -gratuitous invocations of the -.IR showmimeproc . -See the -.BR mh-profile (5) -man page for details about this environment variable. -.PP -The option -.B \-checkmime -(set by default) instructs -.B show -to -test if any of the messages to be displayed are non-text (MIME) -messages. If any are non-text, they are displayed by the program -.IR showmimeproc , -else they are displayed by the program -.IR showproc . -The option -.B \-nocheckmime -disables this test and instructs -.B show -to use -.IR showproc , -regardless of whether -any of the messages are non-text (MIME) messages. -.P -The -.B \-noshowproc -switch will disable any formatting or paging of -messages. It is equivalent to -.B \-nocheckmime -.B \-showproc -.IR cat . -It is still accepted, but should be considered (somewhat) obsolete. -.PP -If the environment variable -.B $NOMHNPROC -is set, the test for -non-text (MIME) messages will be disabled. This method is obsolete. -Use the -.B \-nocheckmime -switch instead. -.PP -The -.B \-header -switch tells -.B show -to display a one\-line -description of the message being shown. This description includes -the folder and the message number. -.PP -If no `msgs' are specified, the current message is used. Although -it depends on the specific -.I showproc -or -.IR showmimeproc , -in the default setup when more than one message is specified, you -will be prompted for a prior to listing each message. -Each message will be listed a page at a time, and when the end of -page is reached, the program will wait for a or . -If a is entered, it will print the next line, whereas - will print the next screenful. -.PP -If the standard output is not a terminal, no queries are made, and -each file is listed with a one\-line header and two lines of -separation. -.PP -.RB \*(lq "show \-draft" \*(rq -will list the file /draft if it -exists. -.PP -If the profile entry \*(lqUnseen\-Sequence\*(rq is present and -non\-empty, then -.B show -will remove each of the messages shown -from each sequence named by the profile entry. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Unseen\-Sequence:~^To name sequences denoting unseen messages -^showproc:~^Program to show text (non-MIME) messages -^showmimeproc:~^Program to show non-text (MIME) messages -.fi - -.SH "SEE ALSO" -mhl(1), mhshow(1), more(1), next(1), prev(1), scan(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-checkmime ' -.RB ` \-header ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. The last -message shown will become the current message. - -.SH BUGS -The -.B \-header -switch doesn't work when `msgs' expands to more than -one message. If the -.I showproc -is -.BR mhl , -then this problem can -be circumvented by referencing the \*(lqmessagename\*(rq field in the -.B mhl -format file. -.PP -.B Show -updates the user's context before showing the message. -Hence -.B show -will mark messages as seen prior to the user actually -seeing them. This is generally not a problem, unless the user relies -on the \*(lqunseen\*(rq messages mechanism, and interrupts -.B show -while it is showing \*(lqunseen\*(rq messages. -.PP -If your -.I showproc -is -.B mhl -(the default), then -.B show -uses -a built\-in -.BR mhl : -it does not actually run the -.B mhl -program. -Hence, if you define your own -.B showproc , -don't call it -.B mhl -since -.B show -won't run it. -.PP -If your -.I showproc -is the pager -.BR more , -then avoid running -.B show -in the background with only its standard output piped to -another process, as in -.PP -.RS 5 -show | imprint & -.RE -.PP -Due to a bug in -.BR more , -show will go into a \*(lqtty input\*(rq state. -To avoid this problem, re\-direct -.BR show 's -diagnostic output as well. -For users of -.BR csh : -.PP -.RS 5 -show |& imprint & -.RE -.PP -For users of -.BR sh : -.PP -.RS 5 -show 2>&1 | imprint & -.RE diff --git a/man/show.man1 b/man/show.man1 new file mode 100644 index 0000000..f7b30fd --- /dev/null +++ b/man/show.man1 @@ -0,0 +1,459 @@ +.\" +.\" %nmhwarning% +.\" +.TH SHOW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +show \- display (MIME) messages +.PP +next \- show the next message +.PP +prev \- show the previous message +.SH SYNOPSIS +.HP 5 +.na +.B show +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-file +.IR file ] +.RB [ \-part +.IR number ] +\&... +.RB [ \-type +.IR content ] +\&... +.RB [ \-form +.IR formfile ] +.RB [ \-Version ] +.RB [ \-help ] +.PP +.HP 5 +.B next +is equivalent to +.B show n +.PP +.HP 5 +.B prev +is equivalent to +.B show p +.ad + +.SH NOTE +This (i.e. mmh's) version of +.B show +is a modified version of nmh's +.B mhshow +program. +The old (non-MIME) +.B show +program was removed from mmh. + +.SH DESCRIPTION +The +.B show +command display contents of a MIME (multi-media) +message or collection of messages. +.B Next +and +.B prev +perform a +.B show +on the next or previous message in the specified +(or current) folder, respectively. +.PP +.B show +manipulates multi-media messages as specified in +RFC\-2045 thru RFC\-2049. Currently +.B show +only supports +encodings in message bodies, and does not support the encoding of +message headers as specified in RFC\-2047. +.PP +By default +.B show +will display all parts of a multipart +message. By using the +.B \-part +and +.B \-type +switches, you may +limit the scope of +.B show +to particular subparts (of a +multipart content) and/or particular content types. +.PP +The option +.B \-file +.I file +directs +.B show +to use the specified file as +the source message, rather than a message from a folder. If you specify +this file as `-', then +.B show +will accept the source message +on the standard input. Note that the file, or input from standard input +should be a validly formatted message, just like any other +.B nmh +message. It should +.B NOT +be in mail drop format (to convert a file in +mail drop format to a folder of +.B nmh +messages, see +.BR inc (1)). +.PP +When displaying multiple messages, +.B show +prepends each of them with a `>>> Message nnn' header, +and separates the messages with two lines of space. +This is similar to the way +.B mhl +acts on multiple files. +.PP +A part specification consists of a series of numbers separated by dots. +For example, in a multipart content containing three parts, these +would be named as 1, 2, and 3, respectively. If part 2 was also a +multipart content containing two parts, these would be named as 2.1 and +2.2, respectively. Note that the +.B \-part +switch is effective for only +messages containing a multipart content. If a message has some other +kind of content, or if the part is itself another multipart content, the +.B \-part +switch will not prevent the content from being acted upon. +.PP +A content specification consists of a content type and a subtype. +The initial list of `standard' content types and subtypes can +be found in RFC\-2046. +.PP +A list of commonly used contents is briefly reproduced here: +.PP +.RS 5 +.nf +.ta \w'application 'u +Type Subtypes +---- -------- +text plain, enriched +multipart mixed, alternative, digest, parallel +message rfc822, partial, external-body +application octet-stream, postscript +image jpeg, gif, png +audio basic +video mpeg +.fi +.RE +.PP +A legal MIME message must contain a subtype specification. +.PP +To specify a content, regardless of its subtype, just use the +name of the content, e.g., `audio'. To specify a specific +subtype, separate the two with a slash, e.g., `audio/basic'. +Note that regardless of the values given to the `\-type' switch, a +multipart content (of any subtype listed above) is always acted upon. +.SS "Unseen Sequence" +If the profile entry `Unseen\-Sequence' is present and +non\-empty, then +.B show +will remove each of the messages shown +from each sequence named by the profile entry. +.SS "Showing the Contents" +.B Mhshow +prints messages in a convenient representation. +If +.B show +is outputting to a terminal, then +a pager will be placed between the terminal and +.BR show . +.PP +The headers of each message are displayed with +.B mhl +using the standard format file +.IR mhl.headers . +You may specify an alternate format file with the +.B \-form +.I formfile +switch. If the format file +.I mhl.null +is specified, then the display +of the message headers is suppressed. +.PP +Next, the contents are extracted from the message and are stored in +a temporary file. Usually, the name of the temporary file is the +word `show' followed by a string of characters. Occasionally, +the method used to display a content (described next), requires that +the file end in a specific suffix. For example, the +.B soffice +command (part of the StarOffice package) can be used to display +Microsoft Word content, but it uses the suffix to determine how to display +the file. If no suffix is present, the file is not correctly loaded. +Similarily, older versions of the +.B gs +command append a `.ps' suffix to +the filename if one was missing. As a result, these cannot be used to read +the default temporary file. +.PP +To get around this, your profile can contain lines of the forms: +.PP +.RS 5 +.nf +mhshow-suffix-/: +mhshow-suffix-: +.fi +.RE +.PP +to specify a suffix which can be automatically added to the temporary +file created for a specific content type. For example, the following +lines might appear in your profile: +.PP +.RS 5 +.nf +mhshow-suffix-text: .txt +mhshow-suffix-application/msword: .doc +mhshow-suffix-application/PostScript: .ps +.fi +.RE +.PP +to automatically append a suffix to the temporary files. +.PP +The method used to display the different contents in the messages bodies +will be determined by a `display string'. To find the display +string, +.B show +will first search your profile for an entry of the form: +.PP +.RS 5 +mhshow-show-/ +.RE +.PP +to determine the display string. If this isn't found, +.B show +will search for an entry of the form: +.PP +.RS 5 +mhshow-show- +.RE +.PP +to determine the display string. +.PP +If a display string is found, any escapes (given below) will be expanded. +The result will be executed under +`/bin/sh', with the standard input +set to the content. +.PP +The display string may contain the following escapes: +.PP +.RS 5 +.nf +.ta \w'%F 'u +%l Display listing prior to displaying content +%f Insert filename containing content +%F %f, but stdin is terminal not content +%a Insert parameters from Content-Type field +%s Insert content subtype +%c Insert foreign charset +%d Insert content description +%% The character % +.fi +.RE +.PP +.B Mhshow +processes the MIME parts serially, i.e. the next display process +is executed after the previous one has terminated. +.PP +Further, when +.B show +is display a content, typing QUIT (usually +control-\\) will tell +.B show +to wrap things up immediately. +.PP +Note that if the content being displayed is multipart, but not one of +the subtypes listed above, then the f- and F-escapes expand to multiple +filenames, one for each subordinate content. Further, stdin is not +redirected from the terminal to the content. +.PP +If a display string is not found, +.B show +has the following default values: +.PP +.RS 5 +.nf +mhshow-show-text/plain: %liconv -f +mhshow-show-message/rfc822: %lshow \-file %F +.fi +.RE +.PP +If a subtype of type text doesn't have a profile entry, it will be +treated as text/plain. +.PP +.B show +has default methods for handling multipart messages of subtype +mixed, alternative, parallel, and digest. Any unknown subtype of type +multipart (without a profile entry), will be treated as multipart/mixed. +.PP +If none of these apply, then +.B show +will complain. +.PP +Example entries might be: +.PP +.RS 5 +.nf +mhshow-show-audio/basic: raw2audio 2>/dev/null | play +mhshow-show-image: xv %f +mhshow-show-application/PostScript: lpr -Pps +.fi +.RE +.PP +When expanding %f and %F escapes, the file names get wrapped in +single-quotes automatically. +.PP +Finally, +.B show +will process each message serially \- it won't start +showing the next message until all the commands executed to display the +current message have terminated. Although a multipart content may +contain advice to display the parts in parallel, +.B show +will never do so. +.SS "Showing Alternate Character Sets" +Because a content of type text might be in a non-ASCII character +set, when +.B show +encounters a `charset' parameter for +this content, it checks if your terminal can display this character +set natively. +.B show +checks this by first examining the the environment +variable +.B $MM_CHARSET +and if not set, taking the character encoding of the current locale. +.PP +If the character set of text/plain cannot be displayed natively, then +the default display method converts the content automatically by +piping it through: +.PP +.RS 5 +iconv -f '' +.RE +.PP +Note that if you have a custom `mhshow-show-*' display string, you +need to care yourself for converting the encodings. +(The foreign charset is available through the %c escape.) +.PP +The tool +.B iconv +needs to be available. +.PP +`mhshow-charset-*' profile entries are not supported anymore. +.SS "Messages of Type message/partial" +.B show +cannot directly display messages of type partial. +You must reassemble them first into a normal message using +.BR mhstore . +Check the man page for +.BR mhstore (1) +for details. +.SS "External Access" +.B Mhshow +does not automatically retrieve message/external-body parts (anymore), +but prints the relevant information to enable the user to retrieve +the files manually. +.SS "User Environment" +Because the display environment in which +.B show +operates may vary for +different machines, +.B show +will look for the environment variable +.BR $MHSHOW . +If present, this specifies the name of an additional +user profile which should be read. Hence, when a user logs in on a +particular display device, this environment variable should be set to +refer to a file containing definitions useful for the given display device. +Normally, only entries that deal with the methods to display different +content type and subtypes +.PP +.RS 5 +.nf +mhshow-show-/ +mhshow-show- +.fi +.RE +.PP +need be present in this additional profile. Finally, +.B show +will attempt to consult one other additional user profile, +e.g., +.PP +.RS 5 +%etcdir%/mhn.defaults +.RE +.PP +which is created automatically during +.B nmh +installation. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^$MHSHOW~^Additional profile entries +^%etcdir%/mhn.defaults~^System default MIME profile entries +^%etcdir%/mhl.headers~^The headers template +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +^Unseen\-Sequence:~^To name sequences denoting unseen messages +^mhshow-show-*~^Template for displaying contents +^Pager:~^Program to use as interactive front\-end +.fi + +.SH "SEE ALSO" +mhbuild(1), mhl(1), mhlist(1), mhstore(1), sendfiles(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs "' defaults to cur" +.RB ` \-form \ mhl.headers' +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. The last +message selected will become the current message. + +.SH BUGS +.B Next +and +.B prev +are really links to the +.B show +program. As a result, if +you make a link to +.B next +or +.B prev +and that link is not called +.B next +or +.BR prev , +your link will act like +.B show +instead. To circumvent this, add a +profile\-entry for the link to your +.B nmh +profile and add the argument +.I n +or +.I p +to the entry. diff --git a/man/slocal.man b/man/slocal.man deleted file mode 100644 index cc822f0..0000000 --- a/man/slocal.man +++ /dev/null @@ -1,434 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SLOCAL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -slocal \- asynchronously filter and deliver new mail -.SH SYNOPSIS -.HP 5 -.na -.B %libdir%/slocal -[address\ info\ sender] -.RB [ \-addr -.IR address ] -.RB [ \-info -.IR data ] -.RB [ \-sender -.IR sender ] -.RB [ \-user -.IR username ] -.RB [ \-mailbox -.IR mbox ] -.\" \%[\-home\ homedir] -.RB [ \-file -.IR file ] -.RB [ \-maildelivery -.IR deliveryfile ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-suppressdup " | " \-nosuppressdup ] -.RB [ \-debug ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Slocal -is a program designed to allow you to have your inbound -mail processed according to a complex set of selection criteria. -You do not normally invoke -.B slocal -yourself, rather -.B slocal -is invoked on your behalf by your system's Message Transfer Agent -(such as -.BR sendmail ) -when the message arrives. -.PP -The message selection criteria used by -.B slocal is specified -in the file -.RI \*(lq \&.maildelivery \*(rq -in the user's home directory. -You can specify an alternate file with the -.B \-maildelivery -.I file -option. The syntax of this file is specified below. -.PP -The message delivery address and message sender are determined from -the Message Transfer Agent envelope information, if possible. -Under -.BR sendmail , -the sender will obtained from the UUCP -\*(lqFrom:\*(rq line, if present. The user may override these -values with command line arguments, or arguments to the -.B \-addr -and -.B \-sender -switches. -.PP -The message is normally read from the standard input. The -.B \-file -switch sets the name of the file from which the message should be -read, instead of reading stdin. This is useful when debugging a -.RI \*(lq \&.maildelivery \*(rq -file. -.PP -The -.B \-user -switch tells -.B slocal -the name of the user for -whom it is delivering mail. The -.B \-mailbox -switch tells -.B slocal -the name of the user's maildrop file. -.PP -.B slocal -is able to detect and suppress duplicate messages. -To enable this, use the option -.BR \-suppressdup . -.B slocal -will -keep a database containing the Message-ID's of incoming messages, -in order to detect duplicates. Depending on your configuration, -this database will be in either ndbm or Berkeley db format. -.PP -The -.B \-info -switch may be used to pass an arbitrary argument to -sub-processes which -.B slocal -may invoke on your behalf. -.PP -The -.B \-verbose -switch causes -.B slocal -to give information on -stdout about its progress. The -.B \-debug -switch produces more -verbose debugging output on stderr. These flags are useful when -creating and debugging your -.RI \*(lq \&.maildelivery \*(rq -file, as they -allow you to see the decisions and actions that -.B slocal -is taking, as well as check for syntax errors in your -.RI \*(lq \&.maildelivery \*(rq -file. - -.SS "Message Transfer Agents" -Most modern MTAs including -.BR sendmail , -.BR postfix -and -.BR exim -support a \&.forward file for directing incoming mail. -You should include the line -.PP -.RS 5 -\*(lq|\ %libdir%/slocal\ \-user\ username\*(rq -.RE -.PP -in your \&.forward file in your home directory. This will cause -your MTA to invoke -.B slocal -on your behalf when a message arrives. - -.SS "The Maildelivery File" -The -.RI \*(lq \&.maildelivery \*(rq -file controls how -.B slocal -filters and delivers -incoming mail. Each line of this file consists of five fields, separated -by white-space or comma. Since double-quotes are honored, these -characters may be included in a single argument by enclosing the entire -argument in double-quotes. A double-quote can be included by preceding it -with a backslash. Lines beginning with `#' and blank lines are ignored. -.PP -The format of each line in the -.RI \*(lq \&.maildelivery \*(rq -file is: -.PP -.RS 5 -.B header pattern action result string -.RE -.PP -.BR header : -.RS 5 -The name of a header field (such as To, Cc, or From) that is to -be searched for a pattern. This is any field in the headers of -the message that might be present. -.PP -The following special fields are also defined: -.TP \w'defaultrrr'u -.I source -the out-of-band sender information -.TP \w'defaultrrr'u -.I addr -the address that was used to cause delivery to the recipient -.TP \w'defaultrrr'u -.I default -this matches -.B only -if the message hasn't been delivered yet -.TP \w'defaultrrr'u -.I * -this always matches -.RE -.PP -.BR pattern : -.RS 5 -The sequence of characters to match in the specified header field. -Matching is case-insensitive, but does not use regular expressions. -.RE -.PP -.BR action : -.RS 5 -The action to take to deliver the message. When a message is delivered, -a \*(lqDelivery\-Date:\ date\*(rq header is added which indicates the date -and time that message was delivered. -.TP 4 -.I destroy -This action always succeeds. -.TP 4 -.IR file ", " mbox ", or " > -Append the message to the file named by -.IR string . -The message is -appended to the file in mbox (uucp) format. This is the format used by most -other mail clients (such as mailx, elm). If the message can be appended to -the file, then this action succeeds. -.TP 4 -.I mmdf -Identical to -.IR file , -but always appends the message using the MMDF mailbox format. -.TP 4 -.IR pipe " or " | -Pipe the message as the standard input to the command named by -.IR string , -using the Bourne shell -.B sh -to interpret the string. -Prior to giving the string to the shell, it is expanded with the following -built-in variables: -.RS -.TP \w'zzreplyztozaaa'u -$(sender) -the out-of-band sender information -.TP \w'zzreplyztozaaa'u -$(address) -the address that was used to cause delivery to the recipient -.TP \w'zzreplyztozaaa'u -$(size) -the size of the message in bytes -.TP \w'zzreplyztozaaa'u -$(reply\-to) -either the \*(lqReply\-To:\*(rq or \*(lqFrom:\*(rq field of the message -.TP \w'zzreplyztozaaa'u -$(info) -the out-of-band information specified -.RE -.TP 4 -.IR qpipe " or " ^ -Similar to -.IR pipe , -but executes the command -directly, after built-in variable expansion, without assistance from -the shell. This action can be used to avoid quoting special characters -which your shell might interpret. -.TP 4 -.IR folder " or " + -Store the message in the -.B nmh -folder named by -.IR string . -Currently this is handled by piping the message to the -.B nmh -program -.BR rcvstore , -although this may change in the future. -.RE -.PP -.BR result : -.RS 5 -Indicates how the action should be performed: -.TP \w'Azzz'u -.I A -Perform the action. If the action succeeds, then the message -is considered delivered. -.TP \w'Azzz'u -.I R -Perform the action. Regardless of the outcome of the action, -the message is not considered delivered. -.TP \w'Azzz'u -.I ? -Perform the action only if the message has not been delivered. -If the action succeeds, then the message is considered delivered. -.TP \w'Azzz'u -.I N -Perform the action only if the message has not been delivered -and the previous action succeeded. If this action succeeds, then the -message is considered delivered. -.PP -The delivery file is always read completely, so that several matches -can be made and several actions can be taken. -.RE - -.SS "Security of Delivery Files" -In order to prevent security problems, the -.RI \*(lq \&.maildelivery \*(rq -file must be owned either by the user or by root, and must be -writable only by the owner. If this is not the case, the file is -not read. -.PP -If the -.RI \*(lq \&.maildelivery \*(rq -file cannot be found, or does not -perform an action which delivers the message, then -.B slocal -will check for a global delivery file at -.IR %etcdir%/maildelivery . -This file is read according to the same rules. This file must be -owned by the root and must be writable only by the root. -.PP -If a global delivery file cannot be found or does not perform an -action which delivers the message, then standard delivery to the -user's maildrop is performed. - -.SS "Example Delivery File" -To summarize, here's an example delivery file: -.PP -.nf -.ta \w'default 'u +\w'mh-workersxx 'uC +\w'destroy 'uC +\w'result 'u -# -# .maildelivery file for nmh's slocal -# -# Blank lines and lines beginning with a '#' are ignored -# -# FIELD PATTERN ACTION RESULT STRING -# - -# File mail with foobar in the \*(lqTo:\*(rq line into file foobar.log -To foobar file A foobar.log - -# Pipe messages from coleman to the program message-archive -From coleman pipe A /bin/message-archive - -# Anything to the \*(lqnmh-workers\*(rq mailing list is put in -# its own folder, if not filed already -To nmh-workers folder ? nmh-workers - -# Anything with Unix in the subject is put into -# the file unix-mail -Subject unix file A unix-mail - -# I don't want to read mail from Steve, so destroy it -From steve destroy A \- - -# Put anything not matched yet into mailbox -default \- file ? mailbox - -# always run rcvtty -* \- pipe R %libdir%/rcvtty -.fi - -.SS "Sub-process environment" -When a process is invoked, its environment is: the user/group-ids are -set to recipient's ids; the working directory is the recipient's home -directory; the umask is 0077; the process has no /dev/tty; the standard -input is set to the message; the standard output and diagnostic output are -set to /dev/null; all other file-descriptors are closed; the environment -variables -.BR $USER , -.BR $HOME , -.B $SHELL -are set appropriately, and no other environment variables exist. -.PP -The process is given a certain amount of time to execute. If the process -does not exit within this limit, the process will be terminated with -extreme prejudice. The amount of time is calculated as ((size / 60) + -300) seconds, where size is the number of bytes in the message (with -30 minutes the maximum time allowed). -.PP -The exit status of the process is consulted in determining the success -of the action. An exit status of zero means that the action succeeded. -Any other exit status (or abnormal termination) means that the action -failed. -.PP -In order to avoid any time limitations, you might implement a process -that began by -.BR fork ()-ing. -The parent would return the appropriate -value immediately, and the child could continue on, doing whatever it -wanted for as long as it wanted. This approach is somewhat risky if -the parent is going to return an exit status of zero. If the parent is -going to return a non-zero exit status, then this approach can lead to -quicker delivery into your maildrop. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/mts.conf~^nmh mts configuration file -^$HOME/\&.maildelivery~^The file controlling local delivery -^%etcdir%/maildelivery~^Rather than the standard file -^%mailspool%/$USER~^The default maildrop -.fi - -.SH "SEE ALSO" -rcvdist(1), rcvpack(1), rcvstore(1), rcvtty(1), mh\-format(5) - -.SH DEFAULTS -.nf -.RB ` \-noverbose ' -.RB ` \-nosuppressdup ' -.RB ` \-maildelivery "' defaults to $HOME/\&.maildelivery" -.RB ` \-mailbox "' deaults to %mailspool%/$USER" -.RB ` \-file "' defaults to stdin" -.RB ` \-user "' defaults to the current user" -.fi - -.SH CONTEXT -None - -.SH HISTORY -.B Slocal -was originally designed to be backward-compatible with -the -.B maildelivery -facility provided by -.BR MMDF-II . -Thus, the -.RI \*(lq \&.maildelivery \*(rq -file syntax is somewhat limited. But -.B slocal -has been modified and extended, so that is it no longer compatible with -.BR MMDF-II . -.PP -In addition to an exit status of zero, the -.B MMDF -values -.B RP_MOK -(32) and -.B RP_OK -(9) mean that the message has been fully delivered. -Any other non-zero exit status, including abnormal termination, is -interpreted as the -.B MMDF -value -.B RP_MECH -(200), which means -\*(lquse an alternate route\*(rq (deliver the message to the maildrop). - -.SH BUGS -Only two return codes are meaningful, others should be. -.PP -.B Slocal -was originally designed to be backwards-compatible with the -.B maildelivery -functionality provided by -.BR MMDF-II . diff --git a/man/slocal.man1 b/man/slocal.man1 new file mode 100644 index 0000000..f6c78d4 --- /dev/null +++ b/man/slocal.man1 @@ -0,0 +1,425 @@ +.\" +.\" %nmhwarning% +.\" +.TH SLOCAL %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +slocal \- asynchronously filter and deliver new mail +.SH SYNOPSIS +.HP 5 +.na +.B slocal +[address\ info\ sender] +.RB [ \-addr +.IR address ] +.RB [ \-info +.IR data ] +.RB [ \-sender +.IR sender ] +.RB [ \-user +.IR username ] +.RB [ \-mailbox +.IR mbox ] +.\" \%[\-home\ homedir] +.RB [ \-file +.IR file ] +.RB [ \-maildelivery +.IR deliveryfile ] +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-debug ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Slocal +is a program designed to allow you to have your inbound +mail processed according to a complex set of selection criteria. +You do not normally invoke +.B slocal +yourself, rather +.B slocal +is invoked on your behalf by your system's Message Transfer Agent +(such as +.BR sendmail ) +when the message arrives. +.PP +The message selection criteria used by +.B slocal is specified +in the file +.RI ` \&.maildelivery ' +in the user's home directory. +You can specify an alternate file with the +.B \-maildelivery +.I file +option. The syntax of this file is specified below. +.PP +The message delivery address and message sender are determined from +the Message Transfer Agent envelope information, if possible. +Under +.BR sendmail , +the sender will obtained from the mbox +`From ' line, if present. The user may override these +values with command line arguments, or arguments to the +.B \-addr +and +.B \-sender +switches. +.PP +The message is normally read from the standard input. The +.B \-file +switch sets the name of the file from which the message should be +read, instead of reading stdin. This is useful when debugging a +.RI ` \&.maildelivery ' +file. +.PP +The +.B \-user +switch tells +.B slocal +the name of the user for +whom it is delivering mail. The +.B \-mailbox +switch tells +.B slocal +the name of the user's maildrop file. +.PP +The +.B \-info +switch may be used to pass an arbitrary argument to +sub-processes which +.B slocal +may invoke on your behalf. +.PP +The +.B \-verbose +switch causes +.B slocal +to give information on +stdout about its progress. The +.B \-debug +switch produces more +verbose debugging output on stderr. These flags are useful when +creating and debugging your +.RI ` \&.maildelivery ' +file, as they +allow you to see the decisions and actions that +.B slocal +is taking, as well as check for syntax errors in your +.RI ` \&.maildelivery ' +file. + +.SS "Message Transfer Agents" +Most modern MTAs including +.BR sendmail , +.BR postfix +and +.BR exim +support a \&.forward file for directing incoming mail. +You should include the line +.PP +.RS 5 +`|\ %bindir%/slocal\ \-user\ username' +.RE +.PP +in your \&.forward file in your home directory. This will cause +your MTA to invoke +.B slocal +on your behalf when a message arrives. + +.SS "The Maildelivery File" +The +.RI ` \&.maildelivery ' +file controls how +.B slocal +filters and delivers +incoming mail. Each line of this file consists of five fields, separated +by white-space or comma. Since double-quotes are honored, these +characters may be included in a single argument by enclosing the entire +argument in double-quotes. A double-quote can be included by preceding it +with a backslash. Lines beginning with `#' and blank lines are ignored. +.PP +The format of each line in the +.RI ` \&.maildelivery ' +file is: +.PP +.RS 5 +.B "header pattern action result string +.RE +.PP +.BR header : +.RS 5 +The name of a header field (such as To, Cc, or From) that is to +be searched for a pattern. This is any field in the headers of +the message that might be present. +.PP +The following special fields are also defined: +.TP \w'defaultrrr'u +.I source +the out-of-band sender information +.TP \w'defaultrrr'u +.I addr +the address that was used to cause delivery to the recipient +.TP \w'defaultrrr'u +.I default +this matches +.B only +if the message hasn't been delivered yet +.TP \w'defaultrrr'u +.I * +this always matches +.RE +.PP +.BR pattern : +.RS 5 +The sequence of characters to match in the specified header field. +Matching is case-insensitive, but does not use regular expressions. +.RE +.PP +.BR action : +.RS 5 +The action to take to deliver the message. When a message is delivered, +a `Delivery\-Date:\ date' header is added which indicates the date +and time that message was delivered. +.TP 4 +.I destroy +This action always succeeds. +.TP 4 +.IR file ", " mbox ", or " > +Append the message to the mbox file named by +.IR string . +This is handled by piping the message to the +.B nmh +program +.BR rcvpack . +If +.B rcvpack +returned successful, then this action succeeds. +.TP 4 +.IR pipe " or " | +Pipe the message as the standard input to the command named by +.IR string , +using the Bourne shell +.B sh +to interpret the string. +Prior to giving the string to the shell, it is expanded with the following +built-in variables: +.RS +.TP \w'zzreplyztozaaa'u +$(sender) +the out-of-band sender information +.TP \w'zzreplyztozaaa'u +$(address) +the address that was used to cause delivery to the recipient +.TP \w'zzreplyztozaaa'u +$(size) +the size of the message in bytes +.TP \w'zzreplyztozaaa'u +$(reply\-to) +either the `Reply\-To:' or `From:' field of the message +.TP \w'zzreplyztozaaa'u +$(info) +the out-of-band information specified +.RE +.TP 4 +.IR qpipe " or " ^ +Similar to +.IR pipe , +but executes the command +directly, after built-in variable expansion, without assistance from +the shell. This action can be used to avoid quoting special characters +which your shell might interpret. +.TP 4 +.IR folder " or " + +Store the message in the +.B nmh +folder named by +.IR string . +This is handled by piping the message to the +.B nmh +program +.BR rcvstore . +If +.B rcvstore +returned successful, then this action succeeds. +.RE +.PP +.BR result : +.RS 5 +Indicates how the action should be performed: +.TP \w'Azzz'u +.I A +Perform the action. If the action succeeds, then the message +is considered delivered. +.TP \w'Azzz'u +.I R +Perform the action. Regardless of the outcome of the action, +the message is not considered delivered. +.TP \w'Azzz'u +.I ? +Perform the action only if the message has not been delivered. +If the action succeeds, then the message is considered delivered. +.TP \w'Azzz'u +.I N +Perform the action only if the message has not been delivered +and the previous action succeeded. If this action succeeds, then the +message is considered delivered. +.PP +The delivery file is always read completely, so that several matches +can be made and several actions can be taken. +.RE + +.SS "Security of Delivery Files" +In order to prevent security problems, the +.RI ` \&.maildelivery ' +file must be owned either by the user or by root, and must be +writable only by the owner. If this is not the case, the file is +not read. +.PP +If the +.RI ` \&.maildelivery ' +file cannot be found, or does not +perform an action which delivers the message, then +.B slocal +will check for a global delivery file at +.IR %etcdir%/maildelivery . +This file is read according to the same rules. This file must be +owned by the root and must be writable only by the root. +.PP +If a global delivery file cannot be found or does not perform an +action which delivers the message, then standard delivery to the +user's maildrop is performed. + +.SS "Example Delivery File" +To summarize, here's an example delivery file: +.PP +.nf +.ta \w'default 'u +\w'mh-workersxx 'uC +\w'destroy 'uC +\w'result 'u +# +# .maildelivery file for nmh's slocal +# +# Blank lines and lines beginning with a '#' are ignored +# +# FIELD PATTERN ACTION RESULT STRING +# + +# File mail with foobar in the `To:' line into file foobar.log +To foobar file A foobar.log + +# Pipe messages from coleman to the program message-archive +From coleman pipe A /bin/message-archive + +# Anything to the `nmh-workers' mailing list is put in +# its own folder, if not filed already +To nmh-workers folder ? nmh-workers + +# Anything with Unix in the subject is put into +# the file unix-mail +Subject unix file A unix-mail + +# I don't want to read mail from Steve, so destroy it +From steve destroy A \- + +# Put anything not matched yet into mailbox +default \- file ? mailbox +.fi + +.SS "Sub-process environment" +When a process is invoked, its environment is: the user/group-ids are +set to recipient's ids; the working directory is the recipient's home +directory; the umask is 0077; the process has no /dev/tty; the standard +input is set to the message; the standard output and diagnostic output are +set to /dev/null; all other file-descriptors are closed; the environment +variables +.BR $USER , +.BR $HOME , +.B $SHELL +are set appropriately, +.B $PATH +is preserved, but no other environment variables exist. +.PP +The process is given a certain amount of time to execute. If the process +does not exit within this limit, the process will be terminated with +extreme prejudice. The amount of time is calculated as ((size / 60) + +300) seconds, where size is the number of bytes in the message (with +30 minutes the maximum time allowed). +.PP +The exit status of the process is consulted in determining the success +of the action. An exit status of zero means that the action succeeded. +Any other exit status (or abnormal termination) means that the action +failed. +.PP +In order to avoid any time limitations, you might implement a process +that began by +.BR fork ()-ing. +The parent would return the appropriate +value immediately, and the child could continue on, doing whatever it +wanted for as long as it wanted. This approach is somewhat risky if +the parent is going to return an exit status of zero. If the parent is +going to return a non-zero exit status, then this approach can lead to +quicker delivery into your maildrop. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/\&.maildelivery~^The file controlling local delivery +^%etcdir%/maildelivery~^Rather than the standard file +^%mailspool%/$USER~^The default maildrop +.fi + +.SH "SEE ALSO" +rcvdist(1), rcvpack(1), rcvstore(1), mh\-format(5) + +.SH DEFAULTS +.nf +.RB ` \-noverbose ' +.RB ` \-maildelivery "' defaults to $HOME/\&.maildelivery" +.RB ` \-mailbox "' deaults to %mailspool%/$USER" +.RB ` \-file "' defaults to stdin" +.RB ` \-user "' defaults to the current user" +.fi + +.SH CONTEXT +.B slocal +does neither read nor change the context. +Nor does it read the user profile. + +.SH HISTORY +.B Slocal +was originally designed to be backward-compatible with +the +.B maildelivery +facility provided by +.BR MMDF-II . +Thus, the +.RI ` \&.maildelivery ' +file syntax is somewhat limited. But +.B slocal +has been modified and extended, so that is it no longer compatible with +.BR MMDF-II . +.PP +In addition to an exit status of zero, the +.B MMDF +values +.B RP_MOK +(32) and +.B RP_OK +(9) mean that the message has been fully delivered. +Any other non-zero exit status, including abnormal termination, is +interpreted as the +.B MMDF +value +.B RP_MECH +(200), which means +`use an alternate route' (deliver the message to the maildrop). +.PP +The `suppress duplicates' function had been removed from slocal for +simplicity reasons. + +.SH BUGS +Only two return codes are meaningful, others should be. +.PP +.B Slocal +was originally designed to be backwards-compatible with the +.B maildelivery +functionality provided by +.BR MMDF-II . diff --git a/man/sortm.man b/man/sortm.man deleted file mode 100644 index 283cf12..0000000 --- a/man/sortm.man +++ /dev/null @@ -1,154 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH SORTM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -sortm \- sort messages -.SH SYNOPSIS -.HP 5 -.na -.B sortm -.RI [ +folder ] -.RI [ msgs ] -.RB [ \-datefield -.IR field ] -.RB [ \-textfield -.IR field ] -.RB [ \-notextfield ] -.RB [ \-limit -.IR days ] -.RB [ \-nolimit ] -.RB [ \-verbose " | " \-noverbose ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Sortm -sorts the specified messages in the named folder according -to the chronological order of the \*(lqDate:\*(rq field of each message. -.PP -The -.B \-verbose -switch directs -.B sortm -to tell the user the general -actions that it is taking to place the folder in sorted order. -.PP -The -.B \-datefield -.I field -switch tells -.B sortm -the name of the field to -use when making the date comparison. If the user has a special field in -each message, such as \*(lqBB\-Posted:\*(rq or \*(lqDelivery\-Date:\*(rq, -then the -.B \-datefield -switch can be used to direct -.B sortm -which field to examine. -.PP -The -.B \-textfield -.I field -switch causes -.B sortm -to sort messages -by the specified text field. If this field is \*(lqsubject\*(rq, any -leading "re:" is stripped off. In any case, all characters except -letters and numbers are stripped and the resulting strings are sorted -datefield\-major, textfield\-minor, using a case insensitive comparison. -.PP -With -.B \-textfield -.IR field , -if -.B \-limit -.I days -is specified, messages -with similar textfields that are dated within `days' of each other -appear together. Specifying -.B \-nolimit -makes the limit infinity. -With -.B \-limit -.IR 0 , -the sort is instead made textfield\-major, date\-minor. -.PP -For example, to order a folder by date-major, subject-minor, use: -.PP -.RS 5 -sortm -textfield subject +folder -.RE - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi - -.SH "SEE ALSO" -folder(1) - -.SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs"' defaults to all" -.RB ` \-datefield "' defaults to date" -.RB ` \-notextfield ' -.RB ` \-noverbose ' -.RB ` \-nolimit ' -.fi - -.SH CONTEXT -If a folder is given, it will become the current folder. If the current -message is moved, -.B sortm - will preserve its status as current. - -.SH HISTORY -Timezones used to be ignored when comparing dates: they aren't any more. -.PP -Messages which were in the folder, but not specified by `msgs', used to -be moved to the end of the folder; now such messages are left untouched. -.PP -.B Sortm -sometimes did not preserve the message numbering in a folder -(e.g., messages 1, 3, and 5, might have been renumbered to 1, 2, 3 after -sorting). This was a bug, and has been fixed. To compress the message -numbering in a folder, use -.RB \*(lq "folder\ \-pack" \*(rq -as always. - -.SH BUGS -If -.B sortm -encounters a message without a date\-field, or if the -message has a date\-field that -.B sortm -cannot parse, then -.B sortm -attempts to keep the message in the same relative position. This does -not always work. For instance, if the first message encountered lacks -a date which can be parsed, then it will usually be placed at the end -of the messages being sorted. -.PP -When -.B sortm -complains about a message which it can't temporally -order, it complains about the message number -.B prior -to sorting. -It should indicate what the message number will be -.B after -sorting. diff --git a/man/sortm.man1 b/man/sortm.man1 new file mode 100644 index 0000000..72ee22d --- /dev/null +++ b/man/sortm.man1 @@ -0,0 +1,154 @@ +.\" +.\" %nmhwarning% +.\" +.TH SORTM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +sortm \- sort messages +.SH SYNOPSIS +.HP 5 +.na +.B sortm +.RI [ +folder ] +.RI [ msgs ] +.RB [ \-datefield +.IR field ] +.RB [ \-textfield +.IR field ] +.RB [ \-notextfield ] +.RB [ \-limit +.IR days ] +.RB [ \-nolimit ] +.RB [ \-verbose " | " \-noverbose ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Sortm +sorts the specified messages in the named folder according +to the chronological order of the `Date:' field of each message. +.PP +The +.B \-verbose +switch directs +.B sortm +to tell the user the general +actions that it is taking to place the folder in sorted order. +.PP +The +.B \-datefield +.I field +switch tells +.B sortm +the name of the field to +use when making the date comparison. If the user has a special field in +each message, such as `BB\-Posted:' or `Delivery\-Date:', +then the +.B \-datefield +switch can be used to direct +.B sortm +which field to examine. +.PP +The +.B \-textfield +.I field +switch causes +.B sortm +to sort messages +by the specified text field. If this field is `subject', any +leading "re:" is stripped off. In any case, all characters except +letters and numbers are stripped and the resulting strings are sorted +datefield\-major, textfield\-minor, using a case insensitive comparison. +.PP +With +.B \-textfield +.IR field , +if +.B \-limit +.I days +is specified, messages +with similar textfields that are dated within `days' of each other +appear together. Specifying +.B \-nolimit +makes the limit infinity. +With +.B \-limit +.IR 0 , +the sort is instead made textfield\-major, date\-minor. +.PP +For example, to order a folder by date-major, subject-minor, use: +.PP +.RS 5 +sortm -textfield subject +folder +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Current\-Folder:~^To find the default current folder +.fi + +.SH "SEE ALSO" +folder(1) + +.SH DEFAULTS +.nf +.RB ` +folder "' defaults to the current folder" +.RB ` msgs"' defaults to all" +.RB ` \-datefield "' defaults to date" +.RB ` \-notextfield ' +.RB ` \-noverbose ' +.RB ` \-nolimit ' +.fi + +.SH CONTEXT +If a folder is given, it will become the current folder. If the current +message is moved, +.B sortm + will preserve its status as current. + +.SH HISTORY +Timezones used to be ignored when comparing dates: they aren't any more. +.PP +Messages which were in the folder, but not specified by `msgs', used to +be moved to the end of the folder; now such messages are left untouched. +.PP +.B Sortm +sometimes did not preserve the message numbering in a folder +(e.g., messages 1, 3, and 5, might have been renumbered to 1, 2, 3 after +sorting). This was a bug, and has been fixed. To compress the message +numbering in a folder, use +.RB ` "folder\ \-pack" ' +as always. + +.SH BUGS +If +.B sortm +encounters a message without a date\-field, or if the +message has a date\-field that +.B sortm +cannot parse, then +.B sortm +attempts to keep the message in the same relative position. This does +not always work. For instance, if the first message encountered lacks +a date which can be parsed, then it will usually be placed at the end +of the messages being sorted. +.PP +When +.B sortm +complains about a message which it can't temporally +order, it complains about the message number +.B prior +to sorting. +It should indicate what the message number will be +.B after +sorting. diff --git a/man/spost.man8 b/man/spost.man8 new file mode 100644 index 0000000..c66ba10 --- /dev/null +++ b/man/spost.man8 @@ -0,0 +1,125 @@ +.\" +.\" %nmhwarning% +.\" +.TH SPOST %manext8% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +spost \- feed a message to sendmail +.SH SYNOPSIS +.HP 5 +.na +.HP 5 +.B spost +.RB [ \-verbose " | " \-noverbose ] +.I file +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Spost +is the program called by +.B send +to feed the message in +.I file +to +.B sendmail +for delivery. In fact, many of +the features attributed to +.B send +in its manual page are performed by +.BR spost , +with +.B send +acting as a preprocessor. +Thus, it is +.B spost +which parses the various header fields, appends +`From:' and `Date:' lines, +and finally feeds the message to the MTA. +.B Spost +will not normally be called directly by the user. +.PP +.B Spost +searches the `To:', `Cc:', `Bcc:', +`Fcc:', and `Resent\-xxx:' header lines of the specified +message for destination addresses, +.PP +If a `Bcc:' field is encountered, its addresses will be used for +delivery, and the `Bcc:' field will be removed from the message +sent to sighted recipients. The blind recipients will receive a newly +constructed message with a copy of the original message attached. +MIME rules are used for encapsulation. +.RB ( spost +invokes +.B send +to send the Bcc message.) +.PP +The `Aliasfile' profile entry +can be used to specify one or more files that spost +should take aliases from. +.PP +The +.B \-verbose +switch enables informational messages. +For example, the `\-v' switch will be added to the +.B sendmail +invocation. +.PP +.B Spost +constructs the `From:' line of the +message from the user's login name and the full name from the GECOS field +of the passwd file. +An example is `From: Dan Harkless '. +.PP +If you set the +.B $SIGNATURE +environment variable. +Its value overrides the full name from the GECOS field. +.PP +If you specify a `From:' +line manually in the message draft. +It will be used as provided. +However, a `Sender:' header with the user's +.B real +address will be added. +.PP +Note that this applies equally to `Resent\-From:' lines +in messages sent with +.BR dist . +.PP +Your MTA is supposed to care to fully qualitfy the addresses +with the correct domain name. +.PP +The draft is filed to the folders in the Fcc headers by +.BR refile . + +.SH FILES +.fc ^ ~ +.nf +.ta \w'ExtraBigFileName 'u +None +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta \w'ExtraBigFileName 'u +^Aliasfile:~^For default alias files +.fi + +.SH "SEE ALSO" +send(1), mh\-mail(5), mh\-alias(5), mh\-tailor(5), refile(1), +.I "Standard for the Format of ARPA Internet Text Messages" +(RFC\-822) + +.SH DEFAULTS +.nf +.RB ` \-noverbose ' +.fi + +.SH CONTEXT +None + +.SH BUGS +Spost does not qualify addresses. +.PP +Spost does only basic processing and checking, yet. diff --git a/man/unseen.man b/man/unseen.man deleted file mode 100644 index 7529017..0000000 --- a/man/unseen.man +++ /dev/null @@ -1 +0,0 @@ -.so man1/new.1 diff --git a/man/unseen.man1 b/man/unseen.man1 new file mode 100644 index 0000000..7529017 --- /dev/null +++ b/man/unseen.man1 @@ -0,0 +1 @@ +.so man1/new.1 diff --git a/man/vmh.man b/man/vmh.man deleted file mode 100644 index 9fe9220..0000000 --- a/man/vmh.man +++ /dev/null @@ -1,101 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH VMH %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -vmh \- visual front-end to nmh -.SH SYNOPSIS -.in +.5i -.ti -.5i -vmh -\%[\-prompt\ string] -\%[\-vmhproc\ program] \%[\-novmhproc] -.br -\%[switches\ for\ \fIvmhproc\fR] -\%[\-version] -\%[\-help] -.in -.5i -.SH DESCRIPTION -\fIvmh\fR is a program which implements the server side of the \fInmh\fR -window management protocol and uses \fIcurses\fR\0(3) routines to maintain -a split\-screen interface to any program which implements the client -side of the protocol. This latter program, called the \fIvmhproc\fR, -is specified using the `\-vmhproc\ program' switch. - -The upshot of all this is that one can run \fImsh\fR on a display terminal -and get a nice visual interface. To do this, for example, just add -the line - -.ti +.5i -mshproc: vmh - -to your \&.mh\(ruprofile. (This takes advantage of the fact that -\fImsh\fR is the default \fIvmhproc\fR for \fIvmh\fR.) - -In order to facilitate things, if the `\-novmhproc' switch is given, -and \fIvmh\fR can't run on the user's terminal, the \fIvmhproc\fR is -run directly without the window management protocol. - -After initializing the protocol, \fIvmh\fR prompts the user for a command -to be given to the client. Usually, this results in output being sent to -one or more windows. If a output to a window would cause it to scroll, -\fIvmh\fR prompts the user for instructions, roughly permitting the -capabilities of \fIless\fR or \fImore\fR (e.g., the ability to scroll -backwards and forwards): - -.nf -.in +.5i -.ta \w'RETURN 'u +\w'* 'u -SPACE advance to the next windowful -RETURN * advance to the next line -y * retreat to the previous line -d * advance to the next ten lines -u * retreat to the previous ten lines -g * go to an arbitrary line - (preceed g with the line number) -G * go to the end of the window - (if a line number is given, this acts like `g') -CTRL\-L refresh the entire screen -h print a help message -q abort the window -.re -.in -.5i -.fi - -(A `*' indicates that a numeric prefix is meaningful for this command.) - -Note that if a command resulted in more than one window's worth of -information being displayed, and you allow the command which is generating -information for the window to gracefully finish (i.e., you don't use -the `q' command to abort information being sent to the window), then -\fIvmh\fR will give you one last change to peruse the window. This is -useful for scrolling back and forth. Just type `q' when you're done. - -To abnormally terminate \fIvmh\fR (without core dump), use -(usually CTRL\-\\). For instance, this does the \*(lqright\*(rq thing -with \fIbbc\fR and \fImsh\fR. - -.Fi -^$HOME/\&.mh\(ruprofile~^The user profile -.Pr -^Path:~^To determine the user's nmh directory -.Sa -msh(1) -.De -`\-prompt\ (vmh)\ ' -.Ds -`\-vmhproc\ msh' -.Co -None -.Bu -The argument to the `\-prompt' switch must be interpreted as a single -token by the shell that invokes \fIvmh\fR. Therefore, one must usually -place the argument to this switch inside double\-quotes. - -At present, there is no way to pass signals (e.g., interrupt, quit) to -the client. However, generating QUIT when \fIvmh\fR is reading a command -from the terminal is sufficient to tell the client to go away quickly. - -Acts strangely (loses peer or botches window management protocol with -peer) on random occasions. -.En diff --git a/man/whatnow.man b/man/whatnow.man deleted file mode 100644 index 4fca2cd..0000000 --- a/man/whatnow.man +++ /dev/null @@ -1,299 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH WHATNOW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -whatnow \- prompting front-end for sending messages -.SH SYNOPSIS -.HP 5 -.na -.B whatnow -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RB [ \-editor -.IR editor ] -.RB [ \-noedit ] -.RB [ \-prompt -.IR string ] -.RI [ file ] -.RB [ \-version ] -.RB [ \-help ] -.RB [ \-attach -.IR header-field-name ] -.ad -.SH DESCRIPTION -.B Whatnow -is the default program that queries the user about -the disposition of a composed draft. It is normally automatically -invoked by one of the -.B nmh -commands -.BR comp , -.BR dist , -.BR forw , -or -.B repl -after the initial edit. -.PP -When started, the editor is started on the draft (unless -.B \-noedit -is given, in which case the initial edit is suppressed). Then, -.B whatnow -repetitively prompts the user with \*(lqWhat now?\*(rq -and awaits a response. The valid responses are: -.PP -.RS 5 -.TP \w'refilezzzzfolderz'u -.B edit -re\-edit using the same editor that was used on the -preceding round unless a profile entry -\*(lq\-next: \*(rq names an alternate editor -.TP \w'refilezzzzfolderz'u -.B edit -invoke for further editing -.TP \w'refilezzzzfolderz'u -.B refile +folder -refile the draft into the given folder -.TP \w'refilezzzzfolderz'u -.B mime -process the draft as MIME composition file using -the -.I buildmimeproc -command -.RB ( mhbuild -by default) -.TP \w'refilezzzzfolderz'u -.B display -list the message being distributed/replied\-to -on the terminal -.TP \w'refilezzzzfolderz'u -.B list -list the draft on the terminal -.TP \w'refilezzzzfolderz'u -.B send -send the message -.TP \w'refilezzzzfolderz'u -.B send \-watch -send the message and monitor the delivery process -.TP \w'refilezzzzfolderz'u -.B push -send the message in the background -.TP \w'refilezzzzfolderz'u -.B whom -list the addresses that the message will go to -.TP \w'refilezzzzfolderz'u -.B whom \-check -list the addresses and verify that they are -acceptable to the transport service -.TP \w'refilezzzzfolderz'u -.B quit -preserve the draft and exit -.TP \w'refilezzzzfolderz'u -.B quit \-delete -delete the draft and exit -.TP \w'refilezzzzfolderz'u -.B delete -delete the draft and exit -.TP \w'refilezzzzfolderz'u -.B cd directory -use the directory when interpreting attachment file names -.TP \w'refilezzzzfolderz'u -.B pwd -print the working directory for attachment files -.TP \w'refilezzzzfolderz'u -.B ls [ls-options] -list files in the attachment working directory using the ls command -.TP \w'refilezzzzfolderz'u -.B attach files -add the named files to the draft as MIME attachments -.TP \w'refilezzzzfolderz'u -.B alist [-ln] -list the MIME attachments, either short, long [-l] or numbered [-n] -.TP \w'refilezzzzfolderz'u -.B detach [-n] files-or-numbers -remove MIME attachments, either by file name or by number with -n -.RE -.PP -When entering your response, you need only type enough characters -to uniquely identify the response. -.PP -For the -.B edit -response, any valid switch to the editor is valid. -.PP -For the -.B send -and -.B push -responses, any valid switch to -.BR send (1) -is valid (as -.B push -merely invokes -.B send -with the -.B \-push -option). -.PP -For the -.B whom -response, any valid switch to -.BR whom (1) -is valid. -.PP -For the -.B refile -response, any valid switch to the -.I fileproc -is valid. -.PP -For the -.B display -and -.B list -responses, any valid argument to -the -.I lproc -is valid. If any non\-switch arguments are present, then -the pathname of the draft will be excluded from the argument list given -to the -.I lproc -(this is useful for listing another -.B nmh -message). -.PP -See -.BR mh\-profile (5) -for further information about how editors -are used by -.BR nmh . -It also discusses how environment variables can be -used to direct -.BR whatnow 's -actions in complex ways. -.PP -The -.B \-prompt -.I string -switch sets the prompting string for -.BR whatnow . -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke -the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more -information. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^\-next:~^To name an editor to be used after exit -^~^from -^automimeproc:~^If value is 1, and the draft is a MIME -^~^composition file, then automatically call -^~^buildmimeproc prior to sending. -^buildmimeproc:~^Program to translate MIME composition files -^fileproc:~^Program to refile the message -^lproc:~^Program to list the contents of a message -^sendproc:~^Program to use to send the message -^whomproc:~^Program to determine who a message would go to -.fi - -.SH "SEE ALSO" -send(1), whom(1) - -.SH DEFAULTS -.nf -.RB ` \-prompt "' defaults to \*(lqWhat\ Now?\ \*(rq" -.fi - -.SH CONTEXT -None - -.SH BUGS -The argument to the -.B \-prompt -switch must be interpreted as a single -token by the shell that invokes -.BR whatnow . -Therefore, one must -usually place the argument to this switch inside double\-quotes. -.PP -If the initial edit fails, -.B whatnow -deletes your draft (by renaming -it with a leading comma); failure of a later edit preserves the draft. -.PP -If the -.I buildmimeproc -fails (returns a nonzero status), -.B whatnow -simply prints a \*(lqWhat now?\*(rq prompt. -.B whatnow -depends on the -.I buildmimeproc -to tell the user that something went wrong. -.PP -If -.I whatnowproc -is -.BR whatnow , -then -.BR comp , -.BR dist , -.BR forw , -and -.B repl -use a built\-in -.BR whatnow , -and do not actually run the -.B whatnow -program. Hence, if you define your own -.IR whatnowproc , -don't call it -.B whatnow -since it won't be run. -.PP -If -.I sendproc -is -.BR send , -then -.B whatnow -uses a built\-in -.BR send , -it does not actually run the -.B send -program. Hence, if -you define your own -.IR sendproc , -don't call it -.B send -since -.B whatnow -won't run it. diff --git a/man/whatnow.man1 b/man/whatnow.man1 new file mode 100644 index 0000000..e13fbfd --- /dev/null +++ b/man/whatnow.man1 @@ -0,0 +1,165 @@ +.\" +.\" %nmhwarning% +.\" +.TH WHATNOW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +whatnow \- prompting front-end for sending messages +.SH SYNOPSIS +.HP 5 +.na +.B whatnow +.RB [ \-editor +.IR editor ] +.RB [ \-prompt +.IR string ] +.RI [ file ] +.RB [ \-Version ] +.RB [ \-help ] +.ad +.SH DESCRIPTION +.B Whatnow +is the default program that queries the user about +the disposition of a composed draft. It is normally automatically +invoked by one of the +.B nmh +commands +.BR comp , +.BR dist , +.BR forw , +or +.B repl +after the initial edit. +.PP +When started, the editor is started on the draft (unless the +.B \-editor +switch with an empty string argument is given, +in which case the initial edit is suppressed). Then, +.B whatnow +repetitively prompts the user with `What now?' +and awaits a response. The valid responses are: +.PP +.RS 5 +.TP \w'refilezzzzfolderz'u +.B edit +re\-edit using the same editor that was used on the +preceding round unless a profile entry +`\-next: ' names an alternate editor +.TP \w'refilezzzzfolderz'u +.B edit +invoke for further editing +.TP \w'refilezzzzfolderz'u +.B list +list the draft on the terminal +.TP \w'refilezzzzfolderz'u +.B display +list the message being distributed/replied\-to on the terminal +.TP \w'refilezzzzfolderz'u +.B whom +list the recipients of the message +.TP \w'refilezzzzfolderz'u +.B send +send the message +.TP \w'refilezzzzfolderz'u +.B refile +folder +refile the draft into the given folder +.TP \w'refilezzzzfolderz'u +.B delete +delete the draft and exit +.TP \w'refilezzzzfolderz'u +.B quit +preserve the draft and exit +.TP \w'refilezzzzfolderz'u +.B cd directory +use the directory when interpreting attachment file names +.TP \w'refilezzzzfolderz'u +.B pwd +print the working directory for attachment files +.TP \w'refilezzzzfolderz'u +.B ls [ls-options] +list files in the attachment working directory using the ls command +.TP \w'refilezzzzfolderz'u +.B attach files +add the named files to the draft as MIME attachments +.TP \w'refilezzzzfolderz'u +.B alist +list the MIME attachments +.TP \w'refilezzzzfolderz'u +.B detach numbers +remove MIME attachments by number +.RE +.PP +When entering your response, you need only type enough characters +to uniquely identify the response. +.PP +For the +.B edit +response, any valid switch to the editor is valid. +.PP +For the +.B send +response, any valid switch to +.BR send (1) +is valid. +.PP +For the +.B refile +response, any valid switch to +.B refile +is valid. +.PP +See +.BR mh\-profile (5) +for further information about how editors +are used by +.BR nmh . +It also discusses how environment variables can be +used to direct +.BR whatnow 's +actions in complex ways. +.PP +If the initial edit fails, no new draft is created, but any +existing re-used draft is preserved. +Failures of later edits are ignored and another prompt is printed. +.PP +The +.B \-prompt +.I string +switch sets the prompting string for +.BR whatnow . +.PP +Consult the +.BR mh-draft (7) +man page for more +information. + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +^+drafts~^The draft folder +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Draft\-Folder:~^To set the default draft\-folder +^Editor:~^To override the default editor +^\-next:~^To name an editor to be used after exit +^~^from +^listproc:~^Program to list the contents of a message +.fi + +.SH "SEE ALSO" +send(1) + +.SH DEFAULTS +.nf +.RB ` \-prompt "' defaults to `What\ Now?\ '" +.fi + +.SH CONTEXT +None diff --git a/man/whom.man b/man/whom.man deleted file mode 100644 index c054dcf..0000000 --- a/man/whom.man +++ /dev/null @@ -1,102 +0,0 @@ -.\" -.\" %nmhwarning% -.\" -.TH WHOM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] -.SH NAME -whom \- report to whom a message would go -.SH SYNOPSIS -.HP 5 -.na -.B whom -.RB [ \-alias -.IR aliasfile ] -.RB [ \-check " | " \-nocheck ] -.RB [ \-draft ] -.RB [ \-draftfolder -.IR +folder ] -.RB [ \-draftmessage -.IR msg ] -.RB [ \-nodraftfolder ] -.RI [ file ] -.RB [ \-version ] -.RB [ \-help ] -.ad -.SH DESCRIPTION -.B Whom -is used to expand the headers of a message into a set of -addresses and optionally verify that those addresses are deliverable at -that time (if -.B \-check -is given). -.PP -The -.B \-draftfolder -.I +folder -and -.B \-draftmessage -.I msg -switches invoke -the -.B nmh -draft folder facility. This is an advanced (and highly -useful) feature. Consult the -.BR mh-draft (5) -man page for more information. -.PP -The files specified by the profile entry \*(lqAliasfile:\*(rq and any -additional alias files given by the -.B \-alias -.I aliasfile -switch will be -read (more than one file, each preceded by -.BR \-alias , -can be named). See -.BR mh\-alias (5) -for more information. - -.SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi - -.SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Draft\-Folder:~^To find the default draft\-folder -^Aliasfile:~^For a default alias file -^postproc:~^Program to post the message -.fi - -.SH "SEE ALSO" -mh\-alias(5), post(8) - -.SH DEFAULTS -.nf -.RB ` file "' defaults to /draft" -.RB ` \-nocheck ' -.RB ` \-alias "' defaults to %etcdir%/MailAliases" -.fi - -.SH CONTEXT -None - -.SH BUGS -With the -.B \-check -option, -.B whom -makes no guarantees that the -addresses listed as being ok are really deliverable, rather, an address -being listed as ok means that at the time that -.B whom -was run -the address was thought to be deliverable by the transport service. -For local addresses, this is absolute; for network addresses, it means -that the host is known; for uucp addresses, it (often) means that the -.B UUCP -network is available for use. diff --git a/man/whom.man1 b/man/whom.man1 new file mode 100644 index 0000000..b40787b --- /dev/null +++ b/man/whom.man1 @@ -0,0 +1,87 @@ +.\" +.\" %nmhwarning% +.\" +.TH WHOM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%] +.SH NAME +whom \- report to whom a message would go +.SH SYNOPSIS +.HP 5 +.na +.B whom +.RB [ \-tocc " | " \-notocc ] +.RB [ \-bcc " | " \-nobcc ] +.RB [ \-alias " | " \-noalias ] +.RB [ \-Version ] +.RB [ \-help ] +.IR file ... +.ad +.SH DESCRIPTION +.B Whom +is used to list the recipient addresses in the headers of a message. +.PP +Per default, +.B whom +lists both, sighted and hidden, recipients. +The +.BR \-notocc +option suppresses the listing of sighted recipients. +The +.BR \-nobcc +option suppresses the listing of hidden recipients. +If the printing of both kinds of recipients, visible and hidden, +is requested and hidden recipients are present, +they are separated by a line similar to ``\0==BCC==''. +The actual separator may change, but the regular expression +/^[\0\\t].*BCC/ should always match. +No separator is printed if only one kind of recipients is requested +for printing, or if both are requested but no hidden recipients are +present. +.PP +With +.BR \-alias , +aliases for all recipients are expanded, according to the +alias files given by the `Aliasfile:' profile entry. +This is somehow similar to running: + +.RS 5 +.nf +ali `whom /path/to/msg` +.fi +.RE + +.SH FILES +.fc ^ ~ +.nf +.ta \w'%etcdir%/ExtraBigFileName 'u +^$HOME/.mmh/profile~^The user profile +.fi + +.SH "PROFILE COMPONENTS" +.fc ^ ~ +.nf +.ta 2.4i +.ta \w'ExtraBigProfileName 'u +^Path:~^To determine the user's mail storage +^Aliasfile:~^For default alias files +.fi + +.SH "SEE ALSO" +mh\-alias(5), spost(8) + +.SH DEFAULTS +.nf +.RB ` \-tocc ' +.RB ` \-bcc ' +.RB ` \-alias ' +.fi + +.SH CONTEXT +None + +.SH BUGS +.B whom +does not (yet) accept +.I msg +and +.I +folder +arguments. diff --git a/mkinstalldirs b/mkinstalldirs deleted file mode 100755 index 0801ec2..0000000 --- a/mkinstalldirs +++ /dev/null @@ -1,32 +0,0 @@ -#! /bin/sh -# mkinstalldirs --- make directory hierarchy -# Author: Noah Friedman -# Created: 1993-05-16 -# Last modified: 1994-03-25 -# Public domain - -errstatus=0 - -for file in ${1+"$@"} ; do - set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` - shift - - pathcomp= - for d in ${1+"$@"} ; do - pathcomp="$pathcomp$d" - case "$pathcomp" in - -* ) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" 1>&2 - mkdir "$pathcomp" || errstatus=$? - fi - - pathcomp="$pathcomp/" - done -done - -exit $errstatus - -# mkinstalldirs ends here diff --git a/mts/Makefile.in b/mts/Makefile.in deleted file mode 100644 index dd2a18f..0000000 --- a/mts/Makefile.in +++ /dev/null @@ -1,111 +0,0 @@ -# -# Makefile for mts subdirectory -# - -SHELL = /bin/sh - -srcdir = @srcdir@ -VPATH = @srcdir@ - -# flags passed to recursive makes in subdirectories -MAKEDEFS = CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' DEFS='$(DEFS)' \ -CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \ -prefix='$(prefix)' exec_prefix='$(exec_prefix)' bindir='$(bindir)' \ -etcdir='$(etcdir)' libdir='$(libdir)' mandir='$(mandir)' \ -mailspool='$(mailspool)' sendmailpath='$(sendmailpath)' \ -default_editor='$(default_editor)' default_pager='$(default_pager)' - -LORDER = @LORDER@ -TSORT = @TSORT@ -RANLIB = @RANLIB@ -LIBTOOL = @LIBTOOL@ -GNU_LIBTOOL = @GNU_LIBTOOL@ - -# object files that go into libmts.a -OBJS = smtp/hosts.o smtp/smtp.o - -# auxiliary files -AUX = Makefile.in - -# all files in this directory included in the distribution -DIST = $(AUX) - -# subdirectories -SUBDIRS = smtp - -# mail transport agent we are using (currently always smtp) -# MTS = smtp -# DEPRECATED: smtp/sendmail functionality handled by mts.conf - -# ========= DEPENDENCIES FOR BUILDING AND INSTALLING ========== - -all: all-recursive libmts.a - -all-recursive: - for subdir in $(SUBDIRS); do \ - (cd $$subdir && $(MAKE) $(MAKEDEFS) all) || exit 1; \ - done - -libmts.a: $(OBJS) - rm -f $@ - if test x$(LIBTOOL) != x -a x$(GNU_LIBTOOL) = x ; then \ - $(LIBTOOL) -static -c $(OBJS) -o $@ ; \ - else \ - ar cr $@ `$(LORDER) $(OBJS) | $(TSORT) 2>/dev/null` ; \ - $(RANLIB) $@ ; \ - fi - -install uninstall: - -# ========== DEPENDENCIES FOR CLEANUP ========== - -mostlyclean: mostlyclean-recursive mostlyclean-local -clean: clean-recursive clean-local -distclean: distclean-recursive distclean-local -realclean: realclean-recursive realclean-local -superclean: superclean-recursive superclean-local - -mostlyclean-local: - rm -f *~ - -clean-local: mostlyclean-local - rm -f libmts.a -distclean-local: clean-local - rm -f Makefile - -realclean-local: distclean-local - -superclean-local: realclean-local - -mostlyclean-recursive clean-recursive distclean-recursive realclean-recursive superclean-recursive: - for subdir in $(SUBDIRS); do \ - target=`echo $@ | sed 's/-recursive//'`; \ - (cd $$subdir && $(MAKE) $(MAKEDEFS) $$target) || exit 1; \ - done - -# ========== DEPENDENCIES FOR LINT ================= - -lint: - for subdir in $(SUBDIRS); do \ - ( cd $$subdir && $(MAKE) $(MAKEDEFS) lint ) || exit 1; \ - done - -# ========== DEPENDENCIES FOR MAINTENANCE ========== - -subdir = mts - -Makefile: Makefile.in ../config.status - cd .. && ./config.status $(subdir)/$@ - -distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) - @echo "Copying distribution files in $(subdir)" - @for file in $(DIST); do \ - cp -p $(srcdir)/$$file $(distdir); \ - done - @for subdir in $(SUBDIRS); do \ - mkdir $(distdir)/$$subdir; \ - chmod 755 $(distdir)/$$subdir; \ - (cd $$subdir && $(MAKE) $@) || exit 1; \ - done - diff --git a/mts/smtp/Makefile.in b/mts/smtp/Makefile.in deleted file mode 100644 index b2a4059..0000000 --- a/mts/smtp/Makefile.in +++ /dev/null @@ -1,87 +0,0 @@ -# -# Makefile for mts/smtp subdirectory -# - -SHELL = /bin/sh - -top_srcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -etcdir = @sysconfdir@ - -CC = @CC@ -CFLAGS = @CFLAGS@ -DEFS = @DEFS@ -INCLUDES = -I../.. -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@ -LINT = @LINT@ -LINTFLAGS = @LINTFLAGS@ - -COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) - -.SUFFIXES: -.SUFFIXES: .c .o - -.c.o: - $(COMPILE) $< - -# header files -HDRS = smtp.h - -# source -SRCS = hosts.c smtp.c - -# object files in libsmtp.a -OBJS = hosts.o smtp.o - -# auxiliary files -AUX = Makefile.in - -# all files in this directory included in the distribution -DIST = $(HDRS) $(SRCS) $(AUX) - -# ========= DEPENDENCIES FOR BUILDING AND INSTALLING ========== - -all: $(OBJS) - -install: - -uninstall: - -# ========== DEPENDENCIES FOR CLEANUP ========== - -mostlyclean: - rm -f *.o *~ - -clean: mostlyclean - -distclean: clean - rm -f Makefile - -realclean: distclean - -superclean: realclean - -# ========== DEPENDENCIES FOR LINT ================= - -lint: - $(LINT) $(LINTFLAGS) $(INCLUDES) $(DEFS) $(SRCS) - -# ========== DEPENDENCIES FOR MAINTENANCE ========== - -subdir = mts/smtp - -Makefile: Makefile.in ../../config.status - cd ../.. && ./config.status $(subdir)/$@ - -distdir = ../../`cat ../../distname`/$(subdir) -nmhdist: $(DIST) - @echo "Copying distribution files in $(subdir)" - @for file in $(DIST); do \ - cp -p $(srcdir)/$$file $(distdir); \ - done - diff --git a/mts/smtp/hosts.c b/mts/smtp/hosts.c deleted file mode 100644 index a10509c..0000000 --- a/mts/smtp/hosts.c +++ /dev/null @@ -1,143 +0,0 @@ - -/* - * hosts.c -- find out the official name of a host - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* - * In the SendMail world, we really don't know what the valid - * hosts are. We could poke around in the sendmail.cf file, but - * that still isn't a guarantee. As a result, we'll say that - * everything is a valid host, and let SendMail worry about it. - */ - -#include -#include -#include - -static struct host { - char *h_name; - char **h_aliases; - struct host *h_next; -} hosts; - - -/* - * static prototypes - */ -static int init_hs(void); - - -char * -OfficialName (char *name) -{ - unsigned char *p; - char *q, site[BUFSIZ]; - struct addrinfo hints, *res; - - static char buffer[BUFSIZ]; - char **r; - struct host *h; - - for (p = name, q = site; *p && (q - site < sizeof(site) - 1); p++, q++) - *q = isupper (*p) ? tolower (*p) : *p; - *q = '\0'; - q = site; - - if (!mh_strcasecmp (LocalName(), site)) - return LocalName(); - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_family = PF_UNSPEC; - - if (getaddrinfo(q, NULL, &hints, &res) == 0) { - strncpy (buffer, res->ai_canonname, sizeof(buffer)); - buffer[sizeof(buffer) - 1] = '\0'; - freeaddrinfo(res); - return buffer; - } - if (hosts.h_name || init_hs ()) { - for (h = hosts.h_next; h; h = h->h_next) - if (!mh_strcasecmp (h->h_name, q)) { - return h->h_name; - } else { - for (r = h->h_aliases; *r; r++) - if (!mh_strcasecmp (*r, q)) - return h->h_name; - } - } - - strncpy (buffer, site, sizeof(buffer)); - return buffer; -} - -/* - * Use hostable as an exception file for those hosts that aren't - * on the Internet (listed in /etc/hosts). These are usually - * PhoneNet and UUCP sites. - */ - -#define NALIASES 50 - -static int -init_hs (void) -{ - unsigned char *cp; - char *dp, **q, **r; - char buffer[BUFSIZ], *aliases[NALIASES]; - register struct host *h; - register FILE *fp; - - if ((fp = fopen (hostable, "r")) == NULL) - return 0; - - h = &hosts; - while (fgets (buffer, sizeof(buffer), fp) != NULL) { - if ((cp = strchr(buffer, '#'))) - *cp = 0; - if ((cp = strchr(buffer, '\n'))) - *cp = 0; - for (cp = buffer; *cp; cp++) - if (isspace (*cp)) - *cp = ' '; - for (cp = buffer; isspace (*cp); cp++) - continue; - if (*cp == 0) - continue; - - q = aliases; - if ((cp = strchr(dp = cp, ' '))) { - *cp = 0; - for (cp++; *cp; cp++) { - while (isspace (*cp)) - cp++; - if (*cp == 0) - break; - if ((cp = strchr(*q++ = cp, ' '))) - *cp = 0; - else - break; - if (q >= aliases + NALIASES) - break; - } - } - - *q = 0; - - h->h_next = (struct host *) calloc (1, sizeof(*h)); - h = h->h_next; - h->h_name = getcpy (dp); - r = h->h_aliases = - (char **) calloc ((size_t) (q - aliases + 1), sizeof(*q)); - for (q = aliases; *q; q++) - *r++ = getcpy (*q); - *r = 0; - } - - fclose (fp); - return 1; -} diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c deleted file mode 100644 index e7a64a0..0000000 --- a/mts/smtp/smtp.c +++ /dev/null @@ -1,1713 +0,0 @@ -/* - * smtp.c -- nmh SMTP interface - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include "smtp.h" -#include -#include -#include - -#ifdef CYRUS_SASL -#include -#include -#include -#include -#include -#include -#include -#endif /* CYRUS_SASL */ - -#ifdef TLS_SUPPORT -#include -#include -#endif /* TLS_SUPPORT */ - -/* - * This module implements an interface to SendMail very similar - * to the MMDF mm_(3) routines. The sm_() routines herein talk - * SMTP to a sendmail process, mapping SMTP reply codes into - * RP_-style codes. - */ - -/* - * On older 4.2BSD machines without the POSIX function `sigaction', - * the alarm handing stuff for time-outs will NOT work due to the way - * syscalls get restarted. This is not really crucial, since SendMail - * is generally well-behaved in this area. - */ - -#ifdef SENDMAILBUG -/* - * It appears that some versions of Sendmail will return Code 451 - * when they don't really want to indicate a failure. - * "Code 451 almost always means sendmail has deferred; we don't - * really want bomb out at this point since sendmail will rectify - * things later." So, if you define SENDMAILBUG, Code 451 is - * considered the same as Code 250. Yuck! - */ -#endif - -#define TRUE 1 -#define FALSE 0 - -#define NBITS ((sizeof (int)) * 8) - -/* - * these codes must all be different! - */ -#define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */ -#define SM_HELO 20 -#define SM_RSET 15 -#define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */ -#define SM_RCPT 302 /* see above */ -#define SM_DATA 120 /* see above */ -#define SM_TEXT 180 /* see above */ -#define SM_DOT 600 /* see above */ -#define SM_QUIT 30 -#define SM_CLOS 10 -#define SM_AUTH 45 - -static int sm_addrs = 0; -static int sm_alarmed = 0; -static int sm_child = NOTOK; -static int sm_debug = 0; -static int sm_nl = TRUE; -static int sm_verbose = 0; - -static FILE *sm_rfp = NULL; -static FILE *sm_wfp = NULL; - -#ifdef CYRUS_SASL -/* - * Some globals needed by SASL - */ - -static sasl_conn_t *conn = NULL; /* SASL connection state */ -static int sasl_complete = 0; /* Has authentication succeded? */ -static sasl_ssf_t sasl_ssf; /* Our security strength factor */ -static char *sasl_pw_context[2]; /* Context to pass into sm_get_pass */ -static int maxoutbuf; /* Maximum crypto output buffer */ -static char *sasl_outbuffer; /* SASL output buffer for encryption */ -static int sasl_outbuflen; /* Current length of data in outbuf */ -static int sm_get_user(void *, int, const char **, unsigned *); -static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **); - -static sasl_callback_t callbacks[] = { - { SASL_CB_USER, sm_get_user, NULL }, -#define SM_SASL_N_CB_USER 0 - { SASL_CB_PASS, sm_get_pass, NULL }, -#define SM_SASL_N_CB_PASS 1 - { SASL_CB_AUTHNAME, sm_get_user, NULL }, -#define SM_SASL_N_CB_AUTHNAME 2 - { SASL_CB_LIST_END, NULL, NULL }, -}; - -#else /* CYRUS_SASL */ -int sasl_ssf = 0; -#endif /* CYRUS_SASL */ - -#ifdef TLS_SUPPORT -static SSL_CTX *sslctx = NULL; -static SSL *ssl = NULL; -static BIO *sbior = NULL; -static BIO *sbiow = NULL; -#endif /* TLS_SUPPORT */ - -#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) -#define SASL_MAXRECVBUF 65536 -static int sm_fgetc(FILE *); -static char *sasl_inbuffer; /* SASL input buffer for encryption */ -static char *sasl_inptr; /* Pointer to current inbuf position */ -static int sasl_inbuflen; /* Current length of data in inbuf */ -#else -#define sm_fgetc fgetc -#endif - -static int tls_active = 0; - -static char *sm_noreply = "No reply text given"; -static char *sm_moreply = "; "; - -struct smtp sm_reply; /* global... */ - -#define MAXEHLO 20 - -static int doingEHLO; -char *EHLOkeys[MAXEHLO + 1]; - -/* - * static prototypes - */ -static int smtp_init (char *, char *, char *, int, int, int, int, int, int, - char *, char *, int); -static int sendmail_init (char *, char *, int, int, int, int, int, int, - char *, char *); - -static int rclient (char *, char *); -static int sm_ierror (char *fmt, ...); -static int smtalk (int time, char *fmt, ...); -static int sm_wrecord (char *, int); -static int sm_wstream (char *, int); -static int sm_werror (void); -static int smhear (void); -static int sm_rrecord (char *, int *); -static int sm_rerror (int); -static RETSIGTYPE alrmser (int); -static char *EHLOset (char *); -static int sm_fwrite(char *, int); -static int sm_fputs(char *); -static int sm_fputc(int); -static void sm_fflush(void); -static int sm_fgets(char *, int, FILE *); - -#ifdef CYRUS_SASL -/* - * Function prototypes needed for SASL - */ - -static int sm_auth_sasl(char *, char *, char *); -#endif /* CYRUS_SASL */ - -int -sm_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int onex, int queued, int sasl, char *saslmech, - char *user, int tls) -{ - if (sm_mts == MTS_SMTP) - return smtp_init (client, server, port, watch, verbose, - debug, onex, queued, sasl, saslmech, user, tls); - else - return sendmail_init (client, server, watch, verbose, - debug, onex, queued, sasl, saslmech, user); -} - -static int -smtp_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int onex, int queued, - int sasl, char *saslmech, char *user, int tls) -{ -#ifdef CYRUS_SASL - char *server_mechs; -#endif /* CYRUS_SASL */ - int result, sd1, sd2; - - if (watch) - verbose = TRUE; - - sm_verbose = verbose; - sm_debug = debug; - - if (sm_rfp != NULL && sm_wfp != NULL) - goto send_options; - - if (client == NULL || *client == '\0') { - if (clientname) { - client = clientname; - } else { - client = LocalName(); /* no clientname -> LocalName */ - } - } - - /* - * Last-ditch check just in case client still isn't set to anything - */ - - if (client == NULL || *client == '\0') - client = "localhost"; - -#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) - sasl_inbuffer = malloc(SASL_MAXRECVBUF); - if (!sasl_inbuffer) - return sm_ierror("Unable to allocate %d bytes for read buffer", - SASL_MAXRECVBUF); -#endif /* CYRUS_SASL || TLS_SUPPORT */ - - if ((sd1 = rclient (server, port)) == NOTOK) - return RP_BHST; - - if ((sd2 = dup (sd1)) == NOTOK) { - close (sd1); - return sm_ierror ("unable to dup"); - } - - SIGNAL (SIGALRM, alrmser); - SIGNAL (SIGPIPE, SIG_IGN); - - if ((sm_rfp = fdopen (sd1, "r")) == NULL - || (sm_wfp = fdopen (sd2, "w")) == NULL) { - close (sd1); - close (sd2); - sm_rfp = sm_wfp = NULL; - return sm_ierror ("unable to fdopen"); - } - - tls_active = 0; - - sm_alarmed = 0; - alarm (SM_OPEN); - result = smhear (); - alarm (0); - - switch (result) { - case 220: - break; - - default: - sm_end (NOTOK); - return RP_RPLY; - } - - /* - * Give EHLO or HELO command - */ - - doingEHLO = 1; - result = smtalk (SM_HELO, "EHLO %s", client); - doingEHLO = 0; - - if (result >= 500 && result <= 599) - result = smtalk (SM_HELO, "HELO %s", client); - - if (result != 250) { - sm_end (NOTOK); - return RP_RPLY; - } - -#ifdef TLS_SUPPORT - /* - * If the user requested TLS support, then try to do the STARTTLS command - * as part of the initial dialog. Assuming this works, we then need to - * restart the EHLO dialog after TLS negotiation is complete. - */ - - if (tls) { - if (! EHLOset("STARTTLS")) { - sm_end(NOTOK); - return sm_ierror("SMTP server does not support TLS"); - } - - result = smtalk(SM_HELO, "STARTTLS"); - - if (result != 220) { - sm_end(NOTOK); - return RP_RPLY; - } - - /* - * Okay, the other side should be waiting for us to start TLS - * negotiation. Oblige them. - */ - - if (! sslctx) { - SSL_METHOD *method; - - SSL_library_init(); - SSL_load_error_strings(); - - method = TLSv1_client_method(); /* Not sure about this */ - - sslctx = SSL_CTX_new(method); - - if (! sslctx) { - sm_end(NOTOK); - return sm_ierror("Unable to initialize OpenSSL context: %s", - ERR_error_string(ERR_get_error(), NULL)); - } - } - - ssl = SSL_new(sslctx); - - if (! ssl) { - sm_end(NOTOK); - return sm_ierror("Unable to create SSL connection: %s", - ERR_error_string(ERR_get_error(), NULL)); - } - - sbior = BIO_new_socket(fileno(sm_rfp), BIO_NOCLOSE); - sbiow = BIO_new_socket(fileno(sm_wfp), BIO_NOCLOSE); - - if (sbior == NULL || sbiow == NULL) { - sm_end(NOTOK); - return sm_ierror("Unable to create BIO endpoints: %s", - ERR_error_string(ERR_get_error(), NULL)); - } - - SSL_set_bio(ssl, sbior, sbiow); - - if (SSL_connect(ssl) < 1) { - sm_end(NOTOK); - return sm_ierror("Unable to negotiate SSL connection: %s", - ERR_error_string(ERR_get_error(), NULL)); - } - - if (sm_debug) { - SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); - printf("SSL negotiation successful: %s(%d) %s\n", - SSL_CIPHER_get_name(cipher), - SSL_CIPHER_get_bits(cipher, NULL), - SSL_CIPHER_get_version(cipher)); - - } - - tls_active = 1; - - doingEHLO = 1; - result = smtalk (SM_HELO, "EHLO %s", client); - doingEHLO = 0; - - if (result != 250) { - sm_end (NOTOK); - return RP_RPLY; - } - } -#endif /* TLS_SUPPORT */ - -#ifdef CYRUS_SASL - /* - * If the user asked for SASL, then check to see if the SMTP server - * supports it. Otherwise, error out (because the SMTP server - * might have been spoofed; we don't want to just silently not - * do authentication - */ - - if (sasl) { - if (! (server_mechs = EHLOset("AUTH"))) { - sm_end(NOTOK); - return sm_ierror("SMTP server does not support SASL"); - } - - if (saslmech && stringdex(saslmech, server_mechs) == -1) { - sm_end(NOTOK); - return sm_ierror("Requested SASL mech \"%s\" is not in the " - "list of supported mechanisms:\n%s", - saslmech, server_mechs); - } - - if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs, - server) != RP_OK) { - sm_end(NOTOK); - return NOTOK; - } - } -#endif /* CYRUS_SASL */ - -send_options: ; - if (watch && EHLOset ("XVRB")) - smtalk (SM_HELO, "VERB on"); - if (onex && EHLOset ("XONE")) - smtalk (SM_HELO, "ONEX"); - if (queued && EHLOset ("XQUE")) - smtalk (SM_HELO, "QUED"); - - return RP_OK; -} - -int -sendmail_init (char *client, char *server, int watch, int verbose, - int debug, int onex, int queued, - int sasl, char *saslmech, char *user) -{ -#ifdef CYRUS_SASL - char *server_mechs; -#endif /* CYRUS_SASL */ - int i, result, vecp; - int pdi[2], pdo[2]; - char *vec[15]; - - if (watch) - verbose = TRUE; - - sm_verbose = verbose; - sm_debug = debug; - if (sm_rfp != NULL && sm_wfp != NULL) - return RP_OK; - - if (client == NULL || *client == '\0') { - if (clientname) - client = clientname; - else - client = LocalName(); /* no clientname -> LocalName */ - } - - /* - * Last-ditch check just in case client still isn't set to anything - */ - - if (client == NULL || *client == '\0') - client = "localhost"; - -#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) - sasl_inbuffer = malloc(SASL_MAXRECVBUF); - if (!sasl_inbuffer) - return sm_ierror("Unable to allocate %d bytes for read buffer", - SASL_MAXRECVBUF); -#endif /* CYRUS_SASL || TLS_SUPPORT */ - - if (pipe (pdi) == NOTOK) - return sm_ierror ("no pipes"); - if (pipe (pdo) == NOTOK) { - close (pdi[0]); - close (pdi[1]); - return sm_ierror ("no pipes"); - } - - for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++) - sleep (5); - - switch (sm_child) { - case NOTOK: - close (pdo[0]); - close (pdo[1]); - close (pdi[0]); - close (pdi[1]); - return sm_ierror ("unable to fork"); - - case OK: - if (pdo[0] != fileno (stdin)) - dup2 (pdo[0], fileno (stdin)); - if (pdi[1] != fileno (stdout)) - dup2 (pdi[1], fileno (stdout)); - if (pdi[1] != fileno (stderr)) - dup2 (pdi[1], fileno (stderr)); - for (i = fileno (stderr) + 1; i < NBITS; i++) - close (i); - - vecp = 0; - vec[vecp++] = r1bindex (sendmail, '/'); - vec[vecp++] = "-bs"; - vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb"; - vec[vecp++] = "-oem"; - vec[vecp++] = "-om"; -# ifndef RAND - if (verbose) - vec[vecp++] = "-ov"; -# endif /* not RAND */ - vec[vecp++] = NULL; - - setgid (getegid ()); - setuid (geteuid ()); - execvp (sendmail, vec); - fprintf (stderr, "unable to exec "); - perror (sendmail); - _exit (-1); /* NOTREACHED */ - - default: - SIGNAL (SIGALRM, alrmser); - SIGNAL (SIGPIPE, SIG_IGN); - - close (pdi[1]); - close (pdo[0]); - if ((sm_rfp = fdopen (pdi[0], "r")) == NULL - || (sm_wfp = fdopen (pdo[1], "w")) == NULL) { - close (pdi[0]); - close (pdo[1]); - sm_rfp = sm_wfp = NULL; - return sm_ierror ("unable to fdopen"); - } - sm_alarmed = 0; - alarm (SM_OPEN); - result = smhear (); - alarm (0); - switch (result) { - case 220: - break; - - default: - sm_end (NOTOK); - return RP_RPLY; - } - - doingEHLO = 1; - result = smtalk (SM_HELO, "EHLO %s", client); - doingEHLO = 0; - - if (500 <= result && result <= 599) - result = smtalk (SM_HELO, "HELO %s", client); - - switch (result) { - case 250: - break; - - default: - sm_end (NOTOK); - return RP_RPLY; - } - -#ifdef CYRUS_SASL - /* - * If the user asked for SASL, then check to see if the SMTP server - * supports it. Otherwise, error out (because the SMTP server - * might have been spoofed; we don't want to just silently not - * do authentication - */ - - if (sasl) { - if (! (server_mechs = EHLOset("AUTH"))) { - sm_end(NOTOK); - return sm_ierror("SMTP server does not support SASL"); - } - - if (saslmech && stringdex(saslmech, server_mechs) == -1) { - sm_end(NOTOK); - return sm_ierror("Requested SASL mech \"%s\" is not in the " - "list of supported mechanisms:\n%s", - saslmech, server_mechs); - } - - if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs, - server) != RP_OK) { - sm_end(NOTOK); - return NOTOK; - } - } -#endif /* CYRUS_SASL */ - - if (onex) - smtalk (SM_HELO, "ONEX"); - if (watch) - smtalk (SM_HELO, "VERB on"); - - return RP_OK; - } -} - -static int -rclient (char *server, char *service) -{ - int sd; - char response[BUFSIZ]; - - if ((sd = client (server, service, response, sizeof(response), - sm_debug)) != NOTOK) - return sd; - - sm_ierror ("%s", response); - return NOTOK; -} - -int -sm_winit (int mode, char *from) -{ - char *smtpcom = NULL; - - switch (mode) { - case S_MAIL: - smtpcom = "MAIL"; - break; - - case S_SEND: - smtpcom = "SEND"; - break; - - case S_SOML: - smtpcom = "SOML"; - break; - - case S_SAML: - smtpcom = "SAML"; - break; - - default: - /* Hopefully, we do not get here. */ - break; - } - - switch (smtalk (SM_MAIL, "%s FROM:<%s>", smtpcom, from)) { - case 250: - sm_addrs = 0; - return RP_OK; - - case 500: - case 501: - case 552: - return RP_PARM; - - default: - return RP_RPLY; - } -} - - -int -sm_wadr (char *mbox, char *host, char *path) -{ - switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>" - : "RCPT TO:<%s%s>", - path ? path : "", mbox, host)) { - case 250: - case 251: - sm_addrs++; - return RP_OK; - - case 451: -#ifdef SENDMAILBUG - sm_addrs++; - return RP_OK; -#endif /* SENDMAILBUG */ - case 421: - case 450: - case 452: - return RP_NO; - - case 500: - case 501: - return RP_PARM; - - case 550: - case 551: - case 552: - case 553: - return RP_USER; - - default: - return RP_RPLY; - } -} - - -int -sm_waend (void) -{ - switch (smtalk (SM_DATA, "DATA")) { - case 354: - sm_nl = TRUE; - return RP_OK; - - case 451: -#ifdef SENDMAILBUG - sm_nl = TRUE; - return RP_OK; -#endif /* SENDMAILBUG */ - case 421: - return RP_NO; - - case 500: - case 501: - case 503: - case 554: - return RP_NDEL; - - default: - return RP_RPLY; - } -} - - -int -sm_wtxt (char *buffer, int len) -{ - int result; - - sm_alarmed = 0; - alarm (SM_TEXT); - result = sm_wstream (buffer, len); - alarm (0); - - return (result == NOTOK ? RP_BHST : RP_OK); -} - - -int -sm_wtend (void) -{ - if (sm_wstream ((char *) NULL, 0) == NOTOK) - return RP_BHST; - - switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) { - case 250: - case 251: - return RP_OK; - - case 451: -#ifdef SENDMAILBUG - return RP_OK; -#endif /* SENDMAILBUG */ - case 452: - default: - return RP_NO; - - case 552: - case 554: - return RP_NDEL; - } -} - - -int -sm_end (int type) -{ - int status; - struct smtp sm_note; - - if (sm_mts == MTS_SENDMAIL) { - switch (sm_child) { - case NOTOK: - case OK: - return RP_OK; - - default: - break; - } - } - - if (sm_rfp == NULL && sm_wfp == NULL) - return RP_OK; - - switch (type) { - case OK: - smtalk (SM_QUIT, "QUIT"); - break; - - case NOTOK: - sm_note.code = sm_reply.code; - sm_note.length = sm_reply.length; - memcpy (sm_note.text, sm_reply.text, sm_reply.length + 1);/* fall */ - case DONE: - if (smtalk (SM_RSET, "RSET") == 250 && type == DONE) - return RP_OK; - if (sm_mts == MTS_SMTP) - smtalk (SM_QUIT, "QUIT"); - else { - kill (sm_child, SIGKILL); - discard (sm_rfp); - discard (sm_wfp); - } - if (type == NOTOK) { - sm_reply.code = sm_note.code; - sm_reply.length = sm_note.length; - memcpy (sm_reply.text, sm_note.text, sm_note.length + 1); - } - break; - } - -#ifdef TLS_SUPPORT - if (tls_active) { - SSL_shutdown(ssl); - SSL_free(ssl); - } -#endif /* TLS_SUPPORT */ - - if (sm_rfp != NULL) { - alarm (SM_CLOS); - fclose (sm_rfp); - alarm (0); - } - if (sm_wfp != NULL) { - alarm (SM_CLOS); - fclose (sm_wfp); - alarm (0); - } - - if (sm_mts == MTS_SMTP) { - status = 0; -#ifdef CYRUS_SASL - if (conn) { - sasl_dispose(&conn); - if (sasl_outbuffer) { - free(sasl_outbuffer); - } - } - if (sasl_inbuffer) - free(sasl_inbuffer); -#endif /* CYRUS_SASL */ - } else { - status = pidwait (sm_child, OK); - sm_child = NOTOK; - } - - sm_rfp = sm_wfp = NULL; - return (status ? RP_BHST : RP_OK); -} - -#ifdef CYRUS_SASL -/* - * This function implements SASL authentication for SMTP. If this function - * completes successfully, then authentication is successful and we've - * (optionally) negotiated a security layer. - */ -static int -sm_auth_sasl(char *user, char *mechlist, char *inhost) -{ - int result, status; - unsigned int buflen, outlen; - char *buf, outbuf[BUFSIZ], host[NI_MAXHOST]; - const char *chosen_mech; - sasl_security_properties_t secprops; - sasl_ssf_t *ssf; - int *outbufmax; - - /* - * Initialize the callback contexts - */ - - if (user == NULL) - user = getusername(); - - callbacks[SM_SASL_N_CB_USER].context = user; - callbacks[SM_SASL_N_CB_AUTHNAME].context = user; - - /* - * This is a _bit_ of a hack ... but if the hostname wasn't supplied - * to us on the command line, then call getpeername and do a - * reverse-address lookup on the IP address to get the name. - */ - - memset(host, 0, sizeof(host)); - - if (!inhost) { - struct sockaddr_storage sin; - socklen_t len = sizeof(sin); - int result; - - if (getpeername(fileno(sm_wfp), (struct sockaddr *) &sin, &len) < 0) { - sm_ierror("getpeername on SMTP socket failed: %s", - strerror(errno)); - return NOTOK; - } - - result = getnameinfo((struct sockaddr *) &sin, len, host, sizeof(host), - NULL, 0, NI_NAMEREQD); - if (result != 0) { - sm_ierror("Unable to look up name of connected host: %s", - gai_strerror(result)); - return NOTOK; - } - } else { - strncpy(host, inhost, sizeof(host) - 1); - } - - sasl_pw_context[0] = host; - sasl_pw_context[1] = user; - - callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context; - - result = sasl_client_init(callbacks); - - if (result != SASL_OK) { - sm_ierror("SASL library initialization failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn); - - if (result != SASL_OK) { - sm_ierror("SASL client initialization failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - /* - * Initialize the security properties. But if TLS is active, then - * don't negotiate encryption here. - */ - - memset(&secprops, 0, sizeof(secprops)); - secprops.maxbufsize = SASL_MAXRECVBUF; - secprops.max_ssf = tls_active ? 0 : UINT_MAX; - - result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); - - if (result != SASL_OK) { - sm_ierror("SASL security property initialization failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - /* - * Start the actual protocol. Feed the mech list into the library - * and get out a possible initial challenge - */ - - result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf, - &buflen, (const char **) &chosen_mech); - - if (result != SASL_OK && result != SASL_CONTINUE) { - sm_ierror("SASL client start failed: %s", sasl_errdetail(conn)); - return NOTOK; - } - - /* - * If we got an initial challenge, send it as part of the AUTH - * command; otherwise, just send a plain AUTH command. - */ - - if (buflen) { - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - if (status != SASL_OK) { - sm_ierror("SASL base64 encode failed: %s", - sasl_errstring(status, NULL, NULL)); - return NOTOK; - } - - status = smtalk(SM_AUTH, "AUTH %s %s", chosen_mech, outbuf); - } else - status = smtalk(SM_AUTH, "AUTH %s", chosen_mech); - - /* - * Now we loop until we either fail, get a SASL_OK, or a 235 - * response code. Receive the challenges and process them until - * we're all done. - */ - - while (result == SASL_CONTINUE) { - - /* - * If we get a 235 response, that means authentication has - * succeeded and we need to break out of the loop (yes, even if - * we still get SASL_CONTINUE from sasl_client_step()). - * - * Otherwise, if we get a message that doesn't seem to be a - * valid response, then abort - */ - - if (status == 235) - break; - else if (status < 300 || status > 399) - return RP_BHST; - - /* - * Special case; a zero-length response from the SMTP server - * is returned as a single =. If we get that, then set buflen - * to be zero. Otherwise, just decode the response. - */ - - if (strcmp("=", sm_reply.text) == 0) { - outlen = 0; - } else { - result = sasl_decode64(sm_reply.text, sm_reply.length, - outbuf, sizeof(outbuf), &outlen); - - if (result != SASL_OK) { - smtalk(SM_AUTH, "*"); - sm_ierror("SASL base64 decode failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - } - - result = sasl_client_step(conn, outbuf, outlen, NULL, - (const char **) &buf, &buflen); - - if (result != SASL_OK && result != SASL_CONTINUE) { - smtalk(SM_AUTH, "*"); - sm_ierror("SASL client negotiation failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - - if (status != SASL_OK) { - smtalk(SM_AUTH, "*"); - sm_ierror("SASL base64 encode failed: %s", - sasl_errstring(status, NULL, NULL)); - return NOTOK; - } - - status = smtalk(SM_AUTH, outbuf); - } - - /* - * Make sure that we got the correct response - */ - - if (status < 200 || status > 299) - return RP_BHST; - - /* - * We _should_ have completed the authentication successfully. - * Get a few properties from the authentication exchange. - */ - - result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax); - - if (result != SASL_OK) { - sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - maxoutbuf = *outbufmax; - - result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf); - - sasl_ssf = *ssf; - - if (result != SASL_OK) { - sm_ierror("Cannot retrieve SASL negotiated security strength " - "factor: %s", sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - if (sasl_ssf > 0) { - sasl_outbuffer = malloc(maxoutbuf); - - if (sasl_outbuffer == NULL) { - sm_ierror("Unable to allocate %d bytes for SASL output " - "buffer", maxoutbuf); - return NOTOK; - } - sasl_outbuflen = 0; - sasl_inbuflen = 0; - sasl_inptr = sasl_inbuffer; - } else { - sasl_outbuffer = NULL; - /* Don't NULL out sasl_inbuffer because it could be used in - sm_fgetc (). */ - } - - sasl_complete = 1; - - return RP_OK; -} - -/* - * Our callback functions to feed data to the SASL library - */ - -static int -sm_get_user(void *context, int id, const char **result, unsigned *len) -{ - char *user = (char *) context; - - if (! result || ((id != SASL_CB_USER) && (id != SASL_CB_AUTHNAME))) - return SASL_BADPARAM; - - *result = user; - if (len) - *len = strlen(user); - - return SASL_OK; -} - -static int -sm_get_pass(sasl_conn_t *conn, void *context, int id, - sasl_secret_t **psecret) -{ - char **pw_context = (char **) context; - char *pass = NULL; - int len; - - if (! psecret || id != SASL_CB_PASS) - return SASL_BADPARAM; - - ruserpass(pw_context[0], &(pw_context[1]), &pass); - - len = strlen(pass); - - *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len); - - if (! *psecret) { - free(pass); - return SASL_NOMEM; - } - - (*psecret)->len = len; - strcpy((char *) (*psecret)->data, pass); -/* free(pass); */ - - return SASL_OK; -} -#endif /* CYRUS_SASL */ - -static int -sm_ierror (char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap); - va_end(ap); - - sm_reply.length = strlen (sm_reply.text); - sm_reply.code = NOTOK; - - return RP_BHST; -} - -static int -smtalk (int time, char *fmt, ...) -{ - va_list ap; - int result; - char buffer[BUFSIZ]; - - va_start(ap, fmt); - vsnprintf (buffer, sizeof(buffer), fmt, ap); - va_end(ap); - - if (sm_debug) { - if (sasl_ssf) - printf("(sasl-encrypted) "); - if (tls_active) - printf("(tls-encrypted) "); - printf ("=> %s\n", buffer); - fflush (stdout); - } - - sm_alarmed = 0; - alarm ((unsigned) time); - if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK) - result = smhear (); - alarm (0); - - return result; -} - - -/* - * write the buffer to the open SMTP channel - */ - -static int -sm_wrecord (char *buffer, int len) -{ - if (sm_wfp == NULL) - return sm_werror (); - - sm_fwrite (buffer, len); - sm_fputs ("\r\n"); - sm_fflush (); - - return (ferror (sm_wfp) ? sm_werror () : OK); -} - - -static int -sm_wstream (char *buffer, int len) -{ - char *bp; - static char lc = '\0'; - - if (sm_wfp == NULL) - return sm_werror (); - - if (buffer == NULL && len == 0) { - if (lc != '\n') - sm_fputs ("\r\n"); - lc = '\0'; - return (ferror (sm_wfp) ? sm_werror () : OK); - } - - for (bp = buffer; len > 0; bp++, len--) { - switch (*bp) { - case '\n': - sm_nl = TRUE; - sm_fputc ('\r'); - break; - - case '.': - if (sm_nl) - sm_fputc ('.');/* FALL THROUGH */ - default: - sm_nl = FALSE; - } - sm_fputc (*bp); - if (ferror (sm_wfp)) - return sm_werror (); - } - - if (bp > buffer) - lc = *--bp; - return (ferror (sm_wfp) ? sm_werror () : OK); -} - -/* - * Write out to the network, but do buffering for SASL (if enabled) - */ - -static int -sm_fwrite(char *buffer, int len) -{ -#ifdef CYRUS_SASL - const char *output; - unsigned int outputlen; - - if (sasl_complete == 0 || sasl_ssf == 0) { -#endif /* CYRUS_SASL */ -#ifdef TLS_SUPPORT - if (tls_active) { - int ret; - - ret = SSL_write(ssl, buffer, len); - - if (SSL_get_error(ssl, ret) != SSL_ERROR_NONE) { - sm_ierror("TLS error during write: %s", - ERR_error_string(ERR_get_error(), NULL)); - return NOTOK; - } - } else -#endif /* TLS_SUPPORT */ - fwrite(buffer, sizeof(*buffer), len, sm_wfp); -#ifdef CYRUS_SASL - } else { - while (len >= maxoutbuf - sasl_outbuflen) { - memcpy(sasl_outbuffer + sasl_outbuflen, buffer, - maxoutbuf - sasl_outbuflen); - len -= maxoutbuf - sasl_outbuflen; - sasl_outbuflen = 0; - - if (sasl_encode(conn, sasl_outbuffer, maxoutbuf, - &output, &outputlen) != SASL_OK) { - sm_ierror("Unable to SASL encode connection data: %s", - sasl_errdetail(conn)); - return NOTOK; - } - - fwrite(output, sizeof(*output), outputlen, sm_wfp); - } - - if (len > 0) { - memcpy(sasl_outbuffer + sasl_outbuflen, buffer, len); - sasl_outbuflen += len; - } - } -#endif /* CYRUS_SASL */ - return ferror(sm_wfp) ? NOTOK : RP_OK; -} - -/* - * Convenience functions to replace occurences of fputs() and fputc() - */ - -static int -sm_fputs(char *buffer) -{ - return sm_fwrite(buffer, strlen(buffer)); -} - -static int -sm_fputc(int c) -{ - char h = c; - - return sm_fwrite(&h, 1); -} - -/* - * Flush out any pending data on the connection - */ - -static void -sm_fflush(void) -{ -#ifdef CYRUS_SASL - const char *output; - unsigned int outputlen; - int result; - - if (sasl_complete == 1 && sasl_ssf > 0 && sasl_outbuflen > 0) { - result = sasl_encode(conn, sasl_outbuffer, sasl_outbuflen, - &output, &outputlen); - if (result != SASL_OK) { - sm_ierror("Unable to SASL encode connection data: %s", - sasl_errdetail(conn)); - return; - } - - fwrite(output, sizeof(*output), outputlen, sm_wfp); - sasl_outbuflen = 0; - } -#endif /* CYRUS_SASL */ - - fflush(sm_wfp); -} - -static int -sm_werror (void) -{ - sm_reply.length = - strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened" - : sm_alarmed ? "write to socket timed out" - : "error writing to socket")); - - return (sm_reply.code = NOTOK); -} - - -static int -smhear (void) -{ - int i, code, cont, bc = 0, rc, more; - unsigned char *bp; - char *rp; - char **ehlo = NULL, buffer[BUFSIZ]; - - if (doingEHLO) { - static int at_least_once = 0; - - if (at_least_once) { - char *ep; - - for (ehlo = EHLOkeys; *ehlo; ehlo++) { - ep = *ehlo; - free (ep); - } - } else { - at_least_once = 1; - } - - ehlo = EHLOkeys; - *ehlo = NULL; - } - -again: ; - - sm_reply.length = 0; - sm_reply.text[0] = 0; - rp = sm_reply.text; - rc = sizeof(sm_reply.text) - 1; - - for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer), - &bc) != NOTOK ; ) { - if (sm_debug) { - if (sasl_ssf > 0) - printf("(sasl-decrypted) "); - if (tls_active) - printf("(tls-decrypted) "); - printf ("<= %s\n", buffer); - fflush (stdout); - } - - if (doingEHLO - && strncmp (buffer, "250", sizeof("250") - 1) == 0 - && (buffer[3] == '-' || doingEHLO == 2) - && buffer[4]) { - if (doingEHLO == 2) { - if ((*ehlo = malloc ((size_t) (strlen (buffer + 4) + 1)))) { - strcpy (*ehlo++, buffer + 4); - *ehlo = NULL; - if (ehlo >= EHLOkeys + MAXEHLO) - doingEHLO = 0; - } - else - doingEHLO = 0; - } - else - doingEHLO = 2; - } - - for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--) - continue; - - cont = FALSE; - code = atoi ((char *) bp); - bp += 3, bc -= 3; - for (; bc > 0 && isspace (*bp); bp++, bc--) - continue; - if (bc > 0 && *bp == '-') { - cont = TRUE; - bp++, bc--; - for (; bc > 0 && isspace (*bp); bp++, bc--) - continue; - } - - if (more) { - if (code != sm_reply.code || cont) - continue; - more = FALSE; - } else { - sm_reply.code = code; - more = cont; - if (bc <= 0) { - /* can never fail to 0-terminate because of size of buffer vs fixed string */ - strncpy (buffer, sm_noreply, sizeof(buffer)); - bp = (unsigned char *) buffer; - bc = strlen (sm_noreply); - } - } - - if ((i = min (bc, rc)) > 0) { - memcpy (rp, bp, i); - rp += i; - rc -= i; - i = strlen(sm_moreply); - if (more && rc > i + 1) { - memcpy (rp, sm_moreply, i); /* safe because of check in if() */ - rp += i; - rc -= i; - } - } - if (more) - continue; - if (sm_reply.code < 100) { - if (sm_verbose) { - printf ("%s\n", sm_reply.text); - fflush (stdout); - } - goto again; - } - - sm_reply.length = rp - sm_reply.text; - sm_reply.text[sm_reply.length] = 0; - return sm_reply.code; - } - return NOTOK; -} - - -static int -sm_rrecord (char *buffer, int *len) -{ - int retval; - - if (sm_rfp == NULL) - return sm_rerror(0); - - buffer[*len = 0] = 0; - - if ((retval = sm_fgets (buffer, BUFSIZ, sm_rfp)) != RP_OK) - return retval; - *len = strlen (buffer); - /* *len should be >0 except on EOF, but check for safety's sake */ - if (*len == 0) - return sm_rerror (RP_EOF); - if (buffer[*len - 1] != '\n') - while ((retval = sm_fgetc (sm_rfp)) != '\n' && retval != EOF && - retval != -2) - continue; - else - if ((*len > 1) && (buffer[*len - 2] == '\r')) - *len -= 1; - *len -= 1; - buffer[*len] = 0; - - return OK; -} - -/* - * Our version of fgets, which calls our private fgetc function - */ - -static int -sm_fgets(char *buffer, int size, FILE *f) -{ - int c; - - do { - c = sm_fgetc(f); - - if (c == EOF) - return RP_EOF; - - if (c == -2) - return NOTOK; - - *buffer++ = c; - } while (size > 1 && c != '\n'); - - *buffer = '\0'; - - return RP_OK; -} - - -#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) -/* - * Read from the network, but do SASL or TLS encryption - */ - -static int -sm_fgetc(FILE *f) -{ - char tmpbuf[BUFSIZ], *retbuf; - unsigned int retbufsize = 0; - int cc, result; - - /* - * If we have leftover data, return it - */ - - if (sasl_inbuflen) { - sasl_inbuflen--; - return (int) *sasl_inptr++; - } - - /* - * If not, read from the network until we have some data to return - */ - - while (retbufsize == 0) { - -#ifdef TLS_SUPPORT - if (tls_active) { - cc = SSL_read(ssl, tmpbuf, sizeof(tmpbuf)); - - if (cc == 0) { - result = SSL_get_error(ssl, cc); - - if (result != SSL_ERROR_ZERO_RETURN) { - sm_ierror("TLS peer aborted connection"); - } - - return EOF; - } - - if (cc < 0) { - sm_ierror("SSL_read failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return -2; - } - } else -#endif /* TLS_SUPPORT */ - - cc = read(fileno(f), tmpbuf, sizeof(tmpbuf)); - - if (cc == 0) - return EOF; - - if (cc < 0) { - sm_ierror("Unable to read from network: %s", strerror(errno)); - return -2; - } - - /* - * Don't call sasl_decode unless sasl is complete and we have - * encryption working - */ - -#ifdef CYRUS_SASL - if (sasl_complete == 0 || sasl_ssf == 0) { - retbuf = tmpbuf; - retbufsize = cc; - } else { - result = sasl_decode(conn, tmpbuf, cc, (const char **) &retbuf, - &retbufsize); - - if (result != SASL_OK) { - sm_ierror("Unable to decode SASL network data: %s", - sasl_errdetail(conn)); - return -2; - } - } -#else /* ! CYRUS_SASL */ - retbuf = tmpbuf; - retbufsize = cc; -#endif /* CYRUS_SASL */ - } - - if (retbufsize > SASL_MAXRECVBUF) { - sm_ierror("Received data (%d bytes) is larger than the buffer " - "size (%d bytes)", retbufsize, SASL_MAXRECVBUF); - return -2; - } - - memcpy(sasl_inbuffer, retbuf, retbufsize); - sasl_inptr = sasl_inbuffer + 1; - sasl_inbuflen = retbufsize - 1; - - return (int) sasl_inbuffer[0]; -} -#endif /* CYRUS_SASL || TLS_SUPPORT */ - -static int -sm_rerror (int rc) -{ - if (sm_mts == MTS_SMTP) - sm_reply.length = - strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened" - : sm_alarmed ? "read from socket timed out" - : rc == RP_EOF ? "premature end-of-file on socket" - : "error reading from socket")); - else - sm_reply.length = - strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened" - : sm_alarmed ? "read from pipe timed out" - : rc == RP_EOF ? "premature end-of-file on pipe" - : "error reading from pipe")); - - return (sm_reply.code = NOTOK); -} - - -static RETSIGTYPE -alrmser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGALRM, alrmser); -#endif - - sm_alarmed++; - if (sm_debug) { - printf ("timed out...\n"); - fflush (stdout); - } -} - - -char * -rp_string (int code) -{ - char *text; - static char buffer[BUFSIZ]; - - switch (sm_reply.code != NOTOK ? code : NOTOK) { - case RP_AOK: - text = "AOK"; - break; - - case RP_MOK: - text = "MOK"; - break; - - case RP_OK: - text = "OK"; - break; - - case RP_RPLY: - text = "RPLY"; - break; - - case RP_BHST: - default: - text = "BHST"; - snprintf (buffer, sizeof(buffer), "[%s] %s", text, sm_reply.text); - return buffer; - - case RP_PARM: - text = "PARM"; - break; - - case RP_NO: - text = "NO"; - break; - - case RP_USER: - text = "USER"; - break; - - case RP_NDEL: - text = "NDEL"; - break; - } - - snprintf (buffer, sizeof(buffer), "[%s] %3d %s", - text, sm_reply.code, sm_reply.text); - return buffer; -} - -static char * -EHLOset (char *s) -{ - size_t len; - char *ep, **ehlo; - - len = strlen (s); - - for (ehlo = EHLOkeys; *ehlo; ehlo++) { - ep = *ehlo; - if (strncmp (ep, s, len) == 0) { - for (ep += len; *ep == ' '; ep++) - continue; - return ep; - } - } - - return 0; -} diff --git a/mts/smtp/smtp.h b/mts/smtp/smtp.h deleted file mode 100644 index c88620e..0000000 --- a/mts/smtp/smtp.h +++ /dev/null @@ -1,291 +0,0 @@ - -/* - * smtp.h -- definitions for the nmh SMTP Interface - */ - -/* various modes for SMTP */ -#define S_MAIL 0 -#define S_SEND 1 -#define S_SOML 2 -#define S_SAML 3 - -/* length is the length of the string in text[], which is also NUL - * terminated, so s.text[s.length] should always be 0. - */ -struct smtp { - int code; - int length; - char text[BUFSIZ]; -}; - -/* - * prototypes - */ -/* int client (); */ -int sm_init (char *, char *, char *, int, int, int, int, int, int, char *, char *, int); -int sm_winit (int, char *); -int sm_wadr (char *, char *, char *); -int sm_waend (void); -int sm_wtxt (char *, int); -int sm_wtend (void); -int sm_end (int); -char *rp_string (int); - -/* The remainder of this file is derived from "mmdf.h" */ - -/* - * Copyright (C) 1979,1980,1981,1982,1983 University of Delaware - * Used by permission, May, 1984. - */ - -/* - * MULTI-CHANNEL MEMO DISTRIBUTION FACILITY (MMDF) - * - * - * Copyright (C) 1979,1980,1981,1982,1983 University of Delaware - * - * Department of Electrical Engineering - * University of Delaware - * Newark, Delaware 19711 - * - * Phone: (302) 738-1163 - * - * - * This program module was developed as part of the University - * of Delaware's Multi-Channel Memo Distribution Facility (MMDF). - * - * Acquisition, use, and distribution of this module and its listings - * are subject restricted to the terms of a license agreement. - * Documents describing systems using this module must cite its source. - * - * The above statements must be retained with all copies of this - * program and may not be removed without the consent of the - * University of Delaware. - * - */ - -/* Reply Codes for MMDF - * - * Based on: "Revised FTP Reply Codes", by Jon Postel & Nancy Neigus Arpanet - * RFC 640 / NIC 30843, in the "Arpanet Protocol Handbook", E. Feinler - * and J. Postel (eds.), NIC 7104, Network Information Center, SRI - * International: Menlo Park, CA. (NTIS AD-A0038901) - * - * Actual values are different, but scheme is same. Codes must fit into - * 8-bits (to pass on exit() calls); fields are packed 2-3-3 and interpreted - * as octal numbers. - * - * Basic format: - * - * 0yz: positive completion; entire action done - * 1yz: positive intermediate; only part done - * 2yz: Transient negative completion; may work later - * 3yz: Permanent negative completion; you lose forever - * - * x0z: syntax - * x1z: general; doesn't fit any other category - * x2z: connections; truly transfer-related - * x3z: user/authentication/account - * x4x: mail - * x5z: file system - * - * 3-bit z field is unique to the reply. In the following, - * the RP_xVAL defines are available for masking to obtain a field. - */ - -/* - * FIELD DEFINITIONS & BASIC VALUES - */ - -/* FIELD 1: Basic degree of success (2-bits) */ - -#define RP_BTYP '\200' /* good vs. bad; on => bad */ -#define RP_BVAL '\300' /* basic degree of success */ - -#define RP_BOK '\000' /* went fine; all done */ -#define RP_BPOK '\100' /* only the first part got done */ -#define RP_BTNO '\200' /* temporary failure; try later */ -#define RP_BNO '\300' /* not now, nor never; you lose */ - -/* FIELD 2: Basic domain of discourse (3-bits) */ - -#define RP_CVAL '\070' /* basic category (domain) of reply */ - -#define RP_CSYN '\000' /* purely a matter of form */ -#define RP_CGEN '\010' /* couldn't find anywhere else for it */ -#define RP_CCON '\020' /* data-transfer-related issue */ -#define RP_CUSR '\030' /* pertaining to the user */ -#define RP_CMAI '\040' /* specific to mail semantics */ -#define RP_CFIL '\050' /* file system */ -#define RP_CLIO '\060' /* local i/o system */ - -/* FIELD 3: Specific value for this reply (3-bits) */ - -#define RP_SVAL '\007' /* specific value of reply */ - - -/* - * SPECIFIC SUCCESS VALUES - */ - -/* - * Complete Success - */ - -/* done (e.g., w/transaction) */ -#define RP_DONE (RP_BOK | RP_CGEN | '\000') - -/* general-purpose OK */ -#define RP_OK (RP_BOK | RP_CGEN | '\001') - -/* message is accepted (w/text) */ -#define RP_MOK (RP_BOK | RP_CMAI | '\000') - - -/* - * Partial Success - */ - -/* you are the requestor */ -#define RP_MAST (RP_BPOK| RP_CGEN | '\000') - -/* you are the requestee */ -#define RP_SLAV (RP_BPOK| RP_CGEN | '\001') - -/* message address is accepted */ -#define RP_AOK (RP_BPOK| RP_CMAI | '\000') - - -/* - * SPECIFIC FALURE VALUES - */ - -/* - * Partial Failure - */ - -/* not now; maybe later */ -#define RP_AGN (RP_BTNO | RP_CGEN | '\000') - -/* timeout */ -#define RP_TIME (RP_BTNO | RP_CGEN | '\001') - -/* no-op; nothing done, this time */ -#define RP_NOOP (RP_BTNO | RP_CGEN | '\002') - -/* encountered an end of file */ -#define RP_EOF (RP_BTNO | RP_CGEN | '\003') - -/* channel went bad */ -#define RP_NET (RP_BTNO | RP_CCON | '\000') - -/* foreign host screwed up */ -#define RP_BHST (RP_BTNO | RP_CCON | '\001') - -/* host went away */ -#define RP_DHST (RP_BTNO | RP_CCON | '\002') - -/* general net i/o problem */ -#define RP_NIO (RP_BTNO | RP_CCON | '\004') - -/* error reading/writing file */ -#define RP_FIO (RP_BTNO | RP_CFIL | '\000') - -/* unable to create file */ -#define RP_FCRT (RP_BTNO | RP_CFIL | '\001') - -/* unable to open file */ -#define RP_FOPN (RP_BTNO | RP_CFIL | '\002') - -/* general local i/o problem */ -#define RP_LIO (RP_BTNO | RP_CLIO | '\000') - -/* resource currently locked */ -#define RP_LOCK (RP_BTNO | RP_CLIO | '\001') - - -/* - * Complete Failure - */ - -/* bad mechanism/path; try alternate? */ -#define RP_MECH (RP_BNO | RP_CGEN | '\000') - -/* general-purpose NO */ -#define RP_NO (RP_BNO | RP_CGEN | '\001') - -/* general prototocol error */ -#define RP_PROT (RP_BNO | RP_CCON | '\000') - -/* bad reply code (PERMANENT ERROR) */ -#define RP_RPLY (RP_BNO | RP_CCON | '\001') - -/* couldn't deliver */ -#define RP_NDEL (RP_BNO | RP_CMAI | '\000') - -/* couldn't parse the request */ -#define RP_HUH (RP_BNO | RP_CSYN | '\000') - -/* no such command defined */ -#define RP_NCMD (RP_BNO | RP_CSYN | '\001') - -/* bad parameter */ -#define RP_PARM (RP_BNO | RP_CSYN | '\002') - -/* command not implemented */ -#define RP_UCMD (RP_BNO | RP_CSYN | '\003') - -/* unknown user */ -#define RP_USER (RP_BNO | RP_CUSR | '\000') - - -/* - * Macros to access reply info - */ - -/* get the entire return value */ -#define rp_gval(val) ((signed char) (val)) - - -/* - * The next three give the field's bits, within the whole value - */ - -/* get the basic part of return value */ -#define rp_gbval(val) (rp_gval (val) & RP_BVAL) - -/* get the domain part of value */ -#define rp_gcval(val) (rp_gval (val) & RP_CVAL) - -/* get the specific part of value */ -#define rp_gsval(val) (rp_gval (val) & RP_SVAL) - - -/* - * The next three give the numeric value withing the field - */ - -/* get the basic part right-shifted */ -#define rp_gbbit(val) ((rp_gval (val) >> 6) & 03) - -/* get the domain part right-shifted */ -#define rp_gcbit(val) ((rp_gval (val) >> 3) & 07) - -/* get the specific part right-shifted */ -#define rp_gsbit(val) (rp_gval (val) & 07) - - -/* - * MACHINE DEPENDENCY - * - * The following treat the value as strictly numeric. - * It relies on the negative values being numerically - * negative. - */ - -/* is return value positive? */ -#define rp_isgood(val) (rp_gval (val) >= 0) - -/* is return value negative? */ -#define rp_isbad(val) (rp_gval (val) < 0) - diff --git a/sbr/Makefile.in b/sbr/Makefile.in index 581cc6d..c6801b3 100644 --- a/sbr/Makefile.in +++ b/sbr/Makefile.in @@ -17,8 +17,7 @@ etcdir = @sysconfdir@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -CONFIGDEFS = -DNMHETCDIR='"$(etcdir)"' -DMAILSPOOL='"$(mailspool)"' -DSENDMAILPATH='"$(sendmailpath)"' -INCLUDES = -I.. -I. -I$(top_srcdir) @CPPFLAGS@ +INCLUDES = -I$(top_srcdir) @CPPFLAGS@ LEX = @LEX@ AWK = @AWK@ @@ -27,16 +26,10 @@ TSORT = @TSORT@ RANLIB = @RANLIB@ LIBTOOL = @LIBTOOL@ GNU_LIBTOOL = @GNU_LIBTOOL@ -LINT = @LINT@ -LINTFLAGS = @LINTFLAGS@ - -LIBOBJS = @LIBOBJS@ - -mailspool = @mailspool@ -sendmailpath = @sendmailpath@ +LINT = @LINT@ +LINTFLAGS = @LINTFLAGS@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) -COMPILE2 = $(CC) -c $(DEFS) $(CONFIGDEFS) $(INCLUDES) $(CFLAGS) @@ -50,42 +43,39 @@ COMPILE2 = $(CC) -c $(DEFS) $(CONFIGDEFS) $(INCLUDES) $(CFLAGS) SIGNAL_H = @SIGNAL_H@ # source for library functions -SRCS = addrsbr.c ambigsw.c atooi.c brkstring.c \ - check_charset.c client.c closefds.c concat.c context_del.c \ - context_find.c context_foil.c context_read.c \ - context_replace.c context_save.c copy.c \ - copyip.c cpydata.c cpydgst.c crawl_folders.c \ - discard.c done.c dtime.c dtimep.c \ - error.c ext_hook.c fdcompare.c folder_addmsg.c folder_delmsgs.c \ - folder_free.c folder_pack.c folder_read.c \ - folder_realloc.c gans.c getans.c getanswer.c \ - getarguments.c getcpy.c getfolder.c getpass.c \ - fmt_addr.c fmt_compile.c fmt_new.c fmt_rfc2047.c \ - fmt_scan.c lock_file.c m_atoi.c m_backup.c \ - m_convert.c m_draft.c m_getfld.c m_gmprot.c \ - m_maildir.c m_name.c m_scratch.c m_tmpfil.c \ - makedir.c mts.c norm_charmap.c \ - path.c peekc.c pidwait.c pidstatus.c \ - print_help.c print_sw.c print_version.c push.c \ - putenv.c refile.c remdir.c r1bindex.c \ - readconfig.c ruserpass.c seq_add.c seq_bits.c \ - seq_del.c seq_getnum.c seq_list.c seq_nameok.c \ - seq_print.c seq_read.c seq_save.c seq_setcur.c \ - seq_setprev.c seq_setunseen.c showfile.c signals.c \ - smatch.c snprintb.c ssequal.c strcasecmp.c \ - strindex.c trimcpy.c uprf.c vfgets.c fmt_def.c \ - m_msgdef.c mf.c utils.c m_mktemp.c - -# source for compatibility functions -COMPAT = memmove.c snprintf.c strdup.c strerror.c - -OBJS = $(SRCS:.c=.o) $(LIBOBJS) +SRCS = addrsbr.c ambigsw.c brkstring.c \ + charset.c concat.c context_del.c \ + context_find.c context_read.c \ + context_replace.c context_save.c \ + cpydata.c cpydgst.c crawl_folders.c \ + discard.c done.c dtime.c dtimep.c \ + error.c ext_hook.c folder_addmsg.c folder_delmsgs.c \ + folder_free.c folder_read.c \ + folder_realloc.c gans.c getans.c getanswer.c \ + getarguments.c getcpy.c getpass.c \ + fmt_addr.c fmt_compile.c fmt_new.c fmt_rfc2047.c \ + fmt_scan.c lock_file.c m_atoi.c \ + m_convert.c m_draft.c m_getfld.c m_gmprot.c \ + m_name.c \ + makedir.c mts.c norm_charmap.c \ + path.c pidwait.c pidstatus.c \ + print_help.c print_sw.c print_version.c \ + putenv.c mhbasename.c \ + readconfig.c seq_add.c seq_bits.c \ + seq_del.c seq_getnum.c seq_list.c seq_nameok.c \ + seq_print.c seq_read.c seq_save.c seq_setcur.c \ + seq_setprev.c seq_setunseen.c signals.c \ + smatch.c snprintb.c strcasecmp.c \ + strindex.c trimcpy.c uprf.c vfgets.c fmt_def.c \ + mf.c utils.c m_mktemp.c + +OBJS = $(SRCS:.c=.o) # auxiliary files AUX = Makefile.in sigmsg.awk dtimep.lex # all files in this directory included in the distribution -DIST = $(SRCS) $(COMPAT) $(AUX) +DIST = $(SRCS) $(AUX) # ========= DEPENDENCIES FOR BUILDING ========== @@ -105,12 +95,6 @@ lint: sigmsg.h dtimep.c: dtimep.lex $(LEX) -n -t $(srcdir)/dtimep.lex > dtimep.c -client.o: client.c - $(COMPILE2) $(srcdir)/client.c - -mts.o: mts.c - $(COMPILE2) $(srcdir)/mts.c - pidstatus.o: sigmsg.h libmh.a: $(OBJS) @@ -147,9 +131,9 @@ subdir = sbr Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ - + distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ diff --git a/sbr/addrsbr.c b/sbr/addrsbr.c index 484ec5e..e759088 100644 --- a/sbr/addrsbr.c +++ b/sbr/addrsbr.c @@ -1,65 +1,33 @@ - /* - * addrsbr.c -- parse addresses 822-style - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** addrsbr.c -- parse addresses 822-style +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -/* High level parsing of addresses: - - The routines in sbr/mf.c parse the syntactic representations of - addresses. The routines in sbr/addrsbr.c associate semantics with those - addresses. - - If #ifdef DUMB is in effect, a full 822-style parser is called - for syntax recongition. This breaks each address into its components. - Note however that no semantics are assumed about the parts or their - totality. This means that implicit hostnames aren't made explicit, - and explicit hostnames aren't expanded to their "official" represenations. - - If DUMB is not in effect, then this module does some - high-level thinking about what the addresses are. - - 1. for MMDF systems: - - string%@ -> string - - 2. for non-MMDF systems: - - string@host. -> host!string - - 3. for any system, an address interpreted relative to the local host: - - string@ -> string - - For cases (1) and (3) above, the leftmost host is extracted. If it's not - present, the local host is used. If the tests above fail, the address is - considered to be a real 822-style address. - - If an explicit host is not present, then MH checks for a bang to indicate - an explicit UUCP-style address. If so, this is noted. If not, the host is - defaulted, typically to the local host. The lack of an explict host is - also noted. - - If an explicit 822-style host is present, then MH checks to see if it - can expand this to the official name for the host. If the hostname is - unknown, the address is so typed. - - To summarize, when we're all done, here's what MH knows about the address: - - DUMB - type: local, uucp, or network - host: not locally defaulted, not explicitly expanded - everything else - - other - type: local, uucp, network, unknown - everything else - */ +/* +** High level parsing of addresses: +** +** The routines in sbr/mf.c parse the syntactic representations of +** addresses. The routines in sbr/addrsbr.c associate semantics with those +** addresses. +** +** A full 822-style parser is called for syntax recongition. This breaks +** each address into its components. Note however that no semantics are +** assumed about the parts or their totality. This means that implicit +** hostnames aren't made explicit, and explicit hostnames aren't expanded +** to their "official" represenations. +** +** To summarize, when we're all done, here's what MH knows about the address: +** type: local or network +** host: not locally defaulted, not explicitly expanded +** everything else +*/ static int ingrp = 0; @@ -73,456 +41,334 @@ static char err[BUFSIZ]; static char adr[BUFSIZ]; -extern boolean username_extension_masquerading; /* defined in mts.c */ - - -/* - * external prototypes - */ -char *getusername (void); - - char * -getname (char *addrs) +getname(char *addrs) { - struct adrx *ap; - - pers = mbox = host = route = grp = note = NULL; - err[0] = '\0'; - - if ((ap = getadrx (addrs ? addrs : "")) == NULL) - return NULL; - - strncpy (adr, ap->text, sizeof(adr)); - pers = ap->pers; - mbox = ap->mbox; - host = ap->host; - route = ap->path; - grp = ap->grp; - ingrp = ap->ingrp; - note = ap->note; - if (ap->err && *ap->err) - strncpy (err, ap->err, sizeof(err)); - - return adr; + struct adrx *ap; + + pers = mbox = host = route = grp = note = NULL; + err[0] = '\0'; + + if ((ap = getadrx(addrs ? addrs : "")) == NULL) + return NULL; + + strncpy(adr, ap->text, sizeof(adr)); + pers = ap->pers; + mbox = ap->mbox; + host = ap->host; + route = ap->path; + grp = ap->grp; + ingrp = ap->ingrp; + note = ap->note; + if (ap->err && *ap->err) + strncpy(err, ap->err, sizeof(err)); + + return adr; } struct mailname * -getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult) +getm(char *str, char *dfhost, int dftype, int wanthost, char *eresult) { - char *pp; - struct mailname *mp; -#ifndef DUMB - char *dp; -#endif /* not DUMB */ - - if (err[0]) { - if (eresult) - strcpy (eresult, err); - else - if (wanthost == AD_HOST) - admonish (NULL, "bad address '%s' - %s", str, err); - return NULL; - } - if (pers == NULL - && mbox == NULL && host == NULL && route == NULL - && grp == NULL) { - if (eresult) - strcpy (eresult, "null address"); - else - if (wanthost == AD_HOST) - admonish (NULL, "null address '%s'", str); - return NULL; - } - if (mbox == NULL && grp == NULL) { - if (eresult) - strcpy (eresult, "no mailbox in address"); - else - if (wanthost == AD_HOST) - admonish (NULL, "no mailbox in address '%s'", str); - return NULL; - } - - if (dfhost == NULL) { - dfhost = LocalName (); - dftype = LOCALHOST; - } - - mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp)); - if (mp == NULL) { - if (eresult) - strcpy (eresult, "insufficient memory to represent address"); - else - if (wanthost == AD_HOST) - adios (NULL, "insufficient memory to represent address"); - return NULL; - } - - mp->m_next = NULL; - mp->m_text = getcpy (str); - if (pers) - mp->m_pers = getcpy (pers); - - if (mbox == NULL) { - mp->m_type = BADHOST; - mp->m_nohost = 1; - mp->m_ingrp = ingrp; - mp->m_gname = getcpy (grp); - if (note) - mp->m_note = getcpy (note); - return mp; - } - - if (host) { - mp->m_mbox = getcpy (mbox); - mp->m_host = getcpy (host); - } - else { - if ((pp = strchr(mbox, '!'))) { - *pp++ = '\0'; - mp->m_mbox = getcpy (pp); - mp->m_host = getcpy (mbox); - mp->m_type = UUCPHOST; + struct mailname *mp; + + if (err[0]) { + if (eresult) + strcpy(eresult, err); + else + if (wanthost == AD_HOST) + admonish(NULL, "bad address '%s' - %s", str, err); + return NULL; + } + if (pers == NULL && mbox == NULL && host == NULL && route == NULL + && grp == NULL) { + if (eresult) + strcpy(eresult, "null address"); + else + if (wanthost == AD_HOST) + admonish(NULL, "null address '%s'", str); + return NULL; + } + if (mbox == NULL && grp == NULL) { + if (eresult) + strcpy(eresult, "no mailbox in address"); + else if (wanthost == AD_HOST) + admonish(NULL, "no mailbox in address '%s'", str); + return NULL; } - else { - mp->m_nohost = 1; - mp->m_mbox = getcpy (mbox); -#ifdef DUMB - if (route == NULL && dftype == LOCALHOST) { - mp->m_host = NULL; - mp->m_type = dftype; - } - else -#endif /* DUMB */ - { - mp->m_host = route ? NULL : getcpy (dfhost); - mp->m_type = route ? NETHOST : dftype; - } + + if (dfhost == NULL) { + dfhost = LocalName(); + dftype = LOCALHOST; } - goto got_host; - } - - if (wanthost == AD_NHST) - mp->m_type = !mh_strcasecmp (LocalName (), mp->m_host) - ? LOCALHOST : NETHOST; -#ifdef DUMB - else - mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST; -#else /* not DUMB */ - else - if (pp = OfficialName (mp->m_host)) { - got_real_host: ; - free (mp->m_host); - mp->m_host = getcpy (pp); - mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST; + + mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp)); + if (mp == NULL) { + if (eresult) + strcpy(eresult, "insufficient memory to represent address"); + else if (wanthost == AD_HOST) + adios(NULL, "insufficient memory to represent address"); + return NULL; } - else { - if (dp = strchr(mp->m_host, '.')) { - *dp = NULL; - if (pp = OfficialName (mp->m_host)) - goto got_real_host; - *dp = '.'; - } - mp->m_type = BADHOST; + + mp->m_next = NULL; + mp->m_text = getcpy(str); + if (pers) + mp->m_pers = getcpy(pers); + + if (mbox == NULL) { + mp->m_type = BADHOST; + mp->m_nohost = 1; + mp->m_ingrp = ingrp; + mp->m_gname = getcpy(grp); + if (note) + mp->m_note = getcpy(note); + return mp; + } + + if (host) { + mp->m_mbox = getcpy(mbox); + mp->m_host = getcpy(host); + } else { + mp->m_nohost = 1; + mp->m_mbox = getcpy(mbox); + if (route == NULL && dftype == LOCALHOST) { + mp->m_host = NULL; + mp->m_type = dftype; + } else { + mp->m_host = route ? NULL : getcpy(dfhost); + mp->m_type = route ? NETHOST : dftype; + } + goto got_host; } -#endif /* not DUMB */ + + if (wanthost == AD_NHST) + mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host) + ? LOCALHOST : NETHOST; + else + mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ? NETHOST : LOCALHOST; got_host: ; - if (route) - mp->m_path = getcpy (route); - mp->m_ingrp = ingrp; - if (grp) - mp->m_gname = getcpy (grp); - if (note) - mp->m_note = getcpy (note); - - return mp; + if (route) + mp->m_path = getcpy(route); + mp->m_ingrp = ingrp; + if (grp) + mp->m_gname = getcpy(grp); + if (note) + mp->m_note = getcpy(note); + + return mp; } void -mnfree (struct mailname *mp) +mnfree(struct mailname *mp) { - if (!mp) - return; - - if (mp->m_text) - free (mp->m_text); - if (mp->m_pers) - free (mp->m_pers); - if (mp->m_mbox) - free (mp->m_mbox); - if (mp->m_host) - free (mp->m_host); - if (mp->m_path) - free (mp->m_path); - if (mp->m_gname) - free (mp->m_gname); - if (mp->m_note) - free (mp->m_note); - - free ((char *) mp); + if (!mp) + return; + + if (mp->m_text) + free(mp->m_text); + if (mp->m_pers) + free(mp->m_pers); + if (mp->m_mbox) + free(mp->m_mbox); + if (mp->m_host) + free(mp->m_host); + if (mp->m_path) + free(mp->m_path); + if (mp->m_gname) + free(mp->m_gname); + if (mp->m_note) + free(mp->m_note); + + free((char *) mp); } #define empty(s) ((s) ? (s) : "") char * -auxformat (struct mailname *mp, int extras) +adrformat(struct mailname *mp) { - static char addr[BUFSIZ]; - static char buffer[BUFSIZ]; + static char addr[BUFSIZ]; + static char buffer[BUFSIZ]; -#ifdef DUMB if (mp->m_nohost) - strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr)); - else -#endif /* DUMB */ - -#ifndef BANG - if (mp->m_type != UUCPHOST) - snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s", - empty(mp->m_path), empty(mp->m_mbox), mp->m_host); - else -#endif /* not BANG */ - snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox); - - if (!extras) - return addr; - - if (mp->m_pers || mp->m_path) { - if (mp->m_note) - snprintf (buffer, sizeof(buffer), "%s %s <%s>", - legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox), - mp->m_note, addr); + strncpy(addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr)); else - snprintf (buffer, sizeof(buffer), "%s <%s>", - legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox), - addr); - } - else - if (mp->m_note) - snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note); + snprintf(addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s", + empty(mp->m_path), empty(mp->m_mbox), mp->m_host); + + if (mp->m_pers || mp->m_path) { + if (mp->m_note) + snprintf(buffer, sizeof(buffer), "%s %s <%s>", + legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox), + mp->m_note, addr); + else + snprintf(buffer, sizeof(buffer), "%s <%s>", + legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox), + addr); + } else if (mp->m_note) + snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note); else - strncpy (buffer, addr, sizeof(buffer)); - - return buffer; -} - + strncpy(buffer, addr, sizeof(buffer)); -/* - * address specific "sprintf" - */ - -char * -adrsprintf (char *username, char *domain) -{ - int snprintf_return; - static char addr[BUFSIZ]; - - if (username == NULL) - username = getusername(); - - if (username_extension_masquerading) { - /* mts.conf contains "masquerade:[...]username_extension[...]", so tack - on the value of the $USERNAME_EXTENSION environment variable, if set, - to username. */ - char* extension = getenv("USERNAME_EXTENSION"); - static char username_with_extension[BUFSIZ]; - - if (extension != NULL && *extension != '\0') { - snprintf_return = snprintf(username_with_extension, - sizeof(username_with_extension), - "%s%s", username, extension); - - if (snprintf_return < 0 || - snprintf_return >= sizeof(username_with_extension)) - adios(NULL, "snprintf() error writing username (%d chars) and" - " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)" - " chars", - strlen(username), strlen(extension), BUFSIZ); - - username = username_with_extension; - } - } - -#ifdef REALLYDUMB - return username; -#endif - - if (domain == NULL) - domain = LocalName(); - -#ifndef BANG - snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain); -#else /* BANG */ - snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username); -#endif /* BANG */ - - if (snprintf_return < 0 || snprintf_return >= sizeof(addr)) - adios(NULL, "snprintf() error writing username (%d chars), domain (%d" - " chars), and 1 separator char to array of BUFSIZ (%d) chars", - strlen(username), strlen(domain), BUFSIZ); - - return addr; + return buffer; } -#define W_NIL 0x0000 -#define W_MBEG 0x0001 -#define W_MEND 0x0002 -#define W_MBOX (W_MBEG | W_MEND) -#define W_HBEG 0x0004 -#define W_HEND 0x0008 -#define W_HOST (W_HBEG | W_HEND) -#define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND" +#define W_NIL 0x0000 +#define W_MBEG 0x0001 +#define W_MEND 0x0002 +#define W_MBOX (W_MBEG | W_MEND) +#define W_HBEG 0x0004 +#define W_HEND 0x0008 +#define W_HOST (W_HBEG | W_HEND) +#define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND" /* - * Check if this is my address - */ +** Check if this is my address +*/ int -ismymbox (struct mailname *np) +ismymbox(struct mailname *np) { - int oops; - register int len, i; - register char *cp; - register char *pp; - char buffer[BUFSIZ]; - struct mailname *mp; - static char *am = NULL; - static struct mailname mq={NULL}; - - /* - * If this is the first call, initialize - * list of alternate mailboxes. - */ - if (am == NULL) { - mq.m_next = NULL; - mq.m_mbox = getusername (); - if ((am = context_find ("alternate-mailboxes")) == NULL) - am = getusername(); - else { - mp = &mq; - oops = 0; - while ((cp = getname (am))) { - if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) { - admonish (NULL, "illegal address: %s", cp); - oops++; - } else { - mp = mp->m_next; - mp->m_type = W_NIL; - if (*mp->m_mbox == '*') { - mp->m_type |= W_MBEG; - mp->m_mbox++; - } - if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') { - mp->m_type |= W_MEND; - *cp = '\0'; - } - if (mp->m_host) { - if (*mp->m_host == '*') { - mp->m_type |= W_HBEG; - mp->m_host++; - } - if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') { - mp->m_type |= W_HEND; - *cp = '\0'; + int oops; + register int len, i; + register char *cp; + register char *pp; + char buffer[BUFSIZ]; + struct mailname *mp; + static char *am = NULL; + static struct mailname mq; + + /* + ** If this is the first call, initialize + ** list of alternate mailboxes. + */ + if (am == NULL) { + mq.m_next = NULL; + mq.m_mbox = getusername(); + if ((am = context_find("alternate-mailboxes")) == NULL) + am = getusername(); + else { + mp = &mq; + oops = 0; + while ((cp = getname(am))) { + if ((mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL)) == NULL) { + admonish(NULL, "illegal address: %s", cp); + oops++; + } else { + mp = mp->m_next; + mp->m_type = W_NIL; + if (*mp->m_mbox == '*') { + mp->m_type |= W_MBEG; + mp->m_mbox++; + } + if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') { + mp->m_type |= W_MEND; + *cp = '\0'; + } + if (mp->m_host) { + if (*mp->m_host == '*') { + mp->m_type |= W_HBEG; + mp->m_host++; + } + if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') { + mp->m_type |= W_HEND; + *cp = '\0'; + } + } + if ((cp = getenv("MHWDEBUG")) && *cp) + fprintf(stderr, "mbox=\"%s\" host=\"%s\" %s\n", + mp->m_mbox, mp->m_host, + snprintb(buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS)); + } } - } - if ((cp = getenv ("MHWDEBUG")) && *cp) - fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n", - mp->m_mbox, mp->m_host, - snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS)); + if (oops) + advise(NULL, "please fix the profile entry %s", + "alternate-mailboxes"); } - } - if (oops) - advise (NULL, "please fix the %s: entry in your %s file", - "alternate-mailboxes", mh_profile); } - } - if (np == NULL) /* XXX */ - return 0; - - switch (np->m_type) { + if (np == NULL) /* XXX */ + return 0; + + switch (np->m_type) { case NETHOST: - len = strlen (cp = LocalName ()); - if (!uprf (np->m_host, cp) || np->m_host[len] != '.') - break; - goto local_test; + len = strlen(cp = LocalName()); + if (!uprf(np->m_host, cp) || np->m_host[len] != '.') + break; + goto local_test; - case UUCPHOST: - if (mh_strcasecmp (np->m_host, SystemName())) - break; /* fall */ case LOCALHOST: local_test: ; - if (!mh_strcasecmp (np->m_mbox, mq.m_mbox)) - return 1; - break; + if (!mh_strcasecmp(np->m_mbox, mq.m_mbox)) + return 1; + break; default: - break; - } - - /* - * Now scan through list of alternate - * mailboxes, and check for a match. - */ - for (mp = &mq; mp->m_next;) { - mp = mp->m_next; - if (!np->m_mbox) - continue; - if ((len = strlen (cp = np->m_mbox)) - < (i = strlen (pp = mp->m_mbox))) - continue; - switch (mp->m_type & W_MBOX) { - case W_NIL: - if (mh_strcasecmp (cp, pp)) - continue; - break; - case W_MBEG: - if (mh_strcasecmp (cp + len - i, pp)) - continue; - break; - case W_MEND: - if (!uprf (cp, pp)) - continue; - break; - case W_MBEG | W_MEND: - if (stringdex (pp, cp) < 0) - continue; break; } - if (mp->m_nohost) - return 1; - if (np->m_host == NULL) - continue; - if ((len = strlen (cp = np->m_host)) - < (i = strlen (pp = mp->m_host))) - continue; - switch (mp->m_type & W_HOST) { - case W_NIL: - if (mh_strcasecmp (cp, pp)) - continue; - break; - case W_HBEG: - if (mh_strcasecmp (cp + len - i, pp)) - continue; - break; - case W_HEND: - if (!uprf (cp, pp)) - continue; - break; - case W_HBEG | W_HEND: - if (stringdex (pp, cp) < 0) - continue; - break; + /* + ** Now scan through list of alternate + ** mailboxes, and check for a match. + */ + for (mp = &mq; mp->m_next;) { + mp = mp->m_next; + if (!np->m_mbox) + continue; + if ((len = strlen(cp = np->m_mbox)) + < (i = strlen(pp = mp->m_mbox))) + continue; + switch (mp->m_type & W_MBOX) { + case W_NIL: + if (mh_strcasecmp(cp, pp)) + continue; + break; + case W_MBEG: + if (mh_strcasecmp(cp + len - i, pp)) + continue; + break; + case W_MEND: + if (!uprf(cp, pp)) + continue; + break; + case W_MBEG | W_MEND: + if (stringdex(pp, cp) < 0) + continue; + break; + } + + if (mp->m_nohost) + return 1; + if (np->m_host == NULL) + continue; + if ((len = strlen(cp = np->m_host)) + < (i = strlen(pp = mp->m_host))) + continue; + switch (mp->m_type & W_HOST) { + case W_NIL: + if (mh_strcasecmp(cp, pp)) + continue; + break; + case W_HBEG: + if (mh_strcasecmp (cp + len - i, pp)) + continue; + break; + case W_HEND: + if (!uprf(cp, pp)) + continue; + break; + case W_HBEG | W_HEND: + if (stringdex(pp, cp) < 0) + continue; + break; + } + return 1; } - return 1; - } - return 0; + return 0; } diff --git a/sbr/ambigsw.c b/sbr/ambigsw.c index c11b9e7..f2126b7 100644 --- a/sbr/ambigsw.c +++ b/sbr/ambigsw.c @@ -1,18 +1,17 @@ - /* - * ambigsw.c -- report an ambiguous switch - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** ambigsw.c -- report an ambiguous switch +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -ambigsw (char *arg, struct swit *swp) +ambigsw(char *arg, struct swit *swp) { - advise (NULL, "-%s ambiguous. It matches", arg); - print_sw (arg, swp, "-", stderr); + advise(NULL, "-%s ambiguous. It matches", arg); + print_sw(arg, swp, "-", stderr); } diff --git a/sbr/atooi.c b/sbr/atooi.c deleted file mode 100644 index d62de17..0000000 --- a/sbr/atooi.c +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * atooi.c -- octal version of atoi() - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -atooi(char *cp) -{ - register int i, base; - - i = 0; - base = 8; - while (*cp >= '0' && *cp <= '7') { - i *= base; - i += *cp++ - '0'; - } - - return i; -} diff --git a/sbr/brkstring.c b/sbr/brkstring.c index 5375596..32dd37f 100644 --- a/sbr/brkstring.c +++ b/sbr/brkstring.c @@ -1,12 +1,11 @@ - /* - * brkstring.c -- (destructively) split a string into - * -- an array of substrings - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** brkstring.c -- (destructively) split a string into +** -- an array of substrings +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,79 +13,63 @@ /* allocate this number of pointers at a time */ #define NUMBROKEN 256 -static char **broken = NULL; /* array of substring start addresses */ -static int len = 0; /* current size of "broken" */ - -/* - * static prototypes - */ -static int brkany (char, char *); +static char **broken = NULL; /* array of substring start addresses */ +static int len = 0; /* current size of "broken" */ +/* +** returns pointer to static memory +*/ char ** -brkstring (char *str, char *brksep, char *brkterm) +brkstring(char *str, char *brksep, char *brkterm) { - int i; - char c, *s; - - /* allocate initial space for pointers on first call */ - if (!broken) { - len = NUMBROKEN; - broken = (char **) mh_xmalloc ((size_t) (len * sizeof(*broken))); - } + int i; + char c, *s; - /* - * scan string, replacing separators with zeroes - * and enter start addresses in "broken". - */ - s = str; - - for (i = 0;; i++) { - - /* enlarge pointer array, if necessary */ - if (i >= len) { - len += NUMBROKEN; - broken = mh_xrealloc (broken, (size_t) (len * sizeof(*broken))); + /* allocate initial space for pointers on first call */ + if (!broken) { + len = NUMBROKEN; + broken = (char **)mh_xmalloc((size_t)(len * sizeof(*broken))); } - while (brkany (c = *s, brksep)) - *s++ = '\0'; - /* - * we are either at the end of the string, or the - * terminator found has been found, so finish up. - */ - if (!c || brkany (c, brkterm)) { - *s = '\0'; - broken[i] = NULL; - return broken; + ** scan string, replacing separators with zeroes + ** and enter start addresses in "broken". + */ + s = str; + for (i = 0;; i++) { + /* enlarge pointer array, if necessary */ + if (i >= len) { + len += NUMBROKEN; + broken = mh_xrealloc(broken, + (size_t)(len * sizeof(*broken))); + } + + /* handle separators */ + while ((c=*s) && brksep && strchr(brksep, c)) { + *s++ = '\0'; + } + + /* + ** we are either at the end of the string, or the + ** terminator found has been found, so finish up. + */ + if (!c || (brkterm && strchr(brkterm, c))) { + *s = '\0'; + broken[i] = NULL; + return broken; + } + + /* set next start addr and walk over word */ + broken[i] = s; + while ((c = *++s)) { + if (brksep && strchr(brksep, c)) { + break; + } + if (brkterm && strchr(brkterm, c)) { + break; + } + } } - - /* set next start addr */ - broken[i] = s; - - while ((c = *++s) && !brkany (c, brksep) && !brkany (c, brkterm)) - ; /* empty body */ - } - - return broken; /* NOT REACHED */ -} - - -/* - * If the character is in the string, - * return 1, else return 0. - */ - -static int -brkany (char c, char *str) -{ - char *s; - - if (str) { - for (s = str; *s; s++) - if (c == *s) - return 1; - } - return 0; + adios("brkstring()", "reached unreachable point"); } diff --git a/sbr/charset.c b/sbr/charset.c new file mode 100644 index 0000000..56f085c --- /dev/null +++ b/sbr/charset.c @@ -0,0 +1,70 @@ +/* +** charset.c -- routines for character sets +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ + +#include +#ifdef HAVE_LANGINFO_H +# include +#endif + + +/* +** Get the current character set +*/ +char * +get_charset() +{ + char *charset = getenv("MM_CHARSET"); +#if defined(HAVE_NL_LANGINFO) && defined(CODESET) + if (!charset) { + charset = norm_charmap(nl_langinfo(CODESET)); + } +#endif + return charset; +} + + +/* +** Check if we can display a given character set natively. +*/ +int +is_native_charset(char *str) +{ + char *mm_charset = NULL; + + if (!(mm_charset = get_charset())) { + mm_charset = "US-ASCII"; + } + if (mh_strcasecmp(str, mm_charset)==0) { + return 1; + } + + /* US-ASCII is a subset of the ISO-8859-X and UTF-8 character sets */ + if (strncasecmp("ISO-8859-", mm_charset, 9)==0 || + mh_strcasecmp("UTF-8", mm_charset)==0) { + if (mh_strcasecmp(str, "US-ASCII")==0) { + return 1; + } + } + return 0; +} + + +/* +** Return the name of the character set we are +** using for 8bit text. +*/ +char * +write_charset_8bit(void) +{ + char *mm_charset = NULL; + + if (!(mm_charset = get_charset())) { + mm_charset = "x-unknown"; + } + return mm_charset; +} diff --git a/sbr/check_charset.c b/sbr/check_charset.c deleted file mode 100644 index 8ee93b1..0000000 --- a/sbr/check_charset.c +++ /dev/null @@ -1,87 +0,0 @@ - -/* - * check_charset.c -- routines for character sets - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#ifdef HAVE_LANGINFO_H -# include -#endif - - -/* - * Get the current character set - */ -char * -get_charset () -{ - char *charset = getenv ("MM_CHARSET"); -#if defined(HAVE_NL_LANGINFO) && defined(CODESET) - if (!charset) - charset = norm_charmap(nl_langinfo (CODESET)); -#endif - return charset; -} - - -/* - * Check if we can display a given character set natively. - * We are passed the length of the initial part of the - * string to check, since we want to allow the name of the - * character set to be a substring of a larger string. - */ - -int -check_charset (char *str, int len) -{ - static char *mm_charset = NULL; - static char *alt_charset = NULL; - static int mm_len; - static int alt_len; - - /* Cache the name of our default character set */ - if (!mm_charset) { - if (!(mm_charset = get_charset ())) - mm_charset = "US-ASCII"; - mm_len = strlen (mm_charset); - - /* US-ASCII is a subset of the ISO-8859-X and UTF-8 character sets */ - if (!strncasecmp("ISO-8859-", mm_charset, 9) || - !mh_strcasecmp("UTF-8", mm_charset)) { - alt_charset = "US-ASCII"; - alt_len = strlen (alt_charset); - } - } - - /* Check if character set is OK */ - if ((len == mm_len) && !strncasecmp(str, mm_charset, mm_len)) - return 1; - if (alt_charset && (len == alt_len) && !strncasecmp(str, alt_charset, alt_len)) - return 1; - - return 0; -} - - -/* - * Return the name of the character set we are - * using for 8bit text. - */ -char * -write_charset_8bit (void) -{ - static char *mm_charset = NULL; - - /* - * Cache the name of the character set to - * use for 8bit text. - */ - if (!mm_charset && !(mm_charset = get_charset ())) - mm_charset = "x-unknown"; - - return mm_charset; -} diff --git a/sbr/client.c b/sbr/client.c deleted file mode 100644 index c558536..0000000 --- a/sbr/client.c +++ /dev/null @@ -1,212 +0,0 @@ - -/* - * client.c -- connect to a server - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_ARPA_INET_H -# include -#endif - -#define TRUE 1 -#define FALSE 0 - -#define MAXARGS 1000 - -/* - * static prototypes - */ - -/* client's own static version of several nmh subroutines */ -static char **client_brkstring (char *, char *, char *); -static int client_brkany (char, char *); -static char **client_copyip (char **, char **, int); -static char *client_getcpy (char *); -static void client_freelist(char **); - - -int -client (char *args, char *service, char *response, int len_response, int debug) -{ - int sd, rc; - char **ap, *arguments[MAXARGS]; - struct addrinfo hints, *res, *ai; - - ap = arguments; - if (args != NULL && *args != 0) { - ap = client_copyip (client_brkstring (client_getcpy (args), " ", "\n"), - ap, MAXARGS); - } else { - if (servers != NULL && *servers != 0) - ap = client_copyip (client_brkstring (client_getcpy (servers), " ", "\n"), - ap, MAXARGS); - } - if (ap == arguments) { - *ap++ = client_getcpy ("localhost"); - *ap = NULL; - } - - memset(&hints, 0, sizeof(hints)); -#ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; -#endif - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - for (ap = arguments; *ap; ap++) { - - if (debug) { - fprintf(stderr, "Trying to connect to \"%s\" ...\n", *ap); - } - - rc = getaddrinfo(*ap, service, &hints, &res); - - if (rc) { - if (debug) { - fprintf(stderr, "Lookup of \"%s\" failed: %s\n", *ap, - gai_strerror(rc)); - } - continue; - } - - for (ai = res; ai != NULL; ai = ai->ai_next) { - if (debug) { - char address[NI_MAXHOST]; - - rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address, - sizeof(address), NULL, 0, NI_NUMERICHOST); - - fprintf(stderr, "Connecting to %s...\n", - rc ? "unknown" : address); - } - - sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - - if (sd < 0) { - if (debug) - fprintf(stderr, "socket() failed: %s\n", strerror(errno)); - continue; - } - - if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) { - freeaddrinfo(res); - client_freelist(ap); - return sd; - } - - if (debug) { - fprintf(stderr, "Connection failed: %s\n", strerror(errno)); - } - - close(sd); - } - - freeaddrinfo(res); - } - - client_freelist(ap); - strncpy (response, "no servers available", len_response); - return NOTOK; -} - - -/* - * Free a list of strings - */ - -static void -client_freelist(char **list) -{ - while (*list++ != NULL) - free(*list); -} - - -/* - * static copies of three nmh subroutines - */ - -static char *broken[MAXARGS + 1]; - -static char ** -client_brkstring (char *strg, char *brksep, char *brkterm) -{ - register int bi; - register char c, *sp; - - sp = strg; - - for (bi = 0; bi < MAXARGS; bi++) { - while (client_brkany (c = *sp, brksep)) - *sp++ = 0; - if (!c || client_brkany (c, brkterm)) { - *sp = 0; - broken[bi] = 0; - return broken; - } - - broken[bi] = sp; - while ((c = *++sp) && !client_brkany (c, brksep) && !client_brkany (c, brkterm)) - continue; - } - broken[MAXARGS] = 0; - - return broken; -} - - -/* - * returns 1 if chr in strg, 0 otherwise - */ -static int -client_brkany (char chr, char *strg) -{ - register char *sp; - - if (strg) - for (sp = strg; *sp; sp++) - if (chr == *sp) - return 1; - return 0; -} - - -/* - * copy a string array and return pointer to end - */ -static char ** -client_copyip (char **p, char **q, int len_q) -{ - while (*p && --len_q > 0) - *q++ = *p++; - - *q = NULL; - - return q; -} - - -static char * -client_getcpy (char *str) -{ - char *cp; - size_t len; - - len = strlen(str) + 1; - cp = mh_xmalloc(len); - - memcpy (cp, str, len); - return cp; -} - diff --git a/sbr/closefds.c b/sbr/closefds.c deleted file mode 100644 index d292112..0000000 --- a/sbr/closefds.c +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * closefds.c -- close-up fd's - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -void -closefds(int i) -{ - int nbits = OPEN_MAX; - - for (; i < nbits; i++) - close (i); -} diff --git a/sbr/concat.c b/sbr/concat.c index 82979f5..5c519e9 100644 --- a/sbr/concat.c +++ b/sbr/concat.c @@ -1,38 +1,48 @@ - /* - * concat.c -- concatenate a variable number (minimum of 1) - * of strings in managed memory - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** concat.c -- concatenate a variable number (minimum of 1) +** of strings in managed memory +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include +static char * +copy(char *from, char *to) +{ + while ((*to = *from)) { + to++; + from++; + } + return (to); +} + + char * -concat (char *s1, ...) +concat(char *s1, ...) { - char *cp, *dp, *sp; - size_t len; - va_list list; + char *cp, *dp, *sp; + size_t len; + va_list list; - len = strlen (s1) + 1; - va_start(list, s1); - while ((cp = va_arg(list, char *))) - len += strlen (cp); - va_end(list); + len = strlen(s1) + 1; + va_start(list, s1); + while ((cp = va_arg(list, char *))) + len += strlen(cp); + va_end(list); - dp = sp = mh_xmalloc(len); + dp = sp = mh_xmalloc(len); - sp = copy(s1, sp); + sp = copy(s1, sp); - va_start(list, s1); - while ((cp = va_arg (list, char *))) - sp = copy(cp, sp); - va_end(list); + va_start(list, s1); + while ((cp = va_arg(list, char *))) + sp = copy(cp, sp); + va_end(list); - return dp; + return dp; } diff --git a/sbr/context_del.c b/sbr/context_del.c index 474e51c..6eebd7e 100644 --- a/sbr/context_del.c +++ b/sbr/context_del.c @@ -1,40 +1,39 @@ - /* - * context_del.c -- delete an entry from the context/profile list - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** context_del.c -- delete an entry from the context/profile list +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * Delete a key/value pair from the context/profile list. - * Return 0 if key is found, else return 1. - */ +** Delete a key/value pair from the context/profile list. +** Return 0 if key is found, else return 1. +*/ int -context_del (char *key) +context_del(char *key) { - register struct node *np, *pp; + register struct node *np, *pp; - for (np = m_defs, pp = NULL; np; pp = np, np = np->n_next) { - if (!mh_strcasecmp (np->n_name, key)) { - if (!np->n_context) - admonish (NULL, "bug: context_del(key=\"%s\")", np->n_name); - if (pp) - pp->n_next = np->n_next; - else - m_defs = np->n_next; - free (np->n_name); - if (np->n_field) - free (np->n_field); - free ((char *) np); - ctxflags |= CTXMOD; - return 0; + for (np = m_defs, pp = NULL; np; pp = np, np = np->n_next) { + if (!mh_strcasecmp(np->n_name, key)) { + if (!np->n_context) + admonish(NULL, "bug: context_del(key=\"%s\")", np->n_name); + if (pp) + pp->n_next = np->n_next; + else + m_defs = np->n_next; + free(np->n_name); + if (np->n_field) + free(np->n_field); + free((char *) np); + ctxflags |= CTXMOD; + return 0; + } } - } - return 1; + return 1; } diff --git a/sbr/context_find.c b/sbr/context_find.c index 8c0675f..64ed8e0 100644 --- a/sbr/context_find.c +++ b/sbr/context_find.c @@ -1,23 +1,22 @@ - /* - * context_find.c -- find an entry in the context/profile list - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** context_find.c -- find an entry in the context/profile list +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include char * -context_find (char *str) +context_find(char *str) { - struct node *np; + struct node *np; - for (np = m_defs; np; np = np->n_next) - if (!mh_strcasecmp (np->n_name, str)) - return (np->n_field); + for (np = m_defs; np; np = np->n_next) + if (!mh_strcasecmp(np->n_name, str)) + return (np->n_field); - return NULL; + return NULL; } diff --git a/sbr/context_foil.c b/sbr/context_foil.c deleted file mode 100644 index 12dab45..0000000 --- a/sbr/context_foil.c +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * context_foil.c -- foil search of profile and context - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - -/* - * Foil search of users .mh_profile - * If error, return -1, else return 0 - */ - -int -context_foil (char *path) -{ - register struct node *np; - - /* In fact, nobody examines defpath in code paths where - * it's been set by us -- the uses in the source tree are: - * 1 sbr/context_read.c uses it only after setting it itself - * 2 uip/install_mh.c uses it only after setting it itself - * 3 uip/mshcmds.c and uip/mark.c print it if given the -debug switch - * A worthwhile piece of code cleanup would be to make 1 and - * 2 use a local variable and just delete 3. - * - * Similarly, context and ctxpath are not really used - * outside the context_* routines. It might be worth combining - * them into one file so the variables can be made static. - */ - - /* We set context to NULL to indicate that no context file - * is to be read. (Using /dev/null doesn't work because we - * would try to lock it, which causes timeouts with some - * locking methods.) - */ - defpath = context = NULL; - - /* - * If path is given, create a minimal profile/context list - */ - if (path) { - m_defs = (struct node *) mh_xmalloc (sizeof(*np)); - - np = m_defs; - if (!(np->n_name = strdup ("Path"))) { - advise (NULL, "strdup failed"); - return -1; - } - if (!(np->n_field = strdup (path))) { - advise (NULL, "strdup failed"); - return -1; - } - np->n_context = 0; - np->n_next = NULL; - - if (mypath == NULL && (mypath = getenv ("HOME")) != NULL) - if (!(mypath = strdup (mypath))) { - advise (NULL, "strdup failed"); - return -1; - } - } - - return 0; -} - diff --git a/sbr/context_read.c b/sbr/context_read.c index a655eff..abf666c 100644 --- a/sbr/context_read.c +++ b/sbr/context_read.c @@ -1,145 +1,198 @@ /* - * context_read.c -- find and read profile and context files - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - * - * This function must be called early on in any nmh utility, and - * may only be called once. It does the following: - * - * o Sets the global variable "mypath" to the home directory path. - * - * o Sets the global variable "defpath" to the absolute path of - * the profile file. - * - * o Reads in the profile file. Bails out if it can't. - * - * o Makes sure that the mail directory exists, prompting for - * creation if it doesn't. - * - * o Reads the context file either as set by the MHCONTEXT - * environment variable or by the profile. - */ - -#include /* mh internals */ -#include /* system call errors */ -#include /* structure for getpwuid() results */ +** context_read.c -- find and read profile and context files +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** This function must be called early on in any nmh utility, and +** may only be called once. It does the following: +** +** o Sets the global variables to absolute paths: +** - "mypath": home directory (HOME) +** - "mmhpath": mmh directory (MMH) +** - "defpath": profile file (MMHP) +** - "ctxpath": context file (MMHC) +** +** o Reads in the profile file. Bails out if it can't. +** +** o Makes sure that the mail directory exists, prompting for +** creation if it doesn't. +** +** o Reads the context file. +** +** You might need to adjust uip/mmh.sh if you make changes here. +*/ + +#include /* mh internals */ +#include /* system call errors */ +#include /* structure for getpwuid() results */ void -context_read (void) +context_read(void) { - char buf[BUFSIZ]; /* path name buffer */ - char *cp; /* miscellaneous pointer */ - char *nd; /* nmh directory pointer */ - struct stat st; /* stat() results */ - register struct passwd *pw; /* getpwuid() results */ - register FILE *ib; /* profile and context file pointer */ - - /* - * If this routine _is_ called again (despite the wanings in the - * comments above), return immediately. - */ - if ( m_defs != 0 ) - return; - - /* - * Find user's home directory. Try the HOME environment variable first, - * the home directory field in the password file if that's not found. - */ - - if ((mypath = getenv("HOME")) == (char *)0) { - if ((pw = getpwuid(getuid())) == (struct passwd *)0 || *pw->pw_dir == '\0') - adios(NULL, "cannot determine your home directory"); - else - mypath = pw->pw_dir; - } - - /* - * Find and read user's profile. Check for the existence of an MH environment - * variable first with non-empty contents. Convert any relative path name - * found there to an absolute one. Look for the profile in the user's home - * directory if the MH environment variable isn't set. - */ - - if ((cp = getenv("MH")) && *cp != '\0') { - defpath = path(cp, TFILE); - - if (stat(defpath, &st) != -1 && (st.st_mode & S_IFREG) == 0) - adios((char *)0, "`%s' specified by your MH environment variable is not a normal file", cp); - - if ((ib = fopen(defpath, "r")) == (FILE *)0) - adios((char *)0, "unable to read the `%s' profile specified by your MH environment variable", defpath); - } - else { - defpath = concat(mypath, "/", mh_profile, NULL); - - if ((ib = fopen(defpath, "r")) == (FILE *)0) - adios((char *)0, "Doesn't look like nmh is installed. Run install-mh to do so."); - - cp = mh_profile; - } - - readconfig (&m_defs, ib, cp, 0); - fclose (ib); - - /* - * Find the user's nmh directory, which is specified by the "path" profile component. - * Convert a relative path name to an absolute one rooted in the home directory. - */ - - if ((cp = context_find ("path")) == (char *)0) - adios(NULL, "Your %s file does not contain a path entry.", defpath); - - if (*cp == '\0') - adios(NULL, "Your `%s' profile file does not contain a valid path entry.", defpath); - - if (*cp != '/') - (void)snprintf (nd = buf, sizeof(buf), "%s/%s", mypath, cp); - else - nd = cp; - - if (stat(nd, &st) == -1) { - if (errno != ENOENT) - adios (nd, "error opening"); - - cp = concat ("Your MH-directory \"", nd, "\" doesn't exist; Create it? ", NULL); - - if (!getanswer(cp)) - adios (NULL, "unable to access MH-directory \"%s\"", nd); - - free (cp); - - if (!makedir (nd)) - adios (NULL, "unable to create %s", nd); - } - - else if ((st.st_mode & S_IFDIR) == 0) - adios ((char *)0, "`%s' is not a directory", nd); - - /* - * Open and read user's context file. The name of the context file comes from the - * profile unless overridden by the MHCONTEXT environment variable. - */ - - if ((cp = getenv ("MHCONTEXT")) == (char *)0 || *cp == '\0') - cp = context; - - /* context is NULL if context_foil() was called to disable use of context - * We also support users setting explicitly setting MHCONTEXT to /dev/null. - * (if this wasn't specialcased then the locking would be liable to fail) - */ - if (!cp || (strcmp(cp,"/dev/null") == 0)) { - ctxpath = NULL; - return; - } - - ctxpath = getcpy (m_maildir (cp)); - - if ((ib = lkfopen (ctxpath, "r"))) { - readconfig ((struct node **) 0, ib, cp, 1); - lkfclose (ib, ctxpath); - } - - return; + char buf[BUFSIZ]; /* path name buffer */ + char *cp; /* miscellaneous pointer */ + char *nd; /* nmh directory pointer */ + struct stat st; /* stat() results */ + register struct passwd *pw; /* getpwuid() results */ + register FILE *ib; /* profile and context file pointer */ + + /* + ** If this routine _is_ called again (despite the wanings in the + ** comments above), return immediately. + */ + if (m_defs) { + return; + } + + /* + ** Find user's home directory. Try the HOME environment variable first, + ** the home directory field in the password file if that's not found. + */ + if (!(mypath = getenv("HOME"))) { + if (!(pw = getpwuid(getuid())) || !*pw->pw_dir) { + adios(NULL, "cannot determine your home directory"); + } + mypath = pw->pw_dir; + } + + /* + ** set mmhpath + */ + if ((cp = getenv("MMH")) && *cp) { + mmhpath = getcpy(expanddir(cp)); /* rel to cwd */ + if (stat(mmhpath, &st) != -1 && (st.st_mode & S_IFDIR) == 0) { + adios(NULL, "`%s' specified by your MMH environment variable is not a directory", cp); + } + } else { + mmhpath = concat(mypath, "/", mmhdir, NULL); + if (stat(mmhpath, &st) == -1 || (st.st_mode & S_IFDIR) == 0) { + adios(NULL, "Doesn't look like mmh is set up for your account. Run `mmh' to do so."); + } + } + + /* + ** Find and read user's profile. Check for the existence of + ** a non-empty MMHP environment variable first. Look for the + ** profile in the mmh directory otherwise. + */ + if ((cp = getenv("MMHP")) && *cp) { + if (*cp == '/') { + defpath = getcpy(cp); + } else { + defpath = concat(mmhpath, "/", cp, NULL); + } + if (stat(defpath, &st) != -1 && (st.st_mode & S_IFREG) == 0) { + adios(NULL, "Your profile `%s', specified by the MMHP environment variable, is not a normal file", cp); + } + if ((ib = fopen(defpath, "r")) == (FILE *)0) { + adios(NULL, "Unable to read your profile `%s', specified by the MMHP environment variable", defpath); + } + } else { + defpath = concat(mmhpath, "/", profile, NULL); + if ((ib = fopen(defpath, "r")) == (FILE *)0) { + adios(NULL, "No profile found. Please create `%s' first.", defpath); + } + cp = profile; + } + readconfig(&m_defs, ib, cp, 0); + fclose(ib); + + /* + ** Find the user's mail storage directory, which is specified by + ** the `Path' profile component. Convert a relative path name + ** to an absolute one rooted in the home directory. + */ + if ((cp = context_find("path")) == NULL) { + adios(NULL, "Your profile `%s' does not contain the required path entry.", defpath); + } + if (!*cp) { + adios(NULL, "The Path entry of your profile `%s' must be non-empty.", defpath); + } + if (*cp == '/') { + nd = cp; + } else { + snprintf(nd = buf, sizeof buf, "%s/%s", mypath, cp); + } + if (stat(nd, &st) == -1) { + if (errno != ENOENT) { + adios(nd, "error opening"); + } + cp = concat("Your mail storage directory `", nd, "' doesn't exist; Create it? ", NULL); + if (!getanswer(cp)) { + adios(NULL, "Unable to access the mail storage directory `%s'", nd); + } + free(cp); + if (!makedir(nd)) { + adios(nd, "unable to create"); + } + } else if ((st.st_mode & S_IFDIR) == 0) { + adios(NULL, "Your mail storage `%s' is not a directory", nd); + } + /* + ** Create the default folder (inbox) + */ + cp = toabsdir(defaultfolder); + if (stat(cp, &st) == -1) { + if (!makedir(cp)) { + adios(cp, "Unable to create the default folder"); + } + } else if ((st.st_mode & S_IFDIR) == 0) { + adios(NULL, "The default folder `%s' is not a directory", cp); + } + + /* + ** Open and read user's context file. The name of the context + ** file comes from the profile unless overridden by the MMHC + ** environment variable. + */ + if (!(cp = getenv("MMHC")) || !*cp) { + if (!(cp = context_find("context")) || !*cp) { + cp = context; + } + } + + /* + ** context is NULL if the use of the context was diabled. + ** We also support users setting explicitly setting + ** MMHC to /dev/null. (If this wasn't special-cased then the + ** locking would be liable to fail.) + */ + if (!context || (strcmp(cp, "/dev/null") == 0)) { + ctxpath = NULL; + return; + } + + if (*cp == '/') { + ctxpath = getcpy(cp); + } else { + ctxpath = concat(mmhpath, "/", cp, NULL); + } + if ((ib = lkfopen(ctxpath, "r"))) { + readconfig((struct node **) 0, ib, cp, 1); + lkfclose(ib, ctxpath); + } + + /* Set editor */ + if (!(cp = getenv("MMHEDITOR")) || !*cp) { + if (!(cp = context_find("editor")) || !*cp) { + if (!(cp = getenv("VISUAL")) || !*cp) { + if (!(cp = getenv("EDITOR")) || !*cp) { + cp = defaulteditor; + } + } + } + } + defaulteditor = cp; + + /* Set pager */ + if (!(cp = getenv("MMHPAGER")) || !*cp) { + if (!(cp = context_find("pager")) || !*cp) { + if (!(cp = getenv("PAGER")) || !*cp) { + cp = defaultpager; + } + } + } + defaultpager = cp; } diff --git a/sbr/context_replace.c b/sbr/context_replace.c index a0c5032..4d81356 100644 --- a/sbr/context_replace.c +++ b/sbr/context_replace.c @@ -1,65 +1,64 @@ - /* - * context_replace.c -- add/replace an entry in the context/profile list - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** context_replace.c -- add/replace an entry in the context/profile list +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include void -context_replace (char *key, char *value) +context_replace(char *key, char *value) { - register struct node *np; - - /* - * If list is emtpy, allocate head of profile/context list. - */ - if (!m_defs) { - m_defs = (struct node *) mh_xmalloc (sizeof(*np)); + register struct node *np; - np = m_defs; - np->n_name = getcpy (key); - np->n_field = getcpy (value); - np->n_context = 1; - np->n_next = NULL; - ctxflags |= CTXMOD; - return; - } + /* + ** If list is emtpy, allocate head of profile/context list. + */ + if (!m_defs) { + m_defs = (struct node *) mh_xmalloc(sizeof(*np)); - /* - * Search list of context/profile entries for - * this key, and replace its value if found. - */ - for (np = m_defs;; np = np->n_next) { - if (!mh_strcasecmp (np->n_name, key)) { - if (strcmp (value, np->n_field)) { - if (!np->n_context) - admonish (NULL, "bug: context_replace(key=\"%s\",value=\"%s\")", key, value); - if (np->n_field) - free (np->n_field); - np->n_field = getcpy (value); + np = m_defs; + np->n_name = getcpy(key); + np->n_field = getcpy(value); + np->n_context = 1; + np->n_next = NULL; ctxflags |= CTXMOD; - } - return; + return; } - if (!np->n_next) - break; - } - /* - * Else add this new entry at the end - */ - np->n_next = (struct node *) mh_xmalloc (sizeof(*np)); + /* + ** Search list of context/profile entries for + ** this key, and replace its value if found. + */ + for (np = m_defs;; np = np->n_next) { + if (!mh_strcasecmp(np->n_name, key)) { + if (strcmp(value, np->n_field)!=0) { + if (!np->n_context) + admonish(NULL, "bug: context_replace(key=\"%s\",value=\"%s\")", key, value); + if (np->n_field) + free(np->n_field); + np->n_field = getcpy(value); + ctxflags |= CTXMOD; + } + return; + } + if (!np->n_next) + break; + } + + /* + ** Else add this new entry at the end + */ + np->n_next = (struct node *) mh_xmalloc(sizeof(*np)); - np = np->n_next; - np->n_name = getcpy (key); - np->n_field = getcpy (value); - np->n_context = 1; - np->n_next = NULL; - ctxflags |= CTXMOD; + np = np->n_next; + np->n_name = getcpy(key); + np->n_field = getcpy(value); + np->n_context = 1; + np->n_next = NULL; + ctxflags |= CTXMOD; } diff --git a/sbr/context_save.c b/sbr/context_save.c index 4ee40ca..d1371d0 100644 --- a/sbr/context_save.c +++ b/sbr/context_save.c @@ -1,96 +1,91 @@ - /* - * context_save.c -- write out the updated context file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** context_save.c -- write out the updated context file +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include /* - * static prototypes - */ +** static prototypes +*/ static int m_chkids(void); void -context_save (void) +context_save(void) { - int action; - register struct node *np; - FILE *out; - sigset_t set, oset; - - /* No context in use -- silently ignore any changes! */ - if (!ctxpath) - return; - - if (!(ctxflags & CTXMOD)) - return; - ctxflags &= ~CTXMOD; - - if ((action = m_chkids ()) > 0) - return; /* child did it for us */ - - /* block a few signals */ - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - - if (!(out = lkfopen (ctxpath, "w"))) - adios (ctxpath, "unable to write"); - for (np = m_defs; np; np = np->n_next) - if (np->n_context) - fprintf (out, "%s: %s\n", np->n_name, np->n_field); - lkfclose (out, ctxpath); - - SIGPROCMASK (SIG_SETMASK, &oset, &set); /* reset the signal mask */ - - if (action == 0) - _exit (0); /* we are child, time to die */ + int action; + register struct node *np; + FILE *out; + sigset_t set, oset; + + /* No context in use -- silently ignore any changes! */ + if (!ctxpath) + return; + + if (!(ctxflags & CTXMOD)) + return; + ctxflags &= ~CTXMOD; + + if ((action = m_chkids()) > 0) + return; /* child did it for us */ + + /* block a few signals */ + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGQUIT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, &oset); + + if (!(out = lkfopen(ctxpath, "w"))) + adios(ctxpath, "unable to write"); + for (np = m_defs; np; np = np->n_next) + if (np->n_context) + fprintf(out, "%s: %s\n", np->n_name, np->n_field); + lkfclose(out, ctxpath); + + sigprocmask(SIG_SETMASK, &oset, &set); /* reset the signal mask */ + + if (action == 0) + _exit(0); /* we are child, time to die */ } /* - * This hack brought to you so we can handle set[ug]id MH programs. - * If we return -1, then no fork is made, we update .mh_profile - * normally, and return to the caller normally. If we return 0, - * then the child is executing, .mh_profile is modified after - * we set our [ug]ids to the norm. If we return > 0, then the - * parent is executed and .mh_profile has already be modified. - * We can just return to the caller immediately. - */ +** This hack brought to you so we can handle set[ug]id MH programs. +** If we return -1, then no fork is made, we update .mh_profile +** normally, and return to the caller normally. If we return 0, +** then the child is executing, .mh_profile is modified after +** we set our [ug]ids to the norm. If we return > 0, then the +** parent is executed and .mh_profile has already be modified. +** We can just return to the caller immediately. +*/ static int -m_chkids (void) +m_chkids(void) { - int i; - pid_t pid; - - if (getuid () == geteuid ()) - return (-1); + pid_t pid; - for (i = 0; (pid = fork ()) == -1 && i < 5; i++) - sleep (5); + if (getuid() == geteuid()) + return (-1); - switch (pid) { + switch (pid = fork()) { case -1: - break; + break; case 0: - setgid (getgid ()); - setuid (getuid ()); - break; + setgid(getgid()); + setuid(getuid()); + break; default: - pidwait (pid, -1); - break; - } + pidwait(pid, -1); + break; + } - return pid; + return pid; } diff --git a/sbr/copy.c b/sbr/copy.c deleted file mode 100644 index cc35e95..0000000 --- a/sbr/copy.c +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * copy.c -- copy a string and return pointer to NULL terminator - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -char * -copy(char *from, char *to) -{ - while ((*to = *from)) { - to++; - from++; - } - return (to); -} diff --git a/sbr/copyip.c b/sbr/copyip.c deleted file mode 100644 index 84f724c..0000000 --- a/sbr/copyip.c +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * copyip.c -- copy a string array and return pointer to end - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -char ** -copyip (char **p, char **q, int len_q) -{ - while (*p && --len_q > 0) - *q++ = *p++; - - *q = NULL; - - return q; -} diff --git a/sbr/cpydata.c b/sbr/cpydata.c index d322ba9..048579e 100644 --- a/sbr/cpydata.c +++ b/sbr/cpydata.c @@ -1,25 +1,24 @@ - /* - * cpydata.c -- copy all data from one fd to another - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** cpydata.c -- copy all data from one fd to another +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -cpydata (int in, int out, char *ifile, char *ofile) +cpydata(int in, int out, char *ifile, char *ofile) { - int i; - char buffer[BUFSIZ]; + int i; + char buffer[BUFSIZ]; - while ((i = read(in, buffer, sizeof(buffer))) > 0) { - if (write(out, buffer, i) != i) - adios(ofile, "error writing"); - } + while ((i = read(in, buffer, sizeof(buffer))) > 0) { + if (write(out, buffer, i) != i) + adios(ofile, "error writing"); + } - if (i == -1) - adios(ifile, "error reading"); + if (i == -1) + adios(ifile, "error reading"); } diff --git a/sbr/cpydgst.c b/sbr/cpydgst.c index 12829f1..b788fef 100644 --- a/sbr/cpydgst.c +++ b/sbr/cpydgst.c @@ -1,67 +1,66 @@ - /* - * cpydgst.c -- copy from one fd to another in encapsulating mode - * -- (do dashstuffing of input data). - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** cpydgst.c -- copy from one fd to another in encapsulating mode +** -- (do dashstuffing of input data). +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * We want to perform the substitution - * - * \n(-.*)\n --> \n- \1\n - * - * This is equivalent to the sed substitution - * - * sed -e 's%^-%- -%' < ifile > ofile - * - * but the routine below is faster than the pipe, fork, and exec. - */ +** We want to perform the substitution +** +** \n(-.*)\n --> \n- \1\n +** +** This is equivalent to the sed substitution +** +** sed -e 's%^-%- -%' < ifile > ofile +** +** but the routine below is faster than the pipe, fork, and exec. +*/ -#define S1 0 -#define S2 1 +#define S1 0 +#define S2 1 -#define output(c) if (bp >= dp) {flush(); *bp++ = c;} else *bp++ = c -#define flush() if ((j = bp - outbuf) && write (out, outbuf, j) != j) \ - adios (ofile, "error writing"); \ - else \ - bp = outbuf +#define output(c) if (bp >= dp) {flush(); *bp++ = c;} else *bp++ = c +#define flush() if ((j = bp - outbuf) && write(out, outbuf, j) != j) \ + adios(ofile, "error writing"); \ + else \ + bp = outbuf void -cpydgst (int in, int out, char *ifile, char *ofile) +cpydgst(int in, int out, char *ifile, char *ofile) { - register int i, j, state; - register char *cp, *ep; - register char *bp, *dp; - char buffer[BUFSIZ], outbuf[BUFSIZ]; + register int i, j, state; + register char *cp, *ep; + register char *bp, *dp; + char buffer[BUFSIZ], outbuf[BUFSIZ]; - dp = (bp = outbuf) + sizeof outbuf; - for (state = S1; (i = read (in, buffer, sizeof buffer)) > 0;) - for (ep = (cp = buffer) + i; cp < ep; cp++) { - if (*cp == '\0') - continue; - switch (state) { - case S1: - if (*cp == '-') { - output ('-'); - output (' '); - } - state = S2; /* fall */ + dp = (bp = outbuf) + sizeof outbuf; + for (state = S1; (i = read(in, buffer, sizeof buffer)) > 0;) + for (ep = (cp = buffer) + i; cp < ep; cp++) { + if (*cp == '\0') + continue; + switch (state) { + case S1: + if (*cp == '-') { + output('-'); + output(' '); + } + state = S2; /* fall */ - case S2: - output (*cp); - if (*cp == '\n') - state = S1; - break; - } - } + case S2: + output(*cp); + if (*cp == '\n') + state = S1; + break; + } + } - if (i == -1) - adios (ifile, "error reading"); - flush(); + if (i == -1) + adios(ifile, "error reading"); + flush(); } diff --git a/sbr/crawl_folders.c b/sbr/crawl_folders.c index d8bcdba..0185bd8 100644 --- a/sbr/crawl_folders.c +++ b/sbr/crawl_folders.c @@ -1,149 +1,156 @@ - /* - * crawl_folders.c -- crawl folder hierarchy - * - * This code is Copyright (c) 2008, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** crawl_folders.c -- crawl folder hierarchy +** +** This code is Copyright (c) 2008, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include struct crawl_context { - int max; /* how many folders we currently can hold in - * the array `folders', increased by - * CRAWL_NUMFOLDERS at a time */ - int total; /* how many `folders' actually has */ - char **folders; /* the array of folders */ - int start; - int foldp; + int max; /* + ** how many folders we currently can hold in the array + ** `folders', increased by CRAWL_NUMFOLDERS at a time + */ + int total; /* how many `folders' actually has */ + char **folders; /* the array of folders */ + int start; + int foldp; }; /* - * Add the folder name into the - * list in a sorted fashion. - */ +** Add the folder name into the +** list in a sorted fashion. +*/ static void -add_folder (char *fold, struct crawl_context *crawl) +add_folder(char *fold, struct crawl_context *crawl) { - register int i, j; - - /* if necessary, reallocate the space for folder names */ - if (crawl->foldp >= crawl->max) { - crawl->max += CRAWL_NUMFOLDERS; - crawl->folders = mh_xrealloc (crawl->folders, - crawl->max * sizeof(char *)); - } - - for (i = crawl->start; i < crawl->foldp; i++) - if (strcmp (fold, crawl->folders[i]) < 0) { - for (j = crawl->foldp - 1; j >= i; j--) - crawl->folders[j + 1] = crawl->folders[j]; - crawl->foldp++; - crawl->folders[i] = fold; - return; + register int i, j; + + /* if necessary, reallocate the space for folder names */ + if (crawl->foldp >= crawl->max) { + crawl->max += CRAWL_NUMFOLDERS; + crawl->folders = mh_xrealloc(crawl->folders, + crawl->max * sizeof(char *)); } - crawl->total++; - crawl->folders[crawl->foldp++] = fold; + for (i = crawl->start; i < crawl->foldp; i++) + if (strcmp(fold, crawl->folders[i]) < 0) { + for (j = crawl->foldp - 1; j >= i; j--) + crawl->folders[j + 1] = crawl->folders[j]; + crawl->foldp++; + crawl->folders[i] = fold; + return; + } + + crawl->total++; + crawl->folders[crawl->foldp++] = fold; } static void -add_children (char *name, struct crawl_context *crawl) +add_children(char *name, struct crawl_context *crawl) { - char *prefix, *child; - struct stat st; - struct dirent *dp; - DIR * dd; - int child_is_folder; - - if (!(dd = opendir (name))) { - admonish (name, "unable to read directory "); - return; - } - - if (strcmp (name, ".") == 0) { - prefix = getcpy (""); - } else { - prefix = concat (name, "/", (void *)NULL); - } - - while ((dp = readdir (dd))) { - /* If the system supports it, try to skip processing of children we - * know are not directories or symlinks. */ - child_is_folder = -1; -#if defined(HAVE_STRUCT_DIRENT_D_TYPE) - if (dp->d_type == DT_DIR) { - child_is_folder = 1; - } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) { - continue; + char *prefix, *child; + struct stat st; + struct dirent *dp; + DIR * dd; + int child_is_folder; + + if (!(dd = opendir(name))) { + admonish(name, "unable to read directory "); + return; } -#endif - if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) { - continue; - } - child = concat (prefix, dp->d_name, (void *)NULL); - /* If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, stat the - * child to see what it is. */ - if (child_is_folder == -1) { - child_is_folder = (stat (child, &st) != -1 && S_ISDIR(st.st_mode)); - } - if (child_is_folder) { - /* add_folder saves child in the list, don't free it */ - add_folder (child, crawl); + + if (strcmp(name, ".") == 0) { + prefix = getcpy(""); } else { - free (child); + prefix = concat(name, "/", (void *)NULL); } - } - closedir (dd); - free(prefix); + while ((dp = readdir(dd))) { + /* + ** If the system supports it, try to skip processing of + ** children we know are not directories or symlinks. + */ + child_is_folder = -1; +#if defined(HAVE_STRUCT_DIRENT_D_TYPE) + if (dp->d_type == DT_DIR) { + child_is_folder = 1; + } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) { + continue; + } +#endif + if (strcmp(dp->d_name, ".")==0 || + strcmp(dp->d_name, "..")==0) { + continue; + } + child = concat(prefix, dp->d_name, (void *)NULL); + /* + ** If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, + ** stat the child to see what it is. + */ + if (child_is_folder == -1) { + child_is_folder = (stat(child, &st) != -1 && S_ISDIR(st.st_mode)); + } + if (child_is_folder) { + /* add_folder saves child in the list, don't free it */ + add_folder(child, crawl); + } else { + free(child); + } + } + + closedir(dd); + free(prefix); } static void -crawl_folders_body (struct crawl_context *crawl, - char *dir, crawl_callback_t *callback, void *baton) +crawl_folders_body(struct crawl_context *crawl, char *dir, + crawl_callback_t *callback, void *baton) { - int i; - int os = crawl->start; - int of = crawl->foldp; + int i; + int os = crawl->start; + int of = crawl->foldp; - crawl->start = crawl->foldp; + crawl->start = crawl->foldp; - add_children (dir, crawl); + add_children(dir, crawl); - for (i = crawl->start; i < crawl->foldp; i++) { - char *fold = crawl->folders[i]; - int crawl_children = 1; + for (i = crawl->start; i < crawl->foldp; i++) { + char *fold = crawl->folders[i]; + int crawl_children = 1; - if (callback != NULL) { - crawl_children = callback (fold, baton); - } + if (callback != NULL) { + crawl_children = callback(fold, baton); + } - if (crawl_children) { - crawl_folders_body (crawl, fold, callback, baton); + if (crawl_children) { + crawl_folders_body(crawl, fold, callback, baton); + } } - } - crawl->start = os; - crawl->foldp = of; + crawl->start = os; + crawl->foldp = of; } void -crawl_folders (char *dir, crawl_callback_t *callback, void *baton) +crawl_folders(char *dir, crawl_callback_t *callback, void *baton) { - struct crawl_context *crawl = mh_xmalloc (sizeof(*crawl)); - crawl->max = CRAWL_NUMFOLDERS; - crawl->total = crawl->start = crawl->foldp = 0; - crawl->folders = mh_xmalloc (crawl->max * sizeof(*crawl->folders)); - - crawl_folders_body (crawl, dir, callback, baton); - - /* Note that we "leak" the folder names, on the assumption that the caller - * is using them. */ - free (crawl->folders); - free (crawl); + struct crawl_context *crawl = mh_xmalloc(sizeof(*crawl)); + crawl->max = CRAWL_NUMFOLDERS; + crawl->total = crawl->start = crawl->foldp = 0; + crawl->folders = mh_xmalloc(crawl->max * sizeof(*crawl->folders)); + + crawl_folders_body(crawl, dir, callback, baton); + + /* + ** Note that we "leak" the folder names, on the assumption that the + ** caller is using them. + */ + free(crawl->folders); + free(crawl); } diff --git a/sbr/discard.c b/sbr/discard.c index dbc865c..d3eabd0 100644 --- a/sbr/discard.c +++ b/sbr/discard.c @@ -1,67 +1,31 @@ - /* - * discard.c -- discard output on a file pointer - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** discard.c -- discard output on a file pointer +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include - -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# else -# include -# endif -#endif - -#ifdef SCO_5_STDIO -# define _ptr __ptr -# define _cnt __cnt -# define _base __base -# define _filbuf(fp) ((fp)->__cnt = 0, __filbuf(fp)) -#endif +#include void -discard (FILE *io) +discard(FILE *io) { -#ifndef HAVE_TERMIOS_H -# ifdef HAVE_TERMIO_H - struct termio tio; -# else - struct sgttyb tio; -# endif -#endif + if (io == NULL) + return; - if (io == NULL) - return; - -#ifdef HAVE_TERMIOS_H - tcflush (fileno(io), TCOFLUSH); -#else -# ifdef HAVE_TERMIO_H - if (ioctl (fileno(io), TCGETA, &tio) != -1) - ioctl (fileno(io), TCSETA, &tio); -# else - if (ioctl (fileno(io), TIOCGETP, (char *) &tio) != -1) - ioctl (fileno(io), TIOCSETP, (char *) &tio); -# endif -#endif + tcflush(fileno(io), TCOFLUSH); #if defined(_FSTDIO) || defined(__DragonFly__) - fpurge (io); + fpurge(io); #else # ifdef LINUX_STDIO - io->_IO_write_ptr = io->_IO_write_base; + io->_IO_write_ptr = io->_IO_write_base; # else - if ((io->_ptr = io->_base)) - io->_cnt = 0; + if ((io->_ptr = io->_base)) + io->_cnt = 0; # endif #endif } - diff --git a/sbr/done.c b/sbr/done.c index 05bcf52..3545d10 100644 --- a/sbr/done.c +++ b/sbr/done.c @@ -1,11 +1,10 @@ - /* - * done.c -- terminate the program - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** done.c -- terminate the program +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include diff --git a/sbr/dtime.c b/sbr/dtime.c index 2e978d7..738ffd5 100644 --- a/sbr/dtime.c +++ b/sbr/dtime.c @@ -1,516 +1,406 @@ - /* - * dtime.c -- time/date routines - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** dtime.c -- time/date routines +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* for snprintf() */ #include #include +#include -#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_TZSET) -# include -#endif - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && defined(HAVE_TZSET) -extern int daylight; +#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) extern long timezone; -extern char *tzname[]; -#endif - -#ifndef abs -# define abs(a) (a >= 0 ? a : -a) #endif /* - * The number of days in the year, accounting for leap years - */ -#define dysize(y) \ +** The number of days in the year, accounting for leap years +*/ +#define dysize(y) \ (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366))) char *tw_moty[] = { - "Jan", "Feb", "Mar", "Apr", - "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec", - NULL + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", + NULL }; char *tw_dotw[] = { - "Sun", "Mon", "Tue", - "Wed", "Thu", "Fri", - "Sat", NULL + "Sun", "Mon", "Tue", + "Wed", "Thu", "Fri", + "Sat", NULL }; char *tw_ldotw[] = { - "Sunday", "Monday", "Tuesday", - "Wednesday", "Thursday", "Friday", - "Saturday", NULL + "Sunday", "Monday", "Tuesday", + "Wednesday", "Thursday", "Friday", + "Saturday", NULL }; struct zone { - char *std; - char *dst; - int shift; -}; - -static struct zone zones[] = { - { "GMT", "BST", 0 }, - { "EST", "EDT", -5 }, - { "CST", "CDT", -6 }, - { "MST", "MDT", -7 }, - { "PST", "PDT", -8 }, -#if 0 -/* RFC1123 specifies do not use military TZs */ - { "A", NULL, -1 }, - { "B", NULL, -2 }, - { "C", NULL, -3 }, - { "D", NULL, -4 }, - { "E", NULL, -5 }, - { "F", NULL, -6 }, - { "G", NULL, -7 }, - { "H", NULL, -8 }, - { "I", NULL, -9 }, - { "K", NULL, -10 }, - { "L", NULL, -11 }, - { "M", NULL, -12 }, - { "N", NULL, 1 }, -#ifndef HUJI - { "O", NULL, 2 }, -#else - { "JST", "JDT", 2 }, -#endif - { "P", NULL, 3 }, - { "Q", NULL, 4 }, - { "R", NULL, 5 }, - { "S", NULL, 6 }, - { "T", NULL, 7 }, - { "U", NULL, 8 }, - { "V", NULL, 9 }, - { "W", NULL, 10 }, - { "X", NULL, 11 }, - { "Y", NULL, 12 }, -#endif - { NULL, NULL, 0 } + char *std; + char *dst; + int shift; }; static int dmsize[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* - * Get current time (adjusted for local time - * zone and daylight savings time) expressed - * as nmh "broken-down" time structure. - */ +** Get current time (adjusted for local time +** zone and daylight savings time) expressed +** as nmh "broken-down" time structure. +*/ struct tws * -dlocaltimenow (void) +dlocaltimenow(void) { - time_t clock; + time_t clock; - time (&clock); - return dlocaltime (&clock); + time(&clock); + return dlocaltime(&clock); } /* - * Take clock value and return pointer to nmh time structure - * containing "broken-down" time. The time is adjusted for - * local time zone and daylight savings time. - */ +** Take clock value and return pointer to nmh time structure +** containing "broken-down" time. The time is adjusted for +** local time zone and daylight savings time. +*/ struct tws * -dlocaltime (time_t *clock) +dlocaltime(time_t *clock) { - static struct tws tw; - struct tm *tm; - -#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_TZSET) - struct timeb tb; -#endif + static struct tws tw; + struct tm *tm; - if (!clock) - return NULL; + if (!clock) + return NULL; - tm = localtime (clock); + tm = localtime(clock); - tw.tw_sec = tm->tm_sec; - tw.tw_min = tm->tm_min; - tw.tw_hour = tm->tm_hour; - tw.tw_mday = tm->tm_mday; - tw.tw_mon = tm->tm_mon; + tw.tw_sec = tm->tm_sec; + tw.tw_min = tm->tm_min; + tw.tw_hour = tm->tm_hour; + tw.tw_mday = tm->tm_mday; + tw.tw_mon = tm->tm_mon; - /* - * tm_year is always "year - 1900". - * So we correct for this. - */ - tw.tw_year = tm->tm_year + 1900; - tw.tw_wday = tm->tm_wday; - tw.tw_yday = tm->tm_yday; + /* + * tm_year is always "year - 1900". + * So we correct for this. + */ + tw.tw_year = tm->tm_year + 1900; + tw.tw_wday = tm->tm_wday; + tw.tw_yday = tm->tm_yday; - tw.tw_flags = TW_NULL; - if (tm->tm_isdst) - tw.tw_flags |= TW_DST; + tw.tw_flags = TW_NULL; + if (tm->tm_isdst) + tw.tw_flags |= TW_DST; #ifdef HAVE_STRUCT_TM_TM_GMTOFF - tw.tw_zone = tm->tm_gmtoff / 60; - if (tm->tm_isdst) /* if DST is in effect */ - tw.tw_zone -= 60; /* reset to normal offset */ + tw.tw_zone = tm->tm_gmtoff / 60; + if (tm->tm_isdst) /* if DST is in effect */ + tw.tw_zone -= 60; /* reset to normal offset */ #else -# ifdef HAVE_TZSET - tzset(); - tw.tw_zone = -(timezone / 60); -# else - ftime (&tb); - tw.tw_zone = -tb.timezone; -# endif + tzset(); + tw.tw_zone = -(timezone / 60); #endif - tw.tw_flags &= ~TW_SDAY; - tw.tw_flags |= TW_SEXP; - tw.tw_flags &= ~TW_SZONE; - tw.tw_flags |= TW_SZEXP; + tw.tw_flags &= ~TW_SDAY; + tw.tw_flags |= TW_SEXP; + tw.tw_flags &= ~TW_SZONE; + tw.tw_flags |= TW_SZEXP; - tw.tw_clock = *clock; + tw.tw_clock = *clock; - return (&tw); + return (&tw); } /* - * Take clock value and return pointer to nmh time - * structure containing "broken-down" time. Time is - * expressed in UTC (Coordinated Universal Time). - */ +** Take clock value and return pointer to nmh time +** structure containing "broken-down" time. Time is +** expressed in UTC (Coordinated Universal Time). +*/ struct tws * -dgmtime (time_t *clock) +dgmtime(time_t *clock) { - static struct tws tw; - struct tm *tm; + static struct tws tw; + struct tm *tm; - if (!clock) - return NULL; + if (!clock) + return NULL; - tm = gmtime (clock); + tm = gmtime(clock); - tw.tw_sec = tm->tm_sec; - tw.tw_min = tm->tm_min; - tw.tw_hour = tm->tm_hour; - tw.tw_mday = tm->tm_mday; - tw.tw_mon = tm->tm_mon; + tw.tw_sec = tm->tm_sec; + tw.tw_min = tm->tm_min; + tw.tw_hour = tm->tm_hour; + tw.tw_mday = tm->tm_mday; + tw.tw_mon = tm->tm_mon; - /* - * tm_year is always "year - 1900" - * So we correct for this. - */ - tw.tw_year = tm->tm_year + 1900; - tw.tw_wday = tm->tm_wday; - tw.tw_yday = tm->tm_yday; + /* + * tm_year is always "year - 1900" + * So we correct for this. + */ + tw.tw_year = tm->tm_year + 1900; + tw.tw_wday = tm->tm_wday; + tw.tw_yday = tm->tm_yday; - tw.tw_flags = TW_NULL; - if (tm->tm_isdst) - tw.tw_flags |= TW_DST; + tw.tw_flags = TW_NULL; + if (tm->tm_isdst) + tw.tw_flags |= TW_DST; - tw.tw_zone = 0; + tw.tw_zone = 0; - tw.tw_flags &= ~TW_SDAY; - tw.tw_flags |= TW_SEXP; - tw.tw_flags &= ~TW_SZONE; - tw.tw_flags |= TW_SZEXP; + tw.tw_flags &= ~TW_SDAY; + tw.tw_flags |= TW_SEXP; + tw.tw_flags &= ~TW_SZONE; + tw.tw_flags |= TW_SZEXP; - tw.tw_clock = *clock; + tw.tw_clock = *clock; - return (&tw); + return (&tw); } /* - * Using a nmh "broken-down" time structure, - * produce a 26-byte date/time string, such as - * - * Tue Jan 14 17:49:03 1992\n\0 - */ +** Using a nmh "broken-down" time structure, +** produce a 26-byte date/time string, such as +** +** Tue Jan 14 17:49:03 1992\n\0 +*/ char * -dctime (struct tws *tw) +dctime(struct tws *tw) { - static char buffer[26]; + static char buffer[26]; - if (!tw) - return NULL; + if (!tw) + return NULL; - snprintf (buffer, sizeof(buffer), "%.3s %.3s %02d %02d:%02d:%02d %.4d\n", - tw_dotw[tw->tw_wday], tw_moty[tw->tw_mon], tw->tw_mday, - tw->tw_hour, tw->tw_min, tw->tw_sec, - tw->tw_year < 100 ? tw->tw_year + 1900 : tw->tw_year); + snprintf(buffer, sizeof(buffer), "%.3s %.3s %02d %02d:%02d:%02d %.4d\n", + tw_dotw[tw->tw_wday], tw_moty[tw->tw_mon], tw->tw_mday, + tw->tw_hour, tw->tw_min, tw->tw_sec, + tw->tw_year < 100 ? tw->tw_year + 1900 : tw->tw_year); - return buffer; + return buffer; } /* - * Produce a date/time string of the form - * - * Mon, 16 Jun 1992 15:30:48 -700 (or) - * Mon, 16 Jun 1992 15:30:48 EDT - * - * for the current time, as specified by rfc822. - * The first form is required by rfc1123. - */ - +** Produce a date/time string of the form +** +** Mon, 16 Jun 1992 15:30:48 -0700 +** +** for the current time, as specified by rfc822 and rfc1123. +*/ char * -dtimenow (int alpha_timezone) +dtimenow(void) { - time_t clock; + time_t clock; - time (&clock); - return dtime (&clock, alpha_timezone); + time(&clock); + return dtime(&clock); } /* - * Using a local calendar time value, produce - * a date/time string of the form - * - * Mon, 16 Jun 1992 15:30:48 -700 (or) - * Mon, 16 Jun 1992 15:30:48 EDT - * - * as specified by rfc822. The first form is required - * by rfc1123 for outgoing messages. - */ - +** Using a local calendar time value, produce +** a date/time string of the form +** +** Mon, 16 Jun 1992 15:30:48 -0700 +** +** as specified by rfc822 and rfc1123. +*/ char * -dtime (time_t *clock, int alpha_timezone) +dtime(time_t *clock) { - if (alpha_timezone) - /* use alpha-numeric timezones */ - return dasctime (dlocaltime (clock), TW_NULL); - else - /* use numeric timezones */ - return dasctime (dlocaltime (clock), TW_ZONE); + return dasctime(dlocaltime(clock)); } /* - * Using a nmh "broken-down" time structure, produce - * a date/time string of the form - * - * Mon, 16 Jun 1992 15:30:48 -0700 - * - * as specified by rfc822 and rfc1123. - */ - +** Using a nmh "broken-down" time structure, produce +** a date/time string of the form +** +** Mon, 16 Jun 1992 15:30:48 -0700 +** +** as specified by rfc822 and rfc1123. +*/ char * -dasctime (struct tws *tw, int flags) +dasctime(struct tws *tw) { - char buffer[80]; - static char result[80]; - - if (!tw) - return NULL; - - /* Display timezone if known */ - if ((tw->tw_flags & TW_SZONE) == TW_SZNIL) - result[0] = '\0'; - else - snprintf(result, sizeof(result), " %s", dtimezone(tw->tw_zone, tw->tw_flags | flags)); - - snprintf(buffer, sizeof(buffer), "%02d %s %0*d %02d:%02d:%02d%s", - tw->tw_mday, tw_moty[tw->tw_mon], - tw->tw_year < 100 ? 2 : 4, tw->tw_year, - tw->tw_hour, tw->tw_min, tw->tw_sec, result); - - if ((tw->tw_flags & TW_SDAY) == TW_SEXP) - snprintf (result, sizeof(result), "%s, %s", tw_dotw[tw->tw_wday], buffer); - else - if ((tw->tw_flags & TW_SDAY) == TW_SNIL) - strncpy (result, buffer, sizeof(result)); + char buffer[80]; + static char result[80]; + + if (!tw) + return NULL; + + /* Display timezone if known */ + if ((tw->tw_flags & TW_SZONE) == TW_SZNIL) + result[0] = '\0'; else - snprintf (result, sizeof(result), "%s (%s)", buffer, tw_dotw[tw->tw_wday]); + snprintf(result, sizeof(result), " %s", dtimezone(tw->tw_zone, tw->tw_flags)); - return result; + snprintf(buffer, sizeof(buffer), "%02d %s %0*d %02d:%02d:%02d%s", + tw->tw_mday, tw_moty[tw->tw_mon], + tw->tw_year < 100 ? 2 : 4, tw->tw_year, + tw->tw_hour, tw->tw_min, tw->tw_sec, result); + + if ((tw->tw_flags & TW_SDAY) == TW_SEXP) + snprintf(result, sizeof(result), "%s, %s", tw_dotw[tw->tw_wday], buffer); + else + if ((tw->tw_flags & TW_SDAY) == TW_SNIL) + strncpy(result, buffer, sizeof(result)); + else + snprintf(result, sizeof(result), "%s (%s)", buffer, tw_dotw[tw->tw_wday]); + + return result; } /* - * Get the timezone for given offset - */ - +** Get the timezone for given offset as numeric value. +*/ char * -dtimezone (int offset, int flags) +dtimezone(int offset, int flags) { - int hours, mins; - struct zone *z; - static char buffer[10]; - - if (offset < 0) { - mins = -((-offset) % 60); - hours = -((-offset) / 60); - } else { - mins = offset % 60; - hours = offset / 60; - } - - if (!(flags & TW_ZONE) && mins == 0) { -#if defined(HAVE_TZSET) && defined(HAVE_TZNAME) - tzset(); - return ((flags & TW_DST) ? tzname[1] : tzname[0]); -#else - for (z = zones; z->std; z++) - if (z->shift == hours) - return (z->dst && (flags & TW_DST) ? z->dst : z->std); -#endif - } + int hours, mins; + static char buffer[10]; + + if (offset < 0) { + mins = -((-offset) % 60); + hours = -((-offset) / 60); + } else { + mins = offset % 60; + hours = offset / 60; + } #ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST - if (flags & TW_DST) - hours += 1; + if (flags & TW_DST) + hours += 1; #endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ - snprintf (buffer, sizeof(buffer), "%s%02d%02d", - offset < 0 ? "-" : "+", abs (hours), abs (mins)); - return buffer; + snprintf(buffer, sizeof(buffer), "%s%02d%02d", + offset < 0 ? "-" : "+", abs(hours), abs(mins)); + return buffer; } /* - * Convert nmh time structure for local "broken-down" - * time to calendar time (clock value). This routine - * is based on the gtime() routine written by Steven Shafer - * at CMU. It was forwarded to MTR by Jay Lepreau at Utah-CS. - */ +** Convert nmh time structure for local "broken-down" +** time to calendar time (clock value). This routine +** is based on the gtime() routine written by Steven Shafer +** at CMU. It was forwarded to MTR by Jay Lepreau at Utah-CS. +*/ time_t -dmktime (struct tws *tw) +dmktime(struct tws *tw) { - int i, sec, min, hour, mday, mon, year; - time_t result; - - if (tw->tw_clock != 0) - return tw->tw_clock; - - if ((sec = tw->tw_sec) < 0 || sec > 61 - || (min = tw->tw_min) < 0 || min > 59 - || (hour = tw->tw_hour) < 0 || hour > 23 - || (mday = tw->tw_mday) < 1 || mday > 31 - || (mon = tw->tw_mon + 1) < 1 || mon > 12) - return (tw->tw_clock = (time_t) -1); - - year = tw->tw_year; - - result = 0; - if (year < 1970) - year += 1900; - - if (year < 1970) - year += 100; - - for (i = 1970; i < year; i++) - result += dysize (i); - if (dysize (year) == 366 && mon >= 3) - result++; - while (--mon) - result += dmsize[mon - 1]; - result += mday - 1; - result = 24 * result + hour; - result = 60 * result + min; - result = 60 * result + sec; - result -= 60 * tw->tw_zone; - if (tw->tw_flags & TW_DST) - result -= 60 * 60; - - return (tw->tw_clock = result); + int i, sec, min, hour, mday, mon, year; + time_t result; + + if (tw->tw_clock != 0) + return tw->tw_clock; + + if ((sec = tw->tw_sec) < 0 || sec > 61 + || (min = tw->tw_min) < 0 || min > 59 + || (hour = tw->tw_hour) < 0 || hour > 23 + || (mday = tw->tw_mday) < 1 || mday > 31 + || (mon = tw->tw_mon + 1) < 1 || mon > 12) + return (tw->tw_clock = (time_t) -1); + + year = tw->tw_year; + + result = 0; + if (year < 1970) + year += 1900; + + if (year < 1970) + year += 100; + + for (i = 1970; i < year; i++) + result += dysize(i); + if (dysize(year) == 366 && mon >= 3) + result++; + while (--mon) + result += dmsize[mon - 1]; + result += mday - 1; + result = 24 * result + hour; + result = 60 * result + min; + result = 60 * result + sec; + result -= 60 * tw->tw_zone; + if (tw->tw_flags & TW_DST) + result -= 60 * 60; + + return (tw->tw_clock = result); } /* - * Simple calculation of day of the week. Algorithm - * used is Zeller's congruence. We assume that - * if tw->tw_year < 100, then the century = 19. - */ +** Simple calculation of day of the week. Algorithm +** used is Zeller's congruence. We assume that +** if tw->tw_year < 100, then the century = 19. +*/ void -set_dotw (struct tws *tw) +set_dotw(struct tws *tw) { - int month, day, year, century; - - month = tw->tw_mon - 1; - day = tw->tw_mday; - year = tw->tw_year % 100; - century = tw->tw_year < 100 ? 19 : tw->tw_year / 100; - - if (month <= 0) { - month += 12; - if (--year < 0) { - year += 100; - century--; + int month, day, year, century; + + month = tw->tw_mon - 1; + day = tw->tw_mday; + year = tw->tw_year % 100; + century = tw->tw_year < 100 ? 19 : tw->tw_year / 100; + + if (month <= 0) { + month += 12; + if (--year < 0) { + year += 100; + century--; + } } - } - tw->tw_wday = - ((26 * month - 2) / 10 + day + year + year / 4 - - 3 * century / 4 + 1) % 7; - if (tw->tw_wday < 0) - tw->tw_wday += 7; + tw->tw_wday = ((26 * month - 2) / 10 + day + year + year / 4 + - 3 * century / 4 + 1) % 7; + if (tw->tw_wday < 0) + tw->tw_wday += 7; - tw->tw_flags &= ~TW_SDAY, tw->tw_flags |= TW_SIMP; + tw->tw_flags &= ~TW_SDAY, tw->tw_flags |= TW_SIMP; } /* - * Copy nmh time structure - */ +** Copy nmh time structure +*/ void -twscopy (struct tws *tb, struct tws *tw) +twscopy(struct tws *tb, struct tws *tw) { - *tb = *tw; /* struct copy */ - -#if 0 - tb->tw_sec = tw->tw_sec; - tb->tw_min = tw->tw_min; - tb->tw_hour = tw->tw_hour; - tb->tw_mday = tw->tw_mday; - tb->tw_mon = tw->tw_mon; - tb->tw_year = tw->tw_year; - tb->tw_wday = tw->tw_wday; - tb->tw_yday = tw->tw_yday; - tb->tw_zone = tw->tw_zone; - tb->tw_clock = tw->tw_clock; - tb->tw_flags = tw->tw_flags; -#endif + *tb = *tw; /* struct copy */ } /* - * Compare two nmh time structures - */ +** Compare two nmh time structures +*/ int -twsort (struct tws *tw1, struct tws *tw2) +twsort(struct tws *tw1, struct tws *tw2) { - time_t c1, c2; + time_t c1, c2; - if (tw1->tw_clock == 0) - dmktime (tw1); - if (tw2->tw_clock == 0) - dmktime (tw2); + if (tw1->tw_clock == 0) + dmktime(tw1); + if (tw2->tw_clock == 0) + dmktime(tw2); - return ((c1 = tw1->tw_clock) > (c2 = tw2->tw_clock) ? 1 - : c1 == c2 ? 0 : -1); + return ((c1 = tw1->tw_clock) > (c2 = tw2->tw_clock) ? 1 + : c1 == c2 ? 0 : -1); } diff --git a/sbr/dtimep.lex b/sbr/dtimep.lex index 0191086..133a9ab 100644 --- a/sbr/dtimep.lex +++ b/sbr/dtimep.lex @@ -34,14 +34,14 @@ */ #define yyterminate() (void)yy_delete_buffer(lexhandle); \ - if(!(tw.tw_flags & TW_SUCC)) { \ - return (struct tws *)NULL; \ - } \ - if(tw.tw_year < 1970) \ - tw.tw_year += 1900; \ - if(tw.tw_year < 1970) \ - tw.tw_year += 100; \ - return(&tw) + if(!(tw.tw_flags & TW_SUCC)) { \ + return (struct tws *)NULL; \ + } \ + if(tw.tw_year < 1970) \ + tw.tw_year += 1900; \ + if(tw.tw_year < 1970) \ + tw.tw_year += 100; \ + return(&tw) /* * Patchable flag that says how to interpret NN/NN/NN dates. When @@ -121,71 +121,48 @@ static int day_map[] = { * character of a particular class. */ -#define INIT() { cp = yytext;} -#define SETWDAY() { tw.tw_wday= day_map[(cp[0] & 7) + (cp[1] & 4)]; \ - tw.tw_flags &= ~TW_SDAY; tw.tw_flags |= TW_SEXP; \ - SKIPA(); } -#define SETMON() { cp++; \ - tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; \ - SKIPA(); } -#define SETMON_NUM() { tw.tw_mon = atoi(cp)-1; \ - SKIPD(); } -#define SETYEAR() { tw.tw_year = atoi(cp); \ - SKIPD(); } -#define SETDAY() { tw.tw_mday = atoi(cp); \ - tw.tw_flags |= TW_YES; \ - SKIPD(); } -#define SETTIME() { tw.tw_hour = atoi(cp); \ - cp += 2; \ - SKIPTOD(); \ - tw.tw_min = atoi(cp); \ - cp += 2; \ - if(*cp == ':') { \ - tw.tw_sec = atoi(++cp); SKIPD(); } } -#define SETZONE(x) { tw.tw_zone = ((x)/100)*60+(x)%100; \ - tw.tw_flags |= TW_SZEXP; \ - SKIPD(); } -#define SETDST() { tw.tw_flags |= TW_DST; } -#define SKIPD() { while ( isdigit(*cp++) ) ; \ - --cp; } -#define SKIPTOD() { while ( !isdigit(*cp++) ) ; \ - --cp; } -#define SKIPA() { while ( isalpha(*cp++) ) ; \ - --cp; } -#define SKIPTOA() { while ( !isalpha(*cp++) ) ; \ - --cp; } -#define SKIPSP() { while ( isspace(*cp++) ) ; \ - --cp; } -#define SKIPTOSP() { while ( !isspace(*cp++) ) ; \ - --cp; } +#define INIT() { cp = yytext;} +#define SETWDAY() { tw.tw_wday= day_map[(cp[0] & 7) + (cp[1] & 4)]; \ + tw.tw_flags &= ~TW_SDAY; tw.tw_flags |= TW_SEXP; SKIPA(); } +#define SETMON() { cp++; tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; \ + SKIPA(); } +#define SETMON_NUM() { tw.tw_mon = atoi(cp)-1; SKIPD(); } +#define SETYEAR() { tw.tw_year = atoi(cp); SKIPD(); } +#define SETDAY() { tw.tw_mday = atoi(cp); tw.tw_flags |= TW_YES; SKIPD(); } +#define SETTIME() { tw.tw_hour = atoi(cp); cp += 2; SKIPTOD(); \ + tw.tw_min = atoi(cp); cp += 2; if(*cp == ':') { \ + tw.tw_sec = atoi(++cp); SKIPD(); } } +#define SETZONE(x) { tw.tw_zone = ((x)/100)*60+(x)%100; \ + tw.tw_flags |= TW_SZEXP; SKIPD(); } +#define SETDST() { tw.tw_flags |= TW_DST; } +#define SKIPD() { while ( isdigit(*cp++) ) ; --cp; } +#define SKIPTOD() { while ( !isdigit(*cp++) ) ; --cp; } +#define SKIPA() { while ( isalpha(*cp++) ) ; --cp; } +#define SKIPTOA() { while ( !isalpha(*cp++) ) ; --cp; } +#define SKIPSP() { while ( isspace(*cp++) ) ; --cp; } +#define SKIPTOSP() { while ( !isspace(*cp++) ) ; --cp; } #ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST -# ifdef TIME_WITH_SYS_TIME +# ifdef HAVE_SYS_TIME_H # include -# include -# else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif # endif +#include static void zonehack (struct tws *tw) { - register struct tm *tm; + register struct tm *tm; - if (dmktime (tw) == (time_t) -1) - return; + if (dmktime (tw) == (time_t) -1) + return; - tm = localtime (&tw->tw_clock); - if (tm->tm_isdst) { - tw->tw_flags |= TW_DST; - tw->tw_zone -= 60; - } + tm = localtime (&tw->tw_clock); + if (tm->tm_isdst) { + tw->tw_flags |= TW_DST; + tw->tw_zone -= 60; + } } -#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ +#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ %} sun ([Ss]un(day)?) @@ -213,201 +190,195 @@ dec ([Dd]ec(ember)?) MONTH ({jan}|{feb}|{mar}|{apr}|{may}|{jun}|{jul}|{aug}|{sep}|{oct}|{nov}|{dec}) -TIME ({D}:{d}{d}(:{d}{d})?) +TIME ({D}:{d}{d}(:{d}{d})?) - /* The year can either be 2 digits, or 4. However, after - Y2K, we found that some MUA were reporting the year 100, hence - the middle term here. yyterminate() resolves the actual - issues with 2-digit years. - */ +/* + * The year can either be 2 digits, or 4. However, after + * Y2K, we found that some MUA were reporting the year 100, hence + * the middle term here. yyterminate() resolves the actual + * issues with 2-digit years. + */ -YEAR (({d}{d})|(1{d}{d})|({d}{4})) +YEAR (({d}{d})|(1{d}{d})|({d}{4})) w ([ \t]*) W ([ \t]+) D ([0-9]?[0-9]) d [0-9] -nl [ \t\n()] +nl [ \t\n()] %% %{ - /* This section begins the definition of dparsetime(). - Put here any local variable definitions and initializations */ - - YY_BUFFER_STATE lexhandle; + /* This section begins the definition of dparsetime(). + * Put here any local variable definitions and initializations */ + + YY_BUFFER_STATE lexhandle; - register unsigned char *cp; - static struct tws tw; + register unsigned char *cp; + static struct tws tw; - memset(&tw,0,sizeof(struct tws)); + memset(&tw,0,sizeof(struct tws)); - lexhandle = yy_scan_string(lexstr); + lexhandle = yy_scan_string(lexstr); %} -{DAY}","?{W}{MONTH}{W}{D}{W}{TIME}{W}{YEAR} { - INIT(); - SETWDAY(); - SKIPTOA(); - SETMON(); - SKIPTOD(); - SETDAY(); - SKIPTOD(); - SETTIME(); - SKIPTOD(); - SETYEAR(); - } - -{DAY}","?{W}{D}{W}{MONTH}{W}{YEAR}{W}{TIME} { - INIT(); - SETWDAY(); - SKIPTOD(); - SETDAY(); - SKIPTOA(); - SETMON(); - SKIPTOD(); - SETYEAR(); - SKIPTOD(); - SETTIME(); - } -{D}{W}{MONTH}{W}{YEAR}{W}{TIME} { - INIT(); - SETDAY(); - SKIPTOA(); - SETMON(); - SKIPTOD(); - SETYEAR(); - SKIPTOD(); - SETTIME(); - } -{DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR}","?{W}{TIME} { - INIT(); - SETWDAY(); - SKIPTOA(); - SETMON(); - SKIPTOD(); - SETDAY(); - SKIPTOD(); - SETYEAR(); - SKIPTOD(); - SETTIME(); - } -{DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR} { - INIT(); - SETWDAY(); - SKIPTOA(); - SETMON(); - SKIPTOD(); - SETDAY(); - SKIPTOD(); - SETYEAR(); - } -{MONTH}{W}{D}","?{W}{YEAR}","?{W}{DAY} { - INIT(); - SETMON(); - SKIPTOD(); - SETDAY(); - SKIPTOD(); - SETYEAR(); - SKIPTOA(); - SETWDAY(); - } -{MONTH}{W}{D}","?{W}{YEAR} { - INIT(); - SETMON(); - SKIPTOD(); - SETDAY(); - SKIPTOD(); - SETYEAR(); - } -{D}("-"|"/"){D}("-"|"/"){YEAR}{W}{TIME} { - INIT(); - if(europeandate) { - /* DD/MM/YY */ - SETDAY(); - SKIPTOD(); - SETMON_NUM(); - } else { - /* MM/DD/YY */ - SETMON_NUM(); - SKIPTOD(); - SETDAY(); - } - SKIPTOD(); - SETYEAR(); - SKIPTOD(); - SETTIME(); - } -{D}("-"|"/"){D}("-"|"/"){YEAR} { - INIT(); - if(europeandate) { - /* DD/MM/YY */ - SETDAY(); - SKIPTOD(); - SETMON_NUM(); - } else { - /* MM/DD/YY */ - SETMON_NUM(); - SKIPTOD(); - SETDAY(); - } - SKIPTOD(); - SETYEAR(); - } +{DAY}","?{W}{MONTH}{W}{D}{W}{TIME}{W}{YEAR} { + INIT(); + SETWDAY(); + SKIPTOA(); + SETMON(); + SKIPTOD(); + SETDAY(); + SKIPTOD(); + SETTIME(); + SKIPTOD(); + SETYEAR(); +} + +{DAY}","?{W}{D}{W}{MONTH}{W}{YEAR}{W}{TIME} { + INIT(); + SETWDAY(); + SKIPTOD(); + SETDAY(); + SKIPTOA(); + SETMON(); + SKIPTOD(); + SETYEAR(); + SKIPTOD(); + SETTIME(); +} +{D}{W}{MONTH}{W}{YEAR}{W}{TIME} { + INIT(); + SETDAY(); + SKIPTOA(); + SETMON(); + SKIPTOD(); + SETYEAR(); + SKIPTOD(); + SETTIME(); +} +{DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR}","?{W}{TIME} { + INIT(); + SETWDAY(); + SKIPTOA(); + SETMON(); + SKIPTOD(); + SETDAY(); + SKIPTOD(); + SETYEAR(); + SKIPTOD(); + SETTIME(); +} +{DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR} { + INIT(); + SETWDAY(); + SKIPTOA(); + SETMON(); + SKIPTOD(); + SETDAY(); + SKIPTOD(); + SETYEAR(); +} +{MONTH}{W}{D}","?{W}{YEAR}","?{W}{DAY} { + INIT(); + SETMON(); + SKIPTOD(); + SETDAY(); + SKIPTOD(); + SETYEAR(); + SKIPTOA(); + SETWDAY(); +} +{MONTH}{W}{D}","?{W}{YEAR} { + INIT(); + SETMON(); + SKIPTOD(); + SETDAY(); + SKIPTOD(); + SETYEAR(); +} +{D}("-"|"/"){D}("-"|"/"){YEAR}{W}{TIME} { + INIT(); + if(europeandate) { + /* DD/MM/YY */ + SETDAY(); + SKIPTOD(); + SETMON_NUM(); + } else { + /* MM/DD/YY */ + SETMON_NUM(); + SKIPTOD(); + SETDAY(); + } + SKIPTOD(); + SETYEAR(); + SKIPTOD(); + SETTIME(); +} +{D}("-"|"/"){D}("-"|"/"){YEAR} { + INIT(); + if(europeandate) { + /* DD/MM/YY */ + SETDAY(); + SKIPTOD(); + SETMON_NUM(); + } else { + /* MM/DD/YY */ + SETMON_NUM(); + SKIPTOD(); + SETDAY(); + } + SKIPTOD(); + SETYEAR(); +} "[Aa][Mm]" -"[Pp][Mm]" tw.tw_hour += 12; - -"+"{D}{d}{d} { - INIT(); - SKIPTOD(); - SETZONE(atoi(cp)); -#ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST - zonehack (&tw); -#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ - yyterminate(); - } -"-"{D}{d}{d} { - INIT(); - SKIPTOD(); - SETZONE(-atoi(cp)); -#ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST - zonehack (&tw); -#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ - yyterminate(); - - } -{nl}("ut"|"UT") INIT(); SETZONE(0); yyterminate(); -{nl}("gmt"|"GMT") INIT(); SETZONE(0); yyterminate(); -{nl}("est"|"EST") INIT(); SETZONE(-500); yyterminate(); -{nl}("edt"|"EDT") { INIT(); SETDST(); SETZONE(-500); - yyterminate(); } -{nl}("cst"|"CST") INIT(); SETZONE(-600); yyterminate(); -{nl}("cdt"|"CDT") { INIT(); SETDST(); SETZONE(-600); - yyterminate(); } -{nl}("mst"|"MST") INIT(); SETZONE(-700); yyterminate(); -{nl}("mdt"|"MDT") { INIT(); SETDST(); SETZONE(-700); - yyterminate(); } -{nl}("pst"|"PST") INIT(); SETZONE(-800); yyterminate(); -{nl}("pdt"|"PDT") { INIT(); SETDST(); SETZONE(-800); - yyterminate(); } -{nl}("nst"|"NST") INIT(); SETZONE(-330); yyterminate(); -{nl}("ast"|"AST") INIT(); SETZONE(-400); yyterminate(); -{nl}("adt"|"ADT") { INIT(); SETDST(); SETZONE(-400); - yyterminate(); } -{nl}("hst"|"HST") INIT(); SETZONE(-1000); yyterminate(); -{nl}("hdt"|"HDT") { INIT(); SETDST(); SETZONE(-1000); - yyterminate(); } +"[Pp][Mm]" tw.tw_hour += 12; + +"+"{D}{d}{d} { + INIT(); + SKIPTOD(); + SETZONE(atoi(cp)); +#ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST + zonehack (&tw); +#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ + yyterminate(); +} +"-"{D}{d}{d} { + INIT(); + SKIPTOD(); + SETZONE(-atoi(cp)); +#ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST + zonehack (&tw); +#endif /* ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST */ + yyterminate(); + +} +{nl}("ut"|"UT") INIT(); SETZONE(0); yyterminate(); +{nl}("gmt"|"GMT") INIT(); SETZONE(0); yyterminate(); +{nl}("est"|"EST") INIT(); SETZONE(-500); yyterminate(); +{nl}("edt"|"EDT") { INIT(); SETDST(); SETZONE(-500); yyterminate(); } +{nl}("cst"|"CST") INIT(); SETZONE(-600); yyterminate(); +{nl}("cdt"|"CDT") { INIT(); SETDST(); SETZONE(-600); yyterminate(); } +{nl}("mst"|"MST") INIT(); SETZONE(-700); yyterminate(); +{nl}("mdt"|"MDT") { INIT(); SETDST(); SETZONE(-700); yyterminate(); } +{nl}("pst"|"PST") INIT(); SETZONE(-800); yyterminate(); +{nl}("pdt"|"PDT") { INIT(); SETDST(); SETZONE(-800); yyterminate(); } +{nl}("nst"|"NST") INIT(); SETZONE(-330); yyterminate(); +{nl}("ast"|"AST") INIT(); SETZONE(-400); yyterminate(); +{nl}("adt"|"ADT") { INIT(); SETDST(); SETZONE(-400); yyterminate(); } +{nl}("hst"|"HST") INIT(); SETZONE(-1000); yyterminate(); +{nl}("hdt"|"HDT") { INIT(); SETDST(); SETZONE(-1000); yyterminate(); } .|\n %% /* This is a portable way to squash a warning about the yyunput() * function being static but never used. It costs us a tiny amount * of extra code in the binary but the other options are: - * "%option nounput" which is flex-specific - * makefile hackery just to compile dtimep.c with different flags + * "%option nounput" which is flex-specific + * makefile hackery just to compile dtimep.c with different flags */ void dtimep_yyunput(int c) { - unput(c); + unput(c); } - diff --git a/sbr/error.c b/sbr/error.c index 6dc6995..d8313ce 100644 --- a/sbr/error.c +++ b/sbr/error.c @@ -1,142 +1,94 @@ - /* - * error.c -- main error handling routines - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** error.c -- main error handling routines +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include - -#ifdef HAVE_WRITEV -# include -# include -#endif - #include /* - * print out error message - */ +** print out error message +*/ void -advise (char *what, char *fmt, ...) +advise(char *what, char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); + va_start(ap, fmt); + advertise(what, NULL, fmt, ap); + va_end(ap); } /* - * print out error message and exit - */ +** print out error message and exit +*/ void -adios (char *what, char *fmt, ...) +adios(char *what, char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); - done (1); + va_start(ap, fmt); + advertise(what, NULL, fmt, ap); + va_end(ap); + done(1); } /* - * admonish the user - */ +** admonish the user +*/ void -admonish (char *what, char *fmt, ...) +admonish(char *what, char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - advertise (what, "continuing...", fmt, ap); - va_end(ap); + va_start(ap, fmt); + advertise(what, "continuing...", fmt, ap); + va_end(ap); } /* - * main routine for printing error messages. - * - * Use writev() if available, for slightly better performance. - * Why? Well, there are a couple of reasons. Primarily, it - * gives a smoother output... More importantly though, it's a - * sexy syscall()... - */ +** main routine for printing error messages. +** +** Until 2011-11-01, this routine used writev(). In order to remove +** ``sexy'' syscalls, in favor for mainstream programming, I removed +** it. But I want to preserve the following comment: +** +** Use writev() if available, for slightly better performance. +** Why? Well, there are a couple of reasons. Primarily, it +** gives a smoother output... More importantly though, it's a +** sexy syscall()... +** +** advertise() does *not* use writev() anymore, and that's good so. +** -- meillo@marmaro.de +*/ void -advertise (char *what, char *tail, char *fmt, va_list ap) +advertise(char *what, char *tail, char *fmt, va_list ap) { - int eindex = errno; - -#ifdef HAVE_WRITEV - char buffer[BUFSIZ], err[BUFSIZ]; - struct iovec iob[20], *iov; -#endif - - fflush (stdout); - -#ifdef HAVE_WRITEV - fflush (stderr); - iov = iob; - - if (invo_name && *invo_name) { - iov->iov_len = strlen (iov->iov_base = invo_name); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - - vsnprintf (buffer, sizeof(buffer), fmt, ap); - iov->iov_len = strlen (iov->iov_base = buffer); - iov++; - if (what) { - if (*what) { - iov->iov_len = strlen (iov->iov_base = " "); - iov++; - iov->iov_len = strlen (iov->iov_base = what); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - if (!(iov->iov_base = strerror (eindex))) { - /* this shouldn't happen, but we'll test for it just in case */ - snprintf (err, sizeof(err), "Error %d", eindex); - iov->iov_base = err; + int eindex = errno; + + fflush(stdout); + if (invo_name && *invo_name) + fprintf(stderr, "%s: ", invo_name); + vfprintf(stderr, fmt, ap); + + if (what) { + char *s; + + if (*what) + fprintf(stderr, " %s: ", what); + if ((s = strerror(eindex))) + fprintf(stderr, "%s", s); + else + fprintf(stderr, "Error %d", eindex); } - iov->iov_len = strlen (iov->iov_base); - iov++; - } - if (tail && *tail) { - iov->iov_len = strlen (iov->iov_base = ", "); - iov++; - iov->iov_len = strlen (iov->iov_base = tail); - iov++; - } - iov->iov_len = strlen (iov->iov_base = "\n"); - iov++; - writev (fileno (stderr), iob, iov - iob); -#else - if (invo_name && *invo_name) - fprintf (stderr, "%s: ", invo_name); - vfprintf (stderr, fmt, ap); - - if (what) { - char *s; - - if (*what) - fprintf (stderr, " %s: ", what); - if ((s = strerror(eindex))) - fprintf (stderr, "%s", s); - else - fprintf (stderr, "Error %d", eindex); - } - if (tail) - fprintf (stderr, ", %s", tail); - fputc ('\n', stderr); -#endif + if (tail) + fprintf(stderr, ", %s", tail); + fputc('\n', stderr); } diff --git a/sbr/ext_hook.c b/sbr/ext_hook.c index e94083b..771d558 100644 --- a/sbr/ext_hook.c +++ b/sbr/ext_hook.c @@ -1,61 +1,58 @@ /* - * - * Run a program that hooks into some other system. The first argument is - * name of the hook to use, the second is the full path name of a mail message. - * The third argument is also the full path name of a mail message, or a NULL - * pointer if it isn't needed. Look in the context for an error message if - * something goes wrong; there is a built-in message in case one isn't specified. - * Only produce the error message once. - */ +** Run a program that hooks into some other system. The first argument is +** name of the hook to use, the second is the full path name of a mail message. +** The third argument is also the full path name of a mail message, or a NULL +** pointer if it isn't needed. Look in the context for an error message if +** something goes wrong; there is a built-in message in case one isn't +** specified. Only produce the error message once. +*/ #include int ext_hook(char *hook_name, char *message_file_name_1, char *message_file_name_2) { - char *hook; /* hook program from context */ - pid_t pid; /* ID of child process */ - int status; /* exit or other child process status */ - char *vec[4]; /* argument vector for child process */ - - static int did_message = 0; /* set if we've already output a message */ - - if ((hook = context_find(hook_name)) == (char *)0) - return (OK); - - switch (pid = vfork()) { - case -1: - status = NOTOK; - advise(NULL, "external database may be out-of-date."); - break; - - case 0: - vec[0] = r1bindex(hook, '/'); - vec[1] = message_file_name_1; - vec[2] = message_file_name_2; - vec[3] = (char *)0; - execvp(hook, vec); - _exit(-1); - /* NOTREACHED */ - - default: - status = pidwait(pid, -1); - break; - } - - if (status != OK) { - if (did_message == 0) { - if ((hook = context_find("msg-hook")) != (char *)0) - advise(NULL, hook); - else - advise(NULL, "external hook (%s) did not work properly.", hook); - - did_message = 1; + char *hook; /* hook program from context */ + pid_t pid; /* ID of child process */ + int status; /* exit or other child process status */ + char *vec[4]; /* argument vector for child process */ + + static int did_message = 0; /* set if we've already output a message */ + + if ((hook = context_find(hook_name)) == NULL) + return (OK); + + switch (pid = fork()) { + case -1: + status = NOTOK; + advise(NULL, "external database may be out-of-date."); + break; + + case 0: + vec[0] = mhbasename(hook); + vec[1] = message_file_name_1; + vec[2] = message_file_name_2; + vec[3] = NULL; + execvp(hook, vec); + _exit(-1); + /* NOTREACHED */ + + default: + status = pidwait(pid, -1); + break; } - return (NOTOK); - } + if (status != OK) { + if (did_message == 0) { + if ((hook = context_find("msg-hook")) != NULL) + advise(NULL, hook); + else + advise(NULL, "external hook (%s) did not work properly.", hook); - else - return (OK); + did_message = 1; + } + + return (NOTOK); + } else + return (OK); } diff --git a/sbr/fdcompare.c b/sbr/fdcompare.c deleted file mode 100644 index 38174e0..0000000 --- a/sbr/fdcompare.c +++ /dev/null @@ -1,40 +0,0 @@ - -/* - * fdcompare.c -- are two files identical? - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -fdcompare (int fd1, int fd2) -{ - register int i, n1, n2, resp; - register char *c1, *c2; - char b1[BUFSIZ], b2[BUFSIZ]; - - resp = 1; - while ((n1 = read (fd1, b1, sizeof(b1))) >= 0 - && (n2 = read (fd2, b2, sizeof(b2))) >= 0 - && n1 == n2) { - c1 = b1; - c2 = b2; - for (i = n1 < sizeof(b1) ? n1 : sizeof(b1); i--;) - if (*c1++ != *c2++) { - resp = 0; - goto leave; - } - if (n1 < sizeof(b1)) - goto leave; - } - resp = 0; - -leave: ; - lseek (fd1, (off_t) 0, SEEK_SET); - lseek (fd2, (off_t) 0, SEEK_SET); - return resp; -} diff --git a/sbr/fmt_addr.c b/sbr/fmt_addr.c index be9b483..d6218b5 100644 --- a/sbr/fmt_addr.c +++ b/sbr/fmt_addr.c @@ -1,114 +1,114 @@ - /* - * fmt_addr.c -- format an address field (from fmt_scan) - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_addr.c -- format an address field (from fmt_scan) +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include -static char *buf; /* our current working buffer */ -static char *bufend; /* end of working buffer */ -static char *last_dst; /* buf ptr at end of last call */ -static unsigned int bufsiz; /* current size of buf */ +static char *buf; /* our current working buffer */ +static char *bufend; /* end of working buffer */ +static char *last_dst; /* buf ptr at end of last call */ +static unsigned int bufsiz; /* current size of buf */ -#define BUFINCR 512 /* how much to expand buf when if fills */ +#define BUFINCR 512 /* how much to expand buf when if fills */ #define CPY(s) { cp = (s); while ((*dst++ = *cp++)) ; --dst; } /* check if there's enough room in buf for str. add more mem if needed */ #define CHECKMEM(str) \ - if ((len = strlen (str)) >= bufend - dst) {\ + if ((len = strlen(str)) >= bufend - dst) {\ int i = dst - buf;\ int n = last_dst - buf;\ bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\ - buf = mh_xrealloc (buf, bufsiz);\ + buf = mh_xrealloc(buf, bufsiz);\ dst = buf + i;\ last_dst = buf + n;\ bufend = buf + bufsiz;\ - } + } -/* fmt_scan will call this routine if the user includes the function - * "(formataddr {component})" in a format string. "orig" is the - * original contents of the string register. "str" is the address - * string to be formatted and concatenated onto orig. This routine - * returns a pointer to the concatenated address string. - * - * We try to not do a lot of malloc/copy/free's (which is why we - * don't call "getcpy") but still place no upper limit on the - * length of the result string. - * - * This routine is placed in a separate library so it can be - * overridden by particular programs (e.g., "replsbr"). - */ +/* +** fmt_scan will call this routine if the user includes the function +** "(formataddr {component})" in a format string. "orig" is the +** original contents of the string register. "str" is the address +** string to be formatted and concatenated onto orig. This routine +** returns a pointer to the concatenated address string. +** +** We try to not do a lot of malloc/copy/free's (which is why we +** don't call "getcpy") but still place no upper limit on the +** length of the result string. +** +** This routine is placed in a separate library so it can be +** overridden by particular programs (e.g., "replsbr"). +*/ char * -formataddr (char *orig, char *str) +formataddr(char *orig, char *str) { - register int len; - register int isgroup; - register char *dst; - register char *cp; - register char *sp; - register struct mailname *mp = NULL; - - /* if we don't have a buffer yet, get one */ - if (bufsiz == 0) { - buf = mh_xmalloc (BUFINCR); - last_dst = buf; /* XXX */ - bufsiz = BUFINCR - 6; /* leave some slop */ - bufend = buf + bufsiz; - } - /* - * If "orig" points to our buffer we can just pick up where we - * left off. Otherwise we have to copy orig into our buffer. - */ - if (orig == buf) - dst = last_dst; - else if (!orig || !*orig) { - dst = buf; - *dst = '\0'; - } else { - dst = last_dst; /* XXX */ - CHECKMEM (orig); - CPY (orig); - } + register int len; + register int isgroup; + register char *dst; + register char *cp; + register char *sp; + register struct mailname *mp = NULL; - /* concatenate all the new addresses onto 'buf' */ - for (isgroup = 0; (cp = getname (str)); ) { - if ((mp = getm (cp, NULL, 0, fmt_norm, NULL)) == NULL) - continue; - - if (isgroup && (mp->m_gname || !mp->m_ingrp)) { - *dst++ = ';'; - isgroup = 0; + /* if we don't have a buffer yet, get one */ + if (bufsiz == 0) { + buf = mh_xmalloc(BUFINCR); + last_dst = buf; /* XXX */ + bufsiz = BUFINCR - 6; /* leave some slop */ + bufend = buf + bufsiz; } - /* if we get here we're going to add an address */ - if (dst != buf) { - *dst++ = ','; - *dst++ = ' '; + /* + ** If "orig" points to our buffer we can just pick up where we + ** left off. Otherwise we have to copy orig into our buffer. + */ + if (orig == buf) + dst = last_dst; + else if (!orig || !*orig) { + dst = buf; + *dst = '\0'; + } else { + dst = last_dst; /* XXX */ + CHECKMEM(orig); + CPY(orig); } - if (mp->m_gname) { - CHECKMEM (mp->m_gname); - CPY (mp->m_gname); - isgroup++; + + /* concatenate all the new addresses onto 'buf' */ + for (isgroup = 0; (cp = getname(str)); ) { + if ((mp = getm(cp, NULL, 0, fmt_norm, NULL)) == NULL) + continue; + + if (isgroup && (mp->m_gname || !mp->m_ingrp)) { + *dst++ = ';'; + isgroup = 0; + } + /* if we get here we're going to add an address */ + if (dst != buf) { + *dst++ = ','; + *dst++ = ' '; + } + if (mp->m_gname) { + CHECKMEM(mp->m_gname); + CPY(mp->m_gname); + isgroup++; + } + sp = adrformat(mp); + CHECKMEM(sp); + CPY(sp); + mnfree(mp); } - sp = adrformat (mp); - CHECKMEM (sp); - CPY (sp); - mnfree (mp); - } - if (isgroup) - *dst++ = ';'; + if (isgroup) + *dst++ = ';'; - *dst = '\0'; - last_dst = dst; - return (buf); + *dst = '\0'; + last_dst = dst; + return (buf); } diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index a180c56..173f12d 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -1,11 +1,42 @@ - /* - * fmt_compile.c -- "compile" format strings for fmt_scan - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_compile.c -- "compile" format strings for fmt_scan +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** This code compiles the format strings (documented in mh-format(5)) into +** an internal form to be later processed by fmt_scan.c. +** +** What happens here is that the format strings are parsed and an array +** of struct format structures are returned. Each format structure is +** a single operation interpreted by the the routines in fmt_scan.c. +** +** There is a NOT a one-to-one correspondence between format strings and +** format instructions; some functions have side effects that can result +** in multiple instructions being generated. The exact list of instructions +** generated by a format string can be seem with the nmh fmtdump utility. +** +** A list of format instructions can be found in fmt_compile.h. +** +** If you wish to add a new function, you will need to do the following +** things: +** +** - Add a new instruction to the list of instructions in fmt_compile.h. +** Note that test instructions (starting with FT_IF_S_NULL) have special +** handling, so if you are NOT writing a test function then you need +** to insert it into the list before that _and_ bump all of the +** following instruction numbers. +** +** - Add the function name to the functable[] array below, and write any +** special code that your function may require in terms of parsing +** (it very well may not need anything). +** +** - Add the code in fmt_scan.c to handle your new function. +** +** - Document the new function in the mh-format(5) man page. +** +*/ #include #include @@ -13,655 +44,697 @@ #include #include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include /* - * hash table for deciding if a component is "interesting" - */ +** hash table for deciding if a component is "interesting" +*/ struct comp *wantcomp[128]; -static struct format *formatvec; /* array to hold formats */ -static struct format *next_fp; /* next free format slot */ -static struct format *fp; /* current format slot */ -static struct comp *cm; /* most recent comp ref */ -static struct ftable *ftbl; /* most recent func ref */ +static struct format *formatvec; /* array to hold formats */ +static struct format *next_fp; /* next free format slot */ +static struct format *fp; /* current format slot */ +static struct comp *cm; /* most recent comp ref */ +static struct ftable *ftbl; /* most recent func ref */ static int ncomp; -static int infunction; /* function nesting cnt */ +static int infunction; /* function nesting cnt */ extern struct mailname fmt_mnull; /* ftable->type (argument type) */ -#define TF_COMP 0 /* component expected */ -#define TF_NUM 1 /* number expected */ -#define TF_STR 2 /* string expected */ -#define TF_EXPR 3 /* component or func. expected */ -#define TF_NONE 4 /* no argument */ -#define TF_MYBOX 5 /* special - get current user's mbox */ -#define TF_NOW 6 /* special - get current unix time */ -#define TF_EXPR_SV 7 /* like expr but save current str reg */ -#define TF_NOP 8 /* like expr but no result */ +#define TF_COMP 0 /* component expected */ +#define TF_NUM 1 /* number expected */ +#define TF_STR 2 /* string expected */ +#define TF_EXPR 3 /* component or func. expected */ +#define TF_NONE 4 /* no argument */ +#define TF_MYBOX 5 /* special - get current user's mbox */ +#define TF_NOW 6 /* special - get current unix time */ +#define TF_EXPR_SV 7 /* like expr but save current str reg */ +#define TF_NOP 8 /* like expr but no result */ /* ftable->flags */ -/* NB that TFL_PUTS is also used to decide whether the test - * in a "%<(function)..." should be a string or numeric one. - */ -#define TFL_PUTS 1 /* implicit putstr if top level */ -#define TFL_PUTN 2 /* implicit putnum if top level */ +/* +** NB that TFL_PUTS is also used to decide whether the test +** in a "%<(function)..." should be a string or numeric one. +*/ +#define TFL_PUTS 1 /* implicit putstr if top level */ +#define TFL_PUTN 2 /* implicit putnum if top level */ +/* +** The functable array maps between the text names of format functions and +** the format instructions interpreted by the engine in fmt_scan.c. +** +** The elements of this structure are as follows: +** +** name: The name of the function as seen in the format string. This is +** what maps a particular function name into a format instruction. +** type: The type of argument this function expects. Those types are +** listed above (with the TF_ prefix). This affects what gets +** placed in the format instruction (the f_un union). +** f_type: The instruction corresponding to this function (from the list +** in fmt_compile.h). +** extra: Used by some functions to provide extra data to the compiler. +** Uses include: +** - Providing an alternate instruction to combine a load +** and test operation (see do_if()). +** - Passed in f_value in the format instruction to provide +** extra information for the engine (see FT_LV_DAT handling +** in fmt_scan.c). +** - Provide a hint as to preprocessing that is required for +** this instruction (see do_name()). +** flags: See the definitions for TFL_PUTS & TFL_PUTN above. +*/ struct ftable { - char *name; /* function name */ - char type; /* argument type */ - char f_type; /* fmt type */ - char extra; /* arg. type dependent extra info */ - char flags; + char *name; /* function name */ + char type; /* argument type */ + char f_type; /* fmt type */ + char extra; /* arg. type dependent extra info */ + char flags; }; static struct ftable functable[] = { - { "nonzero", TF_EXPR, FT_V_NE, FT_IF_V_NE, 0 }, - { "zero", TF_EXPR, FT_V_EQ, FT_IF_V_EQ, 0 }, - { "eq", TF_NUM, FT_V_EQ, FT_IF_V_EQ, 0 }, - { "ne", TF_NUM, FT_V_NE, FT_IF_V_NE, 0 }, - { "gt", TF_NUM, FT_V_GT, FT_IF_V_GT, 0 }, - { "null", TF_EXPR, FT_S_NULL, FT_IF_S_NULL, 0 }, - { "nonnull", TF_EXPR, FT_S_NONNULL, FT_IF_S, 0 }, - { "match", TF_STR, FT_V_MATCH, FT_IF_MATCH, 0 }, - { "amatch", TF_STR, FT_V_AMATCH, FT_IF_AMATCH, 0 }, - - { "putstr", TF_EXPR, FT_STR, 0, 0 }, - { "putstrf", TF_EXPR, FT_STRF, 0, 0 }, - { "putnum", TF_EXPR, FT_NUM, 0, 0 }, - { "putnumf", TF_EXPR, FT_NUMF, 0, 0 }, - { "putaddr", TF_STR, FT_PUTADDR, 0, 0 }, - { "void", TF_NOP, 0, 0, 0 }, - - { "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS }, - { "lit", TF_STR, FT_LS_LIT, 0, TFL_PUTS }, - { "getenv", TF_STR, FT_LS_GETENV, 0, TFL_PUTS }, - { "profile", TF_STR, FT_LS_CFIND, 0, TFL_PUTS }, - { "decodecomp", TF_COMP, FT_LS_DECODECOMP, 0, TFL_PUTS }, - { "decode", TF_EXPR, FT_LS_DECODE, 0, TFL_PUTS }, - { "trim", TF_EXPR, FT_LS_TRIM, 0, 0 }, - { "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN }, - { "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN }, - { "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN }, - { "msg", TF_NONE, FT_LV_DAT, 0, TFL_PUTN }, - { "cur", TF_NONE, FT_LV_DAT, 1, TFL_PUTN }, - { "size", TF_NONE, FT_LV_DAT, 2, TFL_PUTN }, - { "width", TF_NONE, FT_LV_DAT, 3, TFL_PUTN }, - { "unseen", TF_NONE, FT_LV_DAT, 4, TFL_PUTN }, - { "dat", TF_NUM, FT_LV_DAT, 0, TFL_PUTN }, - { "strlen", TF_NONE, FT_LV_STRLEN, 0, TFL_PUTN }, - { "me", TF_MYBOX, FT_LS_LIT, 0, TFL_PUTS }, - { "plus", TF_NUM, FT_LV_PLUS_L, 0, TFL_PUTN }, - { "minus", TF_NUM, FT_LV_MINUS_L, 0, TFL_PUTN }, - { "divide", TF_NUM, FT_LV_DIVIDE_L, 0, TFL_PUTN }, - { "modulo", TF_NUM, FT_LV_MODULO_L, 0, TFL_PUTN }, - { "charleft", TF_NONE, FT_LV_CHAR_LEFT, 0, TFL_PUTN }, - { "timenow", TF_NOW, FT_LV_LIT, 0, TFL_PUTN }, - - { "month", TF_COMP, FT_LS_MONTH, FT_PARSEDATE, TFL_PUTS }, - { "lmonth", TF_COMP, FT_LS_LMONTH, FT_PARSEDATE, TFL_PUTS }, - { "tzone", TF_COMP, FT_LS_ZONE, FT_PARSEDATE, TFL_PUTS }, - { "day", TF_COMP, FT_LS_DAY, FT_PARSEDATE, TFL_PUTS }, - { "weekday", TF_COMP, FT_LS_WEEKDAY, FT_PARSEDATE, TFL_PUTS }, - { "tws", TF_COMP, FT_LS_822DATE, FT_PARSEDATE, TFL_PUTS }, - { "sec", TF_COMP, FT_LV_SEC, FT_PARSEDATE, TFL_PUTN }, - { "min", TF_COMP, FT_LV_MIN, FT_PARSEDATE, TFL_PUTN }, - { "hour", TF_COMP, FT_LV_HOUR, FT_PARSEDATE, TFL_PUTN }, - { "mday", TF_COMP, FT_LV_MDAY, FT_PARSEDATE, TFL_PUTN }, - { "mon", TF_COMP, FT_LV_MON, FT_PARSEDATE, TFL_PUTN }, - { "year", TF_COMP, FT_LV_YEAR, FT_PARSEDATE, TFL_PUTN }, - { "yday", TF_COMP, FT_LV_YDAY, FT_PARSEDATE, TFL_PUTN }, - { "wday", TF_COMP, FT_LV_WDAY, FT_PARSEDATE, TFL_PUTN }, - { "zone", TF_COMP, FT_LV_ZONE, FT_PARSEDATE, TFL_PUTN }, - { "clock", TF_COMP, FT_LV_CLOCK, FT_PARSEDATE, TFL_PUTN }, - { "rclock", TF_COMP, FT_LV_RCLOCK, FT_PARSEDATE, TFL_PUTN }, - { "sday", TF_COMP, FT_LV_DAYF, FT_PARSEDATE, TFL_PUTN }, - { "szone", TF_COMP, FT_LV_ZONEF, FT_PARSEDATE, TFL_PUTN }, - { "dst", TF_COMP, FT_LV_DST, FT_PARSEDATE, TFL_PUTN }, - { "pretty", TF_COMP, FT_LS_PRETTY, FT_PARSEDATE, TFL_PUTS }, - { "nodate", TF_COMP, FT_LV_COMPFLAG, FT_PARSEDATE, TFL_PUTN }, - { "date2local", TF_COMP, FT_LOCALDATE, FT_PARSEDATE, 0 }, - { "date2gmt", TF_COMP, FT_GMTDATE, FT_PARSEDATE, 0 }, - - { "pers", TF_COMP, FT_LS_PERS, FT_PARSEADDR, TFL_PUTS }, - { "mbox", TF_COMP, FT_LS_MBOX, FT_PARSEADDR, TFL_PUTS }, - { "host", TF_COMP, FT_LS_HOST, FT_PARSEADDR, TFL_PUTS }, - { "path", TF_COMP, FT_LS_PATH, FT_PARSEADDR, TFL_PUTS }, - { "gname", TF_COMP, FT_LS_GNAME, FT_PARSEADDR, TFL_PUTS }, - { "note", TF_COMP, FT_LS_NOTE, FT_PARSEADDR, TFL_PUTS }, - { "addr", TF_COMP, FT_LS_ADDR, FT_PARSEADDR, TFL_PUTS }, - { "proper", TF_COMP, FT_LS_822ADDR, FT_PARSEADDR, TFL_PUTS }, - { "type", TF_COMP, FT_LV_HOSTTYPE, FT_PARSEADDR, TFL_PUTN }, - { "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN }, - { "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN }, - { "formataddr", TF_EXPR_SV,FT_FORMATADDR, FT_FORMATADDR, 0 }, - { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, - - { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, - { "addtoseq", TF_STR, FT_ADDTOSEQ, 0, 0 }, - - { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS}, - - { NULL, 0, 0, 0, 0 } + { "nonzero", TF_EXPR, FT_V_NE, FT_IF_V_NE, 0 }, + { "zero", TF_EXPR, FT_V_EQ, FT_IF_V_EQ, 0 }, + { "eq", TF_NUM, FT_V_EQ, FT_IF_V_EQ, 0 }, + { "ne", TF_NUM, FT_V_NE, FT_IF_V_NE, 0 }, + { "gt", TF_NUM, FT_V_GT, FT_IF_V_GT, 0 }, + { "null", TF_EXPR, FT_S_NULL, FT_IF_S_NULL, 0 }, + { "nonnull", TF_EXPR, FT_S_NONNULL, FT_IF_S, 0 }, + { "match", TF_STR, FT_V_MATCH, FT_IF_MATCH, 0 }, + { "amatch", TF_STR, FT_V_AMATCH, FT_IF_AMATCH, 0 }, + + { "putstr", TF_EXPR, FT_STR, 0, 0 }, + { "putstrf", TF_EXPR, FT_STRF, 0, 0 }, + { "putnum", TF_EXPR, FT_NUM, 0, 0 }, + { "putnumf", TF_EXPR, FT_NUMF, 0, 0 }, + { "putaddr", TF_STR, FT_PUTADDR, 0, 0 }, + { "void", TF_NOP, 0, 0, 0 }, + + { "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS }, + { "lit", TF_STR, FT_LS_LIT, 0, TFL_PUTS }, + { "getenv", TF_STR, FT_LS_GETENV, 0, TFL_PUTS }, + { "profile", TF_STR, FT_LS_CFIND, 0, TFL_PUTS }, + { "decodecomp", TF_COMP, FT_LS_DECODECOMP, 0, TFL_PUTS }, + { "decode", TF_EXPR, FT_LS_DECODE, 0, TFL_PUTS }, + { "trim", TF_EXPR, FT_LS_TRIM, 0, 0 }, + { "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN }, + { "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN }, + { "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN }, + { "msg", TF_NONE, FT_LV_DAT, 0, TFL_PUTN }, + { "cur", TF_NONE, FT_LV_DAT, 1, TFL_PUTN }, + { "size", TF_NONE, FT_LV_DAT, 2, TFL_PUTN }, + { "width", TF_NONE, FT_LV_DAT, 3, TFL_PUTN }, + { "unseen", TF_NONE, FT_LV_DAT, 4, TFL_PUTN }, + { "dat", TF_NUM, FT_LV_DAT, 0, TFL_PUTN }, + { "strlen", TF_NONE, FT_LV_STRLEN, 0, TFL_PUTN }, + { "me", TF_MYBOX, FT_LS_LIT, 0, TFL_PUTS }, + { "plus", TF_NUM, FT_LV_PLUS_L, 0, TFL_PUTN }, + { "minus", TF_NUM, FT_LV_MINUS_L, 0, TFL_PUTN }, + { "divide", TF_NUM, FT_LV_DIVIDE_L, 0, TFL_PUTN }, + { "modulo", TF_NUM, FT_LV_MODULO_L, 0, TFL_PUTN }, + { "charleft", TF_NONE, FT_LV_CHAR_LEFT, 0, TFL_PUTN }, + { "timenow", TF_NOW, FT_LV_LIT, 0, TFL_PUTN }, + + { "month", TF_COMP, FT_LS_MONTH, FT_PARSEDATE, TFL_PUTS }, + { "lmonth", TF_COMP, FT_LS_LMONTH, FT_PARSEDATE, TFL_PUTS }, + { "tzone", TF_COMP, FT_LS_ZONE, FT_PARSEDATE, TFL_PUTS }, + { "day", TF_COMP, FT_LS_DAY, FT_PARSEDATE, TFL_PUTS }, + { "weekday", TF_COMP, FT_LS_WEEKDAY, FT_PARSEDATE, TFL_PUTS }, + { "tws", TF_COMP, FT_LS_822DATE, FT_PARSEDATE, TFL_PUTS }, + { "sec", TF_COMP, FT_LV_SEC, FT_PARSEDATE, TFL_PUTN }, + { "min", TF_COMP, FT_LV_MIN, FT_PARSEDATE, TFL_PUTN }, + { "hour", TF_COMP, FT_LV_HOUR, FT_PARSEDATE, TFL_PUTN }, + { "mday", TF_COMP, FT_LV_MDAY, FT_PARSEDATE, TFL_PUTN }, + { "mon", TF_COMP, FT_LV_MON, FT_PARSEDATE, TFL_PUTN }, + { "year", TF_COMP, FT_LV_YEAR, FT_PARSEDATE, TFL_PUTN }, + { "yday", TF_COMP, FT_LV_YDAY, FT_PARSEDATE, TFL_PUTN }, + { "wday", TF_COMP, FT_LV_WDAY, FT_PARSEDATE, TFL_PUTN }, + { "zone", TF_COMP, FT_LV_ZONE, FT_PARSEDATE, TFL_PUTN }, + { "clock", TF_COMP, FT_LV_CLOCK, FT_PARSEDATE, TFL_PUTN }, + { "rclock", TF_COMP, FT_LV_RCLOCK, FT_PARSEDATE, TFL_PUTN }, + { "sday", TF_COMP, FT_LV_DAYF, FT_PARSEDATE, TFL_PUTN }, + { "szone", TF_COMP, FT_LV_ZONEF, FT_PARSEDATE, TFL_PUTN }, + { "dst", TF_COMP, FT_LV_DST, FT_PARSEDATE, TFL_PUTN }, + { "pretty", TF_COMP, FT_LS_PRETTY, FT_PARSEDATE, TFL_PUTS }, + { "nodate", TF_COMP, FT_LV_COMPFLAG, FT_PARSEDATE, TFL_PUTN }, + { "date2local", TF_COMP, FT_LOCALDATE, FT_PARSEDATE, 0 }, + { "date2gmt", TF_COMP, FT_GMTDATE, FT_PARSEDATE, 0 }, + + { "pers", TF_COMP, FT_LS_PERS, FT_PARSEADDR, TFL_PUTS }, + { "mbox", TF_COMP, FT_LS_MBOX, FT_PARSEADDR, TFL_PUTS }, + { "host", TF_COMP, FT_LS_HOST, FT_PARSEADDR, TFL_PUTS }, + { "path", TF_COMP, FT_LS_PATH, FT_PARSEADDR, TFL_PUTS }, + { "gname", TF_COMP, FT_LS_GNAME, FT_PARSEADDR, TFL_PUTS }, + { "note", TF_COMP, FT_LS_NOTE, FT_PARSEADDR, TFL_PUTS }, + { "addr", TF_COMP, FT_LS_ADDR, FT_PARSEADDR, TFL_PUTS }, + { "proper", TF_COMP, FT_LS_822ADDR, FT_PARSEADDR, TFL_PUTS }, + { "type", TF_COMP, FT_LV_HOSTTYPE, FT_PARSEADDR, TFL_PUTN }, + { "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN }, + { "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN }, + { "formataddr", TF_EXPR_SV, FT_FORMATADDR, FT_FORMATADDR, 0 }, + { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, + + { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, + + { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS}, + + { NULL, 0, 0, 0, 0 } }; /* Add new component to the hash table */ #define NEWCOMP(cm,name) do { \ - cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ - cm->c_name = name;\ - ncomp++;\ - i = CHASH(name);\ - cm->c_next = wantcomp[i];\ - wantcomp[i] = cm; \ + cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ + cm->c_name = name;\ + ncomp++;\ + i = CHASH(name);\ + cm->c_next = wantcomp[i];\ + wantcomp[i] = cm; \ } while (0) #define NEWFMT (next_fp++) #define NEW(type,fill,wid) do {\ - fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); \ + fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); \ } while (0) /* Add (possibly new) component to the hash table */ #define ADDC(name) do { \ - FINDCOMP(cm, name);\ - if (!cm) {\ - NEWCOMP(cm,name);\ - }\ - fp->f_comp = cm; \ + FINDCOMP(cm, name);\ + if (!cm) {\ + NEWCOMP(cm,name);\ + }\ + fp->f_comp = cm; \ } while (0) -#define LV(type, value) do { NEW(type,0,0); fp->f_value = (value); } while (0) -#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); } while (0) +#define LV(type, value) do { NEW(type,0,0); fp->f_value = (value); } while (0) +#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); } while (0) -#define PUTCOMP(comp) do { NEW(FT_COMP,0,0); ADDC(comp); } while (0) -#define PUTLIT(str) do { NEW(FT_LIT,0,0); fp->f_text = (str); } while (0) -#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) +#define PUTCOMP(comp) do { NEW(FT_COMP,0,0); ADDC(comp); } while (0) +#define PUTLIT(str) do { NEW(FT_LIT,0,0); fp->f_text = (str); } while (0) +#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) static char *format_string; -static unsigned char *usr_fstring; /* for CERROR */ +static unsigned char *usr_fstring; /* for CERROR */ -#define CERROR(str) compile_error (str, cp) - -/* - * external prototypes - */ -extern char *getusername(void); +#define CERROR(str) compile_error(str, cp) /* - * static prototypes - */ +** static prototypes +*/ static struct ftable *lookup(char *); static void compile_error(char *, char *); -static char *compile (char *); +static char *compile(char *); static char *do_spec(char *); static char *do_name(char *, int); static char *do_func(char *); -static char *do_expr (char *, int); +static char *do_expr(char *, int); static char *do_loop(char *); static char *do_if(char *); +/* +** Lookup a function name in the functable +*/ static struct ftable * lookup(char *name) { - register struct ftable *t = functable; - register char *nm; - register char c = *name; + register struct ftable *t = functable; + register char *nm; + register char c = *name; - while ((nm = t->name)) { - if (*nm == c && strcmp (nm, name) == 0) - return (ftbl = t); + while ((nm = t->name)) { + if (*nm == c && strcmp(nm, name) == 0) + return (ftbl = t); - t++; - } - return (struct ftable *) 0; + t++; + } + return (struct ftable *) 0; } static void compile_error(char *str, char *cp) { - int i, errpos, errctx; + int i, errpos, errctx; - errpos = cp - format_string; - errctx = errpos > 20 ? 20 : errpos; - usr_fstring[errpos] = '\0'; + errpos = cp - format_string; + errctx = errpos > 20 ? 20 : errpos; + usr_fstring[errpos] = '\0'; - for (i = errpos-errctx; i < errpos; i++) { -#ifdef LOCALE - if (iscntrl(usr_fstring[i])) -#else - if (usr_fstring[i] < 32) -#endif - usr_fstring[i] = '_'; - } + for (i = errpos-errctx; i < errpos; i++) { + if (iscntrl(usr_fstring[i])) + usr_fstring[i] = '_'; + } - advise(NULL, "\"%s\": format compile error - %s", - &usr_fstring[errpos-errctx], str); - adios (NULL, "%*s", errctx+1, "^"); + advise(NULL, "\"%s\": format compile error - %s", + &usr_fstring[errpos-errctx], str); + adios(NULL, "%*s", errctx+1, "^"); } /* - * Compile format string "fstring" into format list "fmt". - * Return the number of header components found in the format - * string. - */ - +** Compile format string "fstring" into format list "fmt". +** Return the number of header components found in the format +** string. +*/ int fmt_compile(char *fstring, struct format **fmt) { - register char *cp; - int i; - - if (format_string) - free (format_string); - format_string = getcpy (fstring); - usr_fstring = fstring; - - /* init the component hash table. */ - for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) - wantcomp[i] = 0; - - memset((char *) &fmt_mnull, 0, sizeof(fmt_mnull)); - - /* it takes at least 4 char to generate one format so we - * allocate a worst-case format array using 1/4 the length - * of the format string. We actually need twice this much - * to handle both pre-processing (e.g., address parsing) and - * normal processing. - */ - i = strlen(fstring)/2 + 1; - if (i==1) i++; - next_fp = formatvec = (struct format *)calloc ((size_t) i, - sizeof(struct format)); - if (next_fp == NULL) - adios (NULL, "unable to allocate format storage"); - - ncomp = 0; - infunction = 0; - - cp = compile(format_string); - if (*cp) { - CERROR("extra '%>', '%|' or '%?'"); - } - LV(FT_DONE, 0); /* really done */ - *fmt = formatvec; - - return (ncomp); + register char *cp; + size_t i; + + if (format_string) + free(format_string); + format_string = getcpy(fstring); + usr_fstring = fstring; + + /* init the component hash table. */ + for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) + wantcomp[i] = 0; + + memset((char *) &fmt_mnull, 0, sizeof(fmt_mnull)); + + /* + ** it takes at least 4 char to generate one format so we + ** allocate a worst-case format array using 1/4 the length + ** of the format string. We actually need twice this much + ** to handle both pre-processing (e.g., address parsing) and + ** normal processing. + */ + i = strlen(fstring)/2 + 1; + if (i == 1) + i++; + next_fp = formatvec = (struct format *)calloc((size_t) i, + sizeof(struct format)); + if (next_fp == NULL) + adios(NULL, "unable to allocate format storage"); + + ncomp = 0; + infunction = 0; + + cp = compile(format_string); + if (*cp) { + CERROR("extra '%>', '%|' or '%?'"); + } + LV(FT_DONE, 0); /* really done */ + *fmt = formatvec; + + return (ncomp); } static char * -compile (char *sp) +compile(char *sp) { - register char *cp = sp; - register int c; - - for (;;) { - sp = cp; - while ((c = *cp) && c != '%') - cp++; - *cp = 0; - switch (cp-sp) { - case 0: - break; - case 1: - PUTC(*sp); - break; - default: - PUTLIT(sp); - break; - } - if (c == 0) - return (cp); - - switch (c = *++cp) { - case '%': - PUTC (*cp); - cp++; - break; - - case '|': - case '>': - case '?': - case ']': - return (cp); - - case '<': - cp = do_if(++cp); - break; - - case '[': /* ] */ - cp = do_loop(++cp); - break; - - case ';': /* comment line */ - cp++; - while ((c = *cp++) && c != '\n') - continue; - break; - - default: - cp = do_spec(cp); - break; + register char *cp = sp; + register int c; + + for (;;) { + sp = cp; + while ((c = *cp) && c != '%') + cp++; + *cp = 0; + switch (cp-sp) { + case 0: + break; + case 1: + PUTC(*sp); + break; + default: + PUTLIT(sp); + break; + } + if (c == 0) + return (cp); + + switch (c = *++cp) { + case '%': + PUTC(*cp); + cp++; + break; + + case '|': + case '>': + case '?': + case ']': + return (cp); + + case '<': + cp = do_if(++cp); + break; + + case '[': /* ] */ + cp = do_loop(++cp); + break; + + case ';': /* comment line */ + cp++; + while ((c = *cp++) && c != '\n') + continue; + break; + + default: + cp = do_spec(cp); + break; + } } - } } +/* +** Process functions & components (handle field width here as well +*/ static char * do_spec(char *sp) { - register char *cp = sp; - register int c; -#ifndef lint - register int ljust = 0; -#endif /* not lint */ - register int wid = 0; - register char fill = ' '; - - c = *cp++; - if (c == '-') { - ljust++; - c = *cp++; - } - if (c == '0') { - fill = c; - c = *cp++; - } - while (isdigit(c)) { - wid = wid*10 + (c - '0'); + register char *cp = sp; + register int c; + register int ljust = 0; + register int wid = 0; + register char fill = ' '; + c = *cp++; - } - if (c == '{') { - cp = do_name(cp, 0); - if (! infunction) - fp->f_type = wid? FT_COMPF : FT_COMP; - } - else if (c == '(') { - cp = do_func(cp); - if (! infunction) { - if (ftbl->flags & TFL_PUTS) { - LV( wid? FT_STRF : FT_STR, ftbl->extra); - } - else if (ftbl->flags & TFL_PUTN) { - LV( wid? FT_NUMF : FT_NUM, ftbl->extra); - } + if (c == '-') { + ljust++; + c = *cp++; + } + if (c == '0') { + fill = c; + c = *cp++; } - } - else { - CERROR("component or function name expected"); - } - if (ljust) - wid = -wid; - fp->f_width = wid; - fp->f_fill = fill; - - return (cp); + while (isdigit(c)) { + wid = wid*10 + (c - '0'); + c = *cp++; + } + if (c == '{') { + cp = do_name(cp, 0); + if (! infunction) + fp->f_type = wid? FT_COMPF : FT_COMP; + } else if (c == '(') { + cp = do_func(cp); + if (! infunction) { + if (ftbl->flags & TFL_PUTS) { + LV( wid? FT_STRF : FT_STR, ftbl->extra); + } else if (ftbl->flags & TFL_PUTN) { + LV( wid? FT_NUMF : FT_NUM, ftbl->extra); + } + } + } else { + CERROR("component or function name expected"); + } + if (ljust) + wid = -wid; + fp->f_width = wid; + fp->f_fill = fill; + + return (cp); } + +/* +** Process a component name. Normally this involves generating an FT_COMP +** instruction for the specified component. If preprocess is set, then we +** do some extra processing. +*/ static char * do_name(char *sp, int preprocess) { - register char *cp = sp; - register int c; - register int i; - static int primed = 0; - - while (isalnum(c = *cp++) || c == '-' || c == '_') - ; - if (c != '}') { - CERROR("'}' expected"); - } - cp[-1] = '\0'; - PUTCOMP(sp); - switch (preprocess) { - - case FT_PARSEDATE: - if (cm->c_type & CT_ADDR) { - CERROR("component used as both date and address"); - } - cm->c_tws = (struct tws *) - calloc((size_t) 1, sizeof(*cm->c_tws)); - fp->f_type = preprocess; - PUTCOMP(sp); - cm->c_type |= CT_DATE; - break; - - case FT_MYMBOX: - if (!primed) { - ismymbox ((struct mailname *) 0); - primed++; - } - /* fall through */ - case FT_PARSEADDR: - if (cm->c_type & CT_DATE) { - CERROR("component used as both date and address"); + register char *cp = sp; + register int c; + register int i; + static int primed = 0; + + while (isalnum(c = *cp++) || c == '-' || c == '_') + ; + if (c != '}') { + CERROR("'}' expected"); } - cm->c_mn = &fmt_mnull; - fp->f_type = preprocess; + cp[-1] = '\0'; PUTCOMP(sp); - cm->c_type |= CT_ADDR; - break; + switch (preprocess) { - case FT_FORMATADDR: - if (cm->c_type & CT_DATE) { - CERROR("component used as both date and address"); + case FT_PARSEDATE: + if (cm->c_type & CT_ADDR) { + CERROR("component used as both date and address"); + } + cm->c_tws = (struct tws *) + calloc((size_t) 1, sizeof(*cm->c_tws)); + fp->f_type = preprocess; + PUTCOMP(sp); + cm->c_type |= CT_DATE; + break; + + case FT_MYMBOX: + if (!primed) { + ismymbox((struct mailname *) 0); + primed++; + } + /* fall through */ + case FT_PARSEADDR: + if (cm->c_type & CT_DATE) { + CERROR("component used as both date and address"); + } + cm->c_mn = &fmt_mnull; + fp->f_type = preprocess; + PUTCOMP(sp); + cm->c_type |= CT_ADDR; + break; + + case FT_FORMATADDR: + if (cm->c_type & CT_DATE) { + CERROR("component used as both date and address"); + } + cm->c_type |= CT_ADDR; + break; } - cm->c_type |= CT_ADDR; - break; - } - return (cp); + return (cp); } + +/* +** Generate one or more instructions corresponding to the named function. +** The different type of function arguments are handled here. +*/ static char * do_func(char *sp) { - register char *cp = sp; - register int c; - register struct ftable *t; - register int n; - int mflag; /* minus sign in NUM */ - - infunction++; - - while (isalnum(c = *cp++)) - ; - if (c != '(' && c != '{' && c != ' ' && c != ')') { - CERROR("'(', '{', ' ' or ')' expected"); - } - cp[-1] = '\0'; - if ((t = lookup (sp)) == 0) { - CERROR("unknown function"); - } - if (isspace(c)) - c = *cp++; + register char *cp = sp; + register int c; + register struct ftable *t; + register int n; + int mflag; /* minus sign in NUM */ + + infunction++; + + while (isalnum(c = *cp++)) + ; + if (c != '(' && c != '{' && c != ' ' && c != ')') { + CERROR("'(', '{', ' ' or ')' expected"); + } + cp[-1] = '\0'; + if ((t = lookup(sp)) == 0) { + CERROR("unknown function"); + } + if (isspace(c)) + c = *cp++; - switch (t->type) { + switch (t->type) { - case TF_COMP: - if (c != '{') { - CERROR("component name expected"); + case TF_COMP: + if (c != '{') { + CERROR("component name expected"); + } + cp = do_name(cp, t->extra); + fp->f_type = t->f_type; + c = *cp++; + break; + + case TF_NUM: + if ((mflag = (c == '-'))) + c = *cp++; + n = 0; + while (isdigit(c)) { + n = n*10 + (c - '0'); + c = *cp++; + } + if (mflag) + n = (-n); + LV(t->f_type,n); + break; + + case TF_STR: + sp = cp - 1; + while (c && c != ')') + c = *cp++; + cp[-1] = '\0'; + LS(t->f_type,sp); + break; + + case TF_NONE: + LV(t->f_type,t->extra); + break; + + case TF_MYBOX: + LS(t->f_type, getusername()); + break; + + case TF_NOW: + LV(t->f_type, time((time_t *) 0)); + break; + + case TF_EXPR_SV: + LV(FT_SAVESTR, 0); + /* fall through */ + case TF_EXPR: + *--cp = c; + cp = do_expr(cp, t->extra); + LV(t->f_type, 0); + c = *cp++; + ftbl = t; + break; + + case TF_NOP: + *--cp = c; + cp = do_expr(cp, t->extra); + c = *cp++; + ftbl = t; + break; } - cp = do_name(cp, t->extra); - fp->f_type = t->f_type; - c = *cp++; - break; - - case TF_NUM: - if ((mflag = (c == '-'))) - c = *cp++; - n = 0; - while (isdigit(c)) { - n = n*10 + (c - '0'); - c = *cp++; + if (c != ')') { + CERROR("')' expected"); } - if (mflag) - n = (-n); - LV(t->f_type,n); - break; - - case TF_STR: - sp = cp - 1; - while (c && c != ')') - c = *cp++; - cp[-1] = '\0'; - LS(t->f_type,sp); - break; - - case TF_NONE: - LV(t->f_type,t->extra); - break; - - case TF_MYBOX: - LS(t->f_type, getusername()); - break; - - case TF_NOW: - LV(t->f_type, time((time_t *) 0)); - break; - - case TF_EXPR_SV: - LV(FT_SAVESTR, 0); - /* fall through */ - case TF_EXPR: - *--cp = c; - cp = do_expr(cp, t->extra); - LV(t->f_type, 0); - c = *cp++; - ftbl = t; - break; - - case TF_NOP: - *--cp = c; - cp = do_expr(cp, t->extra); - c = *cp++; - ftbl = t; - break; - } - if (c != ')') { - CERROR("')' expected"); - } - --infunction; - return (cp); + --infunction; + return (cp); } + +/* +** Handle an expression as an argument. Basically we call one of do_name(), +** do_func(), or do_if() +*/ static char * -do_expr (char *sp, int preprocess) +do_expr(char *sp, int preprocess) { - register char *cp = sp; - register int c; - - if ((c = *cp++) == '{') { - cp = do_name (cp, preprocess); - fp->f_type = FT_LS_COMP; - } else if (c == '(') { - cp = do_func (cp); - } else if (c == ')') { - return (--cp); - } else if (c == '%' && *cp == '<') { - cp = do_if (cp+1); - } else { - CERROR ("'(', '{', '%<' or ')' expected"); - } - return (cp); + register char *cp = sp; + register int c; + + if ((c = *cp++) == '{') { + cp = do_name(cp, preprocess); + fp->f_type = FT_LS_COMP; + } else if (c == '(') { + cp = do_func(cp); + } else if (c == ')') { + return (--cp); + } else if (c == '%' && *cp == '<') { + cp = do_if(cp+1); + } else { + CERROR("'(', '{', '%<' or ')' expected"); + } + return (cp); } + +/* +** I am guessing this was for some kind of loop statement, which would have +** looked like %[ .... %]. It looks like the way this would have worked +** is that the format engine would have seen that FT_DONE had a 1 in the +** f_un.f_un_value and then decided whether or not to continue the loop. +** There is no support for this in the format engine, so right now if +** you try using it you will reach the FT_DONE and simply stop. I'm leaving +** this here in case someone wants to continue the work. +*/ static char * do_loop(char *sp) { - register char *cp = sp; - struct format *floop; + register char *cp = sp; + struct format *floop; - floop = next_fp; - cp = compile (cp); - if (*cp++ != ']') - CERROR ("']' expected"); + floop = next_fp; + cp = compile(cp); + if (*cp++ != ']') + CERROR("']' expected"); - LV(FT_DONE, 1); /* not yet done */ - LV(FT_GOTO, 0); - fp->f_skip = floop - fp; /* skip backwards */ + LV(FT_DONE, 1); /* not yet done */ + LV(FT_GOTO, 0); + fp->f_skip = floop - fp; /* skip backwards */ - return cp; + return cp; } + +/* +** Handle an if-elsif-endif statement. Note here that the branching +** is handled by the f_skip member of the struct format (which is really +** just f_width overloaded). This number controls how far to move forward +** (or back) in the format instruction array. +*/ static char * do_if(char *sp) { - register char *cp = sp; - register struct format *fexpr, - *fif = (struct format *)NULL; - register int c = '<'; - - for (;;) { - if (c == '<') { /* doing an IF */ - if ((c = *cp++) == '{') /*}*/{ - cp = do_name(cp, 0); - fp->f_type = FT_LS_COMP; - LV (FT_IF_S, 0); - } - else if (c == '(') { - cp = do_func(cp); - /* see if we can merge the load and the "if" */ - if (ftbl->f_type >= IF_FUNCS) - fp->f_type = ftbl->extra; - else { - /* Put out a string test or a value test depending - * on what this function's return type is. - */ - if (ftbl->flags & TFL_PUTS) { - LV (FT_IF_S, 0); - } else { - LV (FT_IF_V_NE, 0); - } + register char *cp = sp; + register struct format *fexpr, *fif = (struct format *)NULL; + register int c = '<'; + + for (;;) { + if (c == '<') { /* doing an IF */ + if ((c = *cp++) == '{') /*}*/{ + cp = do_name(cp, 0); + fp->f_type = FT_LS_COMP; + LV(FT_IF_S, 0); + } else if (c == '(') { + cp = do_func(cp); + /* see if we can merge the load and the "if" */ + if (ftbl->f_type >= IF_FUNCS) + fp->f_type = ftbl->extra; + else { + /* + ** Put out a string test or a value + ** test depending on what this + ** function 's return type is. + */ + if (ftbl->flags & TFL_PUTS) { + LV(FT_IF_S, 0); + } else { + LV(FT_IF_V_NE, 0); + } + } + } else { + CERROR("'(' or '{' expected"); /*}*/ + } } - } - else { - CERROR("'(' or '{' expected"); /*}*/ - } - } - fexpr = fp; /* loc of [ELS]IF */ - cp = compile (cp); /* compile IF TRUE stmts */ - if (fif) - fif->f_skip = next_fp - fif; + fexpr = fp; /* loc of [ELS]IF */ + cp = compile(cp); /* compile IF TRUE stmts */ + if (fif) + fif->f_skip = next_fp - fif; - if ((c = *cp++) == '|') { /* the last ELSE */ - LV(FT_GOTO, 0); - fif = fp; /* loc of GOTO */ - fexpr->f_skip = next_fp - fexpr; + if ((c = *cp++) == '|') { /* the last ELSE */ + LV(FT_GOTO, 0); + fif = fp; /* loc of GOTO */ + fexpr->f_skip = next_fp - fexpr; - fexpr = (struct format *)NULL;/* no extra ENDIF */ + fexpr = (struct format *)NULL;/* no extra ENDIF */ - cp = compile (cp); /* compile ELSE stmts */ - fif->f_skip = next_fp - fif; - c = *cp++; - } - else if (c == '?') { /* another ELSIF */ - LV(FT_GOTO, 0); - fif = fp; /* loc of GOTO */ - fexpr->f_skip = next_fp - fexpr; + cp = compile(cp); /* compile ELSE stmts */ + fif->f_skip = next_fp - fif; + c = *cp++; + } else if (c == '?') { /* another ELSIF */ + LV(FT_GOTO, 0); + fif = fp; /* loc of GOTO */ + fexpr->f_skip = next_fp - fexpr; - c = '<'; /* impersonate an IF */ - continue; + c = '<'; /* impersonate an IF */ + continue; + } + break; } - break; - } - if (c != '>') { - CERROR("'>' expected."); - } + if (c != '>') { + CERROR("'>' expected."); + } - if (fexpr) /* IF ... [ELSIF ...] ENDIF */ - fexpr->f_skip = next_fp - fexpr; + if (fexpr) /* IF ... [ELSIF ...] ENDIF */ + fexpr->f_skip = next_fp - fexpr; - return (cp); + return (cp); } diff --git a/sbr/fmt_def.c b/sbr/fmt_def.c index 1edb787..65890e9 100644 --- a/sbr/fmt_def.c +++ b/sbr/fmt_def.c @@ -1,11 +1,10 @@ - /* - * fmt_def.c -- some defines for sbr/fmt_scan.c - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_def.c -- some defines for sbr/fmt_scan.c +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include diff --git a/sbr/fmt_new.c b/sbr/fmt_new.c index 44a18b3..9fd34c8 100644 --- a/sbr/fmt_new.c +++ b/sbr/fmt_new.c @@ -1,107 +1,115 @@ - /* - * fmt_new.c -- read format file/string and normalize - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_new.c -- read format file/string and normalize +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include -#define QUOTE '\\' - -static char *formats = 0; +static char *formats = NULL; /* - * static prototypes - */ -static void normalize (char *); +** static prototypes +*/ +static void normalize(char *); /* - * Get new format string - */ - +** Copy first available format string, store in static memory and normalize it. +*/ char * -new_fs (char *form, char *format, char *default_fs) +new_fs(char *form, char *def_form) { - struct stat st; - register FILE *fp; - - if (formats) - free (formats); - - if (form) { - if ((fp = fopen (etcpath (form), "r")) == NULL) - adios (form, "unable to open format file"); + struct stat st; + register FILE *fp; - if (fstat (fileno (fp), &st) == -1) - adios (form, "unable to stat format file"); - - formats = mh_xmalloc ((size_t) st.st_size + 1); - - if (read (fileno(fp), formats, (int) st.st_size) != st.st_size) - adios (form, "error reading format file"); - - formats[st.st_size] = '\0'; - - fclose (fp); - } else { - formats = getcpy (format ? format : default_fs); - } + if (formats) { + free(formats); + } - normalize (formats); /* expand escapes */ + if (form) { + if (*form == '=') { + formats = getcpy(form+1); + } else { + if ((fp = fopen(etcpath(form), "r")) == NULL) { + adios(form, "unable to open format file"); + } + if (fstat(fileno(fp), &st) == -1) { + adios(form, "unable to stat format file"); + } + formats = mh_xmalloc((size_t) st.st_size + 1); + if (read(fileno(fp), formats, (int)st.st_size) != st.st_size) { + adios(form, "error reading format file"); + } + formats[st.st_size] = '\0'; + fclose(fp); + } + } else if (def_form) { + if (*def_form == '=') { + formats = getcpy(def_form+1); + } else { + if ((fp = fopen(etcpath(def_form), "r")) == NULL) { + adios(def_form, "unable to open format file"); + } + if (fstat(fileno(fp), &st) == -1) { + adios(def_form, "unable to stat format file"); + } + formats = mh_xmalloc((size_t) st.st_size + 1); + if (read(fileno(fp), formats, (int)st.st_size) != st.st_size) { + adios(def_form, "error reading format file"); + } + formats[st.st_size] = '\0'; + fclose(fp); + } + } + normalize(formats); /* expand escapes */ - return formats; + return formats; } /* - * Expand escapes in format strings - */ - +** Expand escapes in format strings +*/ static void -normalize (char *cp) +normalize(char *cp) { - char *dp; + char *dp; - for (dp = cp; *cp; cp++) { - if (*cp != QUOTE) { - *dp++ = *cp; - } else { - switch (*++cp) { - case 'b': - *dp++ = '\b'; - break; + for (dp = cp; *cp; cp++) { + if (*cp != '\\') { + *dp++ = *cp; + continue; + } + switch (*++cp) { + case 'b': + *dp++ = '\b'; + break; case 'f': - *dp++ = '\f'; - break; - + *dp++ = '\f'; + break; case 'n': - *dp++ = '\n'; - break; - + *dp++ = '\n'; + break; case 'r': - *dp++ = '\r'; - break; - + *dp++ = '\r'; + break; case 't': - *dp++ = '\t'; - break; - + *dp++ = '\t'; + break; case '\n': - break; - - case 0: - cp--; /* fall */ - default: - *dp++ = *cp; - break; - } + break; + case '\0': + cp--; + /* fall */ + default: + *dp++ = *cp; + break; + } } - } - *dp = '\0'; + *dp = '\0'; } diff --git a/sbr/fmt_rfc2047.c b/sbr/fmt_rfc2047.c index 4d3fc29..4e8231f 100644 --- a/sbr/fmt_rfc2047.c +++ b/sbr/fmt_rfc2047.c @@ -1,11 +1,10 @@ - /* - * fmt_rfc2047.c -- decode RFC-2047 header format - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_rfc2047.c -- decode RFC-2047 header format +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -15,35 +14,35 @@ #endif static signed char hexindex[] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, - -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; static signed char index_64[128] = { - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, - 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, - -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; #define char64(c) (((unsigned char) (c) > 127) ? -1 : index_64[(unsigned char) (c)]) static int -unqp (unsigned char byte1, unsigned char byte2) +unqp(unsigned char byte1, unsigned char byte2) { - if (hexindex[byte1] == -1 || hexindex[byte2] == -1) - return -1; - return (hexindex[byte1] << 4 | hexindex[byte2]); + if (hexindex[byte1] == -1 || hexindex[byte2] == -1) + return -1; + return (hexindex[byte1] << 4 | hexindex[byte2]); } /* Check if character is linear whitespace */ @@ -51,303 +50,321 @@ unqp (unsigned char byte1, unsigned char byte2) /* - * Decode the string as a RFC-2047 header field - */ +** Decode the string as a RFC-2047 header field +*/ /* Add character to the destination buffer, and bomb out if it fills up */ #define ADDCHR(C) do { *q++ = (C); dstlen--; if (!dstlen) goto buffull; } while (0) int -decode_rfc2047 (char *str, char *dst, size_t dstlen) +decode_rfc2047(char *str, char *dst, size_t dstlen) { - char *p, *q, *pp; - char *startofmime, *endofmime; - int c, quoted_printable; - int encoding_found = 0; /* did we decode anything? */ - int between_encodings = 0; /* are we between two encodings? */ - int equals_pending = 0; /* is there a '=' pending? */ - int whitespace = 0; /* how much whitespace between encodings? */ + char *p, *q, *pp; + char *startofmime, *endofmime; + int c, quoted_printable; + int encoding_found = 0; /* did we decode anything? */ + int between_encodings = 0; /* are we between two encodings? */ + int equals_pending = 0; /* is there a '=' pending? */ + int whitespace = 0; /* how much whitespace between encodings? */ #ifdef HAVE_ICONV - int use_iconv = 0; /* are we converting encoding with iconv? */ - iconv_t cd = NULL; - int fromutf8 = 0; - char *saveq, *convbuf = NULL; - size_t savedstlen; + int use_iconv = 0; /* are we converting encoding with iconv? */ + iconv_t cd = NULL; + int fromutf8 = 0; + char *saveq, *convbuf = NULL; + size_t savedstlen; #endif - if (!str) - return 0; + if (!str) + return 0; - /* - * Do a quick and dirty check for the '=' character. - * This should quickly eliminate many cases. - */ - if (!strchr (str, '=')) - return 0; + /* + ** Do a quick and dirty check for the '=' character. + ** This should quickly eliminate many cases. + */ + if (!strchr(str, '=')) + return 0; - for (p = str, q = dst; *p; p++) { + for (p = str, q = dst; *p; p++) { - /* reset iconv */ + /* reset iconv */ #ifdef HAVE_ICONV - if (use_iconv) { - iconv_close(cd); - use_iconv = 0; - } + if (use_iconv) { + iconv_close(cd); + use_iconv = 0; + } #endif - /* - * If we had an '=' character pending from - * last iteration, then add it first. - */ - if (equals_pending) { - ADDCHR('='); - equals_pending = 0; - between_encodings = 0; /* we have added non-whitespace text */ - } + /* + ** If we had an '=' character pending from + ** last iteration, then add it first. + */ + if (equals_pending) { + ADDCHR('='); + equals_pending = 0; + between_encodings = 0; /* we have added non-whitespace text */ + } - if (*p != '=') { - /* count linear whitespace while between encodings */ - if (between_encodings && is_lws(*p)) - whitespace++; - else - between_encodings = 0; /* we have added non-whitespace text */ - ADDCHR(*p); - continue; - } + if (*p != '=') { + /* count linear whitespace while between encodings */ + if (between_encodings && is_lws(*p)) + whitespace++; + else + between_encodings = 0; /* we have added non-whitespace text */ + ADDCHR(*p); + continue; + } - equals_pending = 1; /* we have a '=' pending */ + equals_pending = 1; /* we have a '=' pending */ - /* Check for initial =? */ - if (*p == '=' && p[1] && p[1] == '?' && p[2]) { - startofmime = p + 2; + /* Check for initial =? */ + if (*p == '=' && p[1] && p[1] == '?' && p[2]) { + startofmime = p + 2; - /* Scan ahead for the next '?' character */ - for (pp = startofmime; *pp && *pp != '?'; pp++) - ; + /* Scan ahead for the next '?' character */ + for (pp = startofmime; *pp && *pp != '?'; pp++) + ; - if (!*pp) - continue; + if (!*pp) + continue; + *pp = '\0'; - /* Check if character set can be handled natively */ - if (!check_charset(startofmime, pp - startofmime)) { + /* Check if character set can be handled natively */ + if (!is_native_charset(startofmime)) { #ifdef HAVE_ICONV - /* .. it can't. We'll use iconv then. */ - *pp = '\0'; - cd = iconv_open(get_charset(), startofmime); - fromutf8 = !mh_strcasecmp(startofmime, "UTF-8"); - *pp = '?'; - if (cd == (iconv_t)-1) continue; - use_iconv = 1; + /* .. it can't. We'll use iconv then. */ + cd = iconv_open(get_charset(), startofmime); + fromutf8 = !mh_strcasecmp(startofmime, "UTF-8"); + *pp = '?'; + if (cd == (iconv_t)-1) + continue; + use_iconv = 1; #else - continue; + *pp = '?'; + continue; #endif - } - - startofmime = pp + 1; - - /* Check for valid encoding type */ - if (*startofmime != 'B' && *startofmime != 'b' && - *startofmime != 'Q' && *startofmime != 'q') - continue; - - /* Is encoding quoted printable or base64? */ - quoted_printable = (*startofmime == 'Q' || *startofmime == 'q'); - startofmime++; - - /* Check for next '?' character */ - if (*startofmime != '?') - continue; - startofmime++; - - /* - * Scan ahead for the ending ?= - * - * While doing this, we will also check if encoded - * word has any embedded linear whitespace. - */ - endofmime = NULL; - for (pp = startofmime; *pp && *(pp+1); pp++) { - if (is_lws(*pp)) { - break; - } else if (*pp == '?' && pp[1] == '=') { - endofmime = pp; - break; - } - } - if (is_lws(*pp) || endofmime == NULL) - continue; - - /* - * We've found an encoded word, so we can drop - * the '=' that was pending - */ - equals_pending = 0; - - /* - * If we are between two encoded words separated only by - * linear whitespace, then we ignore the whitespace. - * We will roll back the buffer the number of whitespace - * characters we've seen since last encoded word. - */ - if (between_encodings) { - q -= whitespace; - dstlen += whitespace; - } + } + + *pp = '?'; + startofmime = pp + 1; + + /* Check for valid encoding type */ + if (*startofmime != 'B' && *startofmime != 'b' && + *startofmime != 'Q' && *startofmime != 'q') + continue; + + /* Is encoding quoted printable or base64? */ + quoted_printable = (*startofmime == 'Q' || *startofmime == 'q'); + startofmime++; + + /* Check for next '?' character */ + if (*startofmime != '?') + continue; + startofmime++; + + /* + ** Scan ahead for the ending ?= + ** + ** While doing this, we will also check if encoded + ** word has any embedded linear whitespace. + */ + endofmime = NULL; + for (pp = startofmime; *pp && *(pp+1); pp++) { + if (is_lws(*pp)) { + break; + } else if (*pp == '?' && pp[1] == '=') { + endofmime = pp; + break; + } + } + if (is_lws(*pp) || endofmime == NULL) + continue; + + /* + ** We've found an encoded word, so we can drop + ** the '=' that was pending + */ + equals_pending = 0; + + /* + ** If we are between two encoded words separated + ** only by linear whitespace, then we ignore + ** the whitespace. We will roll back the buffer + ** the number of whitespace characters we've seen + ** since last encoded word. + */ + if (between_encodings) { + q -= whitespace; + dstlen += whitespace; + } #ifdef HAVE_ICONV - /* - * empty encoded text. This ensures that we don't - * malloc 0 bytes but skip on to the end - */ - if (endofmime == startofmime && use_iconv) { - use_iconv = 0; - iconv_close(cd); - } - - if (use_iconv) { - saveq = q; - savedstlen = dstlen; - q = convbuf = (char *) mh_xmalloc(endofmime - startofmime); - } -/* ADDCHR2 is for adding characters when q is or might be convbuf: - * in this case on buffer-full we want to run iconv before returning. - * I apologise for the dreadful name. - */ -#define ADDCHR2(C) do { *q++ = (C); dstlen--; if (!dstlen) goto iconvbuffull; } while (0) + /* + ** empty encoded text. This ensures that we don't + ** malloc 0 bytes but skip on to the end + */ + if (endofmime == startofmime && use_iconv) { + use_iconv = 0; + iconv_close(cd); + } + + if (use_iconv) { + saveq = q; + savedstlen = dstlen; + q = convbuf = (char *) mh_xmalloc(endofmime - startofmime); + } +/* +** ADDCHR2 is for adding characters when q is or might be convbuf: +** in this case on buffer-full we want to run iconv before returning. +** I apologise for the dreadful name. +*/ +# define ADDCHR2(C) do { *q++ = (C); dstlen--; if (!dstlen) goto iconvbuffull; } while (0) #else -#define ADDCHR2(C) ADDCHR(C) +# define ADDCHR2(C) ADDCHR(C) #endif - /* Now decode the text */ - if (quoted_printable) { - for (pp = startofmime; pp < endofmime; pp++) { - if (*pp == '=') { - c = unqp (pp[1], pp[2]); - if (c == -1) - continue; - if (c != 0) - *q++ = c; - pp += 2; - } else if (*pp == '_') { - ADDCHR2(' '); - } else { - ADDCHR2(*pp); - } - } - } else { - /* base64 */ - int c1, c2, c3, c4; - c1 = c2 = c3 = c4 = -1; - - pp = startofmime; - while (pp < endofmime) { - /* 6 + 2 bits */ - while ((pp < endofmime) && - ((c1 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime) { - pp++; - } - while ((pp < endofmime) && - ((c2 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c1 != -1 && c2 != -1) { - ADDCHR2((c1 << 2) | (c2 >> 4)); - pp++; - } - /* 4 + 4 bits */ - while ((pp < endofmime) && - ((c3 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c2 != -1 && c3 != -1) { - ADDCHR2(((c2 & 0xF) << 4) | (c3 >> 2)); - pp++; - } - /* 2 + 6 bits */ - while ((pp < endofmime) && - ((c4 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c3 != -1 && c4 != -1) { - ADDCHR2(((c3 & 0x3) << 6) | (c4)); - pp++; - } - } - } + /* Now decode the text */ + if (quoted_printable) { + for (pp = startofmime; pp < endofmime; pp++) { + if (*pp == '=') { + c = unqp(pp[1], pp[2]); + if (c == -1) + continue; + if (c != 0) + *q++ = c; + pp += 2; + } else if (*pp == '_') { + ADDCHR2(' '); + } else { + ADDCHR2(*pp); + } + } + } else { + /* base64 */ + int c1, c2, c3, c4; + c1 = c2 = c3 = c4 = -1; + + pp = startofmime; + while (pp < endofmime) { + /* 6 + 2 bits */ + while ((pp < endofmime) && + ((c1 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime) { + pp++; + } + while ((pp < endofmime) && + ((c2 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c1 != -1 && c2 != -1) { + ADDCHR2((c1 << 2) | (c2 >> 4)); + pp++; + } + /* 4 + 4 bits */ + while ((pp < endofmime) && + ((c3 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c2 != -1 && c3 != -1) { + ADDCHR2(((c2 & 0xF) << 4) | (c3 >> 2)); + pp++; + } + /* 2 + 6 bits */ + while ((pp < endofmime) && + ((c4 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c3 != -1 && c4 != -1) { + ADDCHR2(((c3 & 0x3) << 6) | (c4)); + pp++; + } + } + } #ifdef HAVE_ICONV - iconvbuffull: - /* NB that the string at convbuf is not necessarily NUL terminated here: - * q points to the first byte after the valid part. - */ - /* Convert to native character set */ - if (use_iconv) { - size_t inbytes = q - convbuf; - ICONV_CONST char *start = convbuf; - - while (inbytes) { - if (iconv(cd, &start, &inbytes, &saveq, &savedstlen) == - (size_t)-1) { - if (errno != EILSEQ) break; - /* character couldn't be converted. we output a `?' - * and try to carry on which won't work if - * either encoding was stateful */ - iconv (cd, 0, 0, &saveq, &savedstlen); - if (!savedstlen) - break; - *saveq++ = '?'; - savedstlen--; - if (!savedstlen) - break; - /* skip to next input character */ - if (fromutf8) { - for (start++;(start < q) && ((*start & 192) == 128);start++) - inbytes--; - } else - start++, inbytes--; - if (start >= q) - break; - } - } - q = saveq; - /* Stop now if (1) we hit the end of the buffer trying to do - * MIME decoding and have just iconv-converted a partial string - * or (2) our iconv-conversion hit the end of the buffer. - */ - if (!dstlen || !savedstlen) - goto buffull; - dstlen = savedstlen; - free(convbuf); - } + iconvbuffull: + /* + ** NB that the string at convbuf is not necessarily + ** NUL terminated here: + ** q points to the first byte after the valid part. + */ + /* Convert to native character set */ + if (use_iconv) { + size_t inbytes = q - convbuf; + ICONV_CONST char *start = convbuf; + + while (inbytes) { + if (iconv(cd, &start, &inbytes, &saveq, &savedstlen) == + (size_t)-1) { + if (errno != EILSEQ) + break; + /* + ** character couldn't be + ** converted. we output a + ** `?' and try to carry on + ** which won't work if either + ** encoding was stateful + */ + iconv(cd, 0, 0, &saveq, &savedstlen); + if (!savedstlen) + break; + *saveq++ = '?'; + savedstlen--; + if (!savedstlen) + break; + /* skip to next input character */ + if (fromutf8) { + for (start++;(start < q) && ((*start & 192) == 128);start++) + inbytes--; + } else + start++, inbytes--; + if (start >= q) + break; + } + } + q = saveq; + /* + ** Stop now if (1) we hit the end of the + ** buffer trying to do MIME decoding and + ** have just iconv-converted a partial + ** string or (2) our iconv-conversion hit + ** the end of the buffer. + */ + if (!dstlen || !savedstlen) + goto buffull; + dstlen = savedstlen; + free(convbuf); + } #endif - - /* - * Now that we are done decoding this particular - * encoded word, advance string to trailing '='. - */ - p = endofmime + 1; - - encoding_found = 1; /* we found (at least 1) encoded word */ - between_encodings = 1; /* we have just decoded something */ - whitespace = 0; /* re-initialize amount of whitespace */ + + /* + ** Now that we are done decoding this particular + ** encoded word, advance string to trailing '='. + */ + p = endofmime + 1; + + encoding_found = 1; /* we found (at least 1) encoded word */ + between_encodings = 1; /* we have just decoded something */ + whitespace = 0; /* re-initialize amount of whitespace */ + } } - } #ifdef HAVE_ICONV - if (use_iconv) iconv_close(cd); + if (use_iconv) iconv_close(cd); #endif - /* If an equals was pending at end of string, add it now. */ - if (equals_pending) - ADDCHR('='); - *q = '\0'; + /* If an equals was pending at end of string, add it now. */ + if (equals_pending) + ADDCHR('='); + *q = '\0'; - return encoding_found; + return encoding_found; buffull: - /* q is currently just off the end of the buffer, so rewind to NUL terminate */ - q--; - *q = '\0'; - return encoding_found; + /* + ** q is currently just off the end of the buffer, + ** so rewind to NUL terminate + */ + q--; + *q = '\0'; + return encoding_found; } diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 97a0b4a..ec086a1 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -1,11 +1,13 @@ - /* - * fmt_scan.c -- format string interpretation - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_scan.c -- format string interpretation +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** This is the engine that processes the format instructions created by +** fmt_compile (found in fmt_compile.c). +*/ #include #include @@ -13,919 +15,875 @@ #include #include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include + #ifdef MULTIBYTE_SUPPORT # include # include #endif -#define NFMTS MAXARGS - -extern char *formataddr (); /* hook for custom address formatting */ - -#ifdef LBL -struct msgs *fmt_current_folder; /* current folder (set by main program) */ -#endif - -extern int fmt_norm; /* defined in sbr/fmt_def.c = AD_NAME */ +extern int fmt_norm; /* defined in sbr/fmt_def.c = AD_NAME */ struct mailname fmt_mnull; /* - * static prototypes - */ -static int match (char *, char *); -static char *get_x400_friendly (char *, char *, int); -static int get_x400_comp (char *, char *, char *, int); +** static prototypes +*/ +static int match(char *, char *); +static char *get_x400_friendly(char *, char *, int); +static int get_x400_comp(char *, char *, char *, int); /* - * test if string "sub" appears anywhere in - * string "str" (case insensitive). - */ +** test if string "sub" appears anywhere in +** string "str" (case insensitive). +*/ static int -match (char *str, char *sub) +match(char *str, char *sub) { - int c1, c2; - char *s1, *s2; - -#ifdef LOCALE - while ((c1 = *sub)) { - c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1; - while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2)) - ; - if (! c2) - return 0; - s1 = sub + 1; s2 = str; - while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2)) - ; - if (! c1) - return 1; - } -#else - while ((c1 = *sub)) { - while ((c2 = *str++) && (c1 | 040) != (c2 | 040)) - ; - if (! c2) - return 0; - s1 = sub + 1; s2 = str; - while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040)) - ; - if (! c1) - return 1; - } -#endif - return 1; + int c1, c2; + char *s1, *s2; + + while ((c1 = *sub)) { + while ((c2 = *str++) && tolower(c1) != tolower(c2)) + ; + if (! c2) + return 0; + s1 = sub + 1; s2 = str; + while ((c1 = *s1++) && tolower(c1) == tolower(*s2++)) + ; + if (! c1) + return 1; + } + return 1; } /* - * copy a number to the destination subject to a maximum width - */ +** copy a number to the destination subject to a maximum width +*/ static void cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) { - int i, c; - char *sp; - char *cp = *dest; - char *ep = cp + n; - - if (cp + wid < ep) { - if ((i = (num)) < 0) - i = -(num); - if ((c = (wid)) < 0) - c = -c; - sp = cp + c; - do { - *--sp = (i % 10) + '0'; - i /= 10; - } while (i > 0 && sp > cp); - if (i > 0) - *sp = '?'; - else if ((num) < 0 && sp > cp) - *--sp = '-'; - while (sp > cp) - *--sp = fill; - cp += c; - } - *dest = cp; + int i, c; + char *sp; + char *cp = *dest; + char *ep = cp + n; + + if (cp + wid < ep) { + if ((i = (num)) < 0) + i = -(num); + if ((c = (wid)) < 0) + c = -c; + sp = cp + c; + do { + *--sp = (i % 10) + '0'; + i /= 10; + } while (i > 0 && sp > cp); + if (i > 0) + *sp = '?'; + else if ((num) < 0 && sp > cp) + *--sp = '-'; + while (sp > cp) + *--sp = fill; + cp += c; + } + *dest = cp; } /* - * copy string from str to dest padding with the fill character to a size - * of wid characters. if wid is negative, the string is right aligned - * no more than n bytes are copied - */ +** copy string from str to dest padding with the fill character to a size +** of wid characters. if wid is negative, the string is right aligned +** no more than n bytes are copied +*/ static void cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { - int remaining; /* remaining output width available */ - int c, ljust, w; - int end; /* number of input bytes remaining in str */ + int remaining; /* remaining output width available */ + int c, ljust, w; + int end; /* number of input bytes remaining in str */ #ifdef MULTIBYTE_SUPPORT - int char_len; /* bytes in current character */ - wchar_t wide_char; + int char_len; /* bytes in current character */ + wchar_t wide_char; #endif - char *sp; /* current position in source string */ - char *cp = *dest; /* current position in destination string */ - char *ep = cp + n; /* end of destination buffer */ - int prevCtrl = 1; - - /* get alignment */ - ljust = 0; - if ((remaining = (wid)) < 0) { - remaining = -remaining; - ljust++; - } - if ((sp = (str))) { - mbtowc(NULL, NULL, 0); /* reset shift state */ - end = strlen(str); - while (*sp && remaining > 0 && end > 0) { + char *sp; /* current position in source string */ + char *cp = *dest; /* current position in destination string */ + char *ep = cp + n; /* end of destination buffer */ + int prevCtrl = 1; + + /* get alignment */ + ljust = 0; + if ((remaining = (wid)) < 0) { + remaining = -remaining; + ljust++; + } + if ((sp = (str))) { + mbtowc(NULL, NULL, 0); /* reset shift state */ + end = strlen(str); + while (*sp && remaining > 0 && end > 0) { #ifdef MULTIBYTE_SUPPORT - char_len = mbtowc(&wide_char, sp, end); - if (char_len <= 0 || (cp + char_len > ep)) - break; + char_len = mbtowc(&wide_char, sp, end); + if (char_len <= 0 || (cp + char_len > ep)) + break; - end -= char_len; + end -= char_len; - if (iswcntrl(wide_char) || iswspace(wide_char)) { - sp += char_len; + if (iswcntrl(wide_char) || iswspace(wide_char)) { + sp += char_len; #else - end--; - if (iscntrl(*sp) || isspace(*sp)) { - sp++; + end--; + if (iscntrl(*sp) || isspace(*sp)) { + sp++; #endif - if (!prevCtrl) { - *cp++ = ' '; - remaining--; - } + if (!prevCtrl) { + *cp++ = ' '; + remaining--; + } - prevCtrl = 1; - continue; - } - prevCtrl = 0; + prevCtrl = 1; + continue; + } + prevCtrl = 0; #ifdef MULTIBYTE_SUPPORT - w = wcwidth(wide_char); - if (w >= 0 && remaining >= w) { - strncpy(cp, sp, char_len); - cp += char_len; - remaining -= w; - } - sp += char_len; + w = wcwidth(wide_char); + if (w >= 0 && remaining >= w) { + strncpy(cp, sp, char_len); + cp += char_len; + remaining -= w; + } + sp += char_len; #else - *cp++ = *sp++; - remaining--; + *cp++ = *sp++; + remaining--; #endif + } } - } - - if (ljust) { - if (cp + remaining > ep) - remaining = ep - cp; - ep = cp + remaining; - if (remaining > 0) { - /* copy string to the right */ - while (--cp >= *dest) - *(cp + remaining) = *cp; - /* add padding at the beginning */ - cp += remaining; - for (c=remaining; c>0; c--) - *cp-- = fill; + + if (ljust) { + if (cp + remaining > ep) + remaining = ep - cp; + ep = cp + remaining; + if (remaining > 0) { + /* copy string to the right */ + while (--cp >= *dest) + *(cp + remaining) = *cp; + /* add padding at the beginning */ + cp += remaining; + for (c=remaining; c>0; c--) + *cp-- = fill; + } + *dest = ep; + } else { + /* pad remaining space */ + while (remaining-- > 0 && cp < ep) + *cp++ = fill; + *dest = cp; } - *dest = ep; - } else { - /* pad remaining space */ - while (remaining-- > 0 && cp < ep) - *cp++ = fill; - *dest = cp; - } } static void -cpstripped (char **start, char *end, char *str) +cpstripped(char **start, char *end, char *str) { - int c; - char *s = str; + int c; + char *s = str; - if (!s) - return; + if (!s) + return; - /* skip any initial control characters or spaces */ - while ((c = (unsigned char) *s) && -#ifdef LOCALE - (iscntrl(c) || isspace(c))) -#else - (c <= 32)) -#endif - s++; - - /* compact repeated control characters and spaces into a single space */ - while((c = (unsigned char) *s++) && *start < end) - if (!iscntrl(c) && !isspace(c)) - *(*start)++ = c; - else { - while ((c = (unsigned char) *s) && -#ifdef LOCALE - (iscntrl(c) || isspace(c))) -#else - (c <= 32)) -#endif + /* skip any initial control characters or spaces */ + while ((c = (unsigned char) *s) && (iscntrl(c) || isspace(c))) s++; - *(*start)++ = ' '; - } + + /* compact repeated control characters and spaces into a single space */ + while((c = (unsigned char) *s++) && *start < end) + if (!iscntrl(c) && !isspace(c)) + *(*start)++ = c; + else { + while ((c = (unsigned char) *s) && + (iscntrl(c) || isspace(c))) + s++; + *(*start)++ = ' '; + } } -static char *lmonth[] = { "January", "February","March", "April", - "May", "June", "July", "August", - "September","October", "November","December" }; +static char *lmonth[] = { + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" +}; static char * -get_x400_friendly (char *mbox, char *buffer, int buffer_len) +get_x400_friendly(char *mbox, char *buffer, int buffer_len) { - char given[BUFSIZ], surname[BUFSIZ]; + char given[BUFSIZ], surname[BUFSIZ]; - if (mbox == NULL) - return NULL; - if (*mbox == '"') - mbox++; - if (*mbox != '/') - return NULL; + if (mbox == NULL) + return NULL; + if (*mbox == '"') + mbox++; + if (*mbox != '/') + return NULL; - if (get_x400_comp (mbox, "/PN=", buffer, buffer_len)) { - for (mbox = buffer; (mbox = strchr(mbox, '.')); ) - *mbox++ = ' '; + if (get_x400_comp(mbox, "/PN=", buffer, buffer_len)) { + for (mbox = buffer; (mbox = strchr(mbox, '.')); ) + *mbox++ = ' '; - return buffer; - } + return buffer; + } - if (!get_x400_comp (mbox, "/S=", surname, sizeof(surname))) - return NULL; + if (!get_x400_comp(mbox, "/S=", surname, sizeof(surname))) + return NULL; - if (get_x400_comp (mbox, "/G=", given, sizeof(given))) - snprintf (buffer, buffer_len, "%s %s", given, surname); - else - snprintf (buffer, buffer_len, "%s", surname); + if (get_x400_comp(mbox, "/G=", given, sizeof(given))) + snprintf(buffer, buffer_len, "%s %s", given, surname); + else + snprintf(buffer, buffer_len, "%s", surname); - return buffer; + return buffer; } static int -get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len) +get_x400_comp(char *mbox, char *key, char *buffer, int buffer_len) { - int idx; - char *cp; + int idx; + char *cp; - if ((idx = stringdex (key, mbox)) < 0 - || !(cp = strchr(mbox += idx + strlen (key), '/'))) - return 0; + if ((idx = stringdex(key, mbox)) < 0 + || !(cp = strchr(mbox += idx + strlen(key), '/'))) + return 0; - snprintf (buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox); - return 1; + snprintf(buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox); + return 1; } struct format * -fmt_scan (struct format *format, char *scanl, int width, int *dat) +fmt_scan(struct format *format, char *scanl, int width, int *dat) { - char *cp, *ep; - unsigned char *sp; - char *savestr = NULL; - unsigned char *str = NULL; - char buffer[BUFSIZ], buffer2[BUFSIZ]; - int i, c, ljust, n; - int value = 0; - time_t t; - struct format *fmt; - struct comp *comp; - struct tws *tws; - struct mailname *mn; - - cp = scanl; - ep = scanl + width - 1; - - for (fmt = format; fmt->f_type != FT_DONE; fmt++) - switch (fmt->f_type) { - case FT_PARSEADDR: - case FT_PARSEDATE: - fmt->f_comp->c_flags &= ~CF_PARSED; - break; - } + char *cp, *ep; + unsigned char *sp; + char *savestr = NULL; + unsigned char *str = NULL; + char buffer[BUFSIZ], buffer2[BUFSIZ]; + int i, c, ljust, n; + int value = 0; + time_t t; + struct format *fmt; + struct comp *comp; + struct tws *tws; + struct mailname *mn; + + cp = scanl; + ep = scanl + width - 1; + + for (fmt = format; fmt->f_type != FT_DONE; fmt++) + switch (fmt->f_type) { + case FT_PARSEADDR: + case FT_PARSEDATE: + fmt->f_comp->c_flags &= ~CF_PARSED; + break; + } + + fmt = format; + + while (cp < ep) { + switch (fmt->f_type) { - fmt = format; - - while (cp < ep) { - switch (fmt->f_type) { - - case FT_COMP: - cpstripped (&cp, ep, fmt->f_comp->c_text); - break; - case FT_COMPF: - cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp); - break; - - case FT_LIT: - sp = fmt->f_text; - while( (c = *sp++) && cp < ep) - *cp++ = c; - break; - case FT_LITF: - sp = fmt->f_text; - ljust = 0; - i = fmt->f_width; - if (i < 0) { - i = -i; - ljust++; /* XXX should do something with this */ - } - while( (c = *sp++) && --i >= 0 && cp < ep) - *cp++ = c; - while( --i >= 0 && cp < ep) - *cp++ = fmt->f_fill; - break; - - case FT_STR: - cpstripped (&cp, ep, str); - break; - case FT_STRF: - cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp); - break; - case FT_STRFW: - adios (NULL, "internal error (FT_STRFW)"); - - case FT_NUM: - n = snprintf(cp, ep - cp + 1, "%d", value); - if (n >= 0) { - if (n >= ep - cp) { - cp = ep; - } else - cp += n; - } - break; - case FT_NUMF: - cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp); - break; - - case FT_CHAR: - *cp++ = fmt->f_char; - break; - - case FT_DONE: - goto finished; - - case FT_IF_S: - if (!(value = (str && *str))) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_IF_S_NULL: - if (!(value = (str == NULL || *str == 0))) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_IF_V_EQ: - if (value != fmt->f_value) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_IF_V_NE: - if (value == fmt->f_value) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_IF_V_GT: - if (value <= fmt->f_value) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_IF_MATCH: - if (!(value = (str && match (str, fmt->f_text)))) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_V_MATCH: - if (str) - value = match (str, fmt->f_text); - else - value = 0; - break; - - case FT_IF_AMATCH: - if (!(value = (str && uprf (str, fmt->f_text)))) { - fmt += fmt->f_skip; - continue; - } - break; - - case FT_V_AMATCH: - value = uprf (str, fmt->f_text); - break; - - case FT_S_NONNULL: - value = (str != NULL && *str != 0); - break; - - case FT_S_NULL: - value = (str == NULL || *str == 0); - break; - - case FT_V_EQ: - value = (fmt->f_value == value); - break; - - case FT_V_NE: - value = (fmt->f_value != value); - break; - - case FT_V_GT: - value = (fmt->f_value > value); - break; - - case FT_GOTO: - fmt += fmt->f_skip; - continue; - - case FT_NOP: - break; - - case FT_LS_COMP: - str = fmt->f_comp->c_text; - break; - case FT_LS_LIT: - str = fmt->f_text; - break; - case FT_LS_GETENV: - if (!(str = getenv (fmt->f_text))) - str = ""; - break; - case FT_LS_CFIND: - if (!(str = context_find (fmt->f_text))) - str = ""; - break; - - case FT_LS_DECODECOMP: - if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2))) - str = buffer2; - else - str = fmt->f_comp->c_text; - break; - - case FT_LS_DECODE: - if (str && decode_rfc2047(str, buffer2, sizeof(buffer2))) - str = buffer2; - break; - - case FT_LS_TRIM: - if (str) { - unsigned char *xp; - - strncpy(buffer, str, sizeof(buffer)); - buffer[sizeof(buffer)-1] = '\0'; - str = buffer; - while (isspace(*str)) - str++; - ljust = 0; - if ((i = fmt->f_width) < 0) { - i = -i; - ljust++; - } - - if (!ljust && i > 0 && strlen(str) > i) - str[i] = '\0'; - xp = str; - xp += strlen(str) - 1; - while (xp > str && isspace(*xp)) - *xp-- = '\0'; - if (ljust && i > 0 && strlen(str) > i) - str += strlen(str) - i; - } - break; - - case FT_LV_COMPFLAG: - value = (fmt->f_comp->c_flags & CF_TRUE) != 0; - break; - case FT_LV_COMP: - value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0; - break; - case FT_LV_LIT: - value = fmt->f_value; - break; - case FT_LV_DAT: - value = dat[fmt->f_value]; - break; - case FT_LV_STRLEN: - if (str != NULL) - value = strlen(str); - else - value = 0; - break; - case FT_LV_CHAR_LEFT: - value = width - (cp - scanl); - break; - case FT_LV_PLUS_L: - value += fmt->f_value; - break; - case FT_LV_MINUS_L: - value = fmt->f_value - value; - break; - case FT_LV_DIVIDE_L: - if (fmt->f_value) - value = value / fmt->f_value; - else - value = 0; - break; - case FT_LV_MODULO_L: - if (fmt->f_value) - value = value % fmt->f_value; - else - value = 0; - break; - case FT_SAVESTR: - savestr = str; - break; - - case FT_LV_SEC: - value = fmt->f_comp->c_tws->tw_sec; - break; - case FT_LV_MIN: - value = fmt->f_comp->c_tws->tw_min; - break; - case FT_LV_HOUR: - value = fmt->f_comp->c_tws->tw_hour; - break; - case FT_LV_MDAY: - value = fmt->f_comp->c_tws->tw_mday; - break; - case FT_LV_MON: - value = fmt->f_comp->c_tws->tw_mon + 1; - break; - case FT_LS_MONTH: - str = tw_moty[fmt->f_comp->c_tws->tw_mon]; - break; - case FT_LS_LMONTH: - str = lmonth[fmt->f_comp->c_tws->tw_mon]; - break; - case FT_LS_ZONE: - str = dtwszone (fmt->f_comp->c_tws); - break; - case FT_LV_YEAR: - value = fmt->f_comp->c_tws->tw_year; - break; - case FT_LV_WDAY: - if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) - set_dotw (tws); - value = tws->tw_wday; - break; - case FT_LS_DAY: - if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) - set_dotw (tws); - str = tw_dotw[tws->tw_wday]; - break; - case FT_LS_WEEKDAY: - if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) - set_dotw (tws); - str = tw_ldotw[tws->tw_wday]; - break; - case FT_LV_YDAY: - value = fmt->f_comp->c_tws->tw_yday; - break; - case FT_LV_ZONE: - value = fmt->f_comp->c_tws->tw_zone; - break; - case FT_LV_CLOCK: - if ((value = fmt->f_comp->c_tws->tw_clock) == 0) - value = dmktime(fmt->f_comp->c_tws); - break; - case FT_LV_RCLOCK: - if ((value = fmt->f_comp->c_tws->tw_clock) == 0) - value = dmktime(fmt->f_comp->c_tws); - value = time((time_t *) 0) - value; - break; - case FT_LV_DAYF: - if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) - set_dotw (tws); - switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) { - case TW_SEXP: - value = 1; break; - case TW_SIMP: - value = 0; break; - default: - value = -1; break; - } - case FT_LV_ZONEF: - if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP) - value = 1; - else - value = -1; - break; - case FT_LV_DST: - value = fmt->f_comp->c_tws->tw_flags & TW_DST; - break; - case FT_LS_822DATE: - str = dasctime (fmt->f_comp->c_tws , TW_ZONE); - break; - case FT_LS_PRETTY: - str = dasctime (fmt->f_comp->c_tws, TW_NULL); - break; - - case FT_LS_PERS: - str = fmt->f_comp->c_mn->m_pers; - break; - case FT_LS_MBOX: - str = fmt->f_comp->c_mn->m_mbox; - break; - case FT_LS_HOST: - str = fmt->f_comp->c_mn->m_host; - break; - case FT_LS_PATH: - str = fmt->f_comp->c_mn->m_path; - break; - case FT_LS_GNAME: - str = fmt->f_comp->c_mn->m_gname; - break; - case FT_LS_NOTE: - str = fmt->f_comp->c_mn->m_note; - break; - case FT_LS_822ADDR: - str = adrformat( fmt->f_comp->c_mn ); - break; - case FT_LV_HOSTTYPE: - value = fmt->f_comp->c_mn->m_type; - break; - case FT_LV_INGRPF: - value = fmt->f_comp->c_mn->m_ingrp; - break; - case FT_LV_NOHOSTF: - value = fmt->f_comp->c_mn->m_nohost; - break; - case FT_LS_ADDR: - case FT_LS_FRIENDLY: - if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) { - str = fmt->f_comp->c_text; - break; - } - if (fmt->f_type == FT_LS_ADDR) - goto unfriendly; - if ((str = mn->m_pers) == NULL) { - if ((str = mn->m_note)) { - strncpy (buffer, str, sizeof(buffer)); - buffer[sizeof(buffer)-1] = '\0'; - str = buffer; - if (*str == '(') - str++; - sp = str + strlen(str) - 1; - if (*sp == ')') { - *sp-- = '\0'; - while (sp >= str) - if (*sp == ' ') - *sp-- = '\0'; - else - break; - } - } else if (!(str = get_x400_friendly (mn->m_mbox, - buffer, sizeof(buffer)))) { - unfriendly: ; - switch (mn->m_type) { - case LOCALHOST: - str = mn->m_mbox; - break; - case UUCPHOST: - snprintf (buffer, sizeof(buffer), "%s!%s", - mn->m_host, mn->m_mbox); - str = buffer; - break; - default: - if (mn->m_mbox) { - snprintf (buffer, sizeof(buffer), "%s@%s", - mn->m_mbox, mn->m_host); - str= buffer; + case FT_COMP: + cpstripped(&cp, ep, fmt->f_comp->c_text); + break; + case FT_COMPF: + cptrimmed(&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp); + break; + + case FT_LIT: + sp = fmt->f_text; + while( (c = *sp++) && cp < ep) + *cp++ = c; + break; + case FT_LITF: + sp = fmt->f_text; + ljust = 0; + i = fmt->f_width; + if (i < 0) { + i = -i; + ljust++; /* XXX should do something with this */ } + while( (c = *sp++) && --i >= 0 && cp < ep) + *cp++ = c; + while( --i >= 0 && cp < ep) + *cp++ = fmt->f_fill; + break; + + case FT_STR: + cpstripped(&cp, ep, str); + break; + case FT_STRF: + cptrimmed(&cp, str, fmt->f_width, fmt->f_fill, ep - cp); + break; + case FT_STRFW: + adios(NULL, "internal error (FT_STRFW)"); + + case FT_NUM: + n = snprintf(cp, ep - cp + 1, "%d", value); + if (n >= 0) { + if (n >= ep - cp) { + cp = ep; + } else + cp += n; + } + break; + case FT_NUMF: + cpnumber(&cp, value, fmt->f_width, fmt->f_fill, ep - cp); + break; + + case FT_CHAR: + *cp++ = fmt->f_char; + break; + + case FT_DONE: + goto finished; + + case FT_IF_S: + if (!(value = (str && *str))) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_IF_S_NULL: + if (!(value = (str == NULL || *str == 0))) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_IF_V_EQ: + if (value != fmt->f_value) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_IF_V_NE: + if (value == fmt->f_value) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_IF_V_GT: + if (value <= fmt->f_value) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_IF_MATCH: + if (!(value = (str && match(str, fmt->f_text)))) { + fmt += fmt->f_skip; + continue; + } + break; + + case FT_V_MATCH: + if (str) + value = match(str, fmt->f_text); else - str = mn->m_text; + value = 0; break; - } - } - } - break; + case FT_IF_AMATCH: + if (!(value = (str && uprf(str, fmt->f_text)))) { + fmt += fmt->f_skip; + continue; + } + break; - /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */ - case FT_LS_UNQUOTE: - if (str) { - int m; - strncpy(buffer, str, sizeof(buffer)); - /* strncpy doesn't NUL-terminate if it fills the buffer */ - buffer[sizeof(buffer)-1] = '\0'; - str = buffer; - - /* we will parse from buffer to buffer2 */ - n = 0; /* n is the input position in str */ - m = 0; /* m is the ouput position in buffer2 */ - - while ( str[n] != '\0') { - switch ( str[n] ) { - case '\\': - n++; - if ( str[n] != '\0') - buffer2[m++] = str[n++]; - break; - case '"': - n++; - break; + case FT_V_AMATCH: + value = uprf(str, fmt->f_text); + break; + + case FT_S_NONNULL: + value = (str != NULL && *str != 0); + break; + + case FT_S_NULL: + value = (str == NULL || *str == 0); + break; + + case FT_V_EQ: + value = (fmt->f_value == value); + break; + + case FT_V_NE: + value = (fmt->f_value != value); + break; + + case FT_V_GT: + value = (fmt->f_value > value); + break; + + case FT_GOTO: + fmt += fmt->f_skip; + continue; + + case FT_NOP: + break; + + case FT_LS_COMP: + str = fmt->f_comp->c_text; + break; + case FT_LS_LIT: + str = fmt->f_text; + break; + case FT_LS_GETENV: + if (!(str = getenv(fmt->f_text))) + str = ""; + break; + case FT_LS_CFIND: + if (!(str = context_find(fmt->f_text))) + str = ""; + break; + + case FT_LS_DECODECOMP: + if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2))) + str = buffer2; + else + str = fmt->f_comp->c_text; + break; + + case FT_LS_DECODE: + if (str && decode_rfc2047(str, buffer2, sizeof(buffer2))) + str = buffer2; + break; + + case FT_LS_TRIM: + if (str) { + unsigned char *xp; + + strncpy(buffer, str, sizeof(buffer)); + buffer[sizeof(buffer)-1] = '\0'; + str = buffer; + while (isspace(*str)) + str++; + ljust = 0; + if ((i = fmt->f_width) < 0) { + i = -i; + ljust++; + } + + if (!ljust && i > 0 && (int)strlen(str) > i) + str[i] = '\0'; + xp = str; + xp += strlen(str) - 1; + while (xp > str && isspace(*xp)) + *xp-- = '\0'; + if (ljust && i > 0 && (int)strlen(str) > i) + str += strlen(str) - i; + } + break; + + case FT_LV_COMPFLAG: + value = (fmt->f_comp->c_flags & CF_TRUE) != 0; + break; + case FT_LV_COMP: + value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0; + break; + case FT_LV_LIT: + value = fmt->f_value; + break; + case FT_LV_DAT: + value = dat[fmt->f_value]; + break; + case FT_LV_STRLEN: + if (str != NULL) + value = strlen(str); + else + value = 0; + break; + case FT_LV_CHAR_LEFT: + value = width - (cp - scanl); + break; + case FT_LV_PLUS_L: + value += fmt->f_value; + break; + case FT_LV_MINUS_L: + value = fmt->f_value - value; + break; + case FT_LV_DIVIDE_L: + if (fmt->f_value) + value = value / fmt->f_value; + else + value = 0; + break; + case FT_LV_MODULO_L: + if (fmt->f_value) + value = value % fmt->f_value; + else + value = 0; + break; + case FT_SAVESTR: + savestr = str; + break; + + case FT_LV_SEC: + value = fmt->f_comp->c_tws->tw_sec; + break; + case FT_LV_MIN: + value = fmt->f_comp->c_tws->tw_min; + break; + case FT_LV_HOUR: + value = fmt->f_comp->c_tws->tw_hour; + break; + case FT_LV_MDAY: + value = fmt->f_comp->c_tws->tw_mday; + break; + case FT_LV_MON: + value = fmt->f_comp->c_tws->tw_mon + 1; + break; + case FT_LS_MONTH: + str = tw_moty[fmt->f_comp->c_tws->tw_mon]; + break; + case FT_LS_LMONTH: + str = lmonth[fmt->f_comp->c_tws->tw_mon]; + break; + case FT_LS_ZONE: + str = dtwszone(fmt->f_comp->c_tws); + break; + case FT_LV_YEAR: + value = fmt->f_comp->c_tws->tw_year; + break; + case FT_LV_WDAY: + if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) + set_dotw(tws); + value = tws->tw_wday; + break; + case FT_LS_DAY: + if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) + set_dotw(tws); + str = tw_dotw[tws->tw_wday]; + break; + case FT_LS_WEEKDAY: + if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) + set_dotw(tws); + str = tw_ldotw[tws->tw_wday]; + break; + case FT_LV_YDAY: + value = fmt->f_comp->c_tws->tw_yday; + break; + case FT_LV_ZONE: + value = fmt->f_comp->c_tws->tw_zone; + break; + case FT_LV_CLOCK: + if ((value = fmt->f_comp->c_tws->tw_clock) == 0) + value = dmktime(fmt->f_comp->c_tws); + break; + case FT_LV_RCLOCK: + if ((value = fmt->f_comp->c_tws->tw_clock) == 0) + value = dmktime(fmt->f_comp->c_tws); + value = time((time_t *) 0) - value; + break; + case FT_LV_DAYF: + if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP))) + set_dotw(tws); + switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) { + case TW_SEXP: + value = 1; break; + case TW_SIMP: + value = 0; break; default: - buffer2[m++] = str[n++]; - break; + value = -1; break; } + case FT_LV_ZONEF: + if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP) + value = 1; + else + value = -1; + break; + case FT_LV_DST: + value = fmt->f_comp->c_tws->tw_flags & TW_DST; + break; + case FT_LS_822DATE: + case FT_LS_PRETTY: + str = dasctime(fmt->f_comp->c_tws); + break; + + case FT_LS_PERS: + str = fmt->f_comp->c_mn->m_pers; + break; + case FT_LS_MBOX: + str = fmt->f_comp->c_mn->m_mbox; + break; + case FT_LS_HOST: + str = fmt->f_comp->c_mn->m_host; + break; + case FT_LS_PATH: + str = fmt->f_comp->c_mn->m_path; + break; + case FT_LS_GNAME: + str = fmt->f_comp->c_mn->m_gname; + break; + case FT_LS_NOTE: + str = fmt->f_comp->c_mn->m_note; + break; + case FT_LS_822ADDR: + str = adrformat( fmt->f_comp->c_mn ); + break; + case FT_LV_HOSTTYPE: + value = fmt->f_comp->c_mn->m_type; + break; + case FT_LV_INGRPF: + value = fmt->f_comp->c_mn->m_ingrp; + break; + case FT_LV_NOHOSTF: + value = fmt->f_comp->c_mn->m_nohost; + break; + case FT_LS_ADDR: + case FT_LS_FRIENDLY: + if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) { + str = fmt->f_comp->c_text; + break; + } + if (fmt->f_type == FT_LS_ADDR) + goto unfriendly; + if ((str = mn->m_pers) == NULL) { + if ((str = mn->m_note)) { + strncpy(buffer, str, sizeof(buffer)); + buffer[sizeof(buffer)-1] = '\0'; + str = buffer; + if (*str == '(') + str++; + sp = str + strlen(str) - 1; + if (*sp == ')') { + *sp-- = '\0'; + while (sp >= str) + if (*sp == ' ') + *sp-- = '\0'; + else + break; + } + } else if (!(str = get_x400_friendly(mn->m_mbox, + buffer, sizeof(buffer)))) { + unfriendly: ; + switch (mn->m_type) { + case LOCALHOST: + str = mn->m_mbox; + break; + default: + if (mn->m_mbox) { + snprintf(buffer, sizeof(buffer), "%s@%s", mn->m_mbox, mn->m_host); + str= buffer; + } else + str = mn->m_text; + break; + } + } + } + break; + + + /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */ + case FT_LS_UNQUOTE: + if (str) { + int m; + strncpy(buffer, str, sizeof(buffer)); + /* strncpy doesn't NUL-terminate if it fills the buffer */ + buffer[sizeof(buffer)-1] = '\0'; + str = buffer; + + /* we will parse from buffer to buffer2 */ + n = 0; /* n is the input position in str */ + m = 0; /* m is the ouput position in buffer2 */ + + while ( str[n] != '\0') { + switch ( str[n] ) { + case '\\': + n++; + if ( str[n] != '\0') + buffer2[m++] = str[n++]; + break; + case '"': + n++; + break; + default: + buffer2[m++] = str[n++]; + break; + } + } + buffer2[m] = '\0'; + str = buffer2; + } + break; + + case FT_LOCALDATE: + comp = fmt->f_comp; + if ((t = comp->c_tws->tw_clock) == 0) + t = dmktime(comp->c_tws); + tws = dlocaltime(&t); + *comp->c_tws = *tws; + break; + + case FT_GMTDATE: + comp = fmt->f_comp; + if ((t = comp->c_tws->tw_clock) == 0) + t = dmktime(comp->c_tws); + tws = dgmtime(&t); + *comp->c_tws = *tws; + break; + + case FT_PARSEDATE: + comp = fmt->f_comp; + if (comp->c_flags & CF_PARSED) + break; + if ((sp = comp->c_text) && (tws = dparsetime(sp))) { + *comp->c_tws = *tws; + comp->c_flags &= ~CF_TRUE; + } else if ((comp->c_flags & CF_DATEFAB) == 0) { + memset((char *) comp->c_tws, 0, sizeof *comp->c_tws); + comp->c_flags = CF_TRUE; + } + comp->c_flags |= CF_PARSED; + break; + + case FT_FORMATADDR: + /* + ** hook for custom address list formatting + ** (see replsbr.c) + */ + str = formataddr(savestr, str); + break; + + case FT_PUTADDR: + /* + ** output the str register as an address component, + ** splitting it into multiple lines if necessary. The + ** value reg. contains the max line length. The lit. + ** field may contain a string to prepend to the result + ** (e.g., "To: ") + */ + { + unsigned char *lp; + char *lastb; + int indent, wid, len; + + lp = str; + wid = value; + len = strlen(str); + sp = fmt->f_text; + indent = strlen(sp); + wid -= indent; + if (wid <= 0) { + adios(NULL, "putaddr -- num register (%d) " + "must be greater than label " + "width (%d)", value, indent); + } + while( (c = *sp++) && cp < ep) + *cp++ = c; + while (len > wid) { + /* try to break at a comma; failing that, + * break at a space. + */ + lastb = 0; sp = lp + wid; + while (sp > lp && (c = *--sp) != ',') { + if (! lastb && isspace(c)) + lastb = sp - 1; + } + if (sp == lp) { + if (! (sp = lastb)) { + sp = lp + wid - 1; + while (*sp && *sp != ',' && !isspace(*sp)) + sp++; + if (*sp != ',') + sp--; + } + } + len -= sp - lp + 1; + while (cp < ep && lp <= sp) + *cp++ = *lp++; + while (isspace(*lp)) + lp++, len--; + if (*lp) { + if (cp < ep) + *cp++ = '\n'; + for (i=indent; cp < ep && i > 0; i--) + *cp++ = ' '; + } + } + cpstripped(&cp, ep, lp); + } + break; + + case FT_PARSEADDR: + comp = fmt->f_comp; + if (comp->c_flags & CF_PARSED) + break; + if (comp->c_mn != &fmt_mnull) + mnfree(comp->c_mn); + if ((sp = comp->c_text) && (sp = getname(sp)) && + (mn = getm(sp, NULL, 0, fmt_norm, NULL))) { + comp->c_mn = mn; + while (getname("")) + ; + comp->c_flags |= CF_PARSED; + } else { + while (getname("")) /* XXX */ + ; + comp->c_mn = &fmt_mnull; + } + break; + + case FT_MYMBOX: + /* + ** if there's no component, we say true. Otherwise we + ** say "true" only if we can parse the address and it + ** matches one of our addresses. + */ + comp = fmt->f_comp; + if (comp->c_mn != &fmt_mnull) + mnfree(comp->c_mn); + if ((sp = comp->c_text) && (sp = getname(sp)) && + (mn = getm(sp, NULL, 0, AD_NAME, NULL))) { + comp->c_mn = mn; + if (ismymbox(mn)) + comp->c_flags |= CF_TRUE; + else + comp->c_flags &= ~CF_TRUE; + while ((sp = getname(sp))) + if ((comp->c_flags & CF_TRUE) == 0 && + (mn = getm(sp, NULL, 0, AD_NAME, NULL))) + if (ismymbox(mn)) + comp->c_flags |= CF_TRUE; + } else { + while (getname("")) /* XXX */ + ; + if (comp->c_text == 0) + comp->c_flags |= CF_TRUE; + else + comp->c_flags &= ~CF_TRUE; + comp->c_mn = &fmt_mnull; + } + break; + } - buffer2[m] = '\0'; - str = buffer2; - } - break; - - case FT_LOCALDATE: - comp = fmt->f_comp; - if ((t = comp->c_tws->tw_clock) == 0) - t = dmktime(comp->c_tws); - tws = dlocaltime(&t); - *comp->c_tws = *tws; - break; - - case FT_GMTDATE: - comp = fmt->f_comp; - if ((t = comp->c_tws->tw_clock) == 0) - t = dmktime(comp->c_tws); - tws = dgmtime(&t); - *comp->c_tws = *tws; - break; - - case FT_PARSEDATE: - comp = fmt->f_comp; - if (comp->c_flags & CF_PARSED) - break; - if ((sp = comp->c_text) && (tws = dparsetime(sp))) { - *comp->c_tws = *tws; - comp->c_flags &= ~CF_TRUE; - } else if ((comp->c_flags & CF_DATEFAB) == 0) { - memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws); - comp->c_flags = CF_TRUE; - } - comp->c_flags |= CF_PARSED; - break; - - case FT_FORMATADDR: - /* hook for custom address list formatting (see replsbr.c) */ - str = formataddr (savestr, str); - break; - - case FT_PUTADDR: - /* output the str register as an address component, - * splitting it into multiple lines if necessary. The - * value reg. contains the max line length. The lit. - * field may contain a string to prepend to the result - * (e.g., "To: ") - */ - { - unsigned char *lp; - char *lastb; - int indent, wid, len; - - lp = str; - wid = value; - len = strlen (str); - sp = fmt->f_text; - indent = strlen (sp); - wid -= indent; - while( (c = *sp++) && cp < ep) - *cp++ = c; - while (len > wid) { - /* try to break at a comma; failing that, break at a - * space. - */ - lastb = 0; sp = lp + wid; - while (sp > lp && (c = *--sp) != ',') { - if (! lastb && isspace(c)) - lastb = sp - 1; - } - if (sp == lp) { - if (! (sp = lastb)) { - sp = lp + wid - 1; - while (*sp && *sp != ',' && !isspace(*sp)) - sp++; - if (*sp != ',') - sp--; - } - } - len -= sp - lp + 1; - while (cp < ep && lp <= sp) - *cp++ = *lp++; - while (isspace(*lp)) - lp++, len--; - if (*lp) { - if (cp < ep) - *cp++ = '\n'; - for (i=indent; cp < ep && i > 0; i--) - *cp++ = ' '; - } - } - cpstripped (&cp, ep, lp); - } - break; - - case FT_PARSEADDR: - comp = fmt->f_comp; - if (comp->c_flags & CF_PARSED) - break; - if (comp->c_mn != &fmt_mnull) - mnfree (comp->c_mn); - if ((sp = comp->c_text) && (sp = getname(sp)) && - (mn = getm (sp, NULL, 0, fmt_norm, NULL))) { - comp->c_mn = mn; - while (getname("")) - ; - comp->c_flags |= CF_PARSED; - } else { - while (getname("")) /* XXX */ - ; - comp->c_mn = &fmt_mnull; - } - break; - - case FT_MYMBOX: - /* - * if there's no component, we say true. Otherwise we - * say "true" only if we can parse the address and it - * matches one of our addresses. - */ - comp = fmt->f_comp; - if (comp->c_mn != &fmt_mnull) - mnfree (comp->c_mn); - if ((sp = comp->c_text) && (sp = getname(sp)) && - (mn = getm (sp, NULL, 0, AD_NAME, NULL))) { - comp->c_mn = mn; - if (ismymbox(mn)) - comp->c_flags |= CF_TRUE; - else - comp->c_flags &= ~CF_TRUE; - while ((sp = getname(sp))) - if ((comp->c_flags & CF_TRUE) == 0 && - (mn = getm (sp, NULL, 0, AD_NAME, NULL))) - if (ismymbox(mn)) - comp->c_flags |= CF_TRUE; - } else { - while (getname("")) /* XXX */ - ; - if (comp->c_text == 0) - comp->c_flags |= CF_TRUE; - else - comp->c_flags &= ~CF_TRUE; - comp->c_mn = &fmt_mnull; - } - break; - - case FT_ADDTOSEQ: -#ifdef LBL - /* If we're working on a folder (as opposed to a file), add the - * current msg to sequence given in literal field. Don't - * disturb string or value registers. - */ - if (fmt_current_folder) - seq_addmsg(fmt_current_folder, fmt->f_text, dat[0], -1); -#endif - break; + fmt++; } - fmt++; - } -#ifndef JLR - finished:; - if (cp[-1] != '\n') - *cp++ = '\n'; - *cp = 0; - return ((struct format *)0); -#else /* JLR */ - if (cp[-1] != '\n') - *cp++ = '\n'; - while (fmt->f_type != FT_DONE) - fmt++; - - finished:; - *cp = '\0'; - return (fmt->f_value ? ++fmt : (struct format *) 0); - +finished:; + if (cp[-1] != '\n') + *cp++ = '\n'; + *cp = '\0'; + return ((struct format *)0); + +#ifdef JLR + /* I'll remove this as soon as I understand what it does. --meillo */ + if (cp[-1] != '\n') + *cp++ = '\n'; + while (fmt->f_type != FT_DONE) + fmt++; + + finished:; + *cp = '\0'; + return (fmt->f_value ? ++fmt : (struct format *) 0); #endif /* JLR */ + } diff --git a/sbr/folder_addmsg.c b/sbr/folder_addmsg.c index a0595e6..69083cc 100644 --- a/sbr/folder_addmsg.c +++ b/sbr/folder_addmsg.c @@ -1,208 +1,207 @@ - /* - * folder_addmsg.c -- Link message into folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder_addmsg.c -- Link message into folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include /* - * Link message into a folder. Return the new number - * of the message. If an error occurs, return -1. - */ +** Link message into a folder. Return the new number +** of the message. If an error occurs, return -1. +*/ int -folder_addmsg (struct msgs **mpp, char *msgfile, int selected, - int unseen, int preserve, int deleting, char *from_dir) +folder_addmsg(struct msgs **mpp, char *msgfile, int selected, + int unseen, int preserve, int deleting, char *from_dir) { - int infd, outfd, linkerr, msgnum; - char *nmsg, newmsg[BUFSIZ]; - char oldmsg[BUFSIZ]; - struct msgs *mp; - struct stat st1, st2; - - mp = *mpp; - - /* should we preserve the numbering of the message? */ - if (preserve && (msgnum = m_atoi (msgfile)) > 0) { - ; - } else if (mp->nummsg == 0) { - /* check if we are adding to empty folder */ - msgnum = 1; - } else { - /* else use highest message number + 1 */ - msgnum = mp->hghmsg + 1; - } - - /* - * We might need to make several attempts - * in order to add the message to the folder. - */ - for (;; msgnum++) { - - /* - * See if we need more space. If we need space at the - * end, then we allocate space for an addition 100 messages. - * If we need space at the beginning of the range, then just - * extend message status range to cover this message number. - */ - if (msgnum > mp->hghoff) { - if ((mp = folder_realloc (mp, mp->lowoff, msgnum + 100))) - *mpp = mp; - else { - advise (NULL, "unable to allocate folder storage"); - return -1; - } - } else if (msgnum < mp->lowoff) { - if ((mp = folder_realloc (mp, msgnum, mp->hghoff))) - *mpp = mp; - else { - advise (NULL, "unable to allocate folder storage"); - return -1; - } + int infd, outfd, linkerr, msgnum; + char *nmsg, newmsg[BUFSIZ]; + char oldmsg[BUFSIZ]; + struct msgs *mp; + struct stat st1, st2; + + mp = *mpp; + + /* should we preserve the numbering of the message? */ + if (preserve && (msgnum = m_atoi(msgfile)) > 0) { + ; + } else if (mp->nummsg == 0) { + /* check if we are adding to empty folder */ + msgnum = 1; + } else { + /* else use highest message number + 1 */ + msgnum = mp->hghmsg + 1; } /* - * If a message is already in that slot, - * then loop to next available slot. - */ - if (does_exist (mp, msgnum)) - continue; - - /* setup the bit flags for this message */ - clear_msg_flags (mp, msgnum); - set_exists (mp, msgnum); - - /* should we set the SELECT_UNSEEN bit? */ - if (unseen) { - set_unseen (mp, msgnum); - } + ** We might need to make several attempts + ** in order to add the message to the folder. + */ + for (;; msgnum++) { + + /* + ** See if we need more space. If we need space at the + ** end, then we allocate space for an addition 100 messages. + ** If we need space at the beginning of the range, then just + ** extend message status range to cover this message number. + */ + if (msgnum > mp->hghoff) { + if ((mp = folder_realloc(mp, mp->lowoff, msgnum + 100))) + *mpp = mp; + else { + advise(NULL, "unable to allocate folder storage"); + return -1; + } + } else if (msgnum < mp->lowoff) { + if ((mp = folder_realloc(mp, msgnum, mp->hghoff))) + *mpp = mp; + else { + advise(NULL, "unable to allocate folder storage"); + return -1; + } + } - /* should we set the SELECTED bit? */ - if (selected) { - set_selected (mp, msgnum); - - /* check if highest or lowest selected */ - if (mp->numsel == 0) { - mp->lowsel = msgnum; - mp->hghsel = msgnum; - } else { - if (msgnum < mp->lowsel) - mp->lowsel = msgnum; - if (msgnum > mp->hghsel) - mp->hghsel = msgnum; - } - - /* increment number selected */ - mp->numsel++; - } + /* + ** If a message is already in that slot, + ** then loop to next available slot. + */ + if (does_exist(mp, msgnum)) + continue; - /* - * check if this is highest or lowest message - */ - if (mp->nummsg == 0) { - mp->lowmsg = msgnum; - mp->hghmsg = msgnum; - } else { - if (msgnum < mp->lowmsg) - mp->lowmsg = msgnum; - if (msgnum > mp->hghmsg) - mp->hghmsg = msgnum; - } + /* setup the bit flags for this message */ + clear_msg_flags(mp, msgnum); + set_exists(mp, msgnum); - /* increment message count */ - mp->nummsg++; + /* should we set the SELECT_UNSEEN bit? */ + if (unseen) { + set_unseen(mp, msgnum); + } - nmsg = m_name (msgnum); - snprintf (newmsg, sizeof(newmsg), "%s/%s", mp->foldpath, nmsg); + /* should we set the SELECTED bit? */ + if (selected) { + set_selected(mp, msgnum); + + /* check if highest or lowest selected */ + if (mp->numsel == 0) { + mp->lowsel = msgnum; + mp->hghsel = msgnum; + } else { + if (msgnum < mp->lowsel) + mp->lowsel = msgnum; + if (msgnum > mp->hghsel) + mp->hghsel = msgnum; + } + + /* increment number selected */ + mp->numsel++; + } - /* - * Now try to link message into folder. - * Then run the external hook on the message if one was specified in the context. - * Run the refile hook if we're moving the message from one place to another. - * We have to construct the from path name for this because it's not there. - * Run the add hook if the message is getting copied or linked somewhere else. - */ - if (link (msgfile, newmsg) != -1) { - - if (deleting) { - (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", from_dir, msgfile); - (void)ext_hook("ref-hook", oldmsg, newmsg); - } - else - (void)ext_hook("add-hook", newmsg, (char *)0); - - return msgnum; - } else { - linkerr = errno; - -#ifdef EISREMOTE - if (linkerr == EISREMOTE) - linkerr = EXDEV; -#endif /* EISREMOTE */ - - /* - * Check if the file in our desired location is the same - * as the source file. If so, then just leave it alone - * and return. Otherwise, we will continue the main loop - * and try again at another slot (hghmsg+1). - */ - if (linkerr == EEXIST) { - if (stat (msgfile, &st2) == 0 && stat (newmsg, &st1) == 0 - && st2.st_ino == st1.st_ino) { - return msgnum; + /* + ** check if this is highest or lowest message + */ + if (mp->nummsg == 0) { + mp->lowmsg = msgnum; + mp->hghmsg = msgnum; } else { - continue; + if (msgnum < mp->lowmsg) + mp->lowmsg = msgnum; + if (msgnum > mp->hghmsg) + mp->hghmsg = msgnum; } - } - - /* - * If link failed because we are trying to link - * across devices, then check if there is a message - * already in the desired location. If so, then return - * error, else just copy the message. - */ - if (linkerr == EXDEV) { - if (stat (newmsg, &st1) == 0) { - advise (NULL, "message %s:%s already exists", mp->foldpath, newmsg); - return -1; + + /* increment message count */ + mp->nummsg++; + + nmsg = m_name(msgnum); + snprintf(newmsg, sizeof(newmsg), "%s/%s", mp->foldpath, nmsg); + + /* + ** Now try to link message into folder. Then run the + ** external hook on the message if one was specified in + ** the context. Run the refile hook if we're moving the + ** message from one place to another. We have to construct + ** the from path name for this because it's not there. + ** Run the add hook if the message is getting copied or + ** linked somewhere else. + */ + if (link(msgfile, newmsg) != -1) { + + if (deleting) { + snprintf(oldmsg, sizeof (oldmsg), "%s/%s", + from_dir, msgfile); + ext_hook("ref-hook", oldmsg, newmsg); + } else + ext_hook("add-hook", newmsg, NULL); + + return msgnum; } else { - if ((infd = open (msgfile, O_RDONLY)) == -1) { - advise (msgfile, "unable to open message %s", msgfile); - return -1; - } - fstat (infd, &st1); - if ((outfd = creat (newmsg, (int) st1.st_mode & 0777)) == -1) { - advise (newmsg, "unable to create"); - close (infd); + linkerr = errno; + + /* + ** Check if the file in our desired location is + ** the same as the source file. If so, then just + ** leave it alone and return. Otherwise, we will + ** continue the main loop and try again at another + ** slot (hghmsg+1). + */ + if (linkerr == EEXIST) { + if (stat(msgfile, &st2) == 0 && stat(newmsg, &st1) == 0 + && st2.st_ino == st1.st_ino) { + return msgnum; + } else { + continue; + } + } + + /* + ** If link failed because we are trying to link + ** across devices, then check if there is a message + ** already in the desired location. If so, then return + ** error, else just copy the message. + */ + if (linkerr == EXDEV) { + if (stat(newmsg, &st1) == 0) { + advise(NULL, "message %s:%s already exists", mp->foldpath, newmsg); + return -1; + } else { + if ((infd = open(msgfile, O_RDONLY)) == -1) { + advise(msgfile, "unable to open message %s", msgfile); + return -1; + } + fstat(infd, &st1); + if ((outfd = creat(newmsg, (int) st1.st_mode & 0777)) == -1) { + advise(newmsg, "unable to create"); + close(infd); + return -1; + } + cpydata(infd, outfd, msgfile, newmsg); + close(infd); + close(outfd); + + if (deleting) { + snprintf(oldmsg, sizeof oldmsg, + "%s/%s", + from_dir, + msgfile); + ext_hook("ref-hook", oldmsg, newmsg); + } else + ext_hook("add-hook", newmsg, NULL); + + return msgnum; + } + } + + /* + ** Else, some other type of link error, + ** so just return error. + */ + advise(newmsg, "error linking %s to", msgfile); return -1; - } - cpydata (infd, outfd, msgfile, newmsg); - close (infd); - close (outfd); - - if (deleting) { - (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", from_dir, msgfile); - (void)ext_hook("ref-hook", oldmsg, newmsg); - } - else - (void)ext_hook("add-hook", newmsg, (char *)0); - - return msgnum; } - } - - /* - * Else, some other type of link error, - * so just return error. - */ - advise (newmsg, "error linking %s to", msgfile); - return -1; } - } } diff --git a/sbr/folder_delmsgs.c b/sbr/folder_delmsgs.c index 6bde76f..17b99be 100644 --- a/sbr/folder_delmsgs.c +++ b/sbr/folder_delmsgs.c @@ -1,131 +1,59 @@ - /* - * folder_delmsgs.c -- "remove" SELECTED messages from a folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder_delmsgs.c -- remove (= unlink) SELECTED messages from a folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * 1) If we are using an external rmmproc, then exec it. - * 2) Else if unlink_msgs is non-zero, then unlink the - * SELECTED messages. - * 3) Else rename SELECTED messages by prefixing name - * with a standard prefix. - * - * If there is an error, return -1, else return 0. - */ - +** Unlink the SELECTED messages. +** +** If there is an error, return -1, else return 0. +*/ int -folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) +folder_delmsgs(struct msgs *mp, int hook) { - pid_t pid; - int msgnum, vecp, retval = 0; - char buf[100], *dp, **vec; - char msgpath[BUFSIZ]; - - /* - * If "rmmproc" is defined, exec it to remove messages. - */ - if (rmmproc) { - /* Unset the EXISTS flag for each message to be removed */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) - unset_exists (mp, msgnum); - } + int msgnum, retval = 0; + char msgpath[BUFSIZ]; - /* Mark that the sequence information has changed */ - mp->msgflags |= SEQMOD; - - if (mp->numsel > MAXARGS - 2) - adios (NULL, "more than %d messages for %s exec", MAXARGS - 2, - rmmproc); - vec = (char **) calloc ((size_t) (mp->numsel + 2), sizeof(*vec)); - if (vec == NULL) - adios (NULL, "unable to allocate exec vector"); - vecp = 1; for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum) && - !(vec[vecp++] = strdup (m_name (msgnum)))) - adios (NULL, "strdup failed"); - } - vec[vecp] = NULL; - - fflush (stdout); - vec[0] = r1bindex (rmmproc, '/'); - - switch (pid = vfork()) { - case -1: - advise ("fork", "unable to"); - return -1; - - case 0: - execvp (rmmproc, vec); - fprintf (stderr, "unable to exec "); - perror (rmmproc); - _exit (-1); - - default: - return (pidwait (pid, -1)); - } - } + if (!is_selected(mp, msgnum)) { + continue; + } - /* - * Either unlink or rename the SELECTED messages - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - /* unselect message */ - unset_selected (mp, msgnum); - mp->numsel--; + /* unselect message */ + unset_selected(mp, msgnum); + mp->numsel--; - /* - * Run the external hook on the message if one was specified in the context. - * All we have is the message number; we have changed to the directory - * containing the message. So, we need to extract that directory to form - * the complete path. Note that the caller knows the directory, but has - * no way of passing that to us. - */ + snprintf(msgpath, sizeof (msgpath), "%s/%d", + mp->foldpath, msgnum); - if (!nohook) { - (void)snprintf(msgpath, sizeof (msgpath), "%s/%d", mp->foldpath, msgnum); - (void)ext_hook("del-hook", msgpath, (char *)0); + if (hook) { + /* Run the external hook on the message. */ + ext_hook("del-hook", msgpath, NULL); } - dp = m_name (msgnum); - - if (unlink_msgs) { /* just unlink the messages */ - if (unlink (dp) == -1) { - admonish (dp, "unable to unlink"); - retval = -1; - continue; - } - } else { - /* or rename messages with standard prefix */ - strncpy (buf, m_backup (dp), sizeof(buf)); - if (rename (dp, buf) == -1) { - admonish (buf, "unable to rename %s to", dp); - retval = -1; - continue; + if (unlink(msgpath) == -1) { + admonish(msgpath, "unable to unlink"); + retval = -1; + continue; } - } - /* If removal was successful, decrement message count */ - unset_exists (mp, msgnum); - mp->nummsg--; + /* If removal was successful, decrement message count */ + unset_exists(mp, msgnum); + mp->nummsg--; } - } - /* Sanity check */ - if (mp->numsel != 0) - adios (NULL, "oops, mp->numsel should be 0"); + /* Sanity check */ + if (mp->numsel != 0) + adios(NULL, "oops, mp->numsel should be 0"); - /* Mark that the sequence information has changed */ - mp->msgflags |= SEQMOD; + /* Mark that the sequence information has changed */ + mp->msgflags |= SEQMOD; - return retval; + return retval; } diff --git a/sbr/folder_free.c b/sbr/folder_free.c index ebb58ab..2930254 100644 --- a/sbr/folder_free.c +++ b/sbr/folder_free.c @@ -1,30 +1,29 @@ - /* - * folder_free.c -- free a folder/message structure - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder_free.c -- free a folder/message structure +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -folder_free (struct msgs *mp) +folder_free(struct msgs *mp) { - int i; + int i; - if (!mp) - return; + if (!mp) + return; - if (mp->foldpath) - free (mp->foldpath); + if (mp->foldpath) + free(mp->foldpath); - /* free the sequence names */ - for (i = 0; mp->msgattrs[i]; i++) - free (mp->msgattrs[i]); + /* free the sequence names */ + for (i = 0; mp->msgattrs[i]; i++) + free(mp->msgattrs[i]); - free (mp->msgstats); /* free message status area */ - free (mp); /* free main folder structure */ + free(mp->msgstats); /* free message status area */ + free(mp); /* free main folder structure */ } diff --git a/sbr/folder_pack.c b/sbr/folder_pack.c deleted file mode 100644 index b0bc67b..0000000 --- a/sbr/folder_pack.c +++ /dev/null @@ -1,98 +0,0 @@ - -/* - * folder_pack.c -- pack (renumber) the messages in a folder - * -- into a contiguous range from 1 to n. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/* - * Pack the message in a folder. - * Return -1 if error, else return 0. - */ - -int -folder_pack (struct msgs **mpp, int verbose) -{ - int hole, msgnum, newcurrent = 0; - char newmsg[BUFSIZ], oldmsg[BUFSIZ]; - struct msgs *mp; - - mp = *mpp; - - /* - * Just return if folder is empty. - */ - if (mp->nummsg == 0) - return 0; - - /* - * Make sure we have message status space allocated - * for all numbers from 1 to current high message. - */ - if (mp->lowoff > 1) { - if ((mp = folder_realloc (mp, 1, mp->hghmsg))) - *mpp = mp; - else { - advise (NULL, "unable to allocate folder storage"); - return -1; - } - } - - for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) { - if (does_exist (mp, msgnum)) { - if (msgnum != hole) { - strncpy (newmsg, m_name (hole), sizeof(newmsg)); - strncpy (oldmsg, m_name (msgnum), sizeof(oldmsg)); - if (verbose) - printf ("message %s becomes %s\n", oldmsg, newmsg); - - /* - * Invoke the external refile hook for each message being renamed. - * This is done before the file is renamed so that the old message - * file is around for the hook. - */ - - (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%d", mp->foldpath, msgnum); - (void)snprintf(newmsg, sizeof (newmsg), "%s/%d", mp->foldpath, hole); - ext_hook("ref-hook", oldmsg, newmsg); - - /* move the message file */ - if (rename (oldmsg, newmsg) == -1) { - advise (newmsg, "unable to rename %s to", oldmsg); - return -1; - } - - /* check if this is the current message */ - if (msgnum == mp->curmsg) - newcurrent = hole; - - /* copy the attribute flags for this message */ - copy_msg_flags (mp, hole, msgnum); - - if (msgnum == mp->lowsel) - mp->lowsel = hole; - if (msgnum == mp->hghsel) - mp->hghsel = hole; - - /* mark that sequence information has been modified */ - mp->msgflags |= SEQMOD; - } - hole++; - } - } - - /* record the new number for the high/low message */ - mp->lowmsg = 1; - mp->hghmsg = hole - 1; - - /* update the "cur" sequence */ - if (newcurrent != 0) - seq_setcur (mp, newcurrent); - - return 0; -} diff --git a/sbr/folder_read.c b/sbr/folder_read.c index bb88659..4265763 100644 --- a/sbr/folder_read.c +++ b/sbr/folder_read.c @@ -1,160 +1,154 @@ - /* - * folder_read.c -- initialize folder structure and read folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder_read.c -- initialize folder structure and read folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include /* We allocate the `mi' array 1024 elements at a time */ -#define NUMMSGS 1024 +#define NUMMSGS 1024 /* - * 1) Create the folder/message structure - * 2) Read the directory (folder) and temporarily - * record the numbers of the messages we have seen. - * 3) Then allocate the array for message attributes and - * set the initial flags for all messages we've seen. - * 4) Read and initialize the sequence information. - */ +** 1) Create the folder/message structure +** 2) Read the directory (folder) and temporarily +** record the numbers of the messages we have seen. +** 3) Then allocate the array for message attributes and +** set the initial flags for all messages we've seen. +** 4) Read and initialize the sequence information. +*/ struct msgs * -folder_read (char *name) +folder_read(char *name) { - int msgnum, prefix_len, len, *mi; - struct msgs *mp; - struct stat st; - struct dirent *dp; - DIR *dd; - - name = m_mailpath (name); - if (!(dd = opendir (name))) { - free (name); - return NULL; - } - - if (stat (name, &st) == -1) { - free (name); - return NULL; - } - - /* Allocate the main structure for folder information */ - mp = (struct msgs *) mh_xmalloc ((size_t) sizeof(*mp)); - - clear_folder_flags (mp); - mp->foldpath = name; - mp->lowmsg = 0; - mp->hghmsg = 0; - mp->curmsg = 0; - mp->lowsel = 0; - mp->hghsel = 0; - mp->numsel = 0; - mp->nummsg = 0; - - if (access (name, W_OK) == -1) - set_readonly (mp); - prefix_len = strlen(BACKUP_PREFIX); - - /* - * Allocate a temporary place to record the - * name of the messages in this folder. - */ - len = NUMMSGS; - mi = (int *) mh_xmalloc ((size_t) (len * sizeof(*mi))); - - while ((dp = readdir (dd))) { - if ((msgnum = m_atoi (dp->d_name)) && msgnum > 0) { - /* - * Check if we need to allocate more - * temporary elements for message names. - */ - if (mp->nummsg >= len) { - len += NUMMSGS; - mi = (int *) mh_xrealloc (mi, (size_t) (len * sizeof(*mi))); - } - - /* Check if this is the first message we've seen */ - if (mp->nummsg == 0) { - mp->lowmsg = msgnum; - mp->hghmsg = msgnum; - } else { - /* Check if this is it the highest or lowest we've seen? */ - if (msgnum < mp->lowmsg) - mp->lowmsg = msgnum; - if (msgnum > mp->hghmsg) - mp->hghmsg = msgnum; - } - - /* - * Now increment count, and record message - * number in a temporary place for now. - */ - mi[mp->nummsg++] = msgnum; - - } else { - switch (dp->d_name[0]) { - case '.': - case ',': -#ifdef MHE - case '+': -#endif /* MHE */ - continue; - - default: - /* skip any files beginning with backup prefix */ - if (!strncmp (dp->d_name, BACKUP_PREFIX, prefix_len)) - continue; - - /* skip the LINK file */ - if (!strcmp (dp->d_name, LINK)) - continue; - - /* indicate that there are other files in folder */ - set_other_files (mp); - continue; - } + int msgnum, len, *mi; + struct msgs *mp; + struct stat st; + struct dirent *dp; + DIR *dd; + + name = getcpy(toabsdir(name)); + if (!(dd = opendir(name))) { + free(name); + return NULL; + } + + if (stat(name, &st) == -1) { + free(name); + closedir(dd); + return NULL; } - } - closedir (dd); - mp->lowoff = max (mp->lowmsg, 1); + /* Allocate the main structure for folder information */ + mp = (struct msgs *) mh_xmalloc((size_t) sizeof(*mp)); + + clear_folder_flags(mp); + mp->foldpath = name; + mp->lowmsg = 0; + mp->hghmsg = 0; + mp->curmsg = 0; + mp->lowsel = 0; + mp->hghsel = 0; + mp->numsel = 0; + mp->nummsg = 0; + + if (access(name, W_OK) == -1) + set_readonly(mp); + + /* + ** Allocate a temporary place to record the + ** name of the messages in this folder. + */ + len = NUMMSGS; + mi = (int *) mh_xmalloc((size_t) (len * sizeof(*mi))); + + while ((dp = readdir(dd))) { + if ((msgnum = m_atoi(dp->d_name)) && msgnum > 0) { + /* + ** Check if we need to allocate more + ** temporary elements for message names. + */ + if (mp->nummsg >= len) { + len += NUMMSGS; + mi = (int *) mh_xrealloc(mi, (size_t) (len * sizeof(*mi))); + } + + /* Check if this is the first message we've seen */ + if (mp->nummsg == 0) { + mp->lowmsg = msgnum; + mp->hghmsg = msgnum; + } else { + /* + ** Check if this is it the highest or + ** lowest we've seen? + */ + if (msgnum < mp->lowmsg) + mp->lowmsg = msgnum; + if (msgnum > mp->hghmsg) + mp->hghmsg = msgnum; + } + + /* + ** Now increment count, and record message + ** number in a temporary place for now. + */ + mi[mp->nummsg++] = msgnum; + + } else { + switch (dp->d_name[0]) { + case '.': + case ',': + continue; + + default: + /* + ** indicate that there are other + ** files in folder + */ + set_other_files(mp); + continue; + } + } + } + + closedir(dd); + mp->lowoff = max(mp->lowmsg, 1); + + /* Go ahead and allocate space for 100 additional messages. */ + mp->hghoff = mp->hghmsg + 100; - /* Go ahead and allocate space for 100 additional messages. */ - mp->hghoff = mp->hghmsg + 100; + /* for testing, allocate minimal necessary space */ + /* mp->hghoff = max(mp->hghmsg, 1); */ - /* for testing, allocate minimal necessary space */ - /* mp->hghoff = max (mp->hghmsg, 1); */ + /* Allocate space for status of each message. */ - /* - * Allocate space for status of each message. - */ - mp->msgstats = mh_xmalloc (MSGSTATSIZE(mp, mp->lowoff, mp->hghoff)); + mp->msgstats = mh_xmalloc(MSGSTATSIZE(mp, mp->lowoff, mp->hghoff)); - /* - * Clear all the flag bits for all the message - * status entries we just allocated. - */ - for (msgnum = mp->lowoff; msgnum <= mp->hghoff; msgnum++) - clear_msg_flags (mp, msgnum); + /* + ** Clear all the flag bits for all the message + ** status entries we just allocated. + ** TODO: use memset() ? + */ + for (msgnum = mp->lowoff; msgnum <= mp->hghoff; msgnum++) + clear_msg_flags(mp, msgnum); - /* - * Scan through the array of messages we've seen and - * setup the initial flags for those messages in the - * newly allocated mp->msgstats area. - */ - for (msgnum = 0; msgnum < mp->nummsg; msgnum++) - set_exists (mp, mi[msgnum]); + /* + ** Scan through the array of messages we've seen and + ** setup the initial flags for those messages in the + ** newly allocated mp->msgstats area. + */ + for (msgnum = 0; msgnum < mp->nummsg; msgnum++) + set_exists(mp, mi[msgnum]); - free (mi); /* We don't need this anymore */ + free(mi); /* We don't need this anymore */ - /* - * Read and initialize the sequence information. - */ - seq_read (mp); + /* + ** Read and initialize the sequence information. + */ + seq_read(mp); - return mp; + return mp; } diff --git a/sbr/folder_realloc.c b/sbr/folder_realloc.c index 6a94a00..e69b833 100644 --- a/sbr/folder_realloc.c +++ b/sbr/folder_realloc.c @@ -1,87 +1,87 @@ - /* - * folder_realloc.c -- realloc a folder/msgs structure - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder_realloc.c -- realloc a folder/msgs structure +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include /* - * Reallocate some of the space in the folder - * structure (currently just message status array). - * - * Return pointer to new folder structure. - * If error, return NULL. - */ +** Reallocate some of the space in the folder +** structure (currently just message status array). +** +** Return pointer to new folder structure. +** If error, return NULL. +*/ struct msgs * -folder_realloc (struct msgs *mp, int lo, int hi) +folder_realloc(struct msgs *mp, int lo, int hi) { - int msgnum; + int msgnum; - /* sanity checks */ - if (lo < 1) - adios (NULL, "BUG: called folder_realloc with lo (%d) < 1", lo); - if (hi < 1) - adios (NULL, "BUG: called folder_realloc with hi (%d) < 1", hi); - if (mp->nummsg > 0 && lo > mp->lowmsg) - adios (NULL, "BUG: called folder_realloc with lo (%d) > mp->lowmsg (%d)", - lo, mp->lowmsg); - if (mp->nummsg > 0 && hi < mp->hghmsg) - adios (NULL, "BUG: called folder_realloc with hi (%d) < mp->hghmsg (%d)", - hi, mp->hghmsg); + /* sanity checks */ + if (lo < 1) + adios(NULL, "BUG: called folder_realloc with lo (%d) < 1", lo); + if (hi < 1) + adios(NULL, "BUG: called folder_realloc with hi (%d) < 1", hi); + if (mp->nummsg > 0 && lo > mp->lowmsg) + adios(NULL, "BUG: called folder_realloc with lo (%d) > mp->lowmsg (%d)", + lo, mp->lowmsg); + if (mp->nummsg > 0 && hi < mp->hghmsg) + adios(NULL, "BUG: called folder_realloc with hi (%d) < mp->hghmsg (%d)", + hi, mp->hghmsg); - /* Check if we really need to reallocate anything */ - if (lo == mp->lowoff && hi == mp->hghoff) - return mp; + /* Check if we really need to reallocate anything */ + if (lo == mp->lowoff && hi == mp->hghoff) + return mp; - if (lo == mp->lowoff) { - /* - * We are just extending (or shrinking) the end of message - * status array. So we don't have to move anything and can - * just realloc the message status array. - */ - mp->msgstats = mh_xrealloc (mp->msgstats, MSGSTATSIZE(mp, lo, hi)); - } else { - /* - * We are changing the offset of the message status - * array. So we will need to shift everything. - */ - seqset_t *tmpstats; + if (lo == mp->lowoff) { + /* + ** We are just extending (or shrinking) the end of message + ** status array. So we don't have to move anything and can + ** just realloc the message status array. + */ + mp->msgstats = mh_xrealloc(mp->msgstats, MSGSTATSIZE(mp, lo, hi)); + } else { + /* + ** We are changing the offset of the message status + ** array. So we will need to shift everything. + */ + seqset_t *tmpstats; - /* first allocate the new message status space */ - tmpstats = mh_xmalloc (MSGSTATSIZE(mp, lo, hi)); + /* first allocate the new message status space */ + tmpstats = mh_xmalloc(MSGSTATSIZE(mp, lo, hi)); - /* then copy messages status array with shift */ - if (mp->nummsg > 0) { - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) - tmpstats[msgnum - lo] = mp->msgstats[msgnum - mp->lowoff]; + /* then copy messages status array with shift */ + if (mp->nummsg > 0) { + for (msgnum=mp->lowmsg; msgnum<=mp->hghmsg; msgnum++) { + tmpstats[msgnum - lo] = mp->msgstats[msgnum - mp->lowoff]; + } + } + free(mp->msgstats); + mp->msgstats = tmpstats; } - free(mp->msgstats); - mp->msgstats = tmpstats; - } - mp->lowoff = lo; - mp->hghoff = hi; + mp->lowoff = lo; + mp->hghoff = hi; - /* - * Clear all the flags for entries outside - * the current message range for this folder. - */ - if (mp->nummsg > 0) { - for (msgnum = mp->lowoff; msgnum < mp->lowmsg; msgnum++) - clear_msg_flags (mp, msgnum); - for (msgnum = mp->hghmsg + 1; msgnum <= mp->hghoff; msgnum++) - clear_msg_flags (mp, msgnum); - } else { - /* no messages, so clear entire range */ - for (msgnum = mp->lowoff; msgnum <= mp->hghoff; msgnum++) - clear_msg_flags (mp, msgnum); - } + /* + ** Clear all the flags for entries outside + ** the current message range for this folder. + */ + if (mp->nummsg > 0) { + for (msgnum = mp->lowoff; msgnum < mp->lowmsg; msgnum++) + clear_msg_flags(mp, msgnum); + for (msgnum = mp->hghmsg + 1; msgnum <= mp->hghoff; msgnum++) + clear_msg_flags(mp, msgnum); + } else { + /* no messages, so clear entire range */ + for (msgnum = mp->lowoff; msgnum <= mp->hghoff; msgnum++) + clear_msg_flags(mp, msgnum); + } - return mp; + return mp; } diff --git a/sbr/gans.c b/sbr/gans.c index 6b76b7b..c90bfef 100644 --- a/sbr/gans.c +++ b/sbr/gans.c @@ -1,51 +1,44 @@ - /* - * gans.c -- get an answer from the user - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** gans.c -- get an answer from the user +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include int -gans (char *prompt, struct swit *ansp) +gans(char *prompt, struct swit *ansp) { - register int i; - register char *cp; - register struct swit *ap; - char ansbuf[BUFSIZ]; + register int i; + register char *cp; + register struct swit *ap; + char ansbuf[BUFSIZ]; - for (;;) { - printf ("%s", prompt); - fflush (stdout); - cp = ansbuf; - while ((i = getchar ()) != '\n') { - if (i == EOF) - return 0; - if (cp < &ansbuf[sizeof ansbuf - 1]) { -#ifdef LOCALE - i = (isalpha(i) && isupper(i)) ? tolower(i) : i; -#else - if (i >= 'A' && i <= 'Z') - i += 'a' - 'A'; -#endif - *cp++ = i; - } - } - *cp = '\0'; - if (ansbuf[0] == '?' || cp == ansbuf) { - printf ("Options are:\n"); - for (ap = ansp; ap->sw; ap++) - printf (" %s\n", ap->sw); - continue; - } - if ((i = smatch (ansbuf, ansp)) < 0) { - printf ("%s: %s.\n", ansbuf, i == -1 ? "unknown" : "ambiguous"); - continue; + for (;;) { + printf("%s", prompt); + fflush(stdout); + cp = ansbuf; + while ((i = getchar()) != '\n') { + if (i == EOF) + return 0; + if (cp < &ansbuf[sizeof ansbuf - 1]) { + *cp++ = tolower(i); + } + } + *cp = '\0'; + if (ansbuf[0] == '?' || cp == ansbuf) { + printf("Options are:\n"); + for (ap = ansp; ap->sw; ap++) + printf(" %s\n", ap->sw); + continue; + } + if ((i = smatch(ansbuf, ansp)) < 0) { + printf("%s: %s.\n", ansbuf, i == -1 ? "unknown" : "ambiguous"); + continue; + } + return i; } - return i; - } } diff --git a/sbr/getans.c b/sbr/getans.c index 3229eb5..7254d6b 100644 --- a/sbr/getans.c +++ b/sbr/getans.c @@ -1,11 +1,10 @@ - /* - * getans.c -- get an answer from the user and return a string array - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** getans.c -- get an answer from the user and return a string array +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -16,62 +15,62 @@ static char ansbuf[BUFSIZ]; static jmp_buf sigenv; /* - * static prototypes - */ -static RETSIGTYPE intrser (int); +** static prototypes +*/ +static void intrser(int); char ** -getans (char *prompt, struct swit *ansp) +getans(char *prompt, struct swit *ansp) { - int i; - SIGNAL_HANDLER istat = NULL; - char *cp, **cpp; - - if (!(setjmp (sigenv))) { - istat = SIGNAL (SIGINT, intrser); - } else { - SIGNAL (SIGINT, istat); - return NULL; - } + int i; + SIGNAL_HANDLER istat = NULL; + char *cp, **cpp; - for (;;) { - printf ("%s", prompt); - fflush (stdout); - cp = ansbuf; - while ((i = getchar ()) != '\n') { - if (i == EOF) - longjmp (sigenv, 1); - if (cp < &ansbuf[sizeof ansbuf - 1]) - *cp++ = i; + if (!(setjmp(sigenv))) { + istat = SIGNAL(SIGINT, intrser); + } else { + SIGNAL(SIGINT, istat); + return NULL; } - *cp = '\0'; - if (ansbuf[0] == '?' || cp == ansbuf) { - printf ("Options are:\n"); - print_sw (ALL, ansp, "", stdout); - continue; - } - cpp = brkstring (ansbuf, " ", NULL); - switch (smatch (*cpp, ansp)) { - case AMBIGSW: - ambigsw (*cpp, ansp); - continue; - case UNKWNSW: - printf (" -%s unknown. Hit for help.\n", *cpp); - continue; - default: - SIGNAL (SIGINT, istat); - return cpp; + + for (;;) { + printf("%s", prompt); + fflush(stdout); + cp = ansbuf; + while ((i = getchar()) != '\n') { + if (i == EOF) + longjmp(sigenv, 1); + if (cp < &ansbuf[sizeof ansbuf - 1]) + *cp++ = i; + } + *cp = '\0'; + if (ansbuf[0] == '?' || cp == ansbuf) { + printf("Options are:\n"); + print_sw(ALL, ansp, "", stdout); + continue; + } + cpp = brkstring(ansbuf, " ", NULL); + switch (smatch(*cpp, ansp)) { + case AMBIGSW: + ambigsw(*cpp, ansp); + continue; + case UNKWNSW: + printf(" -%s unknown. Hit for help.\n", *cpp); + continue; + default: + SIGNAL(SIGINT, istat); + return cpp; + } } - } } -static RETSIGTYPE -intrser (int i) +static void +intrser(int i) { - /* - * should this be siglongjmp? - */ - longjmp (sigenv, 1); + /* + ** should this be siglongjmp? + */ + longjmp(sigenv, 1); } diff --git a/sbr/getanswer.c b/sbr/getanswer.c index d0ec6f8..9bac0e5 100644 --- a/sbr/getanswer.c +++ b/sbr/getanswer.c @@ -1,23 +1,22 @@ - /* - * getanswer.c -- get a yes/no answer from the user - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** getanswer.c -- get a yes/no answer from the user +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include int -getanswer (char *prompt) +getanswer(char *prompt) { - static int interactive = -1; + static int interactive = -1; - if (interactive < 0) - interactive = isatty (fileno (stdin)) ? 1 : 0; + if (interactive < 0) + interactive = isatty(fileno(stdin)) ? 1 : 0; - return (interactive ? gans (prompt, anoyes) : 1); + return (interactive ? gans(prompt, anoyes) : 1); } diff --git a/sbr/getarguments.c b/sbr/getarguments.c index 0f8834b..ce33c2e 100644 --- a/sbr/getarguments.c +++ b/sbr/getarguments.c @@ -1,50 +1,49 @@ - /* - * getarguments.c -- Get the argument vector ready to go. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** getarguments.c -- Get the argument vector ready to go. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include char ** -getarguments (char *invo_name, int argc, char **argv, int check_context) +getarguments(char *invo_name, int argc, char **argv, int check_context) { - char *cp = NULL, **ap = NULL, **bp = NULL, **arguments = NULL; - int n = 0; - - /* - * Check if profile/context specifies any arguments - */ - if (check_context && (cp = context_find (invo_name))) { - cp = getcpy (cp); /* make copy */ - ap = brkstring (cp, " ", "\n"); /* split string */ - - /* Count number of arguments split */ - bp = ap; - while (*bp++) - n++; - } - - arguments = (char **) mh_xmalloc ((argc + n) * sizeof(*arguments)); - bp = arguments; - - /* Copy any arguments from profile/context */ - if (ap != NULL && n > 0) { - while (*ap) - *bp++ = *ap++; - } - - /* Copy arguments from command line */ - argv++; - while (*argv) - *bp++ = *argv++; - - /* Now NULL terminate the array */ - *bp = NULL; - - return arguments; + char *cp = NULL, **ap = NULL, **bp = NULL, **arguments = NULL; + int n = 0; + + /* + ** Check if profile/context specifies any arguments + */ + if (check_context && (cp = context_find(invo_name))) { + cp = getcpy(cp); /* make copy */ + ap = brkstring(cp, " ", "\n"); /* split string */ + + /* Count number of arguments split */ + bp = ap; + while (*bp++) + n++; + } + + arguments = (char **) mh_xmalloc((argc + n) * sizeof(*arguments)); + bp = arguments; + + /* Copy any arguments from profile/context */ + if (ap != NULL && n > 0) { + while (*ap) + *bp++ = *ap++; + } + + /* Copy arguments from command line */ + argv++; + while (*argv) + *bp++ = *argv++; + + /* Now NULL terminate the array */ + *bp = NULL; + + return arguments; } diff --git a/sbr/getcpy.c b/sbr/getcpy.c index 6633248..478986a 100644 --- a/sbr/getcpy.c +++ b/sbr/getcpy.c @@ -1,33 +1,32 @@ - /* - * getcpy.c -- copy a string in managed memory - * - * THIS IS OBSOLETE. NEED TO REPLACE ALL OCCURENCES - * OF GETCPY WITH STRDUP. BUT THIS WILL REQUIRE - * CHANGING PARTS OF THE CODE TO DEAL WITH NULL VALUES. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** getcpy.c -- copy a string in managed memory +** +** THIS IS OBSOLETE. NEED TO REPLACE ALL OCCURENCES +** OF GETCPY WITH STRDUP. BUT THIS WILL REQUIRE +** CHANGING PARTS OF THE CODE TO DEAL WITH NULL VALUES. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include char * -getcpy (char *str) +getcpy(char *str) { - char *cp; - size_t len; + char *cp; + size_t len; - if (str) { - len = strlen(str) + 1; - cp = mh_xmalloc (len); - memcpy (cp, str, len); - } else { - cp = mh_xmalloc ((size_t) 1); - *cp = '\0'; - } - return cp; + if (str) { + len = strlen(str) + 1; + cp = mh_xmalloc(len); + memcpy(cp, str, len); + } else { + cp = mh_xmalloc((size_t) 1); + *cp = '\0'; + } + return cp; } diff --git a/sbr/getfolder.c b/sbr/getfolder.c deleted file mode 100644 index 6c6d267..0000000 --- a/sbr/getfolder.c +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * getfolder.c -- get the current or default folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -char * -getfolder(int wantcurrent) -{ - register char *folder; - - /* - * If wantcurrent == 1, then try the current folder first - */ - if (wantcurrent && (folder = context_find (pfolder)) && *folder != '\0') - return folder; - - /* - * Else try the Inbox profile entry - */ - if ((folder = context_find (inbox)) && *folder != '\0') - return folder; - - /* - * Else return compile time default. - */ - return defaultfolder; -} diff --git a/sbr/getpass.c b/sbr/getpass.c index f3ae829..3fd4528 100644 --- a/sbr/getpass.c +++ b/sbr/getpass.c @@ -1,89 +1,89 @@ /* - * Portions of this code are Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ +** Portions of this code are Copyright (c) 1988, 1993 +** The Regents of the University of California. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. All advertising materials mentioning features or use of this software +** must display the following acknowledgement: +** This product includes software developed by the University of +** California, Berkeley and its contributors. +** 4. Neither the name of the University nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ #include #include #include /* for isatty() */ #include "h/mh.h" /* for adios() */ -/* We don't use MAX_PASS here because the maximum password length on a remote - POP daemon will have nothing to do with the length on our OS. 256 is - arbitrary but hopefully big enough to accomodate everyone. */ +/* +** We don't use MAX_PASS here because the maximum password length on a remote +** POP daemon will have nothing to do with the length on our OS. 256 is +** arbitrary but hopefully big enough to accomodate everyone. +*/ #define MAX_PASSWORD_LEN 256 #ifndef TCSANOW -#define TCSANOW 0 +# define TCSANOW 0 #endif char * nmh_getpass(const char *prompt) { - struct termios oterm, term; - int ch; - char *p; - FILE *fout, *fin; - static char buf[MAX_PASSWORD_LEN + 1]; - int istty = isatty(fileno(stdin)); + struct termios oterm, term; + int ch; + char *p; + FILE *fout, *fin; + static char buf[MAX_PASSWORD_LEN + 1]; + int istty = isatty(fileno(stdin)); - /* Find if stdin is connect to a terminal. If so, read directly from - * the terminal, and turn off echo. Otherwise read from stdin. - */ + /* + ** Find if stdin is connect to a terminal. If so, read directly from + ** the terminal, and turn off echo. Otherwise read from stdin. + */ - if (!istty || !(fout = fin = fopen("/dev/tty", "w+"))) { - fout = stderr; - fin = stdin; - } - else /* Reading directly from terminal here */ - { - (void)tcgetattr(fileno(fin), &oterm); - term = oterm; /* Save original info */ - term.c_lflag &= ~ECHO; - (void)fputs(prompt, fout); - rewind(fout); /* implied flush */ - (void)tcsetattr(fileno(fin), TCSANOW, &term); - } + if (!istty || !(fout = fin = fopen("/dev/tty", "w+"))) { + fout = stderr; + fin = stdin; + } else { /* Reading directly from terminal here */ + tcgetattr(fileno(fin), &oterm); + term = oterm; /* Save original info */ + term.c_lflag &= ~ECHO; + fputs(prompt, fout); + rewind(fout); /* implied flush */ + tcsetattr(fileno(fin), TCSANOW, &term); + } - for (p = buf; (ch = getc(fin)) != EOF && - ch != '\n' && - p < buf + MAX_PASSWORD_LEN;) - *p++ = ch; - *p = '\0'; + for (p = buf; (ch = getc(fin)) != EOF && ch != '\n' && + p < buf + MAX_PASSWORD_LEN;) + *p++ = ch; + *p = '\0'; - if (istty) { - (void)tcsetattr(fileno(fin), TCSANOW, &oterm); - rewind(fout); - (void)fputc('\n', fout); - (void)fclose(fin); - } - return buf; + if (istty) { + tcsetattr(fileno(fin), TCSANOW, &oterm); + rewind(fout); + fputc('\n', fout); + fclose(fin); + } + return buf; } diff --git a/sbr/lock_file.c b/sbr/lock_file.c index 7eaa0de..d15c939 100644 --- a/sbr/lock_file.c +++ b/sbr/lock_file.c @@ -1,38 +1,30 @@ +/* +** lock.c -- routines to lock/unlock files +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ /* - * lock.c -- routines to lock/unlock files - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* Modified by Ruud de Rooij to support Miquel van Smoorenburg's liblockfile - * - * Since liblockfile locking shares most of its code with dot locking, it - * is enabled by defining both DOT_LOCKING and HAVE_LIBLOCKFILE. - * - * Ruud de Rooij Sun, 28 Mar 1999 15:34:03 +0200 - */ - +** Modified by Ruud de Rooij to support Miquel van Smoorenburg's liblockfile +** +** Since liblockfile locking shares most of its code with dot locking, it +** is enabled by defining both DOT_LOCKING and HAVE_LIBLOCKFILE. +** +** Ruud de Rooij Sun, 28 Mar 1999 15:34:03 +0200 +*/ + #include #include #include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include -#ifdef HAVE_ERRNO_H -# include -#endif +#include #ifdef HAVE_FCNTL_H # include @@ -63,31 +55,31 @@ char *lockdir = LOCKDIR; /* struct for getting name of lock file to create */ struct lockinfo { - char curlock[BUFSIZ]; + char curlock[BUFSIZ]; #if !defined(HAVE_LIBLOCKFILE) - char tmplock[BUFSIZ]; + char tmplock[BUFSIZ]; #endif }; /* - * Amount of time to wait before - * updating ctime of lock file. - */ -#define NSECS 20 +** Amount of time to wait before +** updating ctime of lock file. +*/ +#define NSECS 20 #if !defined(HAVE_LIBLOCKFILE) /* - * How old does a lock file need to be - * before we remove it. - */ +** How old does a lock file need to be +** before we remove it. +*/ #define RSECS 180 #endif /* HAVE_LIBLOCKFILE */ /* struct for recording and updating locks */ struct lock { - int l_fd; - char *l_lock; - struct lock *l_next; + int l_fd; + char *l_lock; + struct lock *l_next; }; /* top of list containing all open locks */ @@ -95,253 +87,253 @@ static struct lock *l_top = NULL; #endif /* DOT_LOCKING */ /* - * static prototypes - */ +** static prototypes +*/ #ifdef KERNEL_LOCKING -static int lkopen_kernel (char *, int, mode_t); +static int lkopen_kernel(char *, int, mode_t); #endif #ifdef DOT_LOCKING -static int lkopen_dot (char *, int, mode_t); -static void lockname (char *, struct lockinfo *, int); -static void timerON (char *, int); -static void timerOFF (int); -static RETSIGTYPE alrmser (int); -#endif +static int lkopen_dot(char *, int, mode_t); +static void lockname(char *, struct lockinfo *, int); +static void timerON(char *, int); +static void timerOFF(int); +static void alrmser(int); #if !defined(HAVE_LIBLOCKFILE) -static int lockit (struct lockinfo *); +static int lockit(struct lockinfo *); +#endif #endif /* - * Base routine to open and lock a file, - * and return a file descriptor. - */ +** Base routine to open and lock a file, +** and return a file descriptor. +*/ int -lkopen (char *file, int access, mode_t mode) +lkopen(char *file, int access, mode_t mode) { #ifdef KERNEL_LOCKING - return lkopen_kernel(file, access, mode); + return lkopen_kernel(file, access, mode); #endif #ifdef DOT_LOCKING - return lkopen_dot(file, access, mode); + return lkopen_dot(file, access, mode); #endif } /* - * Base routine to close and unlock a file, - * given a file descriptor. - */ +** Base routine to close and unlock a file, +** given a file descriptor. +*/ int -lkclose (int fd, char *file) +lkclose(int fd, char *file) { #ifdef FCNTL_LOCKING - struct flock buf; + struct flock buf; #endif #ifdef DOT_LOCKING - struct lockinfo lkinfo; + struct lockinfo lkinfo; #endif - if (fd == -1) - return 0; + if (fd == -1) + return 0; #ifdef FCNTL_LOCKING - buf.l_type = F_UNLCK; - buf.l_whence = SEEK_SET; - buf.l_start = 0; - buf.l_len = 0; - fcntl(fd, F_SETLK, &buf); + buf.l_type = F_UNLCK; + buf.l_whence = SEEK_SET; + buf.l_start = 0; + buf.l_len = 0; + fcntl(fd, F_SETLK, &buf); #endif #ifdef FLOCK_LOCKING - flock (fd, LOCK_UN); + flock(fd, LOCK_UN); #endif #ifdef LOCKF_LOCKING - /* make sure we unlock the whole thing */ - lseek (fd, (off_t) 0, SEEK_SET); - lockf (fd, F_ULOCK, 0L); -#endif + /* make sure we unlock the whole thing */ + lseek(fd, (off_t) 0, SEEK_SET); + lockf(fd, F_ULOCK, 0L); +#endif #ifdef DOT_LOCKING - lockname (file, &lkinfo, 0); /* get name of lock file */ + lockname(file, &lkinfo, 0); /* get name of lock file */ #if !defined(HAVE_LIBLOCKFILE) - unlink (lkinfo.curlock); /* remove lock file */ + unlink(lkinfo.curlock); /* remove lock file */ #else - lockfile_remove(lkinfo.curlock); + lockfile_remove(lkinfo.curlock); #endif /* HAVE_LIBLOCKFILE */ - timerOFF (fd); /* turn off lock timer */ + timerOFF(fd); /* turn off lock timer */ #endif /* DOT_LOCKING */ - return (close (fd)); + return (close(fd)); } /* - * Base routine to open and lock a file, - * and return a FILE pointer - */ +** Base routine to open and lock a file, +** and return a FILE pointer +*/ FILE * -lkfopen (char *file, char *mode) +lkfopen(char *file, char *mode) { - int fd, access; - FILE *fp; - - if (strcmp (mode, "r") == 0) - access = O_RDONLY; - else if (strcmp (mode, "r+") == 0) - access = O_RDWR; - else if (strcmp (mode, "w") == 0) - access = O_WRONLY | O_CREAT | O_TRUNC; - else if (strcmp (mode, "w+") == 0) - access = O_RDWR | O_CREAT | O_TRUNC; - else if (strcmp (mode, "a") == 0) - access = O_WRONLY | O_CREAT | O_APPEND; - else if (strcmp (mode, "a+") == 0) - access = O_RDWR | O_CREAT | O_APPEND; - else { - errno = EINVAL; - return NULL; - } - - if ((fd = lkopen (file, access, 0666)) == -1) - return NULL; - - if ((fp = fdopen (fd, mode)) == NULL) { - close (fd); - return NULL; - } - - return fp; + int fd, access; + FILE *fp; + + if (strcmp(mode, "r") == 0) + access = O_RDONLY; + else if (strcmp(mode, "r+") == 0) + access = O_RDWR; + else if (strcmp(mode, "w") == 0) + access = O_WRONLY | O_CREAT | O_TRUNC; + else if (strcmp(mode, "w+") == 0) + access = O_RDWR | O_CREAT | O_TRUNC; + else if (strcmp(mode, "a") == 0) + access = O_WRONLY | O_CREAT | O_APPEND; + else if (strcmp(mode, "a+") == 0) + access = O_RDWR | O_CREAT | O_APPEND; + else { + errno = EINVAL; + return NULL; + } + + if ((fd = lkopen(file, access, 0666)) == -1) + return NULL; + + if ((fp = fdopen(fd, mode)) == NULL) { + close(fd); + return NULL; + } + + return fp; } /* - * Base routine to close and unlock a file, - * given a FILE pointer - */ +** Base routine to close and unlock a file, +** given a FILE pointer +*/ int -lkfclose (FILE *fp, char *file) +lkfclose(FILE *fp, char *file) { #ifdef FCNTL_LOCKING - struct flock buf; + struct flock buf; #endif #ifdef DOT_LOCKING - struct lockinfo lkinfo; + struct lockinfo lkinfo; #endif - if (fp == NULL) - return 0; + if (fp == NULL) + return 0; #ifdef FCNTL_LOCKING - buf.l_type = F_UNLCK; - buf.l_whence = SEEK_SET; - buf.l_start = 0; - buf.l_len = 0; - fcntl(fileno(fp), F_SETLK, &buf); + buf.l_type = F_UNLCK; + buf.l_whence = SEEK_SET; + buf.l_start = 0; + buf.l_len = 0; + fcntl(fileno(fp), F_SETLK, &buf); #endif #ifdef FLOCK_LOCKING - flock (fileno(fp), LOCK_UN); + flock(fileno(fp), LOCK_UN); #endif #ifdef LOCKF_LOCKING - /* make sure we unlock the whole thing */ - fseek (fp, 0L, SEEK_SET); - lockf (fileno(fp), F_ULOCK, 0L); + /* make sure we unlock the whole thing */ + fseek(fp, 0L, SEEK_SET); + lockf(fileno(fp), F_ULOCK, 0L); #endif #ifdef DOT_LOCKING - lockname (file, &lkinfo, 0); /* get name of lock file */ + lockname(file, &lkinfo, 0); /* get name of lock file */ #if !defined(HAVE_LIBLOCKFILE) - unlink (lkinfo.curlock); /* remove lock file */ + unlink(lkinfo.curlock); /* remove lock file */ #else - lockfile_remove(lkinfo.curlock); + lockfile_remove(lkinfo.curlock); #endif /* HAVE_LIBLOCKFILE */ - timerOFF (fileno(fp)); /* turn off lock timer */ + timerOFF(fileno(fp)); /* turn off lock timer */ #endif /* DOT_LOCKING */ - return (fclose (fp)); + return (fclose(fp)); } #ifdef KERNEL_LOCKING /* - * open and lock a file, using kernel locking - */ +** open and lock a file, using kernel locking +*/ static int -lkopen_kernel (char *file, int access, mode_t mode) +lkopen_kernel(char *file, int access, mode_t mode) { - int fd, i, j; + int fd, i, j; # ifdef FCNTL_LOCKING - struct flock buf; + struct flock buf; # endif /* FCNTL_LOCKING */ - for (i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) { # if defined(LOCKF_LOCKING) || defined(FCNTL_LOCKING) - /* remember the original mode */ - j = access; + /* remember the original mode */ + j = access; - /* make sure we open at the beginning */ - access &= ~O_APPEND; + /* make sure we open at the beginning */ + access &= ~O_APPEND; - /* - * We MUST have write permission or - * lockf/fcntl() won't work - */ - if ((access & 03) == O_RDONLY) { - access &= ~O_RDONLY; - access |= O_RDWR; - } + /* + ** We MUST have write permission or + ** lockf/fcntl() won't work + */ + if ((access & 03) == O_RDONLY) { + access &= ~O_RDONLY; + access |= O_RDWR; + } # endif /* LOCKF_LOCKING || FCNTL_LOCKING */ - if ((fd = open (file, access | O_NDELAY, mode)) == -1) - return -1; + if ((fd = open(file, access | O_NDELAY, mode)) == -1) + return -1; # ifdef FCNTL_LOCKING - buf.l_type = F_WRLCK; - buf.l_whence = SEEK_SET; - buf.l_start = 0; - buf.l_len = 0; - if (fcntl (fd, F_SETLK, &buf) != -1) - return fd; + buf.l_type = F_WRLCK; + buf.l_whence = SEEK_SET; + buf.l_start = 0; + buf.l_len = 0; + if (fcntl(fd, F_SETLK, &buf) != -1) + return fd; # endif # ifdef FLOCK_LOCKING - if (flock (fd, (((access & 03) == O_RDONLY) ? LOCK_SH : LOCK_EX) - | LOCK_NB) != -1) - return fd; + if (flock(fd, (((access & 03) == O_RDONLY) ? LOCK_SH : + LOCK_EX) | LOCK_NB) != -1) + return fd; # endif # ifdef LOCKF_LOCKING - if (lockf (fd, F_TLOCK, 0L) != -1) { - /* see if we should be at the end */ - if (j & O_APPEND) - lseek (fd, (off_t) 0, SEEK_END); - return fd; - } + if (lockf(fd, F_TLOCK, 0L) != -1) { + /* see if we should be at the end */ + if (j & O_APPEND) + lseek(fd, (off_t) 0, SEEK_END); + return fd; + } # endif - j = errno; - close (fd); - sleep (5); - } + j = errno; + close(fd); + sleep(5); + } - close (fd); - errno = j; - return -1; + close(fd); + errno = j; + return -1; } #endif /* KERNEL_LOCKING */ @@ -350,280 +342,253 @@ lkopen_kernel (char *file, int access, mode_t mode) #ifdef DOT_LOCKING /* - * open and lock a file, using dot locking - */ +** open and lock a file, using dot locking +*/ static int -lkopen_dot (char *file, int access, mode_t mode) +lkopen_dot(char *file, int access, mode_t mode) { - int fd; - struct lockinfo lkinfo; + int fd; + struct lockinfo lkinfo; - /* open the file */ - if ((fd = open (file, access, mode)) == -1) - return -1; + /* open the file */ + if ((fd = open(file, access, mode)) == -1) + return -1; - /* - * Get the name of the eventual lock file, as well - * as a name for a temporary lock file. - */ - lockname (file, &lkinfo, 1); + /* + ** Get the name of the eventual lock file, as well + ** as a name for a temporary lock file. + */ + lockname(file, &lkinfo, 1); #if !defined(HAVE_LIBLOCKFILE) - { - int i; - for (i = 0;;) { - /* attempt to create lock file */ - if (lockit (&lkinfo) == 0) { - /* if successful, turn on timer and return */ - timerON (lkinfo.curlock, fd); - return fd; - } else { - /* - * Abort locking, if we fail to lock after 5 attempts - * and are never able to stat the lock file. - */ - struct stat st; - if (stat (lkinfo.curlock, &st) == -1) { - if (i++ > 5) - return -1; - sleep (5); - } else { - time_t curtime; - i = 0; - time (&curtime); - - /* check for stale lockfile, else sleep */ - if (curtime > st.st_ctime + RSECS) - unlink (lkinfo.curlock); - else - sleep (5); + { + int i; + for (i = 0;;) { + /* attempt to create lock file */ + if (lockit(&lkinfo) == 0) { + /* if successful, turn on timer and return */ + timerON(lkinfo.curlock, fd); + return fd; + } else { + /* + ** Abort locking, if we fail to lock after 5 + ** attempts and are never able to stat the + ** lock file. + */ + struct stat st; + if (stat(lkinfo.curlock, &st) == -1) { + if (i++ > 5) + return -1; + sleep(5); + } else { + time_t curtime; + i = 0; + time(&curtime); + + /* + ** check for stale lockfile, + ** else sleep + */ + if (curtime > st.st_ctime + RSECS) + unlink(lkinfo.curlock); + else + sleep(5); + } + lockname(file, &lkinfo, 1); + } } - lockname (file, &lkinfo, 1); - } } - } #else - if (lockfile_create(lkinfo.curlock, 5, 0) == L_SUCCESS) { - timerON(lkinfo.curlock, fd); - return fd; - } - else { - close(fd); - return -1; - } + if (lockfile_create(lkinfo.curlock, 5, 0) == L_SUCCESS) { + timerON(lkinfo.curlock, fd); + return fd; + } else { + close(fd); + return -1; + } #endif /* HAVE_LIBLOCKFILE */ } #if !defined(HAVE_LIBLOCKFILE) /* - * Routine that actually tries to create - * the lock file. - */ +** Routine that actually tries to create +** the lock file. +*/ static int -lockit (struct lockinfo *li) +lockit(struct lockinfo *li) { - int fd; - char *curlock, *tmplock; + int fd; + char *curlock, *tmplock; #if 0 - char buffer[128]; + char buffer[128]; #endif - curlock = li->curlock; - tmplock = li->tmplock; + curlock = li->curlock; + tmplock = li->tmplock; -#ifdef HAVE_MKSTEMP - if ((fd = mkstemp(tmplock)) == -1) - return -1; -#else - if (mktemp(tmplock) == NULL) - return -1; - if (unlink(tmplock) == -1 && errno != ENOENT) - return -1; - /* create the temporary lock file */ - if ((fd = creat(tmplock, 0600)) == -1) - return -1; -#endif + if ((fd = mkstemp(tmplock)) == -1) + return -1; #if 0 - /* write our process id into lock file */ - snprintf (buffer, sizeof(buffer), "nmh lock: pid %d\n", (int) getpid()); - write(fd, buffer, strlen(buffer) + 1); + /* write our process id into lock file */ + snprintf(buffer, sizeof(buffer), "nmh lock: pid %d\n", (int) getpid()); + write(fd, buffer, strlen(buffer) + 1); #endif - close (fd); + close(fd); - /* - * Now try to create the real lock file - * by linking to the temporary file. - */ - fd = link(tmplock, curlock); - unlink(tmplock); + /* + ** Now try to create the real lock file + ** by linking to the temporary file. + */ + fd = link(tmplock, curlock); + unlink(tmplock); - return (fd == -1 ? -1 : 0); + return (fd == -1 ? -1 : 0); } #endif /* HAVE_LIBLOCKFILE */ /* - * Get name of lock file, and temporary lock file - */ +** Get name of lock file, and temporary lock file +*/ static void -lockname (char *file, struct lockinfo *li, int isnewlock) +lockname(char *file, struct lockinfo *li, int isnewlock) { - int bplen, tmplen; - char *bp, *cp; + int bplen, tmplen; + char *bp, *cp; -#if 0 - struct stat st; -#endif + if ((cp = strrchr(file, '/')) == NULL || *++cp == 0) + cp = file; - if ((cp = strrchr (file, '/')) == NULL || *++cp == 0) - cp = file; - - bp = li->curlock; - bplen = 0; + bp = li->curlock; + bplen = 0; #ifdef LOCKDIR - snprintf (bp, sizeof(li->curlock), "%s/", lockdir); - tmplen = strlen (bp); - bp += tmplen; - bplen += tmplen; -#else - if (cp != file) { - snprintf (bp, sizeof(li->curlock), "%.*s", (int)(cp - file), file); - tmplen = strlen (bp); - bp += tmplen; + snprintf(bp, sizeof(li->curlock), "%s/", lockdir); + tmplen = strlen(bp); + bp += tmplen; bplen += tmplen; - } -#endif - -#if 0 - /* - * mmdf style dot locking. Currently not supported. - * If we start supporting mmdf style dot locking, - * we will need to change the return value of lockname - */ - if (stat (file, &st) == -1) - return -1; - - snprintf (bp, sizeof(li->curlock) - bplen, "LCK%05d.%05d", - st.st_dev, st.st_ino); +#else + if (cp != file) { + snprintf(bp, sizeof(li->curlock), "%.*s", (int)(cp - file), file); + tmplen = strlen(bp); + bp += tmplen; + bplen += tmplen; + } #endif - snprintf (bp, sizeof(li->curlock) - bplen, "%s.lock", cp); + snprintf(bp, sizeof(li->curlock) - bplen, "%s.lock", cp); #if !defined(HAVE_LIBLOCKFILE) - /* - * If this is for a new lock, create a name for - * the temporary lock file for lockit() - */ - if (isnewlock) { - if ((cp = strrchr (li->curlock, '/')) == NULL || *++cp == 0) - strncpy (li->tmplock, ",LCK.XXXXXX", sizeof(li->tmplock)); - else - snprintf (li->tmplock, sizeof(li->tmplock), "%.*s,LCK.XXXXXX", - (int)(cp - li->curlock), li->curlock); - } + /* + ** If this is for a new lock, create a name for + ** the temporary lock file for lockit() + */ + if (isnewlock) { + if ((cp = strrchr(li->curlock, '/')) == NULL || *++cp == 0) + strncpy(li->tmplock, ",LCK.XXXXXX", sizeof(li->tmplock)); + else + snprintf(li->tmplock, sizeof(li->tmplock), + "%.*s,LCK.XXXXXX", + (int)(cp - li->curlock), li->curlock); + } #endif } /* - * Add new lockfile to the list of open lockfiles - * and start the lock file timer. - */ +** Add new lockfile to the list of open lockfiles +** and start the lock file timer. +*/ static void -timerON (char *curlock, int fd) +timerON(char *curlock, int fd) { - struct lock *lp; - size_t len; + struct lock *lp; + size_t len; - lp = (struct lock *) mh_xmalloc (sizeof(*lp)); + lp = (struct lock *) mh_xmalloc(sizeof(*lp)); - len = strlen(curlock) + 1; - lp->l_fd = fd; - lp->l_lock = mh_xmalloc (len); - memcpy (lp->l_lock, curlock, len); - lp->l_next = l_top; + len = strlen(curlock) + 1; + lp->l_fd = fd; + lp->l_lock = mh_xmalloc(len); + memcpy(lp->l_lock, curlock, len); + lp->l_next = l_top; - if (!l_top) { - /* perhaps SIGT{STP,TIN,TOU} ? */ - SIGNAL (SIGALRM, alrmser); - alarm (NSECS); - } + if (!l_top) { + /* perhaps SIGT{STP,TIN,TOU} ? */ + SIGNAL(SIGALRM, alrmser); + alarm(NSECS); + } - l_top = lp; + l_top = lp; } /* - * Search through the list of lockfiles for the - * current lockfile, and remove it from the list. - */ +** Search through the list of lockfiles for the +** current lockfile, and remove it from the list. +*/ static void -timerOFF (int fd) +timerOFF(int fd) { - struct lock *pp, *lp; + struct lock *pp, *lp; - alarm(0); + alarm(0); - if (l_top) { - for (pp = lp = l_top; lp; pp = lp, lp = lp->l_next) { - if (lp->l_fd == fd) - break; - } - if (lp) { - if (lp == l_top) - l_top = lp->l_next; - else - pp->l_next = lp->l_next; - - free (lp->l_lock); - free (lp); + if (l_top) { + for (pp = lp = l_top; lp; pp = lp, lp = lp->l_next) { + if (lp->l_fd == fd) + break; + } + if (lp) { + if (lp == l_top) + l_top = lp->l_next; + else + pp->l_next = lp->l_next; + + free(lp->l_lock); + free(lp); + } } - } - /* if there are locks left, restart timer */ - if (l_top) - alarm (NSECS); + /* if there are locks left, restart timer */ + if (l_top) + alarm(NSECS); } /* - * If timer goes off, we update the ctime of all open - * lockfiles, so another command doesn't remove them. - */ +** If timer goes off, we update the ctime of all open +** lockfiles, so another command doesn't remove them. +*/ -static RETSIGTYPE -alrmser (int sig) +static void +alrmser(int sig) { - char *lockfile; - struct lock *lp; - -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGALRM, alrmser); -#endif + char *lockfile; + struct lock *lp; - /* update the ctime of all the lock files */ - for (lp = l_top; lp; lp = lp->l_next) { - lockfile = lp->l_lock; + /* update the ctime of all the lock files */ + for (lp = l_top; lp; lp = lp->l_next) { + lockfile = lp->l_lock; #if !defined(HAVE_LIBLOCKFILE) - { - int j; - if (*lockfile && (j = creat (lockfile, 0600)) != -1) - close (j); - } + { + int j; + if (*lockfile && (j = creat(lockfile, 0600)) != -1) + close(j); + } #else - lockfile_touch(lockfile); + lockfile_touch(lockfile); #endif - } + } - /* restart the alarm */ - alarm (NSECS); + /* restart the alarm */ + alarm(NSECS); } #endif /* DOT_LOCKING */ diff --git a/sbr/m_atoi.c b/sbr/m_atoi.c index 174c407..b903b7e 100644 --- a/sbr/m_atoi.c +++ b/sbr/m_atoi.c @@ -1,34 +1,29 @@ - /* - * m_atoi.c -- Parse a string representation of a message number, and - * -- return the numeric value of the message. If the string - * -- contains any non-digit characters, then return 0. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_atoi.c -- Parse a string representation of a message number, and +** -- return the numeric value of the message. If the string +** -- contains any non-digit characters, then return 0. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include int -m_atoi (char *str) +m_atoi(char *str) { - int i; - unsigned char *cp; + int i; + unsigned char *cp; - for (i = 0, cp = str; *cp; cp++) { -#ifdef LOCALE - if (!isdigit(*cp)) -#else - if (*cp < '0' || *cp > '9') -#endif - return 0; + for (i = 0, cp = str; *cp; cp++) { + if (!isdigit(*cp)) + return 0; - i *= 10; - i += (*cp - '0'); - } + i *= 10; + i += (*cp - '0'); + } - return i; + return i; } diff --git a/sbr/m_backup.c b/sbr/m_backup.c deleted file mode 100644 index c34c409..0000000 --- a/sbr/m_backup.c +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * m_backup.c -- construct a backup file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -char * -m_backup (char *file) -{ - char *cp; - static char buffer[BUFSIZ]; - - if ((cp = r1bindex(file, '/')) == file) - snprintf(buffer, sizeof(buffer), "%s%s", - BACKUP_PREFIX, cp); - else - snprintf(buffer, sizeof(buffer), "%.*s%s%s", (int)(cp - file), file, - BACKUP_PREFIX, cp); - - unlink(buffer); - return buffer; -} diff --git a/sbr/m_convert.c b/sbr/m_convert.c index 1696190..85d4e58 100644 --- a/sbr/m_convert.c +++ b/sbr/m_convert.c @@ -1,446 +1,448 @@ - /* - * m_convert.c -- parse a message range or sequence and set SELECTED - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_convert.c -- parse a message range or sequence and set SELECTED +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ + + +/* FIXME: This code needs rework! Rewrite as a parser? */ #include /* - * error codes for sequence - * and message range processing - */ -#define BADMSG (-2) -#define BADRNG (-3) -#define BADNEW (-4) -#define BADNUM (-5) -#define BADLST (-6) +** error codes for sequence +** and message range processing +*/ +#define BADMSG (-2) +#define BADRNG (-3) +#define BADNEW (-4) +#define BADNUM (-5) +#define BADLST (-6) -#define FIRST 1 -#define LAST 2 +#define FIRST 1 +#define LAST 2 -#define getnew(mp) (mp->hghmsg + 1) +#define getbeyond(mp) ((mp)->hghmsg + 1) -static int convdir; /* convert direction */ -static char *delimp; +static int convdir; /* convert direction */ +static char *delimp; /* delimiter pointer */ /* - * static prototypes - */ -static int m_conv (struct msgs *, char *, int); -static int attr (struct msgs *, char *); +** static prototypes +*/ +static int m_conv(struct msgs *, char *, int); +static int attr(struct msgs *, char *); +static void +addtosel(struct msgs *mp, int msg) +{ + if (is_selected(mp, msg)) { + return; /* dont select twice */ + } + set_selected(mp, msg); + mp->numsel++; + if (mp->lowsel == 0 || msg < mp->lowsel) { + mp->lowsel = msg; + } + if (msg > mp->hghsel) { + mp->hghsel = msg; + } +} + int -m_convert (struct msgs *mp, char *name) +m_convert(struct msgs *mp, char *name) { - int first, last, found, range, err; - unsigned char *bp; - char *cp; - - /* check if user defined sequence */ - err = attr (mp, cp = name); - - if (err == -1) - return 0; - else if (err < 0) - goto badmsg; - else if (err > 0) - return 1; - /* - * else err == 0, so continue - */ - - found = 0; - - /* - * Check for special "new" sequence, which - * is valid only if ALLOW_NEW is set. - */ - if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) { - if ((err = first = getnew (mp)) <= 0) - goto badmsg; - else - goto single; - } - - if (!strcmp (cp, "all")) - cp = "first-last"; - - if ((err = first = m_conv (mp, cp, FIRST)) <= 0) - goto badmsg; - - cp = delimp; - if (*cp != '\0' && *cp != '-' && *cp != ':') { -badelim: - advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp); - return 0; - } + int first, last, found, range, err; + unsigned char *bp; + char *cp; - if (*cp == '-') { - cp++; - if ((err = last = m_conv (mp, cp, LAST)) <= 0) { -badmsg: - switch (err) { - case BADMSG: - advise (NULL, "no %s message", cp); - break; + /* check if user defined sequence */ + err = attr(mp, cp = name); + if (err == -1) + return 0; + else if (err < 0) + goto badmsg; + else if (err > 0) { + /* it had been a user-defined sequence: we're finished */ + return 1; + } + /* + ** else err == 0, so continue + ** here we know: it is no user-defined seq + */ - case BADNUM: - advise (NULL, "message %s doesn't exist", cp); - break; + /* + ** Handle the special beyond sequence, which is valid only if + ** ALLOW_BEYOND is set, and can appear only on its own. + ** Also, it is available in any folder. + */ + if ((mp->msgflags & ALLOW_BEYOND) && strcmp(cp, seq_beyond)==0) { + addtosel(mp, getbeyond(mp)); + return 1; + } - case BADRNG: - advise (NULL, "message %s out of range 1-%d", cp, mp->hghmsg); - break; + /* + ** Handle the special all sequence: replace `a' with `f-l' + */ + if (strcmp(cp, seq_all)==0) { + cp = concat(seq_first, "-", seq_last, NULL); + } - case BADLST: -badlist: - advise (NULL, "bad message list %s", name); - break; + if ((err = first = m_conv(mp, cp, FIRST)) <= 0) + goto badmsg; - case BADNEW: - advise (NULL, "folder full, no %s message", name); - break; + cp = delimp; + switch (*cp) { + case '-': + /* global range */ + cp++; + if ((err = last = m_conv(mp, cp, LAST)) <= 0) { +badmsg: + switch (err) { + case BADMSG: + advise(NULL, "no %s message", cp); + break; - default: - advise (NULL, "no messages match specification"); - } - return 0; - } + case BADNUM: + advise(NULL, "message %s doesn't exist", cp); + break; - if (last < first) - goto badlist; - if (*delimp) - goto badelim; - if (first > mp->hghmsg || last < mp->lowmsg) { + case BADRNG: + advise(NULL, "message %s out of range 1-%d", + cp, mp->hghmsg); + break; + + case BADLST: +badlist: + advise(NULL, "bad message list %s", name); + break; + + case BADNEW: + advise(NULL, "folder full, no %s message", + name); + break; + + default: + advise(NULL, "no messages match specification"); + } + return 0; + } + + if (last < first) + goto badlist; + if (*delimp) + goto badelim; + if (first > mp->hghmsg || last < mp->lowmsg) { rangerr: - advise (NULL, "no messages in range %s", name); - return 0; - } + advise(NULL, "no messages in range %s", name); + return 0; + } + + /* tighten the range to search */ + if (last > mp->hghmsg) + last = mp->hghmsg; + if (first < mp->lowmsg) + first = mp->lowmsg; + break; - /* tighten the range to search */ - if (last > mp->hghmsg) - last = mp->hghmsg; - if (first < mp->lowmsg) - first = mp->lowmsg; - - } else if (*cp == ':') { - cp++; - if (*cp == '-') { - convdir = -1; - cp++; - } else { - if (*cp == '+') { - convdir = 1; + case ':': + /* anchored range */ cp++; - } - } - if ((range = atoi (bp = cp)) == 0) - goto badlist; - while (isdigit (*bp)) - bp++; - if (*bp) - goto badelim; - if ((convdir > 0 && first > mp->hghmsg) - || (convdir < 0 && first < mp->lowmsg)) - goto rangerr; - - /* tighten the range to search */ - if (first < mp->lowmsg) - first = mp->lowmsg; - if (first > mp->hghmsg) - first = mp->hghmsg; - - for (last = first; - last >= mp->lowmsg && last <= mp->hghmsg; - last += convdir) - if (does_exist (mp, last)) - if (--range <= 0) - break; - if (last < mp->lowmsg) - last = mp->lowmsg; - if (last > mp->hghmsg) - last = mp->hghmsg; - if (last < first) { - range = last; - last = first; - first = range; - } - } else { + if (*cp == '-') { + convdir = -1; + cp++; + } else if (*cp == '+') { + convdir = 1; + cp++; + } + if ((range = atoi(bp = cp)) == 0) + goto badlist; + while (isdigit(*bp)) + bp++; + if (*bp) + goto badelim; + if ((convdir > 0 && first > mp->hghmsg) + || (convdir < 0 && first < mp->lowmsg)) + goto rangerr; + + /* tighten the range to search */ + if (first < mp->lowmsg) + first = mp->lowmsg; + if (first > mp->hghmsg) + first = mp->hghmsg; + + for (last = first; last >= mp->lowmsg && last <= mp->hghmsg; + last += convdir) + if (does_exist(mp, last) && (--range <= 0)) + break; + if (last < mp->lowmsg) + last = mp->lowmsg; + if (last > mp->hghmsg) + last = mp->hghmsg; + if (last < first) { + range = last; + last = first; + first = range; + } + break; -single: - /* - * Single Message - * - * If ALLOW_NEW is set, then allow selecting of an - * empty slot. If ALLOW_NEW is not set, then we - * check if message is in-range and exists. - */ - if (mp->msgflags & ALLOW_NEW) { - set_select_empty (mp, first); - } else { - if (first > mp->hghmsg - || first < mp->lowmsg - || !(does_exist (mp, first))) { - if (!strcmp (name, "cur") || !strcmp (name, ".")) - advise (NULL, "no %s message", name); - else - advise (NULL, "message %d doesn't exist", first); + case '\0': + /* single name */ + /* + ** AFAICS, the only cases to reach here are: + ** f, l, p, n, c, b + ** But I'm not sure. --meillo + */ + /* + ** Single Message + ** + ** Check if message is in-range and exists. + */ + if (first > mp->hghmsg || first < mp->lowmsg || + !does_exist(mp, first)) { + if (strcmp(name, seq_cur)==0) + advise(NULL, "no current message"); + else + /* this case seems to never be reached */ + advise(NULL, "message %d doesn't exist", + first); + return 0; + } + last = first; /* range of 1 */ + break; + + default: +badelim: + advise(NULL, "illegal argument delimiter: `%c'(0%o)", + *delimp, *delimp); return 0; - } - } - last = first; /* range of 1 */ - } - - /* - * Cycle through the range and select the messages - * that exist. If ALLOW_NEW is set, then we also check - * if we are selecting an empty slot. - */ - for (; first <= last; first++) { - if (does_exist (mp, first) || - ((mp->msgflags & ALLOW_NEW) && is_select_empty (mp, first))) { - if (!is_selected (mp, first)) { - set_selected (mp, first); - mp->numsel++; - if (mp->lowsel == 0 || first < mp->lowsel) - mp->lowsel = first; - if (first > mp->hghsel) - mp->hghsel = first; - } - found++; + break; } - } - if (!found) - goto rangerr; + /* Cycle through the range and select the messages that exist. */ + for (found=0; first <= last; first++) { + if (does_exist(mp, first)) { + addtosel(mp, first); + found++; + } + } + if (!found) + goto rangerr; - return 1; + return 1; } /* - * Convert the various message names to - * their numeric values. - * - * n (integer) - * prev - * next - * first - * last - * cur - * . (same as cur) - */ - +** Convert the various message names to their numeric values. +** +** 42 (any integer) +** p +** n +** f +** l +** c +*/ static int -m_conv (struct msgs *mp, char *str, int call) +m_conv(struct msgs *mp, char *str, int call) { - register int i; - register unsigned char *cp, *bp; - unsigned char buf[16]; - - convdir = 1; - cp = bp = str; - if (isdigit (*cp)) { - while (isdigit (*bp)) - bp++; - delimp = bp; - i = atoi (cp); - - if (i <= mp->hghmsg) - return i; - else if (*delimp || call == LAST) - return mp->hghmsg + 1; - else if (mp->msgflags & ALLOW_NEW) - return BADRNG; - else - return BADNUM; - } - -#ifdef LOCALE - /* doesn't enforce lower case */ - for (bp = buf; (isalpha(*cp) || *cp == '.') - && (bp - buf < sizeof(buf) - 1); ) -#else - for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.') - && (bp - buf < sizeof(buf) - 1); ) -#endif /* LOCALE */ - { - *bp++ = *cp++; - } - *bp++ = '\0'; - delimp = cp; - - if (!strcmp (buf, "first")) - return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) - ? mp->lowmsg : BADMSG); - - if (!strcmp (buf, "last")) { - convdir = -1; - return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG); - } - - if (!strcmp (buf, "cur") || !strcmp (buf, ".")) - return (mp->curmsg > 0 ? mp->curmsg : BADMSG); - - if (!strcmp (buf, "prev")) { - convdir = -1; - for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg; - i >= mp->lowmsg; i--) { - if (does_exist (mp, i)) - return i; + register int i; + register unsigned char *cp, *bp; + unsigned char buf[16]; /* for reserved sequence name */ + + convdir = 1; + cp = bp = str; + + /* Handle an integer */ + if (isdigit(*cp)) { + while (isdigit(*bp)) + bp++; + delimp = bp; + i = atoi(cp); + + if (i <= mp->hghmsg) + return i; + else if (*delimp || call == LAST) + return mp->hghmsg + 1; + else if (mp->msgflags & ALLOW_BEYOND) + return BADRNG; + else + return BADNUM; } - return BADMSG; - } - - if (!strcmp (buf, "next")) { - for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg; - i <= mp->hghmsg; i++) { - if (does_exist (mp, i)) - return i; + + for (bp = buf; isalpha(*cp) && (bp - buf < (int)sizeof(buf) - 1); ) { + *bp++ = *cp++; } - return BADMSG; - } + *bp++ = '\0'; + delimp = cp; - return BADLST; -} + /* Which one of the reserved names is it? */ + if (strcmp(buf, seq_first)==0) { + return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ? + mp->lowmsg : BADMSG); -/* - * Handle user defined sequences. - * They can take the following forms: - * - * seq - * seq:prev - * seq:next - * seq:first - * seq:last - * seq:+n - * seq:-n - * seq:n - */ + } else if (strcmp(buf, seq_last)==0) { + convdir = -1; + return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ? + mp->hghmsg : BADMSG); -static int -attr (struct msgs *mp, char *cp) -{ - register unsigned char *dp; - char *bp = NULL; - register int i, j; - int found, - inverted = 0, - range = 0, /* no range */ - first = 0; - - /* hack for "cur-name", "cur-n", etc. */ - if (!strcmp (cp, "cur")) - return 0; - if (ssequal ("cur:", cp)) /* this code need to be rewritten... */ - return 0; - - /* Check for sequence negation */ - if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) { - inverted = 1; - cp += strlen (dp); - } - - convdir = 1; /* convert direction */ - - for (dp = cp; *dp && isalnum(*dp); dp++) - continue; - - if (*dp == ':') { - bp = dp++; - range = 1; + } else if (strcmp(buf, seq_cur)==0) { + return (mp->curmsg > 0 ? mp->curmsg : BADMSG); - /* - * seq:prev (or) - * seq:next (or) - * seq:first (or) - * seq:last - */ - if (isalpha (*dp)) { - if (!strcmp (dp, "prev")) { - convdir = -1; - first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg) - ? mp->curmsg - 1 - : mp->hghmsg; - } - else if (!strcmp (dp, "next")) { - convdir = 1; - first = (mp->curmsg >= mp->lowmsg) - ? mp->curmsg + 1 - : mp->lowmsg; - } - else if (!strcmp (dp, "first")) { - convdir = 1; - } - else if (!strcmp (dp, "last")) { + } else if (strcmp(buf, seq_prev)==0) { convdir = -1; - } - else - return BADLST; + for (i = (mp->curmsg <= mp->hghmsg) ? + mp->curmsg - 1 : mp->hghmsg; + i >= mp->lowmsg; i--) { + if (does_exist(mp, i)) + return i; + } + return BADMSG; + + } else if (strcmp(buf, seq_next)==0) { + for (i = (mp->curmsg >= mp->lowmsg) ? + mp->curmsg + 1 : mp->lowmsg; + i <= mp->hghmsg; i++) { + if (does_exist(mp, i)) + return i; + } + return BADMSG; + } else { - /* - * seq:n (or) - * seq:+n (or) - * seq:-n - */ - if (*dp == '+') - dp++; - else if (*dp == '-') { - dp++; - convdir = -1; - } - if ((range = atoi(dp)) == 0) - return BADLST; - while (isdigit (*dp)) - dp++; - if (*dp) return BADLST; } +} - *bp = '\0'; /* temporarily terminate sequence name */ - } - - i = seq_getnum (mp, cp); /* get index of sequence */ - - if (bp) - *bp = ':'; /* restore sequence name */ - if (i == -1) - return 0; - - found = 0; /* count the number we select for this argument */ - - for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg; - j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) { - if (does_exist (mp, j) - && inverted ? !in_sequence (mp, i, j) : in_sequence (mp, i, j)) { - if (!is_selected (mp, j)) { - set_selected (mp, j); - mp->numsel++; - if (mp->lowsel == 0 || j < mp->lowsel) - mp->lowsel = j; - if (j > mp->hghsel) - mp->hghsel = j; - } - found++; - - /* - * If we have a range, then break out - * once we've found enough. - */ - if (range && found >= range) - break; +/* +** Handle user defined sequences. +** They can take the following forms: +** +** seq +** seq:p +** seq:n +** seq:f +** seq:l +** seq:+42 +** seq:-42 +** seq:42 +** +** (`42' being an arbitrary integer) +*/ +static int +attr(struct msgs *mp, char *cp) +{ + register unsigned char *dp; + char *bp = NULL; + register int i, j; + int found; + int inverted = 0; + int range = 0; /* no range */ + int first = 0; + + /* hack for "c-..." */ + if (strcmp(cp, seq_cur)==0) + return 0; + /* "c:..." -- this code need to be rewritten... */ + if (strncmp(seq_cur, cp, strlen(seq_cur))==0 && + cp[strlen(seq_cur)] == ':') { + return 0; + } + + /* Check for sequence negation */ + if (!(dp = context_find(nsequence))) { + dp = seq_neg; /* use default */ + } + if (*dp && strncmp(cp, dp, strlen(dp))==0) { + inverted = 1; + cp += strlen(dp); + } + + convdir = 1; /* convert direction */ + + for (dp = cp; *dp && isalnum(*dp); dp++) + continue; + + if (*dp == ':') { + bp = dp++; + range = 1; + + /* + ** seq:p (or) + ** seq:n (or) + ** seq:f (or) + ** seq:l + */ + if (isalpha(*dp)) { + if (strcmp(dp, seq_prev)==0) { + convdir = -1; + first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg) + ? mp->curmsg - 1 : mp->hghmsg; + } else if (strcmp(dp, seq_next)==0) { + convdir = 1; + first = (mp->curmsg >= mp->lowmsg) + ? mp->curmsg + 1 : mp->lowmsg; + } else if (strcmp(dp, seq_first)==0) { + convdir = 1; + } else if (strcmp(dp, seq_last)==0) { + convdir = -1; + } else + return BADLST; + } else { + /* + ** seq:42 (or) + ** seq:+42 (or) + ** seq:-42 + */ + if (*dp == '+') + dp++; + else if (*dp == '-') { + dp++; + convdir = -1; + } + if ((range = atoi(dp)) == 0) + return BADLST; + while (isdigit(*dp)) + dp++; + if (*dp) + return BADLST; + } + + *bp = '\0'; /* temporarily terminate sequence name */ + } + + i = seq_getnum(mp, cp); /* get index of sequence */ + + if (bp) + *bp = ':'; /* restore sequence name */ + if (i == -1) + return 0; + + found = 0; /* count the number we select for this argument */ + + for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg; + j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) { + if (does_exist(mp, j) + && inverted ? !in_sequence(mp, i, j) : + in_sequence(mp, i, j)) { + addtosel(mp, j); + found++; + + /* + ** If we have a range, then break out + ** once we've found enough. + */ + if (range && found >= range) + break; + } } - } - if (found > 0) - return found; + if (found) + return found; - if (first) - return BADMSG; - advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty"); - return -1; + if (first) + return BADMSG; + advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty"); + return -1; } diff --git a/sbr/m_draft.c b/sbr/m_draft.c index e479186..3659ff3 100644 --- a/sbr/m_draft.c +++ b/sbr/m_draft.c @@ -1,80 +1,64 @@ - /* - * m_draft.c -- construct the name of a draft message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_draft.c -- construct the name of a draft message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include +/* +** `which' should either be the cur sequence to use the current draft +** or the beyond sequence to start with a new draft. +*/ char * -m_draft (char *folder, char *msg, int use, int *isdf) +m_draft(char *which) { - register char *cp; - register struct msgs *mp; - static char buffer[BUFSIZ]; + register struct msgs *mp; + static char buffer[BUFSIZ]; + char *folder; - if (*isdf == -1 || folder == NULL || *folder == '\0') { - if (*isdf == -1 || (cp = context_find ("Draft-Folder")) == NULL) { - *isdf = 0; - return m_maildir (msg && *msg ? msg : draft); - } else { - folder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); + folder = getcpy(toabsdir(draftfolder)); + create_folder(folder, 0, done); + if (!(mp = folder_read(folder))) { + adios(NULL, "unable to read folder %s", folder); } - } - *isdf = 1; - - chdir (m_maildir ("")); - strncpy (buffer, m_maildir (folder), sizeof(buffer)); - - create_folder (buffer, 0, done); - - if (chdir (buffer) == -1) - adios (buffer, "unable to change directory to"); + free(folder); - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* - * Make sure we have enough message status space for all - * the message numbers from 1 to "new", since we might - * select an empty slot. If we add more space at the - * end, go ahead and add 10 additional slots. - */ - if (mp->hghmsg >= mp->hghoff) { - if (!(mp = folder_realloc (mp, 1, mp->hghmsg + 10))) - adios (NULL, "unable to allocate folder storage"); - } else if (mp->lowoff > 1) { - if (!(mp = folder_realloc (mp, 1, mp->hghoff))) - adios (NULL, "unable to allocate folder storage"); - } - - mp->msgflags |= ALLOW_NEW; /* allow the "new" sequence */ - - /* - * If we have been give a valid message name, then use that. - * Else, if we are given the "use" option, then use the - * current message. Else, use special sequence "new". - */ - if (!m_convert (mp, msg && *msg ? msg : use ? "cur" : "new")) - done (1); - seq_setprev (mp); + /* + ** Make sure we have enough message status space for all + ** the message numbers from 1 to one beyond last, since we might + ** select an empty slot. If we add more space at the + ** end, go ahead and add 10 additional slots. + */ + if (mp->hghmsg >= mp->hghoff) { + if (!(mp = folder_realloc(mp, 1, mp->hghmsg + 10))) + adios(NULL, "unable to allocate folder storage"); + } else if (mp->lowoff > 1) { + if (!(mp = folder_realloc(mp, 1, mp->hghoff))) + adios(NULL, "unable to allocate folder storage"); + } - if (mp->numsel > 1) - adios (NULL, "only one message draft at a time!"); + mp->msgflags |= ALLOW_BEYOND; /* allow the beyond sequence */ - snprintf (buffer, sizeof(buffer), "%s/%s", mp->foldpath, m_name (mp->lowsel)); - cp = buffer; + /* + ** The draft message name to return is defined by `which'. + ** Usually it is seq_cur (for the current draft) or seq_beyond + ** (to start a new draft). + */ + if (!m_convert(mp, which)) + done(1); + seq_setprev(mp); - seq_setcur (mp, mp->lowsel);/* set current message for folder */ - seq_save (mp); /* synchronize message sequences */ - folder_free (mp); /* free folder/message structure */ + snprintf(buffer, sizeof(buffer), "%s/%s", mp->foldpath, + m_name(mp->lowsel)); + seq_setcur(mp, mp->lowsel); + seq_save(mp); + folder_free(mp); - return cp; + return buffer; } diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c index be871c4..5bd6bbb 100644 --- a/sbr/m_getfld.c +++ b/sbr/m_getfld.c @@ -1,180 +1,144 @@ - /* - * m_getfld.c -- read/parse a message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_getfld.c -- read/parse a message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#include #include -/* This module has a long and checkered history. First, it didn't burst - maildrops correctly because it considered two CTRL-A:s in a row to be - an inter-message delimiter. It really is four CTRL-A:s followed by a - newline. Unfortunately, MMDF will convert this delimiter *inside* a - message to a CTRL-B followed by three CTRL-A:s and a newline. This - caused the old version of m_getfld() to declare eom prematurely. The - fix was a lot slower than - - c == '\001' && peekc (iob) == '\001' - - but it worked, and to increase generality, MBOX style maildrops could - be parsed as well. Unfortunately the speed issue finally caught up with - us since this routine is at the very heart of MH. - - To speed things up considerably, the routine Eom() was made an auxilary - function called by the macro eom(). Unless we are bursting a maildrop, - the eom() macro returns FALSE saying we aren't at the end of the - message. - - The next thing to do is to read the mts.conf file and initialize - delimiter[] and delimlen accordingly... - - After mhl was made a built-in in msh, m_getfld() worked just fine - (using m_unknown() at startup). Until one day: a message which was - the result of a bursting was shown. Then, since the burst boundaries - aren't CTRL-A:s, m_getfld() would blinding plunge on past the boundary. - Very sad. The solution: introduce m_eomsbr(). This hook gets called - after the end of each line (since testing for eom involves an fseek()). - This worked fine, until one day: a message with no body portion arrived. - Then the - - while (eom (c = Getc (iob), iob)) - continue; - - loop caused m_getfld() to return FMTERR. So, that logic was changed to - check for (*eom_action) and act accordingly. - - This worked fine, until one day: someone didn't use four CTRL:A's as - their delimiters. So, the bullet got bit and we read mts.h and - continue to struggle on. It's not that bad though, since the only time - the code gets executed is when inc (or msh) calls it, and both of these - have already called mts_init(). - - ------------------------ - (Written by Van Jacobson for the mh6 m_getfld, January, 1986): - - This routine was accounting for 60% of the cpu time used by most mh - programs. I spent a bit of time tuning and it now accounts for <10% - of the time used. Like any heavily tuned routine, it's a bit - complex and you want to be sure you understand everything that it's - doing before you start hacking on it. Let me try to emphasize - that: every line in this atrocity depends on every other line, - sometimes in subtle ways. You should understand it all, in detail, - before trying to change any part. If you do change it, test the - result thoroughly (I use a hand-constructed test file that exercises - all the ways a header name, header body, header continuation, - header-body separator, body line and body eom can align themselves - with respect to a buffer boundary). "Minor" bugs in this routine - result in garbaged or lost mail. - - If you hack on this and slow it down, I, my children and my - children's children will curse you. - - This routine gets used on three different types of files: normal, - single msg files, "packed" unix or mmdf mailboxs (when used by inc) - and packed, directoried bulletin board files (when used by msh). - The biggest impact of different file types is in "eom" testing. The - code has been carefully organized to test for eom at appropriate - times and at no other times (since the check is quite expensive). - I have tried to arrange things so that the eom check need only be - done on entry to this routine. Since an eom can only occur after a - newline, this is easy to manage for header fields. For the msg - body, we try to efficiently search the input buffer to see if - contains the eom delimiter. If it does, we take up to the - delimiter, otherwise we take everything in the buffer. (The change - to the body eom/copy processing produced the most noticeable - performance difference, particularly for "inc" and "show".) - - There are three qualitatively different things this routine busts - out of a message: field names, field text and msg bodies. Field - names are typically short (~8 char) and the loop that extracts them - might terminate on a colon, newline or max width. I considered - using a Vax "scanc" to locate the end of the field followed by a - "bcopy" but the routine call overhead on a Vax is too large for this - to work on short names. If Berkeley ever makes "inline" part of the - C optimiser (so things like "scanc" turn into inline instructions) a - change here would be worthwhile. - - Field text is typically 60 - 100 characters so there's (barely) - a win in doing a routine call to something that does a "locc" - followed by a "bmove". About 30% of the fields have continuations - (usually the 822 "received:" lines) and each continuation generates - another routine call. "Inline" would be a big win here, as well. - - Messages, as of this writing, seem to come in two flavors: small - (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers - so message bodies average at least a few hundred characters. - Assuming your system uses reasonably sized stdio buffers (1K or - more), this routine should be able to remove the body in large - (>500 byte) chunks. The makes the cost of a call to "bcopy" - small but there is a premium on checking for the eom in packed - maildrops. The eom pattern is always a simple string so we can - construct an efficient pattern matcher for it (e.g., a Vax "matchc" - instruction). Some thought went into recognizing the start of - an eom that has been split across two buffers. - - This routine wants to deal with large chunks of data so, rather - than "getc" into a local buffer, it uses stdio's buffer. If - you try to use it on a non-buffered file, you'll get what you - deserve. This routine "knows" that struct FILEs have a _ptr - and a _cnt to describe the current state of the buffer and - it knows that _filbuf ignores the _ptr & _cnt and simply fills - the buffer. If stdio on your system doesn't work this way, you - may have to make small changes in this routine. - - This routine also "knows" that an EOF indication on a stream is - "sticky" (i.e., you will keep getting EOF until you reposition the - stream). If your system doesn't work this way it is broken and you - should complain to the vendor. As a consequence of the sticky - EOF, this routine will never return any kind of EOF status when - there is data in "name" or "buf"). - */ +/* +** This module has a long and checkered history. +** +** [ Here had been some history of delimiter problems in MMDF maildrops ... ] +** +** Unfortunately the speed issue finally caught up with us since this +** routine is at the very heart of MH. To speed things up considerably, the +** routine Eom() was made an auxilary function called by the macro eom(). +** Unless we are bursting a maildrop, the eom() macro returns FALSE saying +** we aren't at the end of the message. +** +** [ ... and here had been some more of it. ] +** +** +** ------------------------ +** (Written by Van Jacobson for the mh6 m_getfld, January, 1986): +** +** This routine was accounting for 60% of the cpu time used by most mh +** programs. I spent a bit of time tuning and it now accounts for <10% +** of the time used. Like any heavily tuned routine, it's a bit +** complex and you want to be sure you understand everything that it's +** doing before you start hacking on it. Let me try to emphasize +** that: every line in this atrocity depends on every other line, +** sometimes in subtle ways. You should understand it all, in detail, +** before trying to change any part. If you do change it, test the +** result thoroughly (I use a hand-constructed test file that exercises +** all the ways a header name, header body, header continuation, +** header-body separator, body line and body eom can align themselves +** with respect to a buffer boundary). "Minor" bugs in this routine +** result in garbaged or lost mail. +** +** If you hack on this and slow it down, I, my children and my +** children's children will curse you. +** +** This routine gets used on two different types of files: normal, +** single msg files and "packed" unix mailboxs (when used by inc). +** The biggest impact of different file types is in "eom" testing. The +** code has been carefully organized to test for eom at appropriate +** times and at no other times (since the check is quite expensive). +** I have tried to arrange things so that the eom check need only be +** done on entry to this routine. Since an eom can only occur after a +** newline, this is easy to manage for header fields. For the msg +** body, we try to efficiently search the input buffer to see if +** contains the eom delimiter. If it does, we take up to the +** delimiter, otherwise we take everything in the buffer. (The change +** to the body eom/copy processing produced the most noticeable +** performance difference, particularly for "inc" and "show".) +** +** There are three qualitatively different things this routine busts +** out of a message: field names, field text and msg bodies. Field +** names are typically short (~8 char) and the loop that extracts them +** might terminate on a colon, newline or max width. I considered +** using a Vax "scanc" to locate the end of the field followed by a +** "bcopy" but the routine call overhead on a Vax is too large for this +** to work on short names. If Berkeley ever makes "inline" part of the +** C optimiser (so things like "scanc" turn into inline instructions) a +** change here would be worthwhile. +** +** Field text is typically 60 - 100 characters so there's (barely) +** a win in doing a routine call to something that does a "locc" +** followed by a "bmove". About 30% of the fields have continuations +** (usually the 822 "received:" lines) and each continuation generates +** another routine call. "Inline" would be a big win here, as well. +** +** Messages, as of this writing, seem to come in two flavors: small +** (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers +** so message bodies average at least a few hundred characters. +** Assuming your system uses reasonably sized stdio buffers (1K or +** more), this routine should be able to remove the body in large +** (>500 byte) chunks. The makes the cost of a call to "bcopy" +** small but there is a premium on checking for the eom in packed +** maildrops. The eom pattern is always a simple string so we can +** construct an efficient pattern matcher for it (e.g., a Vax "matchc" +** instruction). Some thought went into recognizing the start of +** an eom that has been split across two buffers. +** +** This routine wants to deal with large chunks of data so, rather +** than "getc" into a local buffer, it uses stdio's buffer. If +** you try to use it on a non-buffered file, you'll get what you +** deserve. This routine "knows" that struct FILEs have a _ptr +** and a _cnt to describe the current state of the buffer and +** it knows that _filbuf ignores the _ptr & _cnt and simply fills +** the buffer. If stdio on your system doesn't work this way, you +** may have to make small changes in this routine. +** +** This routine also "knows" that an EOF indication on a stream is +** "sticky" (i.e., you will keep getting EOF until you reposition the +** stream). If your system doesn't work this way it is broken and you +** should complain to the vendor. As a consequence of the sticky +** EOF, this routine will never return any kind of EOF status when +** there is data in "name" or "buf"). +*/ /* - * static prototypes - */ -static int m_Eom (int, FILE *); +** static prototypes +*/ +static int m_Eom(int, FILE *); static unsigned char *matchc(int, char *, int, char *); static unsigned char *locc(int, unsigned char *, unsigned char); -#define Getc(iob) getc(iob) -#define eom(c,iob) (msg_style != MS_DEFAULT && \ - (((c) == *msg_delim && m_Eom(c,iob)) ||\ - (eom_action && (*eom_action)(c)))) +#define eom(c,iob) (ismbox && \ + (((c) == *msg_delim && m_Eom(c,iob)) ||\ + (eom_action && (*eom_action)(c)))) static unsigned char **pat_map; /* - * defined in sbr/m_msgdef.c = 0 - * This is a disgusting hack for "inc" so it can know how many - * characters were stuffed in the buffer on the last call - * (see comments in uip/scansbr.c). - */ -extern int msg_count; +** This is a disgusting hack for "inc" so it can know how many +** characters were stuffed in the buffer on the last call +** (see comments in uip/scansbr.c). +*/ +int msg_count = 0; -/* - * defined in sbr/m_msgdef.c = MS_DEFAULT - */ -extern int msg_style; +int ismbox = FALSE; /* - * The "full" delimiter string for a packed maildrop consists - * of a newline followed by the actual delimiter. E.g., the - * full string for a Unix maildrop would be: "\n\nFrom ". - * "Fdelim" points to the start of the full string and is used - * in the BODY case of the main routine to search the buffer for - * a possible eom. Msg_delim points to the first character of - * the actual delim. string (i.e., fdelim+1). Edelim - * points to the 2nd character of actual delimiter string. It - * is used in m_Eom because the first character of the string - * has been read and matched before m_Eom is called. - */ -extern char *msg_delim; /* defined in sbr/m_msgdef.c = "" */ +** The "full" delimiter string for a packed maildrop consists +** of a newline followed by the actual delimiter. E.g., the +** full string for a Unix maildrop would be: "\n\nFrom ". +** "Fdelim" points to the start of the full string and is used +** in the BODY case of the main routine to search the buffer for +** a possible eom. Msg_delim points to the first character of +** the actual delim. string (i.e., fdelim+1). Edelim +** points to the 2nd character of actual delimiter string. It +** is used in m_Eom because the first character of the string +** has been read and matched before m_Eom is called. +*/ +char *msg_delim = ""; + static unsigned char *fdelim; static unsigned char *delimend; static int fdelimlen; @@ -184,17 +148,9 @@ static int edelimlen; static int (*eom_action)(int) = NULL; #ifdef _FSTDIO -# define _ptr _p /* Gag */ -# define _cnt _r /* Retch */ -# define _filbuf __srget /* Puke */ -# define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC -#endif - -#ifdef SCO_5_STDIO -# define _ptr __ptr -# define _cnt __cnt -# define _base __base -# define _filbuf(fp) ((fp)->__cnt = 0, __filbuf(fp)) +# define _ptr _p /* Gag */ +# define _cnt _r /* Retch */ +# define _filbuf __srget /* Puke */ # define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC #endif @@ -204,592 +160,513 @@ extern int _filbuf(FILE*); int -m_getfld (int state, unsigned char *name, unsigned char *buf, - int bufsz, FILE *iob) +m_getfld(int state, unsigned char *name, unsigned char *buf, + int bufsz, FILE *iob) { - register unsigned char *bp, *cp, *ep, *sp; - register int cnt, c, i, j; - - if ((c = Getc(iob)) < 0) { - msg_count = 0; - *buf = 0; - return FILEEOF; - } - if (eom (c, iob)) { - if (! eom_action) { - /* flush null messages */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) - ; - if (c >= 0) - ungetc(c, iob); + register unsigned char *bp, *cp, *ep, *sp; + register int cnt, c, i, j; + + if ((c = getc(iob)) < 0) { + msg_count = 0; + *buf = 0; + return FILEEOF; } - msg_count = 0; - *buf = 0; - return FILEEOF; - } - - switch (state) { - case FLDEOF: - case BODYEOF: - case FLD: - if (c == '\n' || c == '-') { - /* we hit the header/body separator */ - while (c != '\n' && (c = Getc(iob)) >= 0) - ; - - if (c < 0 || (c = Getc(iob)) < 0 || eom (c, iob)) { - if (! eom_action) { + if (eom(c, iob)) { + if (! eom_action) { /* flush null messages */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) - ; + while ((c = getc(iob)) >= 0 && eom(c, iob)) + ; if (c >= 0) - ungetc(c, iob); - } - msg_count = 0; - *buf = 0; - return FILEEOF; + ungetc(c, iob); + } + msg_count = 0; + *buf = 0; + return FILEEOF; + } + + switch (state) { + case FLDEOF: + case BODYEOF: + case FLD: + if (c == '\n' || c == '-') { + /* we hit the header/body separator */ + while (c != '\n' && (c = getc(iob)) >= 0) + ; + + if (c < 0 || (c = getc(iob)) < 0 || eom(c, iob)) { + if (!eom_action) { + /* flush null messages */ + while ((c = getc(iob)) >= 0 && eom(c, iob)) + ; + if (c >= 0) + ungetc(c, iob); + } + msg_count = 0; + *buf = 0; + return FILEEOF; + } + state = BODY; + goto body; } - state = BODY; - goto body; - } - /* - * get the name of this component. take characters up - * to a ':', a newline or NAMESZ-1 characters, whichever - * comes first. - */ - cp = name; - i = NAMESZ - 1; - for (;;) { + /* + ** get the name of this component. take characters up + ** to a ':', a newline or NAMESZ-1 characters, + ** whichever comes first. + */ + cp = name; + i = NAMESZ - 1; + for (;;) { #ifdef LINUX_STDIO - bp = sp = (unsigned char *) iob->_IO_read_ptr - 1; - j = (cnt = ((long) iob->_IO_read_end - - (long) iob->_IO_read_ptr) + 1) < i ? cnt : i; + bp = sp = (unsigned char *) iob->_IO_read_ptr - 1; + j = (cnt = ((long) iob->_IO_read_end - + (long) iob->_IO_read_ptr) + 1) < i ? cnt : i; #elif defined(__DragonFly__) - bp = sp = (unsigned char *) ((struct __FILE_public *)iob)->_p - 1; - j = (cnt = ((struct __FILE_public *)iob)->_r+1) < i ? cnt : i; + bp = sp = (unsigned char *) ((struct __FILE_public *)iob)->_p - 1; + j = (cnt = ((struct __FILE_public *)iob)->_r+1) < i ? cnt : i; #else - bp = sp = (unsigned char *) iob->_ptr - 1; - j = (cnt = iob->_cnt+1) < i ? cnt : i; + bp = sp = (unsigned char *) iob->_ptr - 1; + j = (cnt = iob->_cnt+1) < i ? cnt : i; #endif - while (--j >= 0 && (c = *bp++) != ':' && c != '\n') - *cp++ = c; + while (--j >= 0 && (c = *bp++) != ':' && c != '\n') + *cp++ = c; - j = bp - sp; - if ((cnt -= j) <= 0) { + j = bp - sp; + if ((cnt -= j) <= 0) { #ifdef LINUX_STDIO - iob->_IO_read_ptr = iob->_IO_read_end; - if (__underflow(iob) == EOF) { + iob->_IO_read_ptr = iob->_IO_read_end; + if (__underflow(iob) == EOF) { #elif defined(__DragonFly__) - if (__srget(iob) == EOF) { + if (__srget(iob) == EOF) { #else - if (_filbuf(iob) == EOF) { + if (_filbuf(iob) == EOF) { #endif - *cp = *buf = 0; - advise (NULL, "eof encountered in field \"%s\"", name); - return FMTERR; - } + *cp = *buf = 0; + advise(NULL, "eof encountered in field \"%s\"", name); + return FMTERR; + } #ifdef LINUX_STDIO - iob->_IO_read_ptr++; /* NOT automatic in __underflow()! */ + iob->_IO_read_ptr++; /* NOT automatic in __underflow()! */ #endif - } else { + } else { #ifdef LINUX_STDIO - iob->_IO_read_ptr = bp + 1; + iob->_IO_read_ptr = bp + 1; #elif defined(__DragonFly__) - ((struct __FILE_public *)iob)->_p = bp + 1; - ((struct __FILE_public *)iob)->_r = cnt - 1; + ((struct __FILE_public *)iob)->_p = bp + 1; + ((struct __FILE_public *)iob)->_r = cnt - 1; #else - iob->_ptr = bp + 1; - iob->_cnt = cnt - 1; + iob->_ptr = bp + 1; + iob->_cnt = cnt - 1; #endif + } + if (c == ':') + break; + + /* + ** something went wrong. possibilities are: + ** . hit a newline (error) + ** . got more than namesz chars. (error) + ** . hit the end of the buffer. (loop) + */ + if (c == '\n') { + /* + ** We hit the end of the line without + ** seeing ':' to terminate the field name. + ** This is usually (always?) spam. But, + ** blowing up is lame, especially when + ** scan(1)ing a folder with such messages. + ** Pretend such lines are the first of + ** the body (at least mutt also handles + ** it this way). + */ + + /* + ** See if buf can hold this line, since we + ** were assuming we had a buffer of NAMESZ, + ** not bufsz. + */ + /* + 1 for the newline */ + if (bufsz < j + 1) { + /* + ** No, it can't. Oh well, + ** guess we'll blow up. + */ + *cp = *buf = 0; + advise(NULL, "eol encountered in field \"%s\"", name); + state = FMTERR; + goto finish; + } + memcpy(buf, name, j - 1); + buf[j - 1] = '\n'; + buf[j] = '\0'; + /* + ** mhparse.c:get_content wants to find + ** the position of the body start, but + ** it thinks there's a blank line between + ** the header and the body (naturally!), + ** so seek back so that things line up + ** even though we don't have that blank + ** line in this case. Simpler parsers + ** (e.g. mhl) get extra newlines, but + ** that should be harmless enough, right? + ** This is a corrupt message anyway. + */ + fseek(iob, ftell(iob) - 2, SEEK_SET); + return BODY; + } + if ((i -= j) <= 0) { + *cp = *buf = 0; + advise(NULL, "field name \"%s\" exceeds %d bytes", name, NAMESZ - 2); + state = LENERR; + goto finish; + } } - if (c == ':') - break; - /* - * something went wrong. possibilities are: - * . hit a newline (error) - * . got more than namesz chars. (error) - * . hit the end of the buffer. (loop) - */ - if (c == '\n') { - /* We hit the end of the line without seeing ':' to - * terminate the field name. This is usually (always?) - * spam. But, blowing up is lame, especially when - * scan(1)ing a folder with such messages. Pretend such - * lines are the first of the body (at least mutt also - * handles it this way). */ - - /* See if buf can hold this line, since we were assuming - * we had a buffer of NAMESZ, not bufsz. */ - /* + 1 for the newline */ - if (bufsz < j + 1) { - /* No, it can't. Oh well, guess we'll blow up. */ - *cp = *buf = 0; - advise (NULL, "eol encountered in field \"%s\"", name); - state = FMTERR; - goto finish; - } - memcpy (buf, name, j - 1); - buf[j - 1] = '\n'; - buf[j] = '\0'; - /* mhparse.c:get_content wants to find the position of the - * body start, but it thinks there's a blank line between - * the header and the body (naturally!), so seek back so - * that things line up even though we don't have that - * blank line in this case. Simpler parsers (e.g. mhl) - * get extra newlines, but that should be harmless enough, - * right? This is a corrupt message anyway. */ - fseek (iob, ftell (iob) - 2, SEEK_SET); - return BODY; - } - if ((i -= j) <= 0) { - *cp = *buf = 0; - advise (NULL, "field name \"%s\" exceeds %d bytes", name, NAMESZ - 2); - state = LENERR; - goto finish; - } - } + while (isspace(*--cp) && cp >= name) + ; + *++cp = 0; + /* fall through */ - while (isspace (*--cp) && cp >= name) - ; - *++cp = 0; - /* fall through */ - - case FLDPLUS: - /* - * get (more of) the text of a field. take - * characters up to the end of this field (newline - * followed by non-blank) or bufsz-1 characters. - */ - cp = buf; i = bufsz-1; - for (;;) { + case FLDPLUS: + /* + ** get (more of) the text of a field. take + ** characters up to the end of this field (newline + ** followed by non-blank) or bufsz-1 characters. + */ + cp = buf; i = bufsz-1; + for (;;) { #ifdef LINUX_STDIO - cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; - bp = (unsigned char *) --iob->_IO_read_ptr; + cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; + bp = (unsigned char *) --iob->_IO_read_ptr; #elif defined(__DragonFly__) - cnt = ((struct __FILE_public *)iob)->_r++; - bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; + cnt = ((struct __FILE_public *)iob)->_r++; + bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; #else - cnt = iob->_cnt++; - bp = (unsigned char *) --iob->_ptr; + cnt = iob->_cnt++; + bp = (unsigned char *) --iob->_ptr; #endif - c = cnt < i ? cnt : i; - while ((ep = locc( c, bp, '\n' ))) { - /* - * if we hit the end of this field, return. - */ - if ((j = *++ep) != ' ' && j != '\t') { + c = cnt < i ? cnt : i; + while ((ep = locc( c, bp, '\n' ))) { + /* + ** if we hit the end of this field, + ** return. + */ + if ((j = *++ep) != ' ' && j != '\t') { #ifdef LINUX_STDIO - j = ep - (unsigned char *) iob->_IO_read_ptr; - memcpy (cp, iob->_IO_read_ptr, j); - iob->_IO_read_ptr = ep; + j = ep - (unsigned char *) iob->_IO_read_ptr; + memcpy(cp, iob->_IO_read_ptr, j); + iob->_IO_read_ptr = ep; #elif defined(__DragonFly__) - j = ep - (unsigned char *) ((struct __FILE_public *)iob)->_p; - memcpy (cp, ((struct __FILE_public *)iob)->_p, j); - ((struct __FILE_public *)iob)->_p = ep; - ((struct __FILE_public *)iob)->_r -= j; + j = ep - (unsigned char *) ((struct __FILE_public *)iob)->_p; + memcpy(cp, ((struct __FILE_public *)iob)->_p, j); + ((struct __FILE_public *)iob)->_p = ep; + ((struct __FILE_public *)iob)->_r -= j; #else - j = ep - (unsigned char *) iob->_ptr; - memcpy (cp, iob->_ptr, j); - iob->_ptr = ep; - iob->_cnt -= j; + j = ep - (unsigned char *) iob->_ptr; + memcpy(cp, iob->_ptr, j); + iob->_ptr = ep; + iob->_cnt -= j; #endif - cp += j; - state = FLD; - goto finish; - } - c -= ep - bp; - bp = ep; - } - /* - * end of input or dest buffer - copy what we've found. - */ + cp += j; + state = FLD; + goto finish; + } + c -= ep - bp; + bp = ep; + } + /* + ** end of input or dest buffer - copy what + ** we've found. + */ #ifdef LINUX_STDIO - c += bp - (unsigned char *) iob->_IO_read_ptr; - memcpy( cp, iob->_IO_read_ptr, c); + c += bp - (unsigned char *) iob->_IO_read_ptr; + memcpy(cp, iob->_IO_read_ptr, c); #elif defined(__DragonFly__) - c += bp - (unsigned char *) ((struct __FILE_public *)iob)->_p; - memcpy( cp, ((struct __FILE_public *)iob)->_p, c); + c += bp - (unsigned char *) ((struct __FILE_public *)iob)->_p; + memcpy(cp, ((struct __FILE_public *)iob)->_p, c); #else - c += bp - (unsigned char *) iob->_ptr; - memcpy( cp, iob->_ptr, c); + c += bp - (unsigned char *) iob->_ptr; + memcpy(cp, iob->_ptr, c); #endif - i -= c; - cp += c; - if (i <= 0) { - /* the dest buffer is full */ + i -= c; + cp += c; + if (i <= 0) { + /* the dest buffer is full */ #ifdef LINUX_STDIO - iob->_IO_read_ptr += c; + iob->_IO_read_ptr += c; #elif defined(__DragonFly__) - ((struct __FILE_public *)iob)->_r -= c; - ((struct __FILE_public *)iob)->_p += c; + ((struct __FILE_public *)iob)->_r -= c; + ((struct __FILE_public *)iob)->_p += c; #else - iob->_cnt -= c; - iob->_ptr += c; + iob->_cnt -= c; + iob->_ptr += c; #endif - state = FLDPLUS; - break; - } - /* - * There's one character left in the input buffer. - * Copy it & fill the buffer. If the last char - * was a newline and the next char is not whitespace, - * this is the end of the field. Otherwise loop. - */ - --i; + state = FLDPLUS; + break; + } + /* + ** There's one character left in the input + ** buffer. Copy it & fill the buffer. + ** If the last char was a newline and the + ** next char is not whitespace, this is + ** the end of the field. Otherwise loop. + */ + --i; #ifdef LINUX_STDIO - *cp++ = j = *(iob->_IO_read_ptr + c); - iob->_IO_read_ptr = iob->_IO_read_end; - c = __underflow(iob); - iob->_IO_read_ptr++; /* NOT automatic! */ + *cp++ = j = *(iob->_IO_read_ptr + c); + iob->_IO_read_ptr = iob->_IO_read_end; + c = __underflow(iob); + iob->_IO_read_ptr++; /* NOT automatic! */ #elif defined(__DragonFly__) - *cp++ =j = *(((struct __FILE_public *)iob)->_p + c); - c = __srget(iob); + *cp++ =j = *(((struct __FILE_public *)iob)->_p + c); + c = __srget(iob); #else - *cp++ = j = *(iob->_ptr + c); - c = _filbuf(iob); + *cp++ = j = *(iob->_ptr + c); + c = _filbuf(iob); #endif - if (c == EOF || - ((j == '\0' || j == '\n') && c != ' ' && c != '\t')) { - if (c != EOF) { + if (c == EOF || + ((j == '\0' || j == '\n') && c != ' ' && c != '\t')) { + if (c != EOF) { #ifdef LINUX_STDIO - --iob->_IO_read_ptr; + --iob->_IO_read_ptr; #elif defined(__DragonFly__) - --((struct __FILE_public *)iob)->_p; - ++((struct __FILE_public *)iob)->_r; + --((struct __FILE_public *)iob)->_p; + ++((struct __FILE_public *)iob)->_r; #else - --iob->_ptr; - ++iob->_cnt; + --iob->_ptr; + ++iob->_cnt; #endif - } - state = FLD; - break; + } + state = FLD; + break; + } } - } - break; + break; - case BODY: + case BODY: body: - /* - * get the message body up to bufsz characters or the - * end of the message. Sleazy hack: if bufsz is negative - * we assume that we were called to copy directly into - * the output buffer and we don't add an eos. - */ - i = (bufsz < 0) ? -bufsz : bufsz-1; + /* + ** get the message body up to bufsz characters or + ** the end of the message. Sleazy hack: if bufsz + ** is negative we assume that we were called to + ** copy directly into the output buffer and we + ** don't add an eos. + */ + i = (bufsz < 0) ? -bufsz : bufsz-1; #ifdef LINUX_STDIO - bp = (unsigned char *) --iob->_IO_read_ptr; - cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; + bp = (unsigned char *) --iob->_IO_read_ptr; + cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr; #elif defined(__DragonFly__) - bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; - cnt = ++((struct __FILE_public *)iob)->_r; + bp = (unsigned char *) --((struct __FILE_public *)iob)->_p; + cnt = ++((struct __FILE_public *)iob)->_r; #else - bp = (unsigned char *) --iob->_ptr; - cnt = ++iob->_cnt; + bp = (unsigned char *) --iob->_ptr; + cnt = ++iob->_cnt; #endif - c = (cnt < i ? cnt : i); - if (msg_style != MS_DEFAULT && c > 1) { - /* - * packed maildrop - only take up to the (possible) - * start of the next message. This "matchc" should - * probably be a Boyer-Moore matcher for non-vaxen, - * particularly since we have the alignment table - * all built for the end-of-buffer test (next). - * But our vax timings indicate that the "matchc" - * instruction is 50% faster than a carefully coded - * B.M. matcher for most strings. (So much for elegant - * algorithms vs. brute force.) Since I (currently) - * run MH on a vax, we use the matchc instruction. --vj - */ - if ((ep = matchc( fdelimlen, fdelim, c, bp ))) - c = ep - bp + 1; - else { - /* - * There's no delim in the buffer but there may be - * a partial one at the end. If so, we want to leave - * it so the "eom" check on the next call picks it up. - * Use a modified Boyer-Moore matcher to make this - * check relatively cheap. The first "if" figures - * out what position in the pattern matches the last - * character in the buffer. The inner "while" matches - * the pattern against the buffer, backwards starting - * at that position. Note that unless the buffer - * ends with one of the characters in the pattern - * (excluding the first and last), we do only one test. - */ - ep = bp + c - 1; - if ((sp = pat_map[*ep])) { - do { - /* This if() is true unless (a) the buffer is too - * small to contain this delimiter prefix, or - * (b) it contains exactly enough chars for the - * delimiter prefix. - * For case (a) obviously we aren't going to match. - * For case (b), if the buffer really contained exactly - * a delim prefix, then the m_eom call at entry - * should have found it. Thus it's not a delim - * and we know we won't get a match. - */ - if (((sp - fdelim) + 2) <= c) { - cp = sp; - /* Unfortunately although fdelim has a preceding NUL - * we can't use this as a sentinel in case the buffer - * contains a NUL in exactly the wrong place (this - * would cause us to run off the front of fdelim). - */ - while (*--ep == *--cp) - if (cp < fdelim) - break; - if (cp < fdelim) { - /* we matched the entire delim prefix, - * so only take the buffer up to there. - * we know ep >= bp -- check above prevents underrun - */ - c = (ep - bp) + 2; - break; + c = (cnt < i ? cnt : i); + if (ismbox && c > 1) { + /* + ** packed maildrop - only take up to the (possible) + ** start of the next message. This "matchc" should + ** probably be a Boyer-Moore matcher for non-vaxen, + ** particularly since we have the alignment table + ** all built for the end-of-buffer test (next). + ** But our vax timings indicate that the "matchc" + ** instruction is 50% faster than a carefully coded + ** B.M. matcher for most strings. (So much for + ** elegant algorithms vs. brute force.) Since I + ** (currently) run MH on a vax, we use the matchc + ** instruction. --vj + */ + if ((ep = matchc( fdelimlen, fdelim, c, bp ))) + c = ep - bp + 1; + else { + /* + ** There's no delim in the buffer but + ** there may be a partial one at the end. + ** If so, we want to leave it so the "eom" + ** check on the next call picks it up. Use a + ** modified Boyer-Moore matcher to make this + ** check relatively cheap. The first "if" + ** figures out what position in the pattern + ** matches the last character in the buffer. + ** The inner "while" matches the pattern + ** against the buffer, backwards starting + ** at that position. Note that unless the + ** buffer ends with one of the characters + ** in the pattern (excluding the first + ** and last), we do only one test. + */ + ep = bp + c - 1; + if ((sp = pat_map[*ep])) { + do { + /* + ** This if() is true unless + ** (a) the buffer is too + ** small to contain this + ** delimiter prefix, + ** or (b) it contains + ** exactly enough chars for + ** the delimiter prefix. + ** For case (a) obviously we + ** aren't going to match. + ** For case (b), if the + ** buffer really contained + ** exactly a delim prefix, + ** then the m_eom call + ** at entry should have + ** found it. Thus it's + ** not a delim and we know + ** we won't get a match. + */ + if (((sp - fdelim) + 2) <= c) { + cp = sp; + /* + ** Unfortunately although fdelim has a preceding NUL + ** we can't use this as a sentinel in case the buffer + ** contains a NUL in exactly the wrong place (this + ** would cause us to run off the front of fdelim). + */ + while (*--ep == *--cp) + if (cp < fdelim) + break; + if (cp < fdelim) { + /* we matched the entire delim prefix, + ** so only take the buffer up to there. + ** we know ep >= bp -- check above prevents underrun + */ + c = (ep - bp) + 2; + break; + } + } + /* try matching one less char of delim string */ + ep = bp + c - 1; + } while (--sp > fdelim); } - } - /* try matching one less char of delim string */ - ep = bp + c - 1; - } while (--sp > fdelim); - } + } } - } - memcpy( buf, bp, c ); + memcpy( buf, bp, c ); #ifdef LINUX_STDIO - iob->_IO_read_ptr += c; + iob->_IO_read_ptr += c; #elif defined(__DragonFly__) - ((struct __FILE_public *)iob)->_r -= c; - ((struct __FILE_public *)iob)->_p += c; + ((struct __FILE_public *)iob)->_r -= c; + ((struct __FILE_public *)iob)->_p += c; #else - iob->_cnt -= c; - iob->_ptr += c; + iob->_cnt -= c; + iob->_ptr += c; #endif - if (bufsz < 0) { - msg_count = c; - return (state); - } - cp = buf + c; - break; - - default: - adios (NULL, "m_getfld() called with bogus state of %d", state); - } -finish: - *cp = 0; - msg_count = cp - buf; - return (state); -} - - -#ifdef RPATHS -static char unixbuf[BUFSIZ] = ""; -#endif /* RPATHS */ - -void -m_unknown(FILE *iob) -{ - register int c; - register long pos; - char text[10]; - register char *cp; - register char *delimstr; + if (bufsz < 0) { + msg_count = c; + return (state); + } + cp = buf + c; + break; -/* - * Figure out what the message delimitter string is for this - * maildrop. (This used to be part of m_Eom but I didn't like - * the idea of an "if" statement that could only succeed on the - * first call to m_Eom getting executed on each call, i.e., at - * every newline in the message). - * - * If the first line of the maildrop is a Unix "From " line, we - * say the style is MBOX and eat the rest of the line. Otherwise - * we say the style is MMDF and look for the delimiter string - * specified when nmh was built (or from the mts.conf file). - */ - - msg_style = MS_UNKNOWN; - - pos = ftell (iob); - if (fread (text, sizeof(*text), 5, iob) == 5 - && strncmp (text, "From ", 5) == 0) { - msg_style = MS_MBOX; - delimstr = "\nFrom "; -#ifndef RPATHS - while ((c = getc (iob)) != '\n' && c >= 0) - ; -#else /* RPATHS */ - cp = unixbuf; - while ((c = getc (iob)) != '\n' && cp - unixbuf < BUFSIZ - 1) - *cp++ = c; + default: + adios(NULL, "m_getfld() called with bogus state of %d", state); + } +finish: *cp = 0; -#endif /* RPATHS */ - } else { - /* not a Unix style maildrop */ - fseek (iob, pos, SEEK_SET); - if (mmdlm2 == NULL || *mmdlm2 == 0) - mmdlm2 = "\001\001\001\001\n"; - delimstr = mmdlm2; - msg_style = MS_MMDF; - } - c = strlen (delimstr); - fdelim = (unsigned char *) mh_xmalloc((size_t) (c + 3)); - *fdelim++ = '\0'; - *fdelim = '\n'; - msg_delim = (char *)fdelim+1; - edelim = (unsigned char *)msg_delim+1; - fdelimlen = c + 1; - edelimlen = c - 1; - strcpy (msg_delim, delimstr); - delimend = (unsigned char *)msg_delim + edelimlen; - if (edelimlen <= 1) - adios (NULL, "maildrop delimiter must be at least 2 bytes"); - /* - * build a Boyer-Moore end-position map for the matcher in m_getfld. - * N.B. - we don't match just the first char (since it's the newline - * separator) or the last char (since the matchc would have found it - * if it was a real delim). - */ - pat_map = (unsigned char **) calloc (256, sizeof(unsigned char *)); - - for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ ) - pat_map[(unsigned char)*cp] = (unsigned char *) cp; - - if (msg_style == MS_MMDF) { - /* flush extra msg hdrs */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) - ; - if (c >= 0) - ungetc(c, iob); - } + msg_count = cp - buf; + return (state); } void -m_eomsbr (int (*action)(int)) +thisisanmbox(FILE *iob) { - if ((eom_action = action)) { - msg_style = MS_MSH; - *msg_delim = 0; - fdelimlen = 1; - delimend = fdelim; - } else { - msg_style = MS_MMDF; - msg_delim = (char *)fdelim + 1; - fdelimlen = strlen((char *)fdelim); - delimend = (unsigned char *)(msg_delim + edelimlen); - } + register int c; + char text[10]; + register char *cp; + register char *delimstr; + + c = getc(iob); + if (feof(iob)) { + return; + } + ungetc(c, iob); + + /* + ** Figure out what the message delimitter string is for this + ** maildrop. (This used to be part of m_Eom but I didn't like + ** the idea of an "if" statement that could only succeed on the + ** first call to m_Eom getting executed on each call, i.e., at + ** every newline in the message). + ** + ** If the first line of the maildrop is a Unix "From " line, we + ** say the style is MBOX and eat the rest of the line. Otherwise + ** abort. + */ + + if (fread(text, sizeof(*text), 5, iob) != 5) { + adios(NULL, "Read error"); + } + if (strncmp(text, "From ", 5)!=0) { + adios(NULL, "No Unix style (mbox) maildrop."); + } + ismbox = TRUE; + delimstr = "\nFrom "; + while ((c = getc(iob)) != '\n' && c >= 0) { + continue; + } + c = strlen(delimstr); + fdelim = (unsigned char *) mh_xmalloc((size_t) (c + 3)); + *fdelim++ = '\0'; + *fdelim = '\n'; + msg_delim = (char *)fdelim+1; + edelim = (unsigned char *)msg_delim+1; + fdelimlen = c + 1; + edelimlen = c - 1; + strcpy(msg_delim, delimstr); + delimend = (unsigned char *)msg_delim + edelimlen; + if (edelimlen <= 1) + adios(NULL, "maildrop delimiter must be at least 2 bytes"); + /* + ** build a Boyer-Moore end-position map for the matcher in m_getfld. + ** N.B. - we don't match just the first char (since it's the newline + ** separator) or the last char (since the matchc would have found it + ** if it was a real delim). + */ + pat_map = (unsigned char **) calloc(256, sizeof(unsigned char *)); + + for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ ) + pat_map[(unsigned char)*cp] = (unsigned char *) cp; } /* - * test for msg delimiter string - */ +** test for msg delimiter string +*/ static int -m_Eom (int c, FILE *iob) +m_Eom(int c, FILE *iob) { - register long pos = 0L; - register int i; - char text[10]; -#ifdef RPATHS - register char *cp; -#endif /* RPATHS */ - - pos = ftell (iob); - if ((i = fread (text, sizeof *text, edelimlen, iob)) != edelimlen - || strncmp (text, (char *)edelim, edelimlen)) { - if (i == 0 && msg_style == MS_MBOX) - /* the final newline in the (brain damaged) unix-format - * maildrop is part of the delimitter - delete it. - */ - return 1; - -#if 0 - fseek (iob, pos, SEEK_SET); -#endif - - fseek (iob, (long)(pos-1), SEEK_SET); - getc (iob); /* should be OK */ - return 0; - } - - if (msg_style == MS_MBOX) { -#ifndef RPATHS - while ((c = getc (iob)) != '\n') - if (c < 0) - break; -#else /* RPATHS */ - cp = unixbuf; - while ((c = getc (iob)) != '\n' && c >= 0 && cp - unixbuf < BUFSIZ - 1) - *cp++ = c; - *cp = 0; -#endif /* RPATHS */ - } - - return 1; -} - - -#ifdef RPATHS -/* - * Return the Return-Path and Delivery-Date - * header information. - * - * Currently, I'm assuming that the "From " line - * takes one of the following forms. - * - * From sender date remote from host (for UUCP delivery) - * From sender@host date (for sendmail delivery) - */ + register long pos = 0L; + register int i; + char text[10]; + + pos = ftell(iob); + if ((i = fread(text, sizeof *text, edelimlen, iob)) != edelimlen || + (strncmp(text, (char *)edelim, edelimlen)!=0)) { + if (i == 0 && ismbox) + /* + ** the final newline in the (brain damaged) unix-format + ** maildrop is part of the delimitter - delete it. + */ + return 1; + + fseek(iob, (long)(pos-1), SEEK_SET); + getc(iob); /* should be OK */ + return 0; + } -int -get_returnpath (char *rp, int rplen, char *dd, int ddlen) -{ - char *ap, *bp, *cp, *dp; - - ap = unixbuf; - if (!(bp = cp = strchr(ap, ' '))) - return 0; - - /* - * Check for "remote from" in envelope to see - * if this message uses UUCP style addressing - */ - while ((cp = strchr(++cp, 'r'))) { - if (strncmp (cp, "remote from", 11) == 0) { - cp = strrchr (cp, ' '); - break; + if (ismbox) { + while ((c = getc(iob)) != '\n' && c >= 0) { + continue; + } } - } - - /* - * Get the Return-Path information from - * the "From " envelope. - */ - if (cp) { - /* return path for UUCP style addressing */ - dp = strchr (++cp, '\n'); - snprintf (rp, rplen, "%.*s!%.*s\n", (int)(dp - cp), cp, (int)(bp - ap), ap); - } else { - /* return path for standard domain addressing */ - snprintf (rp, rplen, "%.*s\n", (int)(bp - ap), ap); - } - - /* - * advance over the spaces to get to - * delivery date on envelope - */ - while (*bp == ' ') - bp++; - - /* Now get delivery date from envelope */ - snprintf (dd, ddlen, "%.*s\n", 24, bp); - - unixbuf[0] = 0; - return 1; + + return 1; } -#endif /* RPATHS */ static unsigned char * @@ -810,22 +687,22 @@ matchc(int patln, char *pat, int strln, char *str) sp = str; pp = pat; while (pp < ep && *sp++ == *pp) pp++; - if (pp >= ep) + if (pp >= ep) return ((unsigned char *)--str); } } /* - * Locate character "term" in the next "cnt" characters of "src". - * If found, return its address, otherwise return 0. - */ +** Locate character "term" in the next "cnt" characters of "src". +** If found, return its address, otherwise return 0. +*/ static unsigned char * locc(int cnt, unsigned char *src, unsigned char term) { - while (*src++ != term && --cnt > 0); + while (*src++ != term && --cnt > 0) + ; - return (cnt > 0 ? --src : (unsigned char *)0); + return (cnt > 0 ? --src : (unsigned char *)0); } - diff --git a/sbr/m_gmprot.c b/sbr/m_gmprot.c index 92ead2d..377be09 100644 --- a/sbr/m_gmprot.c +++ b/sbr/m_gmprot.c @@ -1,19 +1,21 @@ - /* - * m_gmprot.c -- return the msg-protect value - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_gmprot.c -- return the msg-protect value +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include int -m_gmprot (void) +m_gmprot(void) { - register char *cp; + char *cp; - return atooi ((cp = context_find ("msg-protect")) && *cp ? cp : msgprot); + if (!(cp = context_find("msg-protect")) || !*cp) { + cp = msgprot; + } + return strtol(cp, NULL, 8); } diff --git a/sbr/m_maildir.c b/sbr/m_maildir.c deleted file mode 100644 index 6c8c584..0000000 --- a/sbr/m_maildir.c +++ /dev/null @@ -1,96 +0,0 @@ - -/* - * m_maildir.c -- get the path for the mail directory - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -#define CWD "./" -#define NCWD (sizeof(CWD) - 1) -#define DOT "." -#define DOTDOT ".." -#define PWD "../" -#define NPWD (sizeof(PWD) - 1) - -static char mailfold[BUFSIZ]; - -/* - * static prototypes - */ -static char *exmaildir (char *); - - -char * -m_maildir (char *folder) -{ - register char *cp, *ep; - - if ((cp = exmaildir (folder)) - && (ep = cp + strlen (cp) - 1) > cp - && *ep == '/') - *ep = '\0'; - - return cp; -} - - -char * -m_mailpath (char *folder) -{ - register char *cp; - char maildir[BUFSIZ]; - - if (*folder != '/' - && strncmp (folder, CWD, NCWD) - && strcmp (folder, DOT) - && strcmp (folder, DOTDOT) - && strncmp (folder, PWD, NPWD)) { - strncpy (maildir, mailfold, sizeof(maildir)); /* preserve... */ - cp = getcpy (m_maildir (folder)); - strncpy (mailfold, maildir, sizeof(mailfold)); - } else { - cp = path (folder, TFOLDER); - } - - return cp; -} - - -static char * -exmaildir (char *folder) -{ - register char *cp, *pp; - - /* use current folder if none is specified */ - if (folder == NULL) - folder = getfolder(1); - - if (!(*folder != '/' - && strncmp (folder, CWD, NCWD) - && strcmp (folder, DOT) - && strcmp (folder, DOTDOT) - && strncmp (folder, PWD, NPWD))) { - strncpy (mailfold, folder, sizeof(mailfold)); - return mailfold; - } - - cp = mailfold; - if ((pp = context_find ("path")) && *pp) { - if (*pp != '/') { - sprintf (cp, "%s/", mypath); - cp += strlen (cp); - } - cp = copy (pp, cp); - } else { - cp = copy (path ("./", TFOLDER), cp); - } - if (cp[-1] != '/') - *cp++ = '/'; - strcpy (cp, folder); - - return mailfold; -} diff --git a/sbr/m_mktemp.c b/sbr/m_mktemp.c index aa25636..4c7703c 100644 --- a/sbr/m_mktemp.c +++ b/sbr/m_mktemp.c @@ -1,10 +1,10 @@ /* - * m_mktemp.c -- Construct a temporary file. - * - * This code is Copyright (c) 2010, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_mktemp.c -- Construct a temporary file. +** +** This code is Copyright (c) 2010, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -12,135 +12,137 @@ static char *get_temp_dir(); /* Create a temporary file. If pfx_in is null, the temporary file - * will be created in the temporary directory (more on that later). - * If pfx_in is not null, then the temporary file location will be - * defined by the value pfx_in. - * - * The file created will be at the pathname specified appended with - * 6 random (we hope :) characters. - * - * The return value will be the pathname to the file created. - * - * CAUTION: The return pointer references static data. If - * you need to modify, or save, the return string, make a copy of it - * first. - * - * When pfx_in is null, the temporary directory is determined as - * follows, in order: - * - * MHTMPDIR envvar - * TMPDIR envvar - * TMP envvar - * User's mail directory. - * - * NOTE: One will probably use m_mktemp2() instead of this function. - * For example, if you want to create a temp file in the defined - * temporary directory, but with a custom basename prefix, do - * something like the following: - * - * char *tmp_pathname = m_mktemp2(NULL, "mypre", ...); - */ +** will be created in the temporary directory (more on that later). +** If pfx_in is not null, then the temporary file location will be +** defined by the value pfx_in. +** +** The file created will be at the pathname specified appended with +** 6 random (we hope :) characters. +** +** The return value will be the pathname to the file created. +** +** CAUTION: The return pointer references static data. If +** you need to modify, or save, the return string, make a copy of it +** first. +** +** When pfx_in is null, the temporary directory is determined as +** follows, in order: +** +** MHTMPDIR envvar +** TMPDIR envvar +** TMP envvar +** User's mail directory. +** +** NOTE: One will probably use m_mktemp2() instead of this function. +** For example, if you want to create a temp file in the defined +** temporary directory, but with a custom basename prefix, do +** something like the following: +** +** char *tmp_pathname = m_mktemp2(NULL, "mypre", ...); +*/ char * -m_mktemp ( - const char *pfx_in, /* Pathname prefix for temporary file. */ - int *fd_ret, /* (return,optional) File descriptor to temp file. */ - FILE **fp_ret /* (return,optional) FILE pointer to temp file. */ +m_mktemp( + const char *pfx_in, /* Pathname prefix for temporary file. */ + int *fd_ret, /* (return,opt.) File descriptor to temp file. */ + FILE **fp_ret /* (return,opt.) FILE pointer to temp file. */ ) { - static char tmpfil[BUFSIZ]; - int fd = -1; - int keep_open = 0; - mode_t oldmode = umask(077); + static char tmpfil[BUFSIZ]; + int fd = -1; + int keep_open = 0; + mode_t oldmode = umask(077); - if (pfx_in == NULL) { - snprintf(tmpfil, sizeof(tmpfil), "%s/nmhXXXXXX", get_temp_dir()); - } else { - snprintf(tmpfil, sizeof(tmpfil), "%sXXXXXX", pfx_in); - } + if (pfx_in == NULL) { + snprintf(tmpfil, sizeof(tmpfil), "%s/nmhXXXXXX", + get_temp_dir()); + } else { + snprintf(tmpfil, sizeof(tmpfil), "%sXXXXXX", pfx_in); + } - fd = mkstemp(tmpfil); - if (fd < 0) { - umask(oldmode); - return NULL; - } - if (fd_ret != NULL) { - *fd_ret = fd; - keep_open = 1; - } - if (fp_ret != NULL) { - FILE *fp = fdopen(fd, "w+"); - if (fp == NULL) { - int olderr = errno; - unlink(tmpfil); - close(fd); - errno = olderr; - umask(oldmode); - return NULL; - } - *fp_ret = fp; - keep_open = 1; - } - if (!keep_open) { - close(fd); - } - umask(oldmode); - return tmpfil; + fd = mkstemp(tmpfil); + if (fd < 0) { + umask(oldmode); + return NULL; + } + if (fd_ret != NULL) { + *fd_ret = fd; + keep_open = 1; + } + if (fp_ret != NULL) { + FILE *fp = fdopen(fd, "w+"); + if (fp == NULL) { + int olderr = errno; + unlink(tmpfil); + close(fd); + errno = olderr; + umask(oldmode); + return NULL; + } + *fp_ret = fp; + keep_open = 1; + } + if (!keep_open) { + close(fd); + } + umask(oldmode); + return tmpfil; } -/* This version allows one to specify the directory the temp file should - * by created based on a given pathname. Although m_mktemp() technically - * supports this, this version is when the directory is defined by - * a separate variable from the prefix, eliminating the caller from having - * to do string manipulation to generate the desired. pathname prefix. - * - * The pfx_in parameter specifies a basename prefix for the file. If dir_in - * is NULL, then the defined temporary directory (see comments to m_mktemp() - * above) is used to create the temp file. - */ +/* +** This version allows one to specify the directory the temp file should +** by created based on a given pathname. Although m_mktemp() technically +** supports this, this version is when the directory is defined by +** a separate variable from the prefix, eliminating the caller from having +** to do string manipulation to generate the desired. pathname prefix. +** +** The pfx_in parameter specifies a basename prefix for the file. If dir_in +** is NULL, then the defined temporary directory (see comments to m_mktemp() +** above) is used to create the temp file. +*/ char * -m_mktemp2 ( - const char *dir_in, /* Directory to place temp file. */ - const char *pfx_in, /* Basename prefix for temp file. */ - int *fd_ret, /* (return,optional) File descriptor to temp file. */ - FILE **fp_ret /* (return,optional) FILE pointer to temp file. */ +m_mktemp2( + const char *dir_in, /* Directory to place temp file. */ + const char *pfx_in, /* Basename prefix for temp file. */ + int *fd_ret, /* (return,opt.) File descriptor to temp file. */ + FILE **fp_ret /* (return,opt.) FILE pointer to temp file. */ ) { - static char buffer[BUFSIZ]; - char *cp; - int n; + static char buffer[BUFSIZ]; + char *cp; + int n; - if (dir_in == NULL) { - if (pfx_in == NULL) { - return m_mktemp(NULL, fd_ret, fp_ret); - } - snprintf(buffer, sizeof(buffer), "%s/%s", get_temp_dir(), pfx_in); - return m_mktemp(buffer, fd_ret, fp_ret); - } + if (dir_in == NULL) { + if (pfx_in == NULL) { + return m_mktemp(NULL, fd_ret, fp_ret); + } + snprintf(buffer, sizeof(buffer), "%s/%s", get_temp_dir(), pfx_in); + return m_mktemp(buffer, fd_ret, fp_ret); + } - if ((cp = r1bindex ((char *)dir_in, '/')) == dir_in) { - /* No directory component */ - return m_mktemp(pfx_in, fd_ret, fp_ret); - } - n = (int)(cp-dir_in-1); /* Length of dir component */ - snprintf(buffer, sizeof(buffer), "%.*s%s", n, dir_in, pfx_in); - return m_mktemp(buffer, fd_ret, fp_ret); + if ((cp = mhbasename((char *)dir_in)) == dir_in) { + /* No directory component */ + return m_mktemp(pfx_in, fd_ret, fp_ret); + } + n = (int)(cp-dir_in-1); /* Length of dir component */ + snprintf(buffer, sizeof(buffer), "%.*s/%s", n, dir_in, pfx_in); + return m_mktemp(buffer, fd_ret, fp_ret); } static char * get_temp_dir() { - // Ignore envvars if we are setuid - if ((getuid()==geteuid()) && (getgid()==getegid())) { - char *tmpdir = NULL; - tmpdir = getenv("MHTMPDIR"); - if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; + /* Ignore envvars if we are setuid */ + if ((getuid()==geteuid()) && (getgid()==getegid())) { + char *tmpdir = NULL; + tmpdir = getenv("MHTMPDIR"); + if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; - tmpdir = getenv("TMPDIR"); - if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; + tmpdir = getenv("TMPDIR"); + if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; - tmpdir = getenv("TMP"); - if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; - } - return m_maildir(""); + tmpdir = getenv("TMP"); + if (tmpdir != NULL && *tmpdir != '\0') return tmpdir; + } + return toabsdir("+"); } diff --git a/sbr/m_msgdef.c b/sbr/m_msgdef.c deleted file mode 100644 index d602973..0000000 --- a/sbr/m_msgdef.c +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * m_msgdef.c -- some defines for sbr/m_getfld.c - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/* - * disgusting hack for "inc" so it can know how many characters - * were stuffed in the buffer on the last call (see comments - * in uip/scansbr.c) - */ -int msg_count = 0; - -int msg_style = MS_DEFAULT; - -/* - * The "full" delimiter string for a packed maildrop consists - * of a newline followed by the actual delimiter. E.g., the - * full string for a Unix maildrop would be: "\n\nFrom ". - * "Fdelim" points to the start of the full string and is used - * in the BODY case of the main routine to search the buffer for - * a possible eom. Msg_delim points to the first character of - * the actual delim. string (i.e., fdelim+1). Edelim - * points to the 2nd character of actual delimiter string. It - * is used in m_Eom because the first character of the string - * has been read and matched before m_Eom is called. - */ -char *msg_delim = ""; diff --git a/sbr/m_name.c b/sbr/m_name.c index 18ee081..d42c21b 100644 --- a/sbr/m_name.c +++ b/sbr/m_name.c @@ -1,11 +1,10 @@ - /* - * m_name.c -- return a message number as a string - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** m_name.c -- return a message number as a string (in static memory) +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include @@ -13,11 +12,12 @@ static char name[BUFSIZ]; char * -m_name (int num) +m_name(int num) { - if (num <= 0) - return "?"; + if (num <= 0) { + return "?"; + } - snprintf (name, sizeof(name), "%d", num); - return name; + snprintf(name, sizeof(name), "%d", num); + return name; } diff --git a/sbr/m_scratch.c b/sbr/m_scratch.c deleted file mode 100644 index 3c63d09..0000000 --- a/sbr/m_scratch.c +++ /dev/null @@ -1,41 +0,0 @@ - -/* - * m_scratch.c -- construct a scratch file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/*************************************************************************** - * DO NOT USE THIS FUNCTION! IT WILL BE REMOVED IN THE FUTURE. - * THIS FUNCTION IS INSECURE. USE THE FUNCTIONS DEFINED IN m_mktemp.c. - ***************************************************************************/ -char * -m_scratch (char *file, char *template) -{ - char *cp; - static char buffer[BUFSIZ], tmpfil[BUFSIZ]; - - snprintf (tmpfil, sizeof(tmpfil), "%sXXXXXX", template); -/* - Mkstemp work postponed until later -Doug -#ifdef HAVE_MKSTEMP - mkstemp (tmpfil); -#else -*/ - mktemp (tmpfil); -/* -#endif -*/ - /* nasty - this really means: if there is no '/' in the path */ - if ((cp = r1bindex (file, '/')) == file) - strncpy (buffer, tmpfil, sizeof(buffer)); - else - snprintf (buffer, sizeof(buffer), "%.*s%s", (int)(cp - file), file, tmpfil); - unlink (buffer); - - return buffer; -} diff --git a/sbr/m_tmpfil.c b/sbr/m_tmpfil.c deleted file mode 100644 index 291d996..0000000 --- a/sbr/m_tmpfil.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * m_tmpfil.c -- construct a temporary file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/*************************************************************************** - * DO NOT USE THIS FUNCTION! IT WILL BE REMOVED IN THE FUTURE. - * THIS FUNCTION IS INSECURE. USE THE FUNCTIONS DEFINED IN m_mktemp.c. - ***************************************************************************/ -char * -m_tmpfil (char *template) -{ - static char tmpfil[BUFSIZ]; - - snprintf (tmpfil, sizeof(tmpfil), "/tmp/%sXXXXXX", template); -/* - Mkstemp work postponed until later -Doug -#ifdef HAVE_MKSTEMP - unlink(mkstemp(tmpfil)); -#else -*/ - unlink(mktemp(tmpfil)); -/* -#endif -*/ - return tmpfil; -} diff --git a/sbr/makedir.c b/sbr/makedir.c index 4337b7c..ea39385 100644 --- a/sbr/makedir.c +++ b/sbr/makedir.c @@ -1,118 +1,65 @@ - /* - * makedir.c -- make a directory - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** makedir.c -- make a directory +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ /* - * Modified to try recursive create. - */ +** Modified to try recursive create. +*/ #include #include #include #include - + int -makedir (char *dir) +makedir(char *dir) { - char path[PATH_MAX]; - char* folder_perms_ASCII; - int had_an_error = 0; - mode_t folder_perms, saved_umask; - pid_t pid; - register char* c; + char path[PATH_MAX]; + char *cp; + int had_an_error = 0; + mode_t folder_perms, saved_umask; + register char* c; - context_save(); /* save the context file */ - fflush(stdout); + context_save(); /* save the context file */ + fflush(stdout); - if (!(folder_perms_ASCII = context_find ("folder-protect"))) - folder_perms_ASCII = foldprot; /* defaults to "700" */ - - /* Because mh-profile.man documents "Folder-Protect:" as an octal constant, - and we don't want to force the user to remember to include a leading - zero, we call atooi(folder_perms_ASCII) here rather than - strtoul(folder_perms_ASCII, NULL, 0). Therefore, if anyone ever tries to - specify a mode in say, hex, they'll get garbage. (I guess nmh uses its - atooi() function rather than calling strtoul() with a radix of 8 because - some ancient platforms are missing that functionality. */ - folder_perms = atooi(folder_perms_ASCII); + if (!(cp = context_find("folder-protect")) || !*cp) { + cp = foldprot; + } + folder_perms = strtoul(cp, NULL, 8); - /* Folders have definite desired permissions that are set -- we don't want - to interact with the umask. Clear it temporarily. */ - saved_umask = umask(0); + /* + ** Folders have definite desired permissions that are set -- we + ** don't want to interact with the umask. Clear it temporarily. + */ + saved_umask = umask(0); - if (getuid () == geteuid ()) { - c = strncpy(path, dir, sizeof(path)); - - while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) { - *c = (char)0; - if (access(path, X_OK)) { - if (errno != ENOENT){ - advise (dir, "unable to create directory"); - had_an_error = 1; - } + c = strncpy(path, dir, sizeof(path)); + + while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) { + *c = '\0'; /* Create an outer directory. */ - if (mkdir(path, folder_perms)) { - advise (dir, "unable to create directory"); - had_an_error = 1; + if (mkdir(path, folder_perms) == -1 && + errno != EEXIST) { + advise(dir, "unable to create directory"); + had_an_error = 1; } - } - *c = '/'; + *c = '/'; } - if (!had_an_error) { - /* Create the innermost nested subdirectory of the path we're being - asked to create. */ - if (mkdir (dir, folder_perms) == -1) { - advise (dir, "unable to create directory"); + /* + ** Create the innermost nested subdirectory of the + ** path we're being asked to create. + */ + if (!had_an_error && mkdir(dir, folder_perms)==-1) { + advise(dir, "unable to create directory"); had_an_error = 1; - } } - } - else { - /* Ummm, why do we want to avoid creating directories with the effective - user ID? None of the nmh tools are installed such that the effective - should be different from the real, and if some parent process made - the two be different, I don't see why it should be our job to enforce - the real UID. Also, why the heck do we call the mkdir executable - rather than the library function in this case?? If we do want to - call the mkdir executable, we should at least be giving it -p (and - change the single chmod() call below) so it can successfully create - nested directories like the above code can. - - -- Dan Harkless */ - switch (pid = vfork()) { - case -1: - advise ("fork", "unable to"); - return 0; - - case 0: - setgid (getgid ()); - setuid (getuid ()); - - execl ("/bin/mkdir", "mkdir", dir, NULL); - execl ("/usr/bin/mkdir", "mkdir", dir, NULL); - fprintf (stderr, "unable to exec "); - perror ("mkdir"); - _exit (-1); - - default: - if (pidXwait(pid, "mkdir")) - return 0; - break; - } - - chmod (dir, folder_perms); - } - - umask(saved_umask); /* put the user's umask back */ + umask(saved_umask); /* put the user's umask back */ - if (had_an_error) - return 0; /* opposite of UNIX error return convention */ - else - return 1; + return (had_an_error) ? 0 : 1; } diff --git a/sbr/memmove.c b/sbr/memmove.c deleted file mode 100644 index 62a303f..0000000 --- a/sbr/memmove.c +++ /dev/null @@ -1,11 +0,0 @@ -/* public domain function from Jan Wolter Unix Incompatibility Notes */ -/* http://unixpapa.com/incnote/ */ -char *memmove(char *dst, char *src, int n) -{ - if (src > dst) - for ( ; n > 0; n--) - *(dst++)= *(src++); - else - for (dst+= n-1, src+= n-1; n > 0; n--) - *(dst--)= *(src--); -} diff --git a/sbr/mf.c b/sbr/mf.c index fd92e36..6338a6e 100644 --- a/sbr/mf.c +++ b/sbr/mf.c @@ -1,11 +1,10 @@ - /* - * mf.c -- mail filter subroutines - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mf.c -- mail filter subroutines +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -13,319 +12,131 @@ #include /* - * static prototypes - */ -static char *getcpy (char *); -static void compress (char *, unsigned char *); -static int isat (char *); -static int parse_address (void); -static int phrase (char *); -static int route_addr (char *); -static int local_part (char *); -static int domain (char *); -static int route (char *); -static int my_lex (char *); +** static prototypes +*/ +static char *getcpy(char *); +static int parse_address(void); +static int phrase(char *); +static int route_addr(char *); +static int local_part(char *); +static int domain(char *); +static int route(char *); +static int my_lex(char *); static char * -getcpy (char *s) +getcpy(char *s) { - register char *p; - - if (!s) { -/* causes compiles to blow up because the symbol _cleanup is undefined - where did this ever come from? */ - /* _cleanup(); */ - abort(); - for(;;) - pause(); - } - p = mh_xmalloc ((size_t) (strlen (s) + 2)); - strcpy (p, s); - return p; -} - - -int -isfrom(char *string) -{ - return (strncmp (string, "From ", 5) == 0 - || strncmp (string, ">From ", 6) == 0); -} - - -int -lequal (unsigned char *a, unsigned char *b) -{ - for (; *a; a++, b++) - if (*b == 0) - return FALSE; - else { - char c1 = islower (*a) ? toupper (*a) : *a; - char c2 = islower (*b) ? toupper (*b) : *b; - if (c1 != c2) - return FALSE; + register char *p; + + if (!s) { + /* + ** causes compiles to blow up because the symbol _cleanup + ** is undefined where did this ever come from? + */ + /* _cleanup(); */ + abort(); + for(;;) + pause(); } - - return (*b == 0); -} - - -/* - * seekadrx() is tricky. We want to cover both UUCP-style and ARPA-style - * addresses, so for each list of addresses we see if we can find some - * character to give us a hint. - */ - - -#define CHKADR 0 /* undertermined address style */ -#define UNIXDR 1 /* UNIX-style address */ -#define ARPADR 2 /* ARPAnet-style address */ - - -static char *punctuators = ";<>.()[]"; -static char *vp = NULL; -static char *tp = NULL; - -static struct adrx adrxs1; - - -struct adrx * -seekadrx (char *addrs) -{ - static int state = CHKADR; - register char *cp; - register struct adrx *adrxp; - - if (state == CHKADR) - for (state = UNIXDR, cp = addrs; *cp; cp++) - if (strchr(punctuators, *cp)) { - state = ARPADR; - break; - } - - switch (state) { - case UNIXDR: - adrxp = uucpadrx (addrs); - break; - - case ARPADR: - default: - adrxp = getadrx (addrs); - break; - } - - if (adrxp == NULL) - state = CHKADR; - - return adrxp; -} - - -/* - * uucpadrx() implements a partial UUCP-style address parser. It's based - * on the UUCP notion that addresses are separated by spaces or commas. - */ - - -struct adrx * -uucpadrx (char *addrs) -{ - register unsigned char *cp, *wp, *xp, *yp; - register char *zp; - register struct adrx *adrxp = &adrxs1; - - if (vp == NULL) { - vp = tp = getcpy (addrs); - compress (addrs, vp); - } - else - if (tp == NULL) { - free (vp); - vp = NULL; - return NULL; - } - - for (cp = tp; isspace (*cp); cp++) - continue; - if (*cp == 0) { - free (vp); - vp = tp = NULL; - return NULL; - } - - if ((wp = strchr(cp, ',')) == NULL) { - if ((wp = strchr(cp, ' ')) != NULL) { - xp = wp; - while (isspace (*xp)) - xp++; - if (*xp != 0 && isat (--xp)) { - yp = xp + 4; - while (isspace (*yp)) - yp++; - if (*yp != 0) { - if ((zp = strchr(yp, ' ')) != NULL) - *zp = 0, tp = ++zp; - else - tp = NULL; - } - else - *wp = 0, tp = ++wp; - } - else - *wp = 0, tp = ++wp; - } - else - tp = NULL; - } - else - *wp = 0, tp = ++wp; - - if (adrxp->text) - free (adrxp->text); - adrxp->text = getcpy (cp); - adrxp->mbox = cp; - adrxp->host = adrxp->path = NULL; - if ((wp = strrchr(cp, '@')) != NULL) { - *wp++ = 0; - adrxp->host = *wp ? wp : NULL; - } - else - for (wp = cp + strlen (cp) - 4; wp >= cp; wp--) - if (isat (wp)) { - *wp++ = 0; - adrxp->host = wp + 3; - } - - adrxp->pers = adrxp->grp = adrxp->note = adrxp->err = NULL; - adrxp->ingrp = 0; - - return adrxp; -} - - -static void -compress (char *fp, unsigned char *tp) -{ - register char c; - register unsigned char *cp; - - for (c = ' ', cp = tp; (*tp = *fp++) != 0;) - if (isspace (*tp)) { - if (c != ' ') - *tp++ = c = ' '; - } - else - c = *tp++; - - if (c == ' ' && cp < tp) - *--tp = 0; -} - - -static int -isat (char *p) -{ - return (strncmp (p, " AT ", 4) - && strncmp (p, " At ", 4) - && strncmp (p, " aT ", 4) - && strncmp (p, " at ", 4) ? FALSE : TRUE); + p = mh_xmalloc((size_t) (strlen(s) + 2)); + strcpy(p, s); + return p; } /* - * - * getadrx() implements a partial 822-style address parser. The parser - * is neither complete nor correct. It does however recognize nearly all - * of the 822 address syntax. In addition it handles the majority of the - * 733 syntax as well. Most problems arise from trying to accomodate both. - * - * In terms of 822, the route-specification in - * - * "<" [route] local-part "@" domain ">" - * - * is parsed and returned unchanged. Multiple at-signs are compressed - * via source-routing. Recursive groups are not allowed as per the - * standard. - * - * In terms of 733, " at " is recognized as equivalent to "@". - * - * In terms of both the parser will not complain about missing hosts. - * - * ----- - * - * We should not allow addresses like - * - * Marshall T. Rose - * - * but should insist on - * - * "Marshall T. Rose" - * - * Unfortunately, a lot of mailers stupidly let people get away with this. - * - * ----- - * - * We should not allow addresses like - * - * - * - * but should insist on - * - * MRose@UCI - * - * Unfortunately, a lot of mailers stupidly let people's UAs get away with - * this. - * - * ----- - * - * We should not allow addresses like - * - * @UCI:MRose@UCI-750a - * - * but should insist on - * - * Marshall Rose <@UCI:MRose@UCI-750a> - * - * Unfortunately, a lot of mailers stupidly do this. - * - */ - -#define QUOTE '\\' - -#define LX_END 0 -#define LX_ERR 1 -#define LX_ATOM 2 -#define LX_QSTR 3 -#define LX_DLIT 4 -#define LX_SEMI 5 -#define LX_COMA 6 -#define LX_LBRK 7 -#define LX_RBRK 8 -#define LX_COLN 9 -#define LX_DOT 10 -#define LX_AT 11 +** +** getadrx() implements a partial 822-style address parser. The parser +** is neither complete nor correct. It does however recognize nearly all +** of the 822 address syntax. +** Historically, it handled the majority (and still handles parts) of the +** 733 syntax as well. Most problems arise from trying to accomodate both. +** +** In terms of 822, the route-specification in +** +** "<" [route] local-part "@" domain ">" +** +** is parsed and returned unchanged. Multiple at-signs are compressed +** via source-routing. Recursive groups are not allowed as per the +** standard. +** +** In terms of both the parser will not complain about missing hosts. +** +** ----- +** +** We should not allow addresses like +** +** Marshall T. Rose +** +** but should insist on +** +** "Marshall T. Rose" +** +** Unfortunately, a lot of mailers stupidly let people get away with this. +** +** ----- +** +** We should not allow addresses like +** +** +** +** but should insist on +** +** MRose@UCI +** +** Unfortunately, a lot of mailers stupidly let people's UAs get away with +** this. +** +** ----- +** +** We should not allow addresses like +** +** @UCI:MRose@UCI-750a +** +** but should insist on +** +** Marshall Rose <@UCI:MRose@UCI-750a> +** +** Unfortunately, a lot of mailers stupidly do this. +** +*/ + +#define QUOTE '\\' + +#define LX_END 0 +#define LX_ERR 1 +#define LX_ATOM 2 +#define LX_QSTR 3 +#define LX_DLIT 4 +#define LX_SEMI 5 +#define LX_COMA 6 +#define LX_LBRK 7 +#define LX_RBRK 8 +#define LX_COLN 9 +#define LX_DOT 10 +#define LX_AT 11 struct specials { - char lx_chr; - int lx_val; + char lx_chr; + int lx_val; }; static struct specials special[] = { - { ';', LX_SEMI }, - { ',', LX_COMA }, - { '<', LX_LBRK }, - { '>', LX_RBRK }, - { ':', LX_COLN }, - { '.', LX_DOT }, - { '@', LX_AT }, - { '(', LX_ERR }, - { ')', LX_ERR }, - { QUOTE, LX_ERR }, - { '"', LX_ERR }, - { '[', LX_ERR }, - { ']', LX_ERR }, - { 0, 0 } + { ';', LX_SEMI }, + { ',', LX_COMA }, + { '<', LX_LBRK }, + { '>', LX_RBRK }, + { ':', LX_COLN }, + { '.', LX_DOT }, + { '@', LX_AT }, + { '(', LX_ERR }, + { ')', LX_ERR }, + { QUOTE, LX_ERR }, + { '"', LX_ERR }, + { '[', LX_ERR }, + { ']', LX_ERR }, + { 0, 0 } }; static int glevel = 0; @@ -348,621 +159,566 @@ static struct adrx adrxs2; struct adrx * -getadrx (char *addrs) +getadrx(char *addrs) { - register char *bp; - register struct adrx *adrxp = &adrxs2; - - if (pers) - free (pers); - if (mbox) - free (mbox); - if (host) - free (host); - if (path) - free (path); - if (grp) - free (grp); - if (note) - free (note); - pers = mbox = host = path = grp = note = NULL; - err[0] = 0; - - if (dp == NULL) { - dp = cp = getcpy (addrs ? addrs : ""); - glevel = 0; - } - else - if (cp == NULL) { - free (dp); - dp = NULL; - return NULL; + register char *bp; + register struct adrx *adrxp = &adrxs2; + + if (pers) + free(pers); + if (mbox) + free(mbox); + if (host) + free(host); + if (path) + free(path); + if (grp) + free(grp); + if (note) + free(note); + pers = mbox = host = path = grp = note = NULL; + err[0] = 0; + + if (dp == NULL) { + dp = cp = getcpy(addrs ? addrs : ""); + glevel = 0; + } else if (cp == NULL) { + free(dp); + dp = NULL; + return NULL; } - switch (parse_address ()) { + switch (parse_address()) { case DONE: - free (dp); - dp = cp = NULL; - return NULL; + free(dp); + dp = cp = NULL; + return NULL; case OK: - switch (last_lex) { + switch (last_lex) { case LX_COMA: case LX_END: - break; + break; - default: /* catch trailing comments */ - bp = cp; - my_lex (adr); - cp = bp; - break; - } - break; + default: /* catch trailing comments */ + bp = cp; + my_lex(adr); + cp = bp; + break; + } + break; default: - break; - } - - if (err[0]) - for (;;) { - switch (last_lex) { - case LX_COMA: - case LX_END: - break; - - default: - my_lex (adr); - continue; - } - break; + break; } - while (isspace (*ap)) - ap++; - if (cp) - sprintf (adr, "%.*s", (int)(cp - ap), ap); - else - strcpy (adr, ap); - bp = adr + strlen (adr) - 1; - if (*bp == ',' || *bp == ';' || *bp == '\n') - *bp = 0; - adrxp->text = adr; - adrxp->pers = pers; - adrxp->mbox = mbox; - adrxp->host = host; - adrxp->path = path; - adrxp->grp = grp; - adrxp->ingrp = ingrp; - adrxp->note = note; - adrxp->err = err[0] ? err : NULL; - - return adrxp; + if (err[0]) + for (;;) { + switch (last_lex) { + case LX_COMA: + case LX_END: + break; + + default: + my_lex(adr); + continue; + } + break; + } + while (isspace(*ap)) + ap++; + if (cp) + sprintf(adr, "%.*s", (int)(cp - ap), ap); + else + strcpy(adr, ap); + bp = adr + strlen(adr) - 1; + if (*bp == ',' || *bp == ';' || *bp == '\n') + *bp = 0; + + adrxp->text = adr; + adrxp->pers = pers; + adrxp->mbox = mbox; + adrxp->host = host; + adrxp->path = path; + adrxp->grp = grp; + adrxp->ingrp = ingrp; + adrxp->note = note; + adrxp->err = err[0] ? err : NULL; + + return adrxp; } static int -parse_address (void) +parse_address(void) { - char buffer[BUFSIZ]; + char buffer[BUFSIZ]; again: ; - ap = cp; - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_QSTR: - pers = getcpy (buffer); - break; - - case LX_SEMI: - if (glevel-- <= 0) { - strcpy (err, "extraneous semi-colon"); - return NOTOK; - } - case LX_COMA: - if (note) { - free (note); - note = NULL; - } - goto again; - - case LX_END: - return DONE; - - case LX_LBRK: /* sigh (2) */ - goto get_addr; - - case LX_AT: /* sigh (3) */ - cp = ap; - if (route_addr (buffer) == NOTOK) - return NOTOK; - return OK; /* why be choosy? */ - - default: - sprintf (err, "illegal address construct (%s)", buffer); - return NOTOK; - } - - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_QSTR: - pers = add (buffer, add (" ", pers)); - more_phrase: ; /* sigh (1) */ - if (phrase (buffer) == NOTOK) + ap = cp; + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_QSTR: + pers = getcpy(buffer); + break; + + case LX_SEMI: + if (glevel-- <= 0) { + strcpy(err, "extraneous semi-colon"); + return NOTOK; + } + case LX_COMA: + if (note) { + free(note); + note = NULL; + } + goto again; + + case LX_END: + return DONE; + + case LX_LBRK: /* sigh (2) */ + goto get_addr; + + case LX_AT: /* sigh (3) */ + cp = ap; + if (route_addr(buffer) == NOTOK) + return NOTOK; + return OK; /* why be choosy? */ + + default: + sprintf(err, "illegal address construct (%s)", buffer); return NOTOK; + } + + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_QSTR: + pers = add(buffer, add(" ", pers)); +more_phrase: ; /* sigh (1) */ + if (phrase(buffer) == NOTOK) + return NOTOK; + + switch (last_lex) { + case LX_LBRK: +get_addr: ; + if (route_addr(buffer) == NOTOK) + return NOTOK; + if (last_lex == LX_RBRK) + return OK; + sprintf(err, "missing right-bracket (%s)", buffer); + return NOTOK; + + case LX_COLN: +get_group: ; + if (glevel++ > 0) { + sprintf(err, "nested groups not allowed (%s)", pers); + return NOTOK; + } + grp = add(": ", pers); + pers = NULL; + { + char *pp = cp; + + for (;;) + switch (my_lex(buffer)) { + case LX_SEMI: + case LX_END: /* tsk, tsk */ + glevel--; + return OK; + + case LX_COMA: + continue; + + default: + cp = pp; + return parse_address(); + } + } + + case LX_DOT: /* sigh (1) */ + pers = add(".", pers); + goto more_phrase; + + default: + sprintf(err, "no mailbox in address, only a phrase (%s%s)", pers, buffer); + return NOTOK; + } - switch (last_lex) { - case LX_LBRK: - get_addr: ; - if (route_addr (buffer) == NOTOK) + case LX_LBRK: + goto get_addr; + + case LX_COLN: + goto get_group; + + case LX_DOT: + mbox = add(buffer, pers); + pers = NULL; + if (route_addr(buffer) == NOTOK) + return NOTOK; + goto check_end; + + case LX_AT: + ingrp = glevel; + mbox = pers; + pers = NULL; + if (domain(buffer) == NOTOK) return NOTOK; - if (last_lex == LX_RBRK) +check_end: ; + switch (last_lex) { + case LX_SEMI: + if (glevel-- <= 0) { + strcpy(err, "extraneous semi-colon"); + return NOTOK; + } + case LX_COMA: + case LX_END: return OK; - sprintf (err, "missing right-bracket (%s)", buffer); - return NOTOK; - case LX_COLN: - get_group: ; - if (glevel++ > 0) { - sprintf (err, "nested groups not allowed (%s)", pers); + default: + sprintf(err, "junk after local@domain (%s)", buffer); return NOTOK; - } - grp = add (": ", pers); - pers = NULL; - { - char *pp = cp; - - for (;;) - switch (my_lex (buffer)) { - case LX_SEMI: - case LX_END: /* tsk, tsk */ - glevel--; - return OK; - - case LX_COMA: - continue; - - default: - cp = pp; - return parse_address (); - } - } - - case LX_DOT: /* sigh (1) */ - pers = add (".", pers); - goto more_phrase; - - default: - sprintf (err, "no mailbox in address, only a phrase (%s%s)", - pers, buffer); - return NOTOK; - } - - case LX_LBRK: - goto get_addr; - - case LX_COLN: - goto get_group; - - case LX_DOT: - mbox = add (buffer, pers); - pers = NULL; - if (route_addr (buffer) == NOTOK) - return NOTOK; - goto check_end; + } - case LX_AT: - ingrp = glevel; - mbox = pers; - pers = NULL; - if (domain (buffer) == NOTOK) - return NOTOK; - check_end: ; - switch (last_lex) { - case LX_SEMI: - if (glevel-- <= 0) { - strcpy (err, "extraneous semi-colon"); + case LX_SEMI: /* no host */ + case LX_COMA: + case LX_END: + ingrp = glevel; + if (last_lex == LX_SEMI && glevel-- <= 0) { + strcpy(err, "extraneous semi-colon"); return NOTOK; - } - case LX_COMA: - case LX_END: - return OK; - - default: - sprintf (err, "junk after local@domain (%s)", buffer); - return NOTOK; - } - - case LX_SEMI: /* no host */ - case LX_COMA: - case LX_END: - ingrp = glevel; - if (last_lex == LX_SEMI && glevel-- <= 0) { - strcpy (err, "extraneous semi-colon"); + } + mbox = pers; + pers = NULL; + return OK; + + default: + sprintf(err, "missing mailbox (%s)", buffer); return NOTOK; - } - mbox = pers; - pers = NULL; - return OK; - - default: - sprintf (err, "missing mailbox (%s)", buffer); - return NOTOK; - } + } } static int -phrase (char *buffer) +phrase(char *buffer) { - for (;;) - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_QSTR: - pers = add (buffer, add (" ", pers)); - continue; - - default: - return OK; - } + for (;;) + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_QSTR: + pers = add(buffer, add(" ", pers)); + continue; + + default: + return OK; + } } static int -route_addr (char *buffer) +route_addr(char *buffer) { - register char *pp = cp; + register char *pp = cp; - if (my_lex (buffer) == LX_AT) { - if (route (buffer) == NOTOK) - return NOTOK; - } - else - cp = pp; + if (my_lex(buffer) == LX_AT) { + if (route(buffer) == NOTOK) + return NOTOK; + } + else + cp = pp; - if (local_part (buffer) == NOTOK) - return NOTOK; + if (local_part(buffer) == NOTOK) + return NOTOK; - switch (last_lex) { - case LX_AT: - return domain (buffer); + switch (last_lex) { + case LX_AT: + return domain(buffer); - case LX_SEMI: /* if in group */ - case LX_RBRK: /* no host */ + case LX_SEMI: /* if in group */ + case LX_RBRK: /* no host */ case LX_COMA: - case LX_END: - return OK; + case LX_END: + return OK; - default: - sprintf (err, "no at-sign after local-part (%s)", buffer); - return NOTOK; - } + default: + sprintf(err, "no at-sign after local-part (%s)", buffer); + return NOTOK; + } } static int -local_part (char *buffer) +local_part(char *buffer) { - ingrp = glevel; + ingrp = glevel; - for (;;) { - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_QSTR: - mbox = add (buffer, mbox); - break; + for (;;) { + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_QSTR: + mbox = add(buffer, mbox); + break; - default: - sprintf (err, "no mailbox in local-part (%s)", buffer); - return NOTOK; - } + default: + sprintf(err, "no mailbox in local-part (%s)", buffer); + return NOTOK; + } - switch (my_lex (buffer)) { - case LX_DOT: - mbox = add (buffer, mbox); - continue; + switch (my_lex(buffer)) { + case LX_DOT: + mbox = add(buffer, mbox); + continue; - default: - return OK; + default: + return OK; + } } - } } static int -domain (char *buffer) +domain(char *buffer) { - for (;;) { - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_DLIT: - host = add (buffer, host); - break; + for (;;) { + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_DLIT: + host = add(buffer, host); + break; - default: - sprintf (err, "no sub-domain in domain-part of address (%s)", buffer); - return NOTOK; - } + default: + sprintf(err, "no sub-domain in domain-part of address (%s)", buffer); + return NOTOK; + } - switch (my_lex (buffer)) { - case LX_DOT: - host = add (buffer, host); - continue; + switch (my_lex(buffer)) { + case LX_DOT: + host = add(buffer, host); + continue; - case LX_AT: /* sigh (0) */ - mbox = add (host, add ("%", mbox)); - free (host); - host = NULL; - continue; + case LX_AT: /* sigh (0) */ + mbox = add(host, add("%", mbox)); + free(host); + host = NULL; + continue; - default: - return OK; + default: + return OK; + } } - } } static int -route (char *buffer) +route(char *buffer) { - path = getcpy ("@"); + path = getcpy("@"); - for (;;) { - switch (my_lex (buffer)) { - case LX_ATOM: - case LX_DLIT: - path = add (buffer, path); - break; + for (;;) { + switch (my_lex(buffer)) { + case LX_ATOM: + case LX_DLIT: + path = add(buffer, path); + break; - default: - sprintf (err, "no sub-domain in domain-part of address (%s)", buffer); - return NOTOK; - } - switch (my_lex (buffer)) { - case LX_COMA: - path = add (buffer, path); - for (;;) { - switch (my_lex (buffer)) { - case LX_COMA: - continue; - - case LX_AT: - path = add (buffer, path); - break; - - default: - sprintf (err, "no at-sign found for next domain in route (%s)", - buffer); - } - break; + default: + sprintf(err, "no sub-domain in domain-part of address (%s)", buffer); + return NOTOK; } - continue; - - case LX_AT: /* XXX */ - case LX_DOT: - path = add (buffer, path); - continue; - - case LX_COLN: - path = add (buffer, path); - return OK; + switch (my_lex(buffer)) { + case LX_COMA: + path = add(buffer, path); + for (;;) { + switch (my_lex(buffer)) { + case LX_COMA: + continue; + + case LX_AT: + path = add(buffer, path); + break; + + default: + sprintf(err, "no at-sign found for next domain in route (%s)", + buffer); + } + break; + } + continue; + + case LX_AT: /* XXX */ + case LX_DOT: + path = add(buffer, path); + continue; + + case LX_COLN: + path = add(buffer, path); + return OK; - default: - sprintf (err, "no colon found to terminate route (%s)", buffer); - return NOTOK; + default: + sprintf(err, "no colon found to terminate route (%s)", buffer); + return NOTOK; + } } - } } static int -my_lex (char *buffer) +my_lex(char *buffer) { - /* buffer should be at least BUFSIZ bytes long */ - int i, gotat = 0; - register unsigned char c; - register char *bp; - -/* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */ -#define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0) - - bp = buffer; - *bp = 0; - if (!cp) - return (last_lex = LX_END); - - gotat = isat (cp); - c = *cp++; - while (isspace (c)) + /* buffer should be at least BUFSIZ bytes long */ + int i; + register unsigned char c; + register char *bp; + + /* + ** Add C to the buffer bp. After use of this macro *bp is guaranteed + ** to be within the buffer. + */ +#define ADDCHR(C) \ + do { \ + *bp++ = (C); \ + if ((bp - buffer) == (BUFSIZ-1)) \ + goto my_lex_buffull; \ + } while (0) + + bp = buffer; + *bp = 0; + if (!cp) + return (last_lex = LX_END); + c = *cp++; - if (c == 0) { - cp = NULL; - return (last_lex = LX_END); - } + while (isspace(c)) + c = *cp++; + if (c == 0) { + cp = NULL; + return (last_lex = LX_END); + } - if (c == '(') { - ADDCHR(c); - for (i = 0;;) - switch (c = *cp++) { - case 0: - cp = NULL; - return (last_lex = LX_ERR); - case QUOTE: - ADDCHR(c); - if ((c = *cp++) == 0) { - cp = NULL; - return (last_lex = LX_ERR); - } - ADDCHR(c); - continue; - case '(': - i++; - default: - ADDCHR(c); - continue; - case ')': - ADDCHR(c); - if (--i < 0) { - *bp = 0; - note = note ? add (buffer, add (" ", note)) - : getcpy (buffer); - return my_lex (buffer); - } - } - } - - if (c == '"') { - ADDCHR(c); - for (;;) - switch (c = *cp++) { - case 0: - cp = NULL; - return (last_lex = LX_ERR); - case QUOTE: - ADDCHR(c); - if ((c = *cp++) == 0) { - cp = NULL; - return (last_lex = LX_ERR); - } - default: - ADDCHR(c); - continue; - case '"': - ADDCHR(c); - *bp = 0; - return (last_lex = LX_QSTR); - } - } - - if (c == '[') { - ADDCHR(c); - for (;;) - switch (c = *cp++) { - case 0: - cp = NULL; - return (last_lex = LX_ERR); - case QUOTE: - ADDCHR(c); - if ((c = *cp++) == 0) { - cp = NULL; - return (last_lex = LX_ERR); - } - default: - ADDCHR(c); - continue; - case ']': - ADDCHR(c); - *bp = 0; - return (last_lex = LX_DLIT); - } - } - - ADDCHR(c); - *bp = 0; - for (i = 0; special[i].lx_chr != 0; i++) - if (c == special[i].lx_chr) - return (last_lex = special[i].lx_val); - - if (iscntrl (c)) - return (last_lex = LX_ERR); + if (c == '(') { + ADDCHR(c); + for (i = 0;;) + switch (c = *cp++) { + case 0: + cp = NULL; + return (last_lex = LX_ERR); + case QUOTE: + ADDCHR(c); + if ((c = *cp++) == 0) { + cp = NULL; + return (last_lex = LX_ERR); + } + ADDCHR(c); + continue; + case '(': + i++; + default: + ADDCHR(c); + continue; + case ')': + ADDCHR(c); + if (--i < 0) { + *bp = 0; + note = note ? add(buffer, add(" ", note)) : getcpy(buffer); + return my_lex(buffer); + } + } + } + + if (c == '"') { + ADDCHR(c); + for (;;) + switch (c = *cp++) { + case 0: + cp = NULL; + return (last_lex = LX_ERR); + case QUOTE: + ADDCHR(c); + if ((c = *cp++) == 0) { + cp = NULL; + return (last_lex = LX_ERR); + } + default: + ADDCHR(c); + continue; + case '"': + ADDCHR(c); + *bp = 0; + return (last_lex = LX_QSTR); + } + } + + if (c == '[') { + ADDCHR(c); + for (;;) + switch (c = *cp++) { + case 0: + cp = NULL; + return (last_lex = LX_ERR); + case QUOTE: + ADDCHR(c); + if ((c = *cp++) == 0) { + cp = NULL; + return (last_lex = LX_ERR); + } + default: + ADDCHR(c); + continue; + case ']': + ADDCHR(c); + *bp = 0; + return (last_lex = LX_DLIT); + } + } - for (;;) { - if ((c = *cp++) == 0) - break; - for (i = 0; special[i].lx_chr != 0; i++) - if (c == special[i].lx_chr) - goto got_atom; - if (iscntrl (c) || isspace (c)) - break; ADDCHR(c); - } + *bp = 0; + for (i = 0; special[i].lx_chr != 0; i++) + if (c == special[i].lx_chr) + return (last_lex = special[i].lx_val); + + if (iscntrl(c)) + return (last_lex = LX_ERR); + + for (;;) { + if ((c = *cp++) == 0) + break; + for (i = 0; special[i].lx_chr != 0; i++) + if (c == special[i].lx_chr) + goto got_atom; + if (iscntrl(c) || isspace(c)) + break; + ADDCHR(c); + } got_atom: ; - if (c == 0) - cp = NULL; - else - cp--; - *bp = 0; - last_lex = !gotat || cp == NULL || strchr(cp, '<') != NULL - ? LX_ATOM : LX_AT; - return last_lex; + if (c == 0) + cp = NULL; + else + cp--; + *bp = 0; + return LX_ATOM; my_lex_buffull: - /* Out of buffer space. *bp is the last byte in the buffer */ - *bp = 0; - return (last_lex = LX_ERR); + /* Out of buffer space. *bp is the last byte in the buffer */ + *bp = 0; + return (last_lex = LX_ERR); } char * -legal_person (char *p) +legal_person(char *p) { - int i; - register char *cp; - static char buffer[BUFSIZ]; + int i; + register char *cp; + static char buffer[BUFSIZ]; + + if (*p == '"') + return p; + for (cp = p; *cp; cp++) + for (i = 0; special[i].lx_chr; i++) + if (*cp == special[i].lx_chr) { + sprintf(buffer, "\"%s\"", p); + return buffer; + } - if (*p == '"') return p; - for (cp = p; *cp; cp++) - for (i = 0; special[i].lx_chr; i++) - if (*cp == special[i].lx_chr) { - sprintf (buffer, "\"%s\"", p); - return buffer; - } - - return p; -} - - -int -mfgets (FILE *in, char **bp) -{ - int i; - register char *cp, *dp, *ep; - static int len = 0; - static char *pp = NULL; - - if (pp == NULL) - pp = mh_xmalloc ((size_t) (len = BUFSIZ)); - - for (ep = (cp = pp) + len - 2;;) { - switch (i = getc (in)) { - case EOF: - eol: ; - if (cp != pp) { - *cp = 0; - *bp = pp; - return OK; - } - eoh: ; - *bp = NULL; - free (pp); - pp = NULL; - return DONE; - - case 0: - continue; - - case '\n': - if (cp == pp) /* end of headers, gobble it */ - goto eoh; - switch (i = getc (in)) { - default: /* end of line */ - case '\n': /* end of headers, save for next call */ - ungetc (i, in); - goto eol; - - case ' ': /* continue headers */ - case '\t': - *cp++ = '\n'; - break; - } /* fall into default case */ - - default: - *cp++ = i; - break; - } - if (cp >= ep) { - dp = mh_xrealloc (pp, (size_t) (len += BUFSIZ)); - cp += dp - pp, ep = (pp = cp) + len - 2; - } - } } diff --git a/sbr/mhbasename.c b/sbr/mhbasename.c new file mode 100644 index 0000000..038e506 --- /dev/null +++ b/sbr/mhbasename.c @@ -0,0 +1,32 @@ +/* +** mhbasename.c -- Given a path name, return a pointer to the character +** -- after the last slash. If none present, return the the +** -- beginning of the path. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ + +#include + + +/* +** Note: In contrast to POSIX basename(), we don't handle trailing +** slashes special. If path has a trailing slash, we return a pointer +** to a null byte (i.e. to an empty string). Also different: We don't +** modify the original string neither do we return a pointer to static +** memory. +*/ +char * +mhbasename(char *path) +{ + char *cp; + + if (!path) { + return NULL; + } + cp = strrchr(path, '/'); + return (!cp) ? path : ++cp; + +} diff --git a/sbr/mts.c b/sbr/mts.c index cd2a3d8..95c0a3f 100644 --- a/sbr/mts.c +++ b/sbr/mts.c @@ -1,527 +1,155 @@ - /* - * mts.c -- definitions for the mail transport system - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mts.c -- definitions for the mail transport system +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* for snprintf() */ #include #include - -#define nmhetcdir(file) NMHETCDIR#file - #include #include -#include #include +#include #include -#ifdef HAVE_SYS_UTSNAME_H -# include -#endif - -#define NOTOK (-1) -#define OK 0 - -/* - * static prototypes - */ -static char *tailor_value (unsigned char *); -static void getuserinfo (void); -static const char *get_mtsconf_pathname(void); -static const char *get_mtsuserconf_pathname(void); -static void mts_read_conf_file (FILE *fp); - /* - * *mmdfldir and *uucpldir are the maildrop directories. If maildrops - * are kept in the user's home directory, then these should be empty - * strings. In this case, the appropriate ...lfil array should contain - * the name of the file in the user's home directory. Usually, this is - * something like ".mail". - */ - -/* - * nmh mail transport interface customization file - */ -static char *mtsconf = nmhetcdir(/mts.conf); - -static char *localname = ""; -static char *localdomain = ""; -static char *systemname = ""; - -char *mmdfldir = MAILSPOOL; -char *mmdflfil = ""; -char *uucpldir = "/usr/spool/mail"; -char *uucplfil = ""; - -char *mmdlm1 = "\001\001\001\001\n"; -char *mmdlm2 = "\001\001\001\001\n"; +** static prototypes +*/ +static void getuserinfo(void); /* Cache the username and fullname of the user */ static char username[BUFSIZ]; static char fullname[BUFSIZ]; -/* Variables for username masquerading: */ - boolean draft_from_masquerading = FALSE; /* also used from post.c */ -static boolean mmailid_masquerading = FALSE; - boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */ -static char* masquerade = ""; - -/* - * MTS specific variables - */ -#if defined(SMTPMTS) -static char *sm_method = "smtp"; -int sm_mts = MTS_SMTP; -char *hostable = nmhetcdir(/hosts); -char *sendmail = SENDMAILPATH; -#endif - -/* - * SMTP/POP stuff - */ -char *clientname = NULL; -char *servers = "localhost \01localnet"; -char *pophost = ""; - -/* - * Global MailDelivery file - */ -char *maildelivery = nmhetcdir(/maildelivery); - - -/* - * Aliasing Facility (doesn't belong here) - */ -int Everyone = NOTOK; -static char *everyone = "-1"; -char *NoShell = ""; - -/* - * Customize the MTS settings for nmh by adjusting - * the file mts.conf in the nmh etc directory. - */ - -struct bind { - char *keyword; - char **value; -}; - -static struct bind binds[] = { - { "localname", &localname }, - { "localdomain", &localdomain }, - { "systemname", &systemname }, - { "mmdfldir", &mmdfldir }, - { "mmdflfil", &mmdflfil }, - { "uucpldir", &uucpldir }, - { "uucplfil", &uucplfil }, - { "mmdelim1", &mmdlm1 }, - { "mmdelim2", &mmdlm2 }, - { "masquerade", &masquerade }, - -#if defined(SMTPMTS) - { "mts", &sm_method }, - { "hostable", &hostable }, - { "sendmail", &sendmail }, -#endif - - { "clientname", &clientname }, - { "servers", &servers }, - { "pophost", &pophost }, - - { "maildelivery", &maildelivery }, - { "everyone", &everyone }, - { "noshell", &NoShell }, - { NULL, NULL } -}; - /* - * Read the configuration file for the nmh interface - * to the mail transport system (MTS). - */ - -void -mts_init (char *name) -{ - const char *cp; - FILE *fp; - static int inited = 0; - - if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL) - return; - mts_read_conf_file(fp); - fclose (fp); - - cp = get_mtsuserconf_pathname(); - if (cp != NULL && - ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) { - mts_read_conf_file(fp); - fclose (fp); - } - - Everyone = atoi (everyone); - - if (strstr(masquerade, "draft_from") != NULL) - draft_from_masquerading = TRUE; - - if (strstr(masquerade, "mmailid") != NULL) - mmailid_masquerading = TRUE; - - if (strstr(masquerade, "username_extension") != NULL) - username_extension_masquerading = TRUE; - -#ifdef SMTPMTS - if (strcmp(sm_method, "smtp") == 0) - sm_mts = MTS_SMTP; - else if (strcmp(sm_method, "sendmail") == 0) - sm_mts = MTS_SENDMAIL; - else { - advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method); - sm_mts = MTS_SMTP; - } -#endif -} - - -#define QUOTE '\\' - -/* - * Convert escaped values, malloc some new space, - * and copy string to malloc'ed memory. - */ - -static char * -tailor_value (unsigned char *s) -{ - int i, r; - char *bp; - char buffer[BUFSIZ]; - size_t len; - - for (bp = buffer; *s; bp++, s++) { - if (*s != QUOTE) { - *bp = *s; - } else { - switch (*++s) { - case 'b': *bp = '\b'; break; - case 'f': *bp = '\f'; break; - case 'n': *bp = '\n'; break; - case 't': *bp = '\t'; break; - - case 0: s--; - case QUOTE: - *bp = QUOTE; - break; - - default: - if (!isdigit (*s)) { - *bp++ = QUOTE; - *bp = *s; - } - r = *s != '0' ? 10 : 8; - for (i = 0; isdigit (*s); s++) - i = i * r + *s - '0'; - s--; - *bp = toascii (i); - break; - } - } - } - *bp = 0; - - len = strlen (buffer) + 1; - bp = mh_xmalloc (len); - memcpy (bp, buffer, len); - - return bp; -} - -/* - * Get the fully qualified name of the local host. - */ - +** Get the fully qualified name of the local host. +*/ char * -LocalName (void) +LocalName(void) { - static char buffer[BUFSIZ] = ""; - struct addrinfo hints, *res; -#ifdef HAVE_UNAME - struct utsname name; -#endif - - /* check if we have cached the local name */ - if (buffer[0]) - return buffer; + static char buffer[BUFSIZ] = ""; + struct addrinfo hints, *res; - mts_init ("mts"); + /* check if we have cached the local name */ + if (buffer[0]) + return buffer; - /* check if the mts.conf file specifies a "localname" */ - if (*localname) { - strncpy (buffer, localname, sizeof(buffer)); - } else { memset(buffer, 0, sizeof(buffer)); -#ifdef HAVE_UNAME /* first get our local name */ - uname (&name); - strncpy (buffer, name.nodename, sizeof(buffer) - 1); -#else - /* first get our local name */ - gethostname (buffer, sizeof(buffer) - 1); -#endif - /* now fully qualify our name */ + gethostname(buffer, sizeof(buffer) - 1); + /* now fully qualify our name */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = PF_UNSPEC; if (getaddrinfo(buffer, NULL, &hints, &res) == 0) { - strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1); - freeaddrinfo(res); + strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1); + freeaddrinfo(res); } - } - /* - * If the mts.conf file specifies a "localdomain", - * we append that now. This should rarely be needed. - */ - if (*localdomain) { - strcat (buffer, "."); - strcat (buffer, localdomain); - } - - return buffer; -} - - -/* - * This is only for UUCP mail. It gets the hostname - * as part of the UUCP "domain". - */ - -char * -SystemName (void) -{ - static char buffer[BUFSIZ] = ""; - -#ifdef HAVE_UNAME - struct utsname name; -#endif - - /* check if we have cached the system name */ - if (buffer[0]) return buffer; - - mts_init ("mts"); - - /* check if mts.conf file specifies a "systemname" */ - if (*systemname) { - strncpy (buffer, systemname, sizeof(buffer)); - return buffer; - } - -#ifdef HAVE_UNAME - uname (&name); - strncpy (buffer, name.nodename, sizeof(buffer)); -#else - gethostname (buffer, sizeof(buffer)); -#endif - - return buffer; } /* - * Get the username of current user - */ - +** Get the username of current user +*/ char * -getusername (void) +getusername(void) { - if (username[0] == '\0') - getuserinfo(); + if (username[0] == '\0') + getuserinfo(); - return username; + return username; } /* - * Get full name of current user (typically from GECOS - * field of password file). - */ - +** Get full name of current user (typically from GECOS +** field of password file). +*/ char * -getfullname (void) +getfullname(void) { - if (username[0] == '\0') - getuserinfo(); + if (username[0] == '\0') + getuserinfo(); - return fullname; + return fullname; } /* - * Find the user's username and full name, and cache them. - * Also, handle "mmailid" username masquerading controlled from the GECOS field - * of the passwd file. - */ - +** Find the user's username and full name, and cache them. +*/ static void -getuserinfo (void) +getuserinfo(void) { - register unsigned char *cp; - register char *np; - register struct passwd *pw; + unsigned char *cp; + char *np; + struct passwd *pw; + int needquotes = 0; + char tmp[BUFSIZ]; + char *tp; - if ((pw = getpwuid (getuid ())) == NULL - || pw->pw_name == NULL - || *pw->pw_name == '\0') { - strncpy (username, "unknown", sizeof(username)); - snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)", - (int) getuid ()); - return; - } + if (!(pw = getpwuid(getuid())) || !pw->pw_name || !*pw->pw_name) { + strncpy(username, "unknown", sizeof(username)); + snprintf(fullname, sizeof(fullname), + "The Unknown User-ID (%d)", (int)getuid()); + return; + } - np = pw->pw_gecos; + np = pw->pw_gecos; - /* Get the user's real name from the GECOS field. Stop once we hit a ',', - which some OSes use to separate other 'finger' information in the GECOS - field, like phone number. Also, if mmailid masquerading is turned on due - to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we - hit a '<' (which should precede any ','s). */ -#ifndef BSD42 - if (mmailid_masquerading) - /* Stop at ',' or '<'. */ - for (cp = fullname; *np != '\0' && *np != ',' && *np != '<'; - *cp++ = *np++) - continue; - else - /* Allow '<' as a legal character of the user's name. This code is - basically a duplicate of the code above the "else" -- we don't - collapse it down to one copy and put the mmailid_masquerading check - inside the loop with "(x ? y : z)" because that's inefficient and the - value'll never change while it's in there. */ - for (cp = fullname; *np != '\0' && *np != ','; - *cp++ = *np++) - continue; -#else /* BSD42 */ - /* On BSD(-derived) systems, the system utilities that deal with the GECOS - field (finger, mail, sendmail, etc.) translate any '&' character in it to - the login name, with the first letter capitalized. So, for instance, - fingering a user "bob" with the GECOS field "& Jones" would reveal him to - be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do - the translation for you, so we have to do it manually here. */ - if (mmailid_masquerading) - /* Stop at ',' or '<'. */ - for (cp = fullname; - *np != '\0' && *np != ',' && *np != '<';) { - if (*np == '&') { /* blech! */ - strcpy (cp, pw->pw_name); - *cp = toupper(*cp); - while (*cp) - cp++; - np++; - } else { + /* + ** Get the user's real name from the GECOS field. Stop once + ** we hit a ',', which some OSes use to separate other 'finger' + ** information in the GECOS field, like phone number. + */ + for (cp = tmp; *np != '\0' && *np != ',';) { *cp++ = *np++; - } } - else - /* Allow '<' as a legal character of the user's name. This code is - basically a duplicate of the code above the "else" -- we don't - collapse it down to one copy and put the mmailid_masquerading check - inside the loop with "(x ? y : z)" because that's inefficient and the - value'll never change while it's in there. */ - for (cp = fullname; - *np != '\0' && *np != ',';) { - if (*np == '&') { /* blech! */ - strcpy (cp, pw->pw_name); - *cp = toupper(*cp); - while (*cp) - cp++; - np++; - } else { - *cp++ = *np++; - } + *cp = '\0'; + strncpy(username, pw->pw_name, sizeof(username)); + + /* + ** The $SIGNATURE environment variable overrides the GECOS field's + ** idea of your real name. + */ + if ((cp = getenv("SIGNATURE")) && *cp) + strncpy(tmp, cp, sizeof(tmp)); + + /* quote the fullname as needed */ + needquotes = 0; + for (tp=tmp; *tp; tp++) { + switch (*tp) { + case '(': case ')': case '<': case '>': case '[': case ']': + case ':': case ';': case '@': case '\\': case ',': case '.': + case '"': /* cf. RFC 5322 */ + break; /* ... the switch */ + default: + continue; /* ... the loop */ + } + /* we've found a special char */ + needquotes = 1; + break; + } + cp=fullname; + if (needquotes) { + *cp++ = '"'; + } + for (tp=tmp; *tp; *cp++=*tp++) { + if (*tp == '"') { + *cp++ = '\\'; /* prepend backslash */ + } + } + if (needquotes) { + *cp++ = '"'; } -#endif /* BSD42 */ - *cp = '\0'; - - if (mmailid_masquerading) { - /* Do mmailid processing. The GECOS field should have the form - "Full Name ". For instance, - "Dan Harkless ". Naturally, you'll want your MTA to - have an alias (e.g. in /etc/aliases) from "fakeusername" to your - account name. */ - if (*np) - np++; - for (cp = username; *np && *np != '>'; *cp++ = *np++) - continue; *cp = '\0'; - } - if (!mmailid_masquerading || *np == '\0') - strncpy (username, pw->pw_name, sizeof(username)); - - /* The $SIGNATURE environment variable overrides the GECOS field's idea of - your real name. */ - if ((cp = getenv ("SIGNATURE")) && *cp) - strncpy (fullname, cp, sizeof(fullname)); - - if (strchr(fullname, '.')) { /* quote any .'s */ - char tmp[BUFSIZ]; - - /* should quote "'s too */ - snprintf (tmp, sizeof(tmp), "\"%s\"", fullname); - strncpy (fullname, tmp, sizeof(fullname)); - } - - return; -} - -static const char* -get_mtsconf_pathname (void) -{ - const char *cp = getenv ( "MHMTSCONF "); - if (cp != NULL && *cp != '\0') { - return cp; - } - return mtsconf; -} - -static const char* -get_mtsuserconf_pathname (void) -{ - const char *cp = getenv ( "MHMTSUSERCONF" ); - if (cp != NULL && *cp != '\0') { - return cp; - } - return NULL; -} -static void -mts_read_conf_file (FILE *fp) -{ - unsigned char *bp; - char *cp, buffer[BUFSIZ]; - struct bind *b; - - while (fgets (buffer, sizeof(buffer), fp)) { - if (!(cp = strchr(buffer, '\n'))) - break; - *cp = 0; - if (*buffer == '#' || *buffer == '\0') - continue; - if (!(bp = strchr(buffer, ':'))) - break; - *bp++ = 0; - while (isspace (*bp)) - *bp++ = 0; - - for (b = binds; b->keyword; b++) - if (!strcmp (buffer, b->keyword)) - break; - if (b->keyword && (cp = tailor_value (bp))) - *b->value = cp; - } + return; } diff --git a/sbr/norm_charmap.c b/sbr/norm_charmap.c index ae81046..02e6a3c 100644 --- a/sbr/norm_charmap.c +++ b/sbr/norm_charmap.c @@ -1,28 +1,28 @@ /* - * The Single Unix Specification function nl_langinfo(CODESET) - * returns the name of the encoding used by the currently selected - * locale: - * - * http://www.opengroup.org/onlinepubs/7908799/xsh/langinfo.h.html - * - * Unfortunately the encoding names are not yet standardized. - * This function knows about the encoding names used on many - * different systems and converts them where possible into - * the corresponding MIME charset name registered in - * - * http://www.iana.org/assignments/character-sets - * - * Please extend it as needed and suggest improvements to the author. - * - * Markus.Kuhn@cl.cam.ac.uk -- 2002-03-11 - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted. The author - * disclaims all warranties with regard to this software. - * - * Latest version: - * - * http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c - */ +** The Single Unix Specification function nl_langinfo(CODESET) +** returns the name of the encoding used by the currently selected +** locale: +** +** http://www.opengroup.org/onlinepubs/7908799/xsh/langinfo.h.html +** +** Unfortunately the encoding names are not yet standardized. +** This function knows about the encoding names used on many +** different systems and converts them where possible into +** the corresponding MIME charset name registered in +** +** http://www.iana.org/assignments/character-sets +** +** Please extend it as needed and suggest improvements to the author. +** +** Markus.Kuhn@cl.cam.ac.uk -- 2002-03-11 +** Permission to use, copy, modify, and distribute this software +** for any purpose and without fee is hereby granted. The author +** disclaims all warranties with regard to this software. +** +** Latest version: +** +** http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c +*/ #include @@ -33,80 +33,86 @@ static char buf[16]; char * norm_charmap(char *name) { - char *p; - - if (!name) - return name; - - /* Many need no remapping, but they are listed here so you - * can see what output to expect, and modify for your needs - * as necessary. */ - if (!strcmp(name, "UTF-8")) - return "UTF-8"; - if (!strcmp(name, "EUC-JP")) - return "EUC-JP"; - if (!strcmp(name, "EUC-KR")) - return "EUC-KR"; - if (!strcmp(name, "EUC-TW")) - return "EUC-TW"; - if (!strcmp(name, "KOI8-R")) - return "KOI8-R"; - if (!strcmp(name, "KOI8-U")) - return "KOI8-U"; - if (!strcmp(name, "GBK")) - return "GBK"; - if (!strcmp(name, "GB2312")) - return "GB2312"; - if (!strcmp(name, "GB18030")) - return "GB18030"; - if (!strcmp(name, "VSCII")) - return "VSCII"; - - /* ASCII comes in many names */ - if (!strcmp(name, "ASCII") || - !strcmp(name, "US-ASCII") || - !strcmp(name, "ANSI_X3.4-1968") || - !strcmp(name, "646") || - !strcmp(name, "ISO646") || - !strcmp(name, "ISO_646.IRV")) - return "US-ASCII"; + char *p; - /* ISO 8859 will be converted to "ISO-8859-x" */ - if ((p = strstr(name, "8859-"))) { - memcpy(buf, "ISO-8859-\0\0", 12); - p += 5; - if (digit(*p)) { - buf[9] = *p++; - if (digit(*p)) buf[10] = *p++; - return buf; - } - } + if (!name) + return name; - /* Windows code pages will be converted to "WINDOWS-12xx" */ - if ((p = strstr(name, "CP12"))) { - memcpy(buf, "WINDOWS-12\0\0", 13); - p += 4; - if (digit(*p)) { - buf[10] = *p++; - if (digit(*p)) buf[11] = *p++; - return buf; - } - } + /* + ** Many need no remapping, but they are listed here so you + ** can see what output to expect, and modify for your needs + ** as necessary. + */ + if (strcmp(name, "UTF-8")==0) + return "UTF-8"; + if (strcmp(name, "EUC-JP")==0) + return "EUC-JP"; + if (strcmp(name, "EUC-KR")==0) + return "EUC-KR"; + if (strcmp(name, "EUC-TW")==0) + return "EUC-TW"; + if (strcmp(name, "KOI8-R")==0) + return "KOI8-R"; + if (strcmp(name, "KOI8-U")==0) + return "KOI8-U"; + if (strcmp(name, "GBK")==0) + return "GBK"; + if (strcmp(name, "GB2312")==0) + return "GB2312"; + if (strcmp(name, "GB18030")==0) + return "GB18030"; + if (strcmp(name, "VSCII")==0) + return "VSCII"; - /* TIS-620 comes in at least the following two forms */ - if (!strcmp(name, "TIS-620") || - !strcmp(name, "TIS620.2533")) - return "ISO-8859-11"; + /* ASCII comes in many names */ + if (strcmp(name, "ASCII")==0 || + strcmp(name, "US-ASCII")==0 || + strcmp(name, "ANSI_X3.4-1968")==0 || + strcmp(name, "646")==0 || + strcmp(name, "ISO646")==0 || + strcmp(name, "ISO_646.IRV")==0) + return "US-ASCII"; - /* For some, uppercase/lowercase might differ */ - if (!strcmp(name, "Big5") || !strcmp(name, "BIG5")) - return "Big5"; - if (!strcmp(name, "Big5HKSCS") || !strcmp(name, "BIG5HKSCS")) - return "Big5HKSCS"; + /* ISO 8859 will be converted to "ISO-8859-x" */ + if ((p = strstr(name, "8859-"))) { + memcpy(buf, "ISO-8859-\0\0", 12); + p += 5; + if (digit(*p)) { + buf[9] = *p++; + if (digit(*p)) + buf[10] = *p++; + return buf; + } + } - /* I don't know of any implementation of nl_langinfo(CODESET) out - * there that returns anything else (and I'm not even certain all of - * the above occur in the wild), but just in case, as a fallback, - * return the unmodified name. */ - return name; + /* Windows code pages will be converted to "WINDOWS-12xx" */ + if ((p = strstr(name, "CP12"))) { + memcpy(buf, "WINDOWS-12\0\0", 13); + p += 4; + if (digit(*p)) { + buf[10] = *p++; + if (digit(*p)) + buf[11] = *p++; + return buf; + } + } + + /* TIS-620 comes in at least the following two forms */ + if (strcmp(name, "TIS-620")==0 || + strcmp(name, "TIS620.2533")==0) + return "ISO-8859-11"; + + /* For some, uppercase/lowercase might differ */ + if (strcmp(name, "Big5")==0 || strcmp(name, "BIG5")==0) + return "Big5"; + if (strcmp(name, "Big5HKSCS")==0 || strcmp(name, "BIG5HKSCS")==0) + return "Big5HKSCS"; + + /* + ** I don't know of any implementation of nl_langinfo(CODESET) out + ** there that returns anything else (and I'm not even certain all of + ** the above occur in the wild), but just in case, as a fallback, + ** return the unmodified name. + */ + return name; } diff --git a/sbr/path.c b/sbr/path.c index 5a9529d..21796a7 100644 --- a/sbr/path.c +++ b/sbr/path.c @@ -1,168 +1,302 @@ - /* - * path.c -- return a pathname - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** path.c -- return or convert paths +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include +#include + + +/* +** Find the location of a format or configuration +** file, and return its absolute pathname. +** +** 1) If it begins with ~user, then expand it. +** 2) Next, if already absolute pathname, then leave unchanged. +** 3) Next, check in mmh directory. +** 4) Next, check in mmh `etc' directory. +** 5) As fall-back, return `file' unchanged. +*/ +char * +etcpath(char *file) +{ + static char epath[PATH_MAX]; + char *cp; + char *pp; + struct passwd *pw; + + /* XXX: here was: ``context_read();'' -- why? */ + if (*file == '~') { + /* Expand `~user' */ + if ((cp = strchr(pp = file + 1, '/'))) + *cp++ = '\0'; + if (*pp == '\0') { + pp = mypath; + } else { + if ((pw = getpwnam(pp))) + pp = pw->pw_dir; + else { + if (cp) + *--cp = '/'; + goto try_it; + } + } + + snprintf(epath, sizeof epath, "%s/%s", pp, cp ? cp : ""); + if (cp) + *--cp = '/'; -#define CWD "./" -#define NCWD (sizeof(CWD) - 1) -#define DOT "." -#define DOTDOT ".." -#define PWD "../" -#define NPWD (sizeof(PWD) - 1) + if (access(epath, R_OK) != NOTOK) + return epath; /* else fall */ + } + +try_it: + if (*file == '/') { + /* absolute pathname, return it */ + return file; + } + + /* Check mmh directory */ + snprintf(epath, sizeof epath, "%s/%s", mmhpath, file); + if (access(epath, R_OK) != NOTOK) + return epath; + + /* Check nmh `etc' directory */ + snprintf(epath, sizeof epath, "%s/%s", mhetcdir, file); + if (access(epath, R_OK) != NOTOK) + return epath; + + /* The fall-back */ + return file; +} -static char *pwds; /* - * static prototypes - */ -static char *expath(char *,int); -static void compath(char *); +** Compactify a path name by removing unneccessary parts. +** Removes trailing slashes. Cares to never remove all characters. +** Modifies f (never enlarges it). +** +** FIXME: Cannot use strcpy() as the areas overlap! +*/ +static void +packpath(char *f) +{ + char *cp, *dp; + int abspath; + + if (!f || !*f) { + return; + } + abspath = (*f == '/'); + + for (cp=f; *cp; ) { + if (*cp != '/') { + /* Skip. Interesting places are only after slashes. */ + /* We don't care about "./" beginnings */ + cp++; + continue; + } + + /* Let's see what follows the slash ... */ + switch (*++cp) { + case '\0': + *--cp = '\0'; + continue; /* ... and thus exit the loop */ + + case '/': + /* reduce subsequent slashes to one */ + for (dp = cp; *dp == '/'; dp++) { + continue; + } + strcpy(cp, dp); + cp--; + continue; /* ... at the slash */ + + case '.': + if (cp[1] == '/' || cp[1] == '\0') { + /* one-dot element */ + strcpy(cp-1, cp+1); + cp--; + continue; + } else if ((strncmp(cp, "../", 3) == 0) || + (strcmp(cp, "..") == 0)) { + /* dot-dot element */ + /* crop out previous path element */ + for (dp=cp-2; dp>f && *dp!='/'; dp--) { + continue; + } + if (dp < f) { + /* path starts with "/.." */ + dp = f; + } + strcpy(dp, cp+2); + cp = dp; + continue; + } else { + /* a normal hidden file */ + cp++; + continue; + } + + default: + /* nothing special */ + cp++; + continue; + } + } + + if (!strlen(f)) { + /* We have removed everything, but need something. */ + strcpy(f, abspath ? "/" : "."); + } +} + + + +/* +** Get the default folder +** Return the Inbox profile entry or, as fallback, the compile time default +** Returns a pointer to the abs folpath +*/ char * -pluspath(char *name) +getdeffol(void) { - return path(name + 1, *name == '+' ? TFOLDER : TSUBCWF); + char *folder = context_find(inbox); + + if (!folder || !*folder) { + folder = defaultfolder; /* the compile time default */ + } + if (*folder == '+') { + folder++; + } + return folder; +} + + +/* +** Get the current folder +** Return the Current-Folder context entry or, as fallback, the default folder +** Returns a pointer to the abs folpath +** +** Equivalent to: expandfol("@") +*/ +char * +getcurfol(void) +{ + char *folder = context_find(curfolder); + + if (!folder || !*folder) { + folder = getdeffol(); + } + return folder; } + +/* +** Expand folder path +** Convert rel folpaths (@) into abs folpaths +** dir paths are simply passed through +** Returns the abs folpath (without prefix), in static mem +** +** TODO: Always copy into the static buffer, or just return the pointer? +*/ char * -path(char *name, int flag) +expandfol(char *f) { - register char *cp, *ep; + static char buf[BUFSIZ]; - if ((cp = expath (name, flag)) - && (ep = cp + strlen (cp) - 1) > cp - && *ep == '/') - *ep = '\0'; + if (*f == '@') { + /* f = concat(getcurfol(), "/", f+1, NULL); */ + snprintf(buf, sizeof buf, "%s/%s", getcurfol(), f+1); - return cp; + } else if (*f == '+') { + strcpy(buf, f+1); + + } else { + strcpy(buf, f); + } + packpath(buf); + return buf; } -static char * -expath (char *name, int flag) +/* +** Expand directory path +** Convert rel dirpath into abs dirpath +** The argument is assumed to be a dir path relative to the cwd, +** except when beginning with '/' (then it will be passed through). +** Returns the abs dirpath, in static mem +** +** TODO: Always copy into the static buffer, or just return the pointer? +*/ +char * +expanddir(char *d) { - register char *cp, *ep; - char buffer[BUFSIZ]; - - if (flag == TSUBCWF) { - snprintf (buffer, sizeof(buffer), "%s/%s", getfolder (1), name); - name = m_mailpath (buffer); - compath (name); - snprintf (buffer, sizeof(buffer), "%s/", m_maildir ("")); - if (ssequal (buffer, name)) { - cp = name; - name = getcpy (name + strlen (buffer)); - free (cp); + static char buf[BUFSIZ]; + int len; + + if (*d == '/') { + strcpy(buf, d); + } else { + getcwd(buf, sizeof buf); + len = strlen(buf); + snprintf(buf+len, sizeof buf - len, "/%s", d); } - flag = TFOLDER; - } - - if (*name == '/' - || (flag == TFOLDER - && (strncmp (name, CWD, NCWD) - && strcmp (name, DOT) - && strcmp (name, DOTDOT) - && strncmp (name, PWD, NPWD)))) - return getcpy (name); - - if (pwds == NULL) - pwds = pwd (); - - if (strcmp (name, DOT) == 0 || strcmp (name, CWD) == 0) - return getcpy (pwds); - - ep = pwds + strlen (pwds); - if ((cp = strrchr(pwds, '/')) == NULL) - cp = ep; - else - if (cp == pwds) - cp++; - - if (strncmp (name, CWD, NCWD) == 0) - name += NCWD; - - if (strcmp (name, DOTDOT) == 0 || strcmp (name, PWD) == 0) { - snprintf (buffer, sizeof(buffer), "%.*s", (int)(cp - pwds), pwds); - return getcpy (buffer); - } - - if (strncmp (name, PWD, NPWD) == 0) - name += NPWD; - else - cp = ep; - - snprintf (buffer, sizeof(buffer), "%.*s/%s", (int)(cp - pwds), pwds, name); - return getcpy (buffer); + packpath(buf); + return buf; } -static void -compath (char *f) +/* +** Anypath to absolute directory path +** Convert any kind of path into an abs dirpath +** A path without distinguishing prefix is assumed to be an abs folpath +** Abs dirpaths are passed unchanged +** Rel dirpaths ('.') get prefixed with the (abs) cwd +** Return pointer to static memory +** +** To get the dir path of the mail storage root, call: toabsdir("+") +** +** TODO: check lengths for copies +*/ +char * +toabsdir(char *path) { - register char *cp, *dp; + static char buf[BUFSIZ]; - if (*f != '/') - return; + if (*path == '/') { + /* nothing to do */ + strncpy(buf, path, sizeof buf); + packpath(buf); + return buf; - for (cp = f; *cp;) - if (*cp == '/') { - switch (*++cp) { - case 0: - if (--cp > f) - *cp = '\0'; - break; + } else if (*path == '.') { + /* rel dir path */ + strncpy(buf, expanddir(path), sizeof buf); + return buf; - case '/': - for (dp = cp; *dp == '/'; dp++) - continue; - strcpy (cp--, dp); - continue; - - case '.': - if (strcmp (cp, DOT) == 0) { - if (cp > f + 1) - cp--; - *cp = '\0'; - break; - } - if (strcmp (cp, DOTDOT) == 0) { - for (cp -= 2; cp > f; cp--) - if (*cp == '/') - break; - if (cp <= f) - cp = f + 1; - *cp = '\0'; - break; - } - if (strncmp (cp, PWD, NPWD) == 0) { - for (dp = cp - 2; dp > f; dp--) - if (*dp == '/') - break; - if (dp <= f) - dp = f; - strcpy (dp, cp + NPWD - 1); - cp = dp; - continue; - } - if (strncmp (cp, CWD, NCWD) == 0) { - strcpy (cp - 1, cp + NCWD - 1); - cp--; - continue; - } - continue; - - default: - cp++; - continue; - } - break; + } else { + /* folder path */ + char *cp=buf, *pp; + + if (!(pp = context_find("path")) || !*pp) { + adios(NULL, "Non-empty profile entry `Path' required"); + } + if (*pp != '/') { + /* Path is relative to $HOME */ + snprintf(buf, sizeof buf, "%s/", mypath); + cp += strlen(buf); + } + strcpy(cp, pp); + packpath(buf); + /* append the mail folder */ + cp = buf + strlen(buf); + *cp++ = '/'; + strcpy(cp, expandfol(path)); + return buf; } - else - cp++; } diff --git a/sbr/peekc.c b/sbr/peekc.c deleted file mode 100644 index 5ed8c3f..0000000 --- a/sbr/peekc.c +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * peekc.c -- peek at the next character in a stream - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -peekc(FILE *fp) -{ - register int c; - - c = getc(fp); - ungetc(c, fp); - return c; -} diff --git a/sbr/pidstatus.c b/sbr/pidstatus.c index f16f7e0..c4e1e75 100644 --- a/sbr/pidstatus.c +++ b/sbr/pidstatus.c @@ -1,22 +1,18 @@ - /* - * pidstatus.c -- report child's status - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** pidstatus.c -- report child's status +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * auto-generated header - */ -#include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif +** auto-generated header +*/ +#include "sigmsg.h" +#include #ifndef WTERMSIG # define WTERMSIG(s) ((int)((s) & 0x7F)) @@ -27,39 +23,40 @@ #endif int -pidstatus (int status, FILE *fp, char *cp) +pidstatus(int status, FILE *fp, char *cp) { - int signum; - -/* - * I have no idea what this is for (rc) - * so I'm commenting it out for right now. - * - * if ((status & 0xff00) == 0xff00) - * return status; - */ - - /* If child process returned normally */ - if (WIFEXITED(status)) { - if ((signum = WEXITSTATUS(status))) { - if (cp) - fprintf (fp, "%s: ", cp); - fprintf (fp, "exit %d\n", signum); - } - } else if (WIFSIGNALED(status)) { - /* If child process terminated due to receipt of a signal */ - signum = WTERMSIG(status); - if (signum != SIGINT) { - if (cp) - fprintf (fp, "%s: ", cp); - fprintf (fp, "signal %d", signum); - if (signum >= 0 && signum < sizeof(sigmsg) && sigmsg[signum] != NULL) - fprintf (fp, " (%s%s)\n", sigmsg[signum], - WCOREDUMP(status) ? ", core dumped" : ""); - else - fprintf (fp, "%s\n", WCOREDUMP(status) ? " (core dumped)" : ""); + int signum; + + /* + ** I have no idea what this is for (rc) + ** so I'm commenting it out for right now. + ** + ** if ((status & 0xff00) == 0xff00) + ** return status; + */ + + /* If child process returned normally */ + if (WIFEXITED(status)) { + if ((signum = WEXITSTATUS(status))) { + if (cp) + fprintf(fp, "%s: ", cp); + fprintf(fp, "exit %d\n", signum); + } + } else if (WIFSIGNALED(status)) { + /* If child process terminated due to receipt of a signal */ + signum = WTERMSIG(status); + if (signum != SIGINT) { + if (cp) + fprintf(fp, "%s: ", cp); + fprintf(fp, "signal %d", signum); + if (signum >= 0 && signum < (int)sizeof(sigmsg) && + sigmsg[signum] != NULL) + fprintf(fp, " (%s%s)\n", sigmsg[signum], + WCOREDUMP(status) ? ", core dumped" : ""); + else + fprintf(fp, "%s\n", WCOREDUMP(status) ? " (core dumped)" : ""); + } } - } - return status; + return status; } diff --git a/sbr/pidwait.c b/sbr/pidwait.c index ef42e1a..ba9bae2 100644 --- a/sbr/pidwait.c +++ b/sbr/pidwait.c @@ -1,56 +1,38 @@ - /* - * pidwait.c -- wait for child to exit - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** pidwait.c -- wait for child to exit +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif +#include int -pidwait (pid_t id, int sigsok) +pidwait(pid_t id, int sigsok) { - pid_t pid; - SIGNAL_HANDLER istat = NULL, qstat = NULL; - -#ifdef HAVE_UNION_WAIT - union wait status; -#else - int status; -#endif - - if (sigsok == -1) { - /* ignore a couple of signals */ - istat = SIGNAL (SIGINT, SIG_IGN); - qstat = SIGNAL (SIGQUIT, SIG_IGN); - } - -#ifdef HAVE_WAITPID - while ((pid = waitpid(id, &status, 0)) == -1 && errno == EINTR) - ; -#else - while ((pid = wait(&status)) != -1 && pid != id) - continue; -#endif - - if (sigsok == -1) { - /* reset the signal handlers */ - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - } - -#ifdef HAVE_UNION_WAIT - return (pid == -1 ? -1 : status.w_status); -#else - return (pid == -1 ? -1 : status); -#endif + pid_t pid; + SIGNAL_HANDLER istat = NULL, qstat = NULL; + int status; + + if (sigsok == -1) { + /* ignore a couple of signals */ + istat = SIGNAL(SIGINT, SIG_IGN); + qstat = SIGNAL(SIGQUIT, SIG_IGN); + } + + while ((pid = waitpid(id, &status, 0)) == -1 && errno == EINTR) + ; + + if (sigsok == -1) { + /* reset the signal handlers */ + SIGNAL(SIGINT, istat); + SIGNAL(SIGQUIT, qstat); + } + + return (pid == -1 ? -1 : status); } diff --git a/sbr/print_help.c b/sbr/print_help.c index e045788..039ab31 100644 --- a/sbr/print_help.c +++ b/sbr/print_help.c @@ -1,31 +1,30 @@ - /* - * print_help.c -- print a help message, and possibly the - * -- profile/context entries for this command - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** print_help.c -- print a help message, and possibly the +** -- profile/context entries for this command +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -print_help (char *str, struct swit *swp, int print_context) +print_help(char *str, struct swit *swp, int print_context) { - char *s; + char *s; - /* print Usage string */ - printf ("Usage: %s\n", str); + /* print Usage string */ + printf("Usage: %s\n", str); - /* print all the switches */ - printf (" switches are:\n"); - print_sw (ALL, swp, "-", stdout); + /* print all the switches */ + printf(" switches are:\n"); + print_sw(ALL, swp, "-", stdout); - /* - * check if we should print any profile entries - */ - if (print_context && (s = context_find (invo_name))) - printf ("\nProfile: %s\n", s); + /* + ** check if we should print any profile entries + */ + if (print_context && (s = context_find(invo_name))) + printf("\nProfile: %s\n", s); } diff --git a/sbr/print_sw.c b/sbr/print_sw.c index 6d475ab..3a70c54 100644 --- a/sbr/print_sw.c +++ b/sbr/print_sw.c @@ -1,56 +1,56 @@ - /* - * print_sw.c -- print switches - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** print_sw.c -- print switches +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -print_sw (char *substr, struct swit *swp, char *prefix, FILE *fp) +print_sw(char *substr, struct swit *swp, char *prefix, FILE *fp) { - int len, optno; - register int i; - register char *cp, *cp1, *sp; - char buf[128]; + int len, optno; + register int i; + register char *cp, *cp1, *sp; + char buf[128]; - len = strlen(substr); - for (; swp->sw; swp++) { - /* null matches all strings */ - if (!*substr || (ssequal (substr, swp->sw) && len >= swp->minchars)) { - optno = 0; - /* next switch */ - if ((sp = (&swp[1])->sw)) { - if (!*substr && sp[0] == 'n' && sp[1] == 'o' && - strcmp (&sp[2], swp->sw) == 0 && ( - ((&swp[1])->minchars == 0 && swp->minchars == 0) || - ((&swp[1])->minchars == (swp->minchars) + 2))) - optno++; - } + len = strlen(substr); + for (; swp->sw; swp++) { + /* null matches all strings */ + if (!*substr || (strncmp(swp->sw, substr, len)==0 && + len >= swp->minchars)) { + optno = 0; + /* next switch */ + if ((sp = (&swp[1])->sw)) { + if (!*substr && sp[0] == 'n' && sp[1] == 'o' && + strcmp(&sp[2], swp->sw) == 0 && ( + ((&swp[1])->minchars == 0 && swp->minchars == 0) || + ((&swp[1])->minchars == (swp->minchars) + 2))) + optno++; + } - if (swp->minchars > 0) { - cp = buf; - *cp++ = '('; - if (optno) { - strcpy (cp, "[no]"); - cp += strlen (cp); + if (swp->minchars > 0) { + cp = buf; + *cp++ = '('; + if (optno) { + strcpy(cp, "[no]"); + cp += strlen(cp); + } + for (cp1 = swp->sw, i = 0; i < swp->minchars; i++) + *cp++ = *cp1++; + *cp++ = ')'; + while ((*cp++ = *cp1++)); + fprintf(fp, " %s%s\n", prefix, buf); + } else { + if (!swp->minchars) + fprintf(fp, optno ? " %s[no]%s\n" : " %s%s\n", + prefix, swp->sw); + } + if (optno) + swp++; /* skip -noswitch */ } - for (cp1 = swp->sw, i = 0; i < swp->minchars; i++) - *cp++ = *cp1++; - *cp++ = ')'; - while ((*cp++ = *cp1++)); - fprintf (fp, " %s%s\n", prefix, buf); - } else { - if (!swp->minchars) - fprintf(fp, optno ? " %s[no]%s\n" : " %s%s\n", - prefix, swp->sw); - } - if (optno) - swp++; /* skip -noswitch */ } - } } diff --git a/sbr/print_version.c b/sbr/print_version.c index b828b3c..8361c66 100644 --- a/sbr/print_version.c +++ b/sbr/print_version.c @@ -1,17 +1,16 @@ - /* - * print_version.c -- print a version string - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** print_version.c -- print a version string +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -print_version (char *invo_name) +print_version(char *invo_name) { - printf("%s -- %s\n", invo_name, version_str); + printf("%s -- %s\n", invo_name, version_str); } diff --git a/sbr/push.c b/sbr/push.c deleted file mode 100644 index ce00f68..0000000 --- a/sbr/push.c +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * push.c -- push a fork into the background - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include - - -void -push(void) -{ - pid_t pid; - int i; - - for (i = 0; (pid = fork()) == -1 && i < 5; i++) - sleep (5); - - switch (pid) { - case -1: - /* fork error */ - advise (NULL, "unable to fork, so can't push..."); - break; - - case 0: - /* child, block a few signals and continue */ - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); -#ifdef SIGTSTP - SIGNAL (SIGTSTP, SIG_IGN); - SIGNAL (SIGTTIN, SIG_IGN); - SIGNAL (SIGTTOU, SIG_IGN); -#endif - freopen ("/dev/null", "r", stdin); - freopen ("/dev/null", "w", stdout); - break; - - default: - /* parent, just exit */ - done (0); - } -} - diff --git a/sbr/putenv.c b/sbr/putenv.c index dd66514..5c7279b 100644 --- a/sbr/putenv.c +++ b/sbr/putenv.c @@ -1,11 +1,10 @@ - /* - * putenv.c -- (un)set an envariable - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** putenv.c -- (un)set an envariable +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -13,65 +12,65 @@ extern char **environ; /* - * prototypes - */ -int m_putenv (char *, char *); -int unputenv (char *); -static int nvmatch (char *, char *); +** prototypes +*/ +int m_putenv(char *, char *); +int unputenv(char *); +static int nvmatch(char *, char *); int -m_putenv (char *name, char *value) +m_putenv(char *name, char *value) { - register int i; - register char **ep, **nep, *cp; + register int i; + register char **ep, **nep, *cp; - cp = mh_xmalloc ((size_t) (strlen (name) + strlen (value) + 2)); + cp = mh_xmalloc((size_t) (strlen(name) + strlen(value) + 2)); - sprintf (cp, "%s=%s", name, value); + sprintf(cp, "%s=%s", name, value); - for (ep = environ, i = 0; *ep; ep++, i++) - if (nvmatch (name, *ep)) { - *ep = cp; - return 0; - } + for (ep = environ, i = 0; *ep; ep++, i++) + if (nvmatch(name, *ep)) { + *ep = cp; + return 0; + } - nep = (char **) mh_xmalloc ((size_t) ((i + 2) * sizeof(*nep))); + nep = (char **) mh_xmalloc((size_t) ((i + 2) * sizeof(*nep))); - for (ep = environ, i = 0; *ep; nep[i++] = *ep++) - continue; - nep[i++] = cp; - nep[i] = NULL; - environ = nep; - return 0; + for (ep = environ, i = 0; *ep; nep[i++] = *ep++) + continue; + nep[i++] = cp; + nep[i] = NULL; + environ = nep; + return 0; } int -unputenv (char *name) +unputenv(char *name) { - char **ep, **nep; - - for (ep = environ; *ep; ep++) - if (nvmatch (name, *ep)) - break; - if (*ep == NULL) - return 1; - - for (nep = ep + 1; *nep; nep++) - continue; - *ep = *--nep; - *nep = NULL; - return 0; + char **ep, **nep; + + for (ep = environ; *ep; ep++) + if (nvmatch(name, *ep)) + break; + if (*ep == NULL) + return 1; + + for (nep = ep + 1; *nep; nep++) + continue; + *ep = *--nep; + *nep = NULL; + return 0; } static int -nvmatch (char *s1, char *s2) +nvmatch(char *s1, char *s2) { - while (*s1 == *s2++) - if (*s1++ == '=') - return 1; + while (*s1 == *s2++) + if (*s1++ == '=') + return 1; - return (*s1 == '\0' && *--s2 == '='); + return (*s1 == '\0' && *--s2 == '='); } diff --git a/sbr/r1bindex.c b/sbr/r1bindex.c deleted file mode 100644 index 92818f9..0000000 --- a/sbr/r1bindex.c +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * r1bindex.c -- Given a string and a character, return a pointer - * -- to the right of the rightmost occurrence of the - * -- character. If the character doesn't occur, the - * -- pointer will be at the beginning of the string. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -char * -r1bindex(char *str, int chr) -{ - char *cp; - - /* find null at the end of the string */ - for (cp = str; *cp; cp++) - continue; - - /* backup to the rightmost character */ - --cp; - - /* now search for the rightmost occurrence of the character */ - while (cp >= str && *cp != chr) - --cp; - - /* now move one to the right */ - return (++cp); -} diff --git a/sbr/readconfig.c b/sbr/readconfig.c index 2a68019..d93d04b 100644 --- a/sbr/readconfig.c +++ b/sbr/readconfig.c @@ -1,111 +1,102 @@ - /* - * readconfig.c -- base routine to read nmh configuration files - * -- such as nmh profile, context file, or mhn.defaults. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** readconfig.c -- base routine to read nmh configuration files +** -- such as nmh profile, context file, or mhn.defaults. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include struct procstr { - char *procname; - char **procnaddr; + char *procname; + char **procnaddr; }; static struct procstr procs[] = { - { "context", &context }, - { "mh-sequences", &mh_seq }, - { "buildmimeproc", &buildmimeproc }, - { "faceproc", &faceproc }, - { "fileproc", &fileproc }, - { "incproc", &incproc }, - { "installproc", &installproc }, - { "lproc", &lproc }, - { "mailproc", &mailproc }, - { "mhlproc", &mhlproc }, - { "moreproc", &moreproc }, - { "mshproc", &mshproc }, - { "packproc", &packproc }, - { "postproc", &postproc }, - { "rmfproc", &rmfproc }, - { "rmmproc", &rmmproc }, - { "sendproc", &sendproc }, - { "showmimeproc", &showmimeproc }, - { "showproc", &showproc }, - { "vmhproc", &vmhproc }, - { "whatnowproc", &whatnowproc }, - { "whomproc", &whomproc }, - { NULL, NULL } + { "attachment-header", &attach_hdr }, + { "sign-header", &sign_hdr }, + { "enc-header", &enc_hdr }, + { "context", &context }, + { "mh-sequences", &mh_seq }, + { "draft-folder", &draftfolder }, + { "listproc", &listproc }, + { "sendmail", &sendmail }, + { "trash-folder", &trashfolder }, + { "whatnowproc", &whatnowproc }, + { NULL, NULL } }; static struct node **opp = NULL; void -readconfig (struct node **npp, FILE *ib, char *file, int ctx) +readconfig(struct node **npp, FILE *ib, char *file, int ctx) { - register int state; - register char *cp; - char name[NAMESZ], field[BUFSIZ]; - register struct node *np; - register struct procstr *ps; + register int state; + register char *cp; + char name[NAMESZ], field[BUFSIZ]; + register struct node *np; + register struct procstr *ps; - if (npp == NULL && (npp = opp) == NULL) { - admonish (NULL, "bug: readconfig called but pump not primed"); - return; - } + if (npp == NULL && (npp = opp) == NULL) { + admonish(NULL, "bug: readconfig called but pump not primed"); + return; + } - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), ib)) { - case FLD: - case FLDPLUS: - case FLDEOF: - np = (struct node *) mh_xmalloc (sizeof(*np)); - *npp = np; - *(npp = &np->n_next) = NULL; - np->n_name = getcpy (name); - if (state == FLDPLUS) { - cp = getcpy (field); - while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), ib); - cp = add (field, cp); - } - np->n_field = trimcpy (cp); - free (cp); - } else { - np->n_field = trimcpy (field); - } - np->n_context = ctx; + for (state = FLD;;) { + switch (state = m_getfld(state, name, field, sizeof(field), + ib)) { + case FLD: + case FLDPLUS: + case FLDEOF: + np = (struct node *) mh_xmalloc(sizeof(*np)); + *npp = np; + *(npp = &np->n_next) = NULL; + np->n_name = getcpy(name); + if (state == FLDPLUS) { + cp = getcpy(field); + while (state == FLDPLUS) { + state = m_getfld(state, name, field, + sizeof(field), ib); + cp = add(field, cp); + } + np->n_field = trimcpy(cp); + free(cp); + } else { + np->n_field = trimcpy(field); + } + np->n_context = ctx; - /* - * Now scan the list of `procs' and link in the - * field value to the global variable. - */ - for (ps = procs; ps->procname; ps++) - if (strcmp (np->n_name, ps->procname) == 0) { - *ps->procnaddr = np->n_field; - break; - } - if (state == FLDEOF) - break; - continue; + /* + ** Now scan the list of `procs' and link in + ** the field value to the global variable. + */ + for (ps = procs; ps->procname; ps++) + if (mh_strcasecmp(np->n_name, + ps->procname) == 0) { + *ps->procnaddr = np->n_field; + break; + } + if (state == FLDEOF) + break; + continue; - case BODY: - case BODYEOF: - adios (NULL, "no blank lines are permitted in %s", file); + case BODY: + case BODYEOF: + adios(NULL, "no blank lines are permitted in %s", + file); - case FILEEOF: - break; + case FILEEOF: + break; - default: - adios (NULL, "%s is poorly formatted", file); + default: + adios(NULL, "%s is poorly formatted", file); + } + break; } - break; - } - opp = npp; + opp = npp; } diff --git a/sbr/refile.c b/sbr/refile.c deleted file mode 100644 index fc2793c..0000000 --- a/sbr/refile.c +++ /dev/null @@ -1,51 +0,0 @@ - -/* - * refile.c -- call the "fileproc" to refile the - * -- msg or draft into another folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -refile (char **arg, char *file) -{ - pid_t pid; - register int vecp; - char *vec[MAXARGS]; - - vecp = 0; - vec[vecp++] = r1bindex (fileproc, '/'); - vec[vecp++] = "-nolink"; /* override bad .mh_profile defaults */ - vec[vecp++] = "-nopreserve"; - vec[vecp++] = "-file"; - vec[vecp++] = file; - - if (arg) { - while (*arg) - vec[vecp++] = *arg++; - } - vec[vecp] = NULL; - - context_save(); /* save the context file */ - fflush(stdout); - - switch (pid = vfork()) { - case -1: - advise ("fork", "unable to"); - return -1; - - case 0: - execvp (fileproc, vec); - fprintf (stderr, "unable to exec "); - perror (fileproc); - _exit (-1); - - default: - return (pidwait (pid, -1)); - } -} diff --git a/sbr/remdir.c b/sbr/remdir.c deleted file mode 100644 index 4ce0b14..0000000 --- a/sbr/remdir.c +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * remdir.c -- remove a directory - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -remdir (char *dir) -{ - context_save(); /* save the context file */ - fflush(stdout); - - if (rmdir(dir) == -1) { - admonish (dir, "unable to remove directory"); - return 0; - } - return 1; -} diff --git a/sbr/ruserpass.c b/sbr/ruserpass.c deleted file mode 100644 index 882889c..0000000 --- a/sbr/ruserpass.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Portions of this code are - * Copyright (c) 1985 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include - -static FILE *cfile; - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 64 -#endif - -#define DEFAULT 1 -#define LOGIN 2 -#define PASSWD 3 -#define ACCOUNT 4 -#define MACDEF 5 -#define ID 10 -#define MACH 11 - -static char tokval[100]; - -struct toktab { - char *tokstr; - int tval; -}; - -static struct toktab toktabs[] = { - { "default", DEFAULT }, - { "login", LOGIN }, - { "password", PASSWD }, - { "passwd", PASSWD }, - { "account", ACCOUNT }, - { "machine", MACH }, - { "macdef", MACDEF }, - { 0, 0 } -}; - -/* - * prototypes - */ -static int token(void); - - -void -ruserpass(char *host, char **aname, char **apass) -{ - char *hdir, buf[BUFSIZ]; - int t, usedefault = 0; - struct stat stb; - - hdir = getenv("HOME"); - if (hdir == NULL) - hdir = "."; - snprintf(buf, sizeof(buf), "%s/.netrc", hdir); - cfile = fopen(buf, "r"); - if (cfile == NULL) { - if (errno != ENOENT) - perror(buf); - goto done; - } - - while ((t = token())) { - switch(t) { - case DEFAULT: - usedefault = 1; - /* FALL THROUGH */ - - case MACH: - if (!usedefault) { - if (token() != ID) - continue; - /* - * Allow match either for user's host name. - */ - if (mh_strcasecmp(host, tokval) == 0) - goto match; - continue; - } -match: - while ((t = token()) && t != MACH && t != DEFAULT) { - switch(t) { - case LOGIN: - if (token() && *aname == 0) { - *aname = mh_xmalloc((size_t) strlen(tokval) + 1); - strcpy(*aname, tokval); - } - break; - case PASSWD: - if (fstat(fileno(cfile), &stb) >= 0 && - (stb.st_mode & 077) != 0) { - /* We make this a fatal error to force the user to correct it */ - advise(NULL, "Error - ~/.netrc file must not be world or group readable."); - adios(NULL, "Remove password or correct file permissions."); - } - if (token() && *apass == 0) { - *apass = mh_xmalloc((size_t) strlen(tokval) + 1); - strcpy(*apass, tokval); - } - break; - case ACCOUNT: - break; - - case MACDEF: - goto done_close; - break; - default: - fprintf(stderr, "Unknown .netrc keyword %s\n", tokval); - break; - } - } - goto done; - } - } - -done_close: - fclose(cfile); - -done: - if (!*aname) { - char tmp[80]; - char *myname; - - if ((myname = getlogin()) == NULL) { - struct passwd *pp; - - if ((pp = getpwuid (getuid())) != NULL) - myname = pp->pw_name; - } - printf("Name (%s:%s): ", host, myname); - - fgets(tmp, sizeof(tmp) - 1, stdin); - tmp[strlen(tmp) - 1] = '\0'; - if (*tmp != '\0') { - myname = tmp; - } - - *aname = mh_xmalloc((size_t) strlen(myname) + 1); - strcpy (*aname, myname); - } - - if (!*apass) { - char prompt[256]; - char *mypass; - - snprintf(prompt, sizeof(prompt), "Password (%s:%s): ", host, *aname); - mypass = nmh_getpass(prompt); - - if (*mypass == '\0') { - mypass = *aname; - } - - *apass = mh_xmalloc((size_t) strlen(mypass) + 1); - strcpy (*apass, mypass); - } - -} - -static int -token(void) -{ - char *cp; - int c; - struct toktab *t; - - if (feof(cfile)) - return (0); - while ((c = getc(cfile)) != EOF && - (c == '\n' || c == '\t' || c == ' ' || c == ',')) - continue; - if (c == EOF) - return (0); - cp = tokval; - if (c == '"') { - while ((c = getc(cfile)) != EOF && c != '"') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } else { - *cp++ = c; - while ((c = getc(cfile)) != EOF - && c != '\n' && c != '\t' && c != ' ' && c != ',') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } - *cp = 0; - if (tokval[0] == 0) - return (0); - for (t = toktabs; t->tokstr; t++) - if (!strcmp(t->tokstr, tokval)) - return (t->tval); - return (ID); -} diff --git a/sbr/seq_add.c b/sbr/seq_add.c index 68fa724..fd18a11 100644 --- a/sbr/seq_add.c +++ b/sbr/seq_add.c @@ -1,191 +1,182 @@ - /* - * seq_add.c -- add message(s) to a sequence - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_add.c -- add message(s) to a sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * Add all the SELECTED messages to a (possibly new) sequence. - * - * If public == 1, make sequence public. - * If public == 0, make sequence private. - * If public == -1, leave the public/private bit alone for existing - * sequences. For new sequences, set this bit based - * on its readonly status. - * - * If error, return 0, else return 1. - */ +** Add all the SELECTED messages to a (possibly new) sequence. +** +** If public == 1, make sequence public. +** If public == 0, make sequence private. +** If public == -1, leave the public/private bit alone for existing +** sequences. For new sequences, set this bit based +** on its readonly status. +** +** If error, return 0, else return 1. +*/ int -seq_addsel (struct msgs *mp, char *cp, int public, int zero) +seq_addsel(struct msgs *mp, char *cp, int public, int zero) { - int i, msgnum, new_seq = 1; - - if (!seq_nameok (cp)) - return 0; - - /* - * We keep mp->curmsg and "cur" sequence in sync. - * See seq_list() and seq_init(). - */ - if (!strcmp (current,cp)) - mp->curmsg = mp->hghsel; - - /* - * Get the number for this sequence - */ - for (i = 0; mp->msgattrs[i]; i++) { - if (!strcmp (mp->msgattrs[i], cp)) { - new_seq = 0; - break; + unsigned int i; + int msgnum, new_seq = 1; + + if (!seq_nameok(cp)) + return 0; + + /* + ** We keep mp->curmsg and cur sequence in sync. + ** See seq_list() and seq_init(). + */ + if (strcmp(seq_cur, cp)==0) + mp->curmsg = mp->hghsel; + + /* + ** Get the number for this sequence + */ + for (i = 0; mp->msgattrs[i]; i++) { + if (strcmp(mp->msgattrs[i], cp)==0) { + new_seq = 0; + break; + } } - } - - /* - * If this is a new sequence, add a slot for it - */ - if (new_seq) { - if (i >= NUMATTRS) { - advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); - return 0; + + /* + ** If this is a new sequence, add a slot for it + */ + if (new_seq) { + if (i >= NUMATTRS) { + advise(NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); + return 0; + } + if (!(mp->msgattrs[i] = strdup(cp))) { + advise(NULL, "strdup failed"); + return 0; + } + mp->msgattrs[i + 1] = NULL; } - if (!(mp->msgattrs[i] = strdup (cp))) { - advise (NULL, "strdup failed"); - return 0; + + /* + ** If sequence is new, or zero flag is set, then first + ** clear the bit for this sequence from all messages. + */ + if (mp->nummsg>0 && (new_seq || zero)) { + for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) + clear_sequence(mp, i, msgnum); } - mp->msgattrs[i + 1] = NULL; - } - - /* - * If sequence is new, or zero flag is set, then first - * clear the bit for this sequence from all messages. - */ - if (new_seq || zero) { - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) - clear_sequence (mp, i, msgnum); - } - - /* - * Now flip on the bit for this sequence - * for all selected messages. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) - add_sequence (mp, i, msgnum); - - /* - * Set the public/private bit for this sequence. - */ - if (public == 1) - make_seq_public (mp, i); - else if (public == 0) - make_seq_private (mp, i); - else if (new_seq) { + + /* + ** Now flip on the bit for this sequence + ** for all selected messages. + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) + if (is_selected(mp, msgnum)) + add_sequence(mp, i, msgnum); + /* - * If public == -1, then only set the - * public/private bit for new sequences. - */ - if (is_readonly (mp)) - make_seq_private (mp, i); - else - make_seq_public (mp, i); - } - - mp->msgflags |= SEQMOD; - return 1; + ** Set the public/private bit for this sequence. + */ + if (public == 1) + make_seq_public(mp, i); + else if (public == 0) + make_seq_private(mp, i); + else if (new_seq) { + /* + ** If public == -1, then only set the + ** public/private bit for new sequences. + */ + if (is_readonly(mp)) + make_seq_private(mp, i); + else + make_seq_public(mp, i); + } + + mp->msgflags |= SEQMOD; + return 1; } /* - * Add a message to a (possibly new) sequence. - * - * If public == 1, make sequence public. - * If public == 0, make sequence private. - * If public == -1, leave the public/private bit alone for existing - * sequences. For new sequences, set this bit based - * on its readonly status. - * - * If error, return 0, else return 1. - */ +** Add a message to a (possibly new) sequence. +** +** If public == 1, make sequence public. +** If public == 0, make sequence private. +** If public == -1, leave the public/private bit alone for existing +** sequences. For new sequences, set this bit based +** on its readonly status. +** +** If error, return 0, else return 1. +*/ int -seq_addmsg (struct msgs *mp, char *cp, int msgnum, int public, int zero) +seq_addmsg(struct msgs *mp, char *cp, int msgnum, int public, int zero) { - int i, j, new_seq = 1; - - if (!seq_nameok (cp)) - return 0; - - /* - * keep mp->curmsg and msgattrs["cur"] in sync - see seq_list() - */ - if (!strcmp (current,cp)) - mp->curmsg = msgnum; - - /* - * Get the number for this sequence - */ - for (i = 0; mp->msgattrs[i]; i++) { - if (!strcmp (mp->msgattrs[i], cp)) { - new_seq = 0; - break; + unsigned int i; + int j, new_seq = 1; + + if (!seq_nameok(cp)) + return 0; + + /* + ** keep mp->curmsg and msgattrs[] of seq_cur in sync - see seq_list() + */ + if (strcmp(seq_cur, cp)==0) + mp->curmsg = msgnum; + + /* + ** Get the number for this sequence + */ + for (i = 0; mp->msgattrs[i]; i++) { + if (strcmp(mp->msgattrs[i], cp)==0) { + new_seq = 0; + break; + } } - } - - /* - * If this is a new sequence, add a slot for it - */ - if (new_seq) { - if (i >= NUMATTRS) { - advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); - return 0; + + if (new_seq) { + /* If this is a new sequence, add a slot for it */ + if (i >= NUMATTRS) { + advise(NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); + return 0; + } + if (!(mp->msgattrs[i] = strdup(cp))) { + advise(NULL, "strdup failed"); + return 0; + } + mp->msgattrs[i + 1] = NULL; } - if (!(mp->msgattrs[i] = strdup (cp))) { - advise (NULL, "strdup failed"); - return 0; + + if (mp->nummsg>0 && (new_seq || zero)) { + /* Clear the bit for this sequence from all messages. */ + for (j = mp->lowmsg; j <= mp->hghmsg; j++) + clear_sequence(mp, i, j); } - mp->msgattrs[i + 1] = NULL; - } - - /* - * If sequence is new, or zero flag is set, then first - * clear the bit for this sequence from all messages. - */ - if (new_seq || zero) { - for (j = mp->lowmsg; j <= mp->hghmsg; j++) - clear_sequence (mp, i, j); - } - - /* - * Now flip on the bit for this sequence - * for this particular message. - */ - add_sequence (mp, i, msgnum); - - /* - * Set the public/private bit for this sequence. - */ - if (public == 1) - make_seq_public (mp, i); - else if (public == 0) - make_seq_private (mp, i); - else if (new_seq) { - /* - * If public == -1, then only set the - * public/private bit for new sequences. - */ - if (is_readonly (mp)) - make_seq_private (mp, i); - else - make_seq_public (mp, i); - } - - mp->msgflags |= SEQMOD; - return 1; + + /* Set the bit for this sequence for this particular message. */ + add_sequence(mp, i, msgnum); + + /* Set the public/private bit for this sequence. */ + if (public == 1) + make_seq_public(mp, i); + else if (public == 0) + make_seq_private(mp, i); + else if (new_seq) { + /* + ** If public == -1, then only set the + ** public/private bit for new sequences. + */ + if (is_readonly(mp)) + make_seq_private(mp, i); + else + make_seq_public(mp, i); + } + + mp->msgflags |= SEQMOD; + return 1; } diff --git a/sbr/seq_bits.c b/sbr/seq_bits.c index 30dd3f5..589bc03 100644 --- a/sbr/seq_bits.c +++ b/sbr/seq_bits.c @@ -1,29 +1,28 @@ - /* - * seq_bits.c -- return the snprintb() string for a sequence - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_bits.c -- return the snprintb() string for a sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include char * -seq_bits (struct msgs *mp) +seq_bits(struct msgs *mp) { - int i; - size_t len; - static char buffer[BUFSIZ]; + int i; + size_t len; + static char buffer[BUFSIZ]; - strncpy (buffer, MBITS, sizeof(buffer)); + strncpy(buffer, MBITS, sizeof(buffer)); - for (i = 0; mp->msgattrs[i]; i++) { - len = strlen (buffer); - snprintf (buffer + len, sizeof(buffer) - len, - "%c%s", FFATTRSLOT + 1 + i, mp->msgattrs[i]); - } + for (i = 0; mp->msgattrs[i]; i++) { + len = strlen(buffer); + snprintf(buffer + len, sizeof(buffer) - len, + "%c%s", FFATTRSLOT + 1 + i, mp->msgattrs[i]); + } - return buffer; + return buffer; } diff --git a/sbr/seq_del.c b/sbr/seq_del.c index eb41ec4..5555f11 100644 --- a/sbr/seq_del.c +++ b/sbr/seq_del.c @@ -1,132 +1,132 @@ - /* - * seq_del.c -- delete message(s) from a sequence - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_del.c -- delete message(s) from a sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * Delete all SELECTED messages from sequence - * - * If public == 1, make sequence public. - * If public == 0, make sequence private. - * If public == -1, leave the public/private bit alone for existing - * sequences. For new sequences, set this bit based - * on its readonly status. - * - * If error, return 0, else return 1. - */ +** Delete all SELECTED messages from sequence +** +** If public == 1, make sequence public. +** If public == 0, make sequence private. +** If public == -1, leave the public/private bit alone for existing +** sequences. For new sequences, set this bit based +** on its readonly status. +** +** If error, return 0, else return 1. +*/ int -seq_delsel (struct msgs *mp, char *cp, int public, int zero) +seq_delsel(struct msgs *mp, char *cp, int public, int zero) { - int i, msgnum, new_seq = 1; + unsigned int i; + int msgnum, new_seq = 1; - if (!seq_nameok (cp)) - return 0; + if (!seq_nameok(cp)) + return 0; - /* - * Get the number for this sequence - */ - for (i = 0; mp->msgattrs[i]; i++) { - if (!strcmp (mp->msgattrs[i], cp)) { - new_seq = 0; - break; + /* + ** Get the number for this sequence + */ + for (i = 0; mp->msgattrs[i]; i++) { + if (strcmp(mp->msgattrs[i], cp)==0) { + new_seq = 0; + break; + } } - } - /* - * If the zero flag is set, first add all existing - * messages in this folder to the sequence. - */ - if (zero) { /* - * create the sequence, if necessary - */ - if (new_seq) { - if (i >= NUMATTRS) { - advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); - return 0; - } - if (!(mp->msgattrs[i] = strdup (cp))) { - advise (NULL, "strdup failed"); - return 0; - } - mp->msgattrs[i + 1] = NULL; + ** If the zero flag is set, first add all existing + ** messages in this folder to the sequence. + */ + if (zero) { + /* + ** create the sequence, if necessary + */ + if (new_seq) { + if (i >= NUMATTRS) { + advise(NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp); + return 0; + } + if (!(mp->msgattrs[i] = strdup(cp))) { + advise(NULL, "strdup failed"); + return 0; + } + mp->msgattrs[i + 1] = NULL; + } + /* + ** now add sequence bit to all existing messages + */ + for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { + if (does_exist(mp, msgnum)) + add_sequence(mp, i, msgnum); + else + clear_sequence(mp, i, msgnum); + } + } else { + if (new_seq) { + advise(NULL, "no such sequence as %s", cp); + return 0; + } } + /* - * now add sequence bit to all existing messages - */ - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { - if (does_exist (mp, msgnum)) - add_sequence (mp, i, msgnum); - else - clear_sequence (mp, i, msgnum); - } - } else { - if (new_seq) { - advise (NULL, "no such sequence as %s", cp); - return 0; - } - } - - /* - * Now clear the bit on all selected messages - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) - clear_sequence (mp, i, msgnum); - - /* - * Set the public/private bit for this sequence. - */ - if (public == 1) - make_seq_public (mp, i); - else if (public == 0) - make_seq_private (mp, i); - else if (new_seq) { + ** Now clear the bit on all selected messages + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) + if (is_selected(mp, msgnum)) + clear_sequence(mp, i, msgnum); + /* - * If public == -1, then only set the - * public/private bit for new sequences. - */ - if (is_readonly (mp)) - make_seq_private (mp, i); - else - make_seq_public (mp, i); - } - - mp->msgflags |= SEQMOD; - return 1; + ** Set the public/private bit for this sequence. + */ + if (public == 1) + make_seq_public(mp, i); + else if (public == 0) + make_seq_private(mp, i); + else if (new_seq) { + /* + ** If public == -1, then only set the + ** public/private bit for new sequences. + */ + if (is_readonly(mp)) + make_seq_private(mp, i); + else + make_seq_public(mp, i); + } + + mp->msgflags |= SEQMOD; + return 1; } /* - * Delete message from sequence. - * - * If error, return 0, else return 1. - */ +** Delete message from sequence. +** +** If error, return 0, else return 1. +*/ int -seq_delmsg (struct msgs *mp, char *cp, int msgnum) +seq_delmsg(struct msgs *mp, char *cp, int msgnum) { - int i; + int i; - if (!seq_nameok (cp)) - return 0; + if (!seq_nameok(cp)) + return 0; - for (i = 0; mp->msgattrs[i]; i++) { - if (!strcmp (mp->msgattrs[i], cp)) { - clear_sequence (mp, i, msgnum); - mp->msgflags |= SEQMOD; - return 1; + for (i = 0; mp->msgattrs[i]; i++) { + if (strcmp(mp->msgattrs[i], cp)==0) { + clear_sequence(mp, i, msgnum); + mp->msgflags |= SEQMOD; + return 1; + } } - } - advise (NULL, "no such sequence as %s", cp); - return 0; + advise(NULL, "no such sequence as %s", cp); + return 0; } diff --git a/sbr/seq_getnum.c b/sbr/seq_getnum.c index 251b609..3c3b910 100644 --- a/sbr/seq_getnum.c +++ b/sbr/seq_getnum.c @@ -1,24 +1,23 @@ - /* - * seq_getnum.c -- find the index for a sequence - * -- return -1 if sequence doesn't exist - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_getnum.c -- find the index for a sequence +** -- return -1 if sequence doesn't exist +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include int -seq_getnum (struct msgs *mp, char *seqname) +seq_getnum(struct msgs *mp, char *seqname) { - int i; + int i; - for (i = 0; mp->msgattrs[i]; i++) - if (!strcmp (mp->msgattrs[i], seqname)) - return i; + for (i = 0; mp->msgattrs[i]; i++) + if (strcmp(mp->msgattrs[i], seqname)==0) + return i; - return -1; + return -1; } diff --git a/sbr/seq_list.c b/sbr/seq_list.c index b64e8cd..f051e38 100644 --- a/sbr/seq_list.c +++ b/sbr/seq_list.c @@ -1,12 +1,11 @@ - /* - * seq_list.c -- Get all messages in a sequence and return them - * -- as a space separated list of message ranges. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_list.c -- Get all messages in a sequence and return them +** -- as a space separated list of message ranges. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -22,84 +21,84 @@ static int len = 0; char * seq_list(struct msgs *mp, char *seqname) { - int i, j, seqnum; - char *bp; - - /* On first invocation, allocate initial buffer space */ - if (!buffer) { - len = MAXBUFFER; - buffer = mh_xmalloc ((size_t) len); - } - - /* - * Special processing for "cur" sequence. We assume that the - * "cur" sequence and mp->curmsg are in sync (see seq_add.c). - * This is returned, even if message doesn't exist or the - * folder is empty. - */ - if (!strcmp (current, seqname)) { - if (mp->curmsg) { - sprintf(buffer, "%s", m_name(mp->curmsg)); - return (buffer); - } else - return (NULL); - } - - /* If the folder is empty, just return NULL */ - if (mp->nummsg == 0) - return NULL; - - /* Get the index of the sequence */ - if ((seqnum = seq_getnum (mp, seqname)) == -1) - return NULL; - - bp = buffer; - - for (i = mp->lowmsg; i <= mp->hghmsg; ++i) { - /* - * If message doesn't exist, or isn't in - * the sequence, then continue. - */ - if (!does_exist(mp, i) || !in_sequence(mp, seqnum, i)) - continue; + int i, j, seqnum; + char *bp; - /* - * See if we need to enlarge buffer. Since we don't know - * exactly how many character this particular message range - * will need, we enlarge the buffer if we are within - * 50 characters of the end. - */ - if (bp - buffer > len - 50) { - char *newbuf; - - len += MAXBUFFER; - newbuf = mh_xrealloc (buffer, (size_t) len); - bp = newbuf + (bp - buffer); - buffer = newbuf; + /* On first invocation, allocate initial buffer space */ + if (!buffer) { + len = MAXBUFFER; + buffer = mh_xmalloc((size_t) len); } /* - * If this is not the first message range in - * the list, first add a space. - */ - if (bp > buffer) - *bp++ = ' '; - - sprintf(bp, "%s", m_name(i)); - bp += strlen(bp); - j = i; /* Remember beginning of message range */ + ** Special processing for the cur sequence. We assume that the + ** cur sequence and mp->curmsg are in sync (see seq_add.c). + ** This is returned, even if message doesn't exist or the + ** folder is empty. + */ + if (strcmp(seq_cur, seqname)==0) { + if (mp->curmsg) { + sprintf(buffer, "%s", m_name(mp->curmsg)); + return (buffer); + } else + return (NULL); + } - /* - * Scan to the end of this message range - */ - for (++i; i <= mp->hghmsg && does_exist(mp, i) && in_sequence(mp, seqnum, i); - ++i) - ; - - if (i - j > 1) { - sprintf(bp, "-%s", m_name(i - 1)); - bp += strlen(bp); + /* If the folder is empty, just return NULL */ + if (mp->nummsg == 0) + return NULL; + + /* Get the index of the sequence */ + if ((seqnum = seq_getnum(mp, seqname)) == -1) + return NULL; + + bp = buffer; + + for (i = mp->lowmsg; i <= mp->hghmsg; ++i) { + /* + ** If message doesn't exist, or isn't in + ** the sequence, then continue. + */ + if (!does_exist(mp, i) || !in_sequence(mp, seqnum, i)) + continue; + + /* + ** See if we need to enlarge buffer. Since we don't know + ** exactly how many character this particular message range + ** will need, we enlarge the buffer if we are within + ** 50 characters of the end. + */ + if (bp - buffer > len - 50) { + char *newbuf; + + len += MAXBUFFER; + newbuf = mh_xrealloc(buffer, (size_t) len); + bp = newbuf + (bp - buffer); + buffer = newbuf; + } + + /* + ** If this is not the first message range in + ** the list, first add a space. + */ + if (bp > buffer) + *bp++ = ' '; + + sprintf(bp, "%s", m_name(i)); + bp += strlen(bp); + j = i; /* Remember beginning of message range */ + + /* + ** Scan to the end of this message range + */ + for (++i; i <= mp->hghmsg && does_exist(mp, i) && in_sequence(mp, seqnum, i); + ++i) + ; + + if (i - j > 1) { + sprintf(bp, "-%s", m_name(i - 1)); + bp += strlen(bp); + } } - } - return (bp > buffer? buffer : NULL); + return (bp > buffer? buffer : NULL); } diff --git a/sbr/seq_nameok.c b/sbr/seq_nameok.c index 6887ac6..a61dd9c 100644 --- a/sbr/seq_nameok.c +++ b/sbr/seq_nameok.c @@ -1,56 +1,58 @@ - /* - * seq_nameok.c -- check if a sequence name is ok - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_nameok.c -- check if a name is ok for a user-defined sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include +/* +** returns true if it is a valid name for a user-defined sequence +*/ int -seq_nameok (unsigned char *s) +seq_nameok(unsigned char *s) { - unsigned char *pp; - - if (s == NULL || *s == '\0') { - advise (NULL, "empty sequence name"); - return 0; - } - - /* - * Make sure sequence name doesn't clash with one - * of the `reserved' sequence names. - */ - if (!(strcmp (s, "new") && - strcmp (s, "all") && - strcmp (s, "first") && - strcmp (s, "last") && - strcmp (s, "prev") && - strcmp (s, "next"))) { - advise (NULL, "illegal sequence name: %s", s); - return 0; - } - - /* - * First character in a sequence name must be - * an alphabetic character ... - */ - if (!isalpha (*s)) { - advise (NULL, "illegal sequence name: %s", s); - return 0; - } - - /* - * and can be followed by zero or more alphanumeric characters - */ - for (pp = s + 1; *pp; pp++) - if (!isalnum (*pp)) { - advise (NULL, "illegal sequence name: %s", s); - return 0; + unsigned char *pp; + + if (s == NULL || *s == '\0') { + advise(NULL, "empty sequence name"); + return 0; + } + + /* + ** Make sure sequence name doesn't clash with one + ** of the `reserved' sequence names. + ** Note: Accept `cur' here! But why is it treated special? --meillo + */ + if (strcmp(s, seq_first)==0 || strcmp(s, seq_last)==0 || + strcmp(s, seq_prev)==0 || strcmp(s, seq_next)==0 || + strcmp(s, seq_all)==0 || strcmp(s, seq_beyond)==0) { + advise(NULL, "collision with reserved sequence name: `%s'", s); + return 0; + } + + /* + ** First character in a sequence name must be + ** an alphabetic character ... + */ + if (!isalpha(*s)) { + advise(NULL, "sequence name must start with a letter: %s", s); + return 0; + } + + /* + ** and can be followed by zero or more alphanumeric characters + */ + for (pp = s+1; *pp; pp++) { + if (!isalnum(*pp)) { + advise(NULL, "sequence name must only contain " + "letters and digits: %s", s); + return 0; + } } - return 1; + return 1; } diff --git a/sbr/seq_print.c b/sbr/seq_print.c index 3d97038..7cd7c1a 100644 --- a/sbr/seq_print.c +++ b/sbr/seq_print.c @@ -1,48 +1,48 @@ - /* - * seq_print.c -- Routines to print sequence information. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_print.c -- Routines to print sequence information. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #define empty(s) ((s) ? (s) : "") /* - * Print all the sequences in a folder - */ +** Print all the sequences in a folder +*/ void -seq_printall (struct msgs *mp) +seq_printall(struct msgs *mp) { - int i; - char *list; - - for (i = 0; mp->msgattrs[i]; i++) { - list = seq_list (mp, mp->msgattrs[i]); - printf ("%s%s: %s\n", mp->msgattrs[i], - is_seq_private (mp, i) ? " (private)" : "", empty(list)); - } + int i; + char *list; + + for (i = 0; mp->msgattrs[i]; i++) { + list = seq_list(mp, mp->msgattrs[i]); + printf("%s%s: %s\n", mp->msgattrs[i], + is_seq_private(mp, i) ? " (private)" : "", + empty(list)); + } } /* - * Print a particular sequence in a folder - */ +** Print a particular sequence in a folder +*/ void -seq_print (struct msgs *mp, char *seqname) +seq_print(struct msgs *mp, char *seqname) { - int i; - char *list; + int i; + char *list; - /* get the index of sequence */ - i = seq_getnum (mp, seqname); + /* get the index of sequence */ + i = seq_getnum(mp, seqname); - /* get sequence information */ - list = seq_list (mp, seqname); + /* get sequence information */ + list = seq_list(mp, seqname); - printf ("%s%s: %s\n", seqname, - (i == -1) ? "" : is_seq_private(mp, i) ? " (private)" : "", empty(list)); + printf("%s%s: %s\n", seqname, (i == -1) ? "" : + is_seq_private(mp, i) ? " (private)" : "", empty(list)); } diff --git a/sbr/seq_read.c b/sbr/seq_read.c index e349121..bfecaf0 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -1,234 +1,236 @@ - /* - * seq_read.c -- read the .mh_sequence file and - * -- initialize sequence information - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_read.c -- read the .mh_sequence file and +** -- initialize sequence information +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include /* - * static prototypes - */ -static int seq_init (struct msgs *, char *, char *); -static void seq_public (struct msgs *); -static void seq_private (struct msgs *); +** static prototypes +*/ +static int seq_init(struct msgs *, char *, char *); +static void seq_public(struct msgs *); +static void seq_private(struct msgs *); /* - * Get the sequence information for this folder from - * .mh_sequences (or equivalent specified in .mh_profile) - * or context file (for private sequences). - */ +** Get the sequence information for this folder from +** .mh_sequences (or equivalent specified in .mh_profile) +** or context file (for private sequences). +*/ void -seq_read (struct msgs *mp) +seq_read(struct msgs *mp) { - /* - * Initialize the list of sequence names. Go ahead and - * add the "cur" sequence to the list of sequences. - */ - mp->msgattrs[0] = getcpy (current); - mp->msgattrs[1] = NULL; - make_all_public (mp); /* initially, make all public */ - - /* If folder is empty, don't scan for sequence information */ - if (mp->nummsg == 0) - return; - - /* Initialize the public sequences */ - seq_public (mp); - - /* Initialize the private sequences */ - seq_private (mp); + /* + ** Initialize the list of sequence names. Go ahead and + ** add the cur sequence to the list of sequences. + */ + mp->msgattrs[0] = getcpy(seq_cur); + mp->msgattrs[1] = NULL; + make_all_public(mp); /* initially, make all public */ + + /* If folder is empty, don't scan for sequence information */ + if (mp->nummsg == 0) + return; + + /* Initialize the public sequences */ + seq_public(mp); + + /* Initialize the private sequences */ + seq_private(mp); } /* - * read folder's sequences file for public sequences - */ +** read folder's sequences file for public sequences +*/ static void -seq_public (struct msgs *mp) +seq_public(struct msgs *mp) { - int state; - char *cp, seqfile[PATH_MAX]; - char name[NAMESZ], field[BUFSIZ]; - FILE *fp; - - /* - * If mh_seq == NULL (such as if nmh been compiled with - * NOPUBLICSEQ), or if *mh_seq == '\0' (the user has defined - * the "mh-sequences" profile entry, but left it empty), - * then just return, and do not initialize any public sequences. - */ - if (mh_seq == NULL || *mh_seq == '\0') - return; - - /* get filename of sequence file */ - snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq); - - if ((fp = lkfopen (seqfile, "r")) == NULL) - return; - - /* Use m_getfld to scan sequence file */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - if (state == FLDPLUS) { - cp = getcpy (field); - while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), fp); - cp = add (field, cp); - } - seq_init (mp, getcpy (name), trimcpy (cp)); - free (cp); - } else { - seq_init (mp, getcpy (name), trimcpy (field)); + int state; + char *cp, seqfile[PATH_MAX]; + char name[NAMESZ], field[BUFSIZ]; + FILE *fp; + + /* + ** If public sequences are disabled (e.g. the user has defined + ** an empty `Mh-Sequences' profile entry), then just return. + */ + if (mh_seq == NULL || *mh_seq == '\0') + return; + + /* get filename of sequence file */ + snprintf(seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq); + + if ((fp = lkfopen(seqfile, "r")) == NULL) + return; + + /* Use m_getfld to scan sequence file */ + for (state = FLD;;) { + switch (state = m_getfld(state, name, field, sizeof(field), + fp)) { + case FLD: + case FLDPLUS: + case FLDEOF: + if (state == FLDPLUS) { + cp = getcpy(field); + while (state == FLDPLUS) { + state = m_getfld(state, name, field, + sizeof(field), fp); + cp = add(field, cp); + } + seq_init(mp, getcpy(name), trimcpy(cp)); + free(cp); + } else { + seq_init(mp, getcpy(name), trimcpy(field)); + } + if (state == FLDEOF) + break; + continue; + + case BODY: + case BODYEOF: + adios(NULL, "no blank lines are permitted in %s", + seqfile); + /* fall */ + + case FILEEOF: + break; + + default: + adios(NULL, "%s is poorly formatted", seqfile); } - if (state == FLDEOF) - break; - continue; - - case BODY: - case BODYEOF: - adios (NULL, "no blank lines are permitted in %s", seqfile); - /* fall */ - - case FILEEOF: - break; - - default: - adios (NULL, "%s is poorly formatted", seqfile); + break; /* break from for loop */ } - break; /* break from for loop */ - } - lkfclose (fp, seqfile); + lkfclose(fp, seqfile); } /* - * Scan profile/context list for private sequences. - * - * We search the context list for all keys that look like - * "atr-seqname-folderpath", and add them as private sequences. - */ +** Scan profile/context list for private sequences. +** +** We search the context list for all keys that look like +** "atr-seqname-folderpath", and add them as private sequences. +*/ static void -seq_private (struct msgs *mp) +seq_private(struct msgs *mp) { - int i, j, alen, plen; - char *cp; - struct node *np; - - alen = strlen ("atr-"); - plen = strlen (mp->foldpath) + 1; - - for (np = m_defs; np; np = np->n_next) { - if (ssequal ("atr-", np->n_name) - && (j = strlen (np->n_name) - plen) > alen - && *(np->n_name + j) == '-' - && strcmp (mp->foldpath, np->n_name + j + 1) == 0) { - cp = getcpy (np->n_name + alen); - *(cp + j - alen) = '\0'; - if ((i = seq_init (mp, cp, getcpy (np->n_field))) != -1) - make_seq_private (mp, i); + int i, j, alen, plen; + char *cp; + struct node *np; + + alen = strlen("atr-"); + plen = strlen(mp->foldpath) + 1; + + for (np = m_defs; np; np = np->n_next) { + if (strncmp(np->n_name, "atr-", alen)==0 && + (j = strlen(np->n_name) - plen) > alen && + *(np->n_name + j) == '-' && + strcmp(mp->foldpath, np->n_name + j + 1)==0) { + cp = getcpy(np->n_name + alen); + *(cp + j - alen) = '\0'; + if ((i = seq_init(mp, cp, getcpy(np->n_field))) != -1) + make_seq_private(mp, i); + } } - } } /* - * Add the name of sequence to the list of folder sequences. - * Then parse the list of message ranges for this - * sequence, and setup the various bit flags for each - * message in the sequence. - * - * Return internal index for the sequence if successful. - * Return -1 on error. - */ +** Add the name of sequence to the list of folder sequences. +** Then parse the list of message ranges for this +** sequence, and setup the various bit flags for each +** message in the sequence. +** +** Return internal index for the sequence if successful. +** Return -1 on error. +*/ static int -seq_init (struct msgs *mp, char *name, char *field) +seq_init(struct msgs *mp, char *name, char *field) { - int i, j, k, is_current; - char *cp, **ap; - - /* - * Check if this is "cur" sequence, - * so we can do some special things. - */ - is_current = !strcmp (current, name); - - /* - * Search for this sequence name to see if we've seen - * it already. If we've seen this sequence before, - * then clear the bit for this sequence from all the - * mesages in this folder. - */ - for (i = 0; mp->msgattrs[i]; i++) { - if (!strcmp (mp->msgattrs[i], name)) { - for (j = mp->lowmsg; j <= mp->hghmsg; j++) - clear_sequence (mp, i, j); - break; + unsigned int i; + int j, k, is_current; + char *cp, **ap; + + /* + ** Check if this is the cur sequence, + ** so we can do some special things. + */ + is_current = (strcmp(seq_cur, name)==0); + + /* + ** Search for this sequence name to see if we've seen + ** it already. If we've seen this sequence before, + ** then clear the bit for this sequence from all the + ** mesages in this folder. + */ + for (i = 0; mp->msgattrs[i]; i++) { + if (strcmp(mp->msgattrs[i], name)==0) { + for (j = mp->lowmsg; j <= mp->hghmsg; j++) + clear_sequence(mp, i, j); + break; + } } - } - - /* Return error, if too many sequences */ - if (i >= NUMATTRS) { - free (name); - free (field); - return -1; - } - - /* - * If we've already seen this sequence name, just free the - * name string. Else add it to the list of sequence names. - */ - if (mp->msgattrs[i]) { - free (name); - } else { - mp->msgattrs[i] = name; - mp->msgattrs[i + 1] = NULL; - } - - /* - * Split up the different message ranges at whitespace - */ - for (ap = brkstring (field, " ", "\n"); *ap; ap++) { - if ((cp = strchr(*ap, '-'))) - *cp++ = '\0'; - if ((j = m_atoi (*ap)) > 0) { - k = cp ? m_atoi (cp) : j; - - /* - * Keep mp->curmsg and "cur" sequence in synch. Unlike - * other sequences, this message doesn't need to exist. - * Think about the series of command (rmm; next) to - * understand why this can be the case. But if it does - * exist, we will still set the bit flag for it like - * other sequences. - */ - if (is_current) - mp->curmsg = j; - /* - * We iterate through messages in this range - * and flip on bit for this sequence. - */ - for (; j <= k; j++) { - if (j >= mp->lowmsg && j <= mp->hghmsg && does_exist(mp, j)) - add_sequence (mp, i, j); - } + + /* Return error, if too many sequences */ + if (i >= NUMATTRS) { + free(name); + free(field); + return -1; + } + + /* + ** If we've already seen this sequence name, just free the + ** name string. Else add it to the list of sequence names. + */ + if (mp->msgattrs[i]) { + free(name); + } else { + mp->msgattrs[i] = name; + mp->msgattrs[i + 1] = NULL; + } + + /* + ** Split up the different message ranges at whitespace + */ + for (ap = brkstring(field, " ", "\n"); *ap; ap++) { + if ((cp = strchr(*ap, '-'))) + *cp++ = '\0'; + if ((j = m_atoi(*ap)) > 0) { + k = cp ? m_atoi(cp) : j; + + /* + ** Keep mp->curmsg and cur sequence in sync. Unlike + ** other sequences, this message doesn't need to exist. + ** Think about the series of command (rmm; next) to + ** understand why this can be the case. But if it does + ** exist, we will still set the bit flag for it like + ** other sequences. + */ + if (is_current) + mp->curmsg = j; + /* + ** We iterate through messages in this range + ** and flip on bit for this sequence. + */ + for (; j <= k; j++) { + if (j >= mp->lowmsg && j <= mp->hghmsg && + does_exist(mp, j)) + add_sequence(mp, i, j); + } + } } - } - free (field); /* free string containing message ranges */ - return i; + free(field); /* free string containing message ranges */ + return i; } diff --git a/sbr/seq_save.c b/sbr/seq_save.c index 94b7543..745fa25 100644 --- a/sbr/seq_save.c +++ b/sbr/seq_save.c @@ -1,113 +1,111 @@ - /* - * seq_save.c -- 1) synchronize sequences - * -- 2) save public sequences - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_save.c -- 1) synchronize sequences +** -- 2) save public sequences +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include /* - * 1. If sequence is public and folder is readonly, - * then change it to be private - * 2a. If sequence is public, then add it to the sequences file - * in folder (name specified by mh-sequences profile entry). - * 2b. If sequence is private, then add it to the - * context file. - */ +** 1. If sequence is public and folder is readonly, +** then change it to be private +** 2a. If sequence is public, then add it to the sequences file +** in folder (name specified by mh-sequences profile entry). +** 2b. If sequence is private, then add it to the +** context file. +*/ void -seq_save (struct msgs *mp) +seq_save(struct msgs *mp) { - int i; - char flags, *cp, attr[BUFSIZ], seqfile[PATH_MAX]; - FILE *fp; - sigset_t set, oset; + int i; + char flags, *cp, attr[BUFSIZ], seqfile[PATH_MAX]; + FILE *fp; + sigset_t set, oset; - /* check if sequence information has changed */ - if (!(mp->msgflags & SEQMOD)) - return; - mp->msgflags &= ~SEQMOD; + /* check if sequence information has changed */ + if (!(mp->msgflags & SEQMOD)) + return; + mp->msgflags &= ~SEQMOD; - fp = NULL; - flags = mp->msgflags; /* record folder flags */ + fp = NULL; + flags = mp->msgflags; /* record folder flags */ - /* - * If no mh-sequences file is defined, or if a mh-sequences file - * is defined but empty (*mh_seq == '\0'), then pretend folder - * is readonly. This will force all sequences to be private. - */ - if (mh_seq == NULL || *mh_seq == '\0') - set_readonly (mp); - else - snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq); + /* + ** If no mh-sequences file is defined, or if a mh-sequences file + ** is defined but empty (*mh_seq == '\0'), then pretend folder + ** is readonly. This will force all sequences to be private. + */ + if (mh_seq == NULL || *mh_seq == '\0') + set_readonly(mp); + else + snprintf(seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, + mh_seq); - for (i = 0; mp->msgattrs[i]; i++) { - snprintf (attr, sizeof(attr), "atr-%s-%s", mp->msgattrs[i], mp->foldpath); + for (i = 0; mp->msgattrs[i]; i++) { + snprintf(attr, sizeof(attr), "atr-%s-%s", mp->msgattrs[i], + mp->foldpath); - /* get space separated list of sequence ranges */ - if (!(cp = seq_list(mp, mp->msgattrs[i]))) { - context_del (attr); /* delete sequence from context */ - continue; - } + /* get space separated list of sequence ranges */ + if (!(cp = seq_list(mp, mp->msgattrs[i]))) { + context_del(attr); /* delete sequence from context */ + continue; + } - if (is_readonly(mp) || is_seq_private(mp, i)) { + if (is_readonly(mp) || is_seq_private(mp, i)) { priv: - /* - * sequence is private - */ - context_replace (attr, cp); /* update sequence in context */ - } else { - /* - * sequence is public - */ - context_del (attr); /* delete sequence from context */ + /* sequence is private */ + context_replace(attr, cp); /* update seq in ctx */ + } else { + /* sequence is public */ + context_del(attr); /* delete sequence from context */ - if (!fp) { - /* - * Attempt to open file for public sequences. - * If that fails (probably because folder is - * readonly), then make sequence private. - */ - if ((fp = lkfopen (seqfile, "w")) == NULL - && (unlink (seqfile) == -1 || - (fp = lkfopen (seqfile, "w")) == NULL)) { - admonish (attr, "unable to write"); - goto priv; + if (!fp) { + /* + ** Attempt to open file for public sequences. + ** If that fails (probably because folder is + ** readonly), then make sequence private. + */ + if ((fp = lkfopen(seqfile, "w")) == NULL + && (unlink(seqfile) == -1 || + (fp = lkfopen(seqfile, "w")) + == NULL)) { + admonish(attr, "unable to write"); + goto priv; + } + + /* block a few signals */ + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGQUIT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, &oset); + } + fprintf(fp, "%s: %s\n", mp->msgattrs[i], cp); } + } - /* block a few signals */ - sigemptyset (&set); - sigaddset(&set, SIGHUP); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGQUIT); - sigaddset(&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - } - fprintf (fp, "%s: %s\n", mp->msgattrs[i], cp); + if (fp) { + lkfclose(fp, seqfile); + sigprocmask(SIG_SETMASK, &oset, &set); /* reset signal mask */ + } else { + /* + ** If folder is not readonly, and we didn't save any + ** public sequences, then remove that file. + */ + if (!is_readonly(mp)) + unlink(seqfile); } - } - if (fp) { - lkfclose (fp, seqfile); - SIGPROCMASK (SIG_SETMASK, &oset, &set); /* reset signal mask */ - } else { /* - * If folder is not readonly, and we didn't save any - * public sequences, then remove that file. - */ - if (!is_readonly(mp)) - unlink (seqfile); - } - - /* - * Reset folder flag, since we may be - * pretending that folder is readonly. - */ - mp->msgflags = flags; + ** Reset folder flag, since we may be + ** pretending that folder is readonly. + */ + mp->msgflags = flags; } diff --git a/sbr/seq_setcur.c b/sbr/seq_setcur.c index f18a388..f8668b0 100644 --- a/sbr/seq_setcur.c +++ b/sbr/seq_setcur.c @@ -1,21 +1,17 @@ - /* - * seq_setcur.c -- set the current message ("cur" sequence) for a folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_setcur.c -- set the current message (cur sequence) for a folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include void -seq_setcur (struct msgs *mp, int msgnum) +seq_setcur(struct msgs *mp, int msgnum) { - /* - * Just call seq_addmsg() to update the - * "cur" sequence. - */ - seq_addmsg (mp, current, msgnum, -1, 1); + /* Just call seq_addmsg() to update the cur sequence. */ + seq_addmsg(mp, seq_cur, msgnum, -1, 1); } diff --git a/sbr/seq_setprev.c b/sbr/seq_setprev.c index 11de143..c66c132 100644 --- a/sbr/seq_setprev.c +++ b/sbr/seq_setprev.c @@ -1,44 +1,43 @@ - /* - * seq_setprev.c -- set the Previous-Sequence - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_setprev.c -- set the Previous-Sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * Add all the messages currently SELECTED to - * the Previous-Sequence. This way, when the next - * command is given, there is a convenient way to - * selected all the messages used in the previous - * command. - */ +** Add all the messages currently SELECTED to +** the Previous-Sequence. This way, when the next +** command is given, there is a convenient way to +** selected all the messages used in the previous +** command. +*/ void -seq_setprev (struct msgs *mp) +seq_setprev(struct msgs *mp) { - char **ap, *cp, *dp; + char **ap, *cp, *dp; - /* - * Get the list of sequences for Previous-Sequence - * and split them. - */ - if ((cp = context_find (psequence))) { - dp = getcpy (cp); - if (!(ap = brkstring (dp, " ", "\n")) || !*ap) { - free (dp); - return; + /* + ** Get the list of sequences for Previous-Sequence + ** and split them. + */ + if ((cp = context_find(psequence))) { + dp = getcpy(cp); + if (!(ap = brkstring(dp, " ", "\n")) || !*ap) { + free(dp); + return; + } + } else { + return; } - } else { - return; - } - /* Now add all SELECTED messages to each sequence */ - for (; *ap; ap++) - seq_addsel (mp, *ap, -1, 1); + /* Now add all SELECTED messages to each sequence */ + for (; *ap; ap++) + seq_addsel(mp, *ap, -1, 1); - free (dp); + free(dp); } diff --git a/sbr/seq_setunseen.c b/sbr/seq_setunseen.c index ea18d17..e628393 100644 --- a/sbr/seq_setunseen.c +++ b/sbr/seq_setunseen.c @@ -1,60 +1,65 @@ - /* - * seq_setunseen.c -- add/delete all messages which have the SELECT_UNSEEN - * -- bit set to/from the Unseen-Sequence - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** seq_setunseen.c -- add/delete all messages which have the SELECT_UNSEEN +** -- bit set to/from the Unseen-Sequence +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * We scan through the folder and act upon all messages - * that are marked with the SELECT_UNSEEN bit. - * - * If seen == 1, delete messages from unseen sequence. - * If seen == 0, add messages to unseen sequence. - */ - +** We scan through the folder and act upon all messages +** that are marked with the SELECT_UNSEEN bit. +** +** Either add messages to or (if doadd is false) delete messages from +** the unseen sequence(s). +*/ void -seq_setunseen (struct msgs *mp, int seen) +seq_setunseen(struct msgs *mp, int doadd) { - int msgnum; - char **ap, *cp, *dp; + int n; + char **ap, *cp, *dp; - /* - * Get the list of sequences for Unseen-Sequence - * and split them. - */ - if ((cp = context_find (usequence))) { - dp = getcpy (cp); - if (!(ap = brkstring (dp, " ", "\n")) || !*ap) { - free (dp); - return; + /* + ** Get the list of sequences for Unseen-Sequence + ** and split them. + */ + if ((cp = context_find(usequence))) { + dp = getcpy(cp); + } else { + /* not set in profile, thus use the default */ + dp = getcpy(seq_unseen); + } + if (!(ap = brkstring(dp, " ", "\n")) || !*ap) { + /* contains no sequence name, i.e. we're finished */ + free(dp); + return; } - } else { - return; - } - /* - * Now add/delete each message which has the SELECT_UNSEEN - * bit set to/from each of these sequences. - */ - for (; *ap; ap++) { - if (seen) { - /* make sure sequence exists first */ - if (seq_getnum(mp, *ap) != -1) - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_unseen (mp, msgnum)) - seq_delmsg (mp, *ap, msgnum); - } else { - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) - if (is_unseen (mp, msgnum)) - seq_addmsg (mp, *ap, msgnum, -1, 0); + /* + ** Now add/delete each message which has the SELECT_UNSEEN + ** bit set to/from each of these sequences. + */ + for (; *ap; ap++) { + if (doadd) { + for (n = mp->lowmsg; n <= mp->hghmsg; n++) { + if (is_unseen(mp, n)) { + seq_addmsg(mp, *ap, n, -1, 0); + } + } + } else { + /* make sure sequence exists first */ + if (seq_getnum(mp, *ap) != -1) { + for (n = mp->lowsel; n <= mp->hghsel; n++) { + if (is_unseen(mp, n)) { + seq_delmsg(mp, *ap, n); + } + } + } + } } - } - free (dp); + free(dp); } diff --git a/sbr/showfile.c b/sbr/showfile.c deleted file mode 100644 index 59ae795..0000000 --- a/sbr/showfile.c +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * showfile.c -- invoke the `lproc' command - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - - -int -showfile (char **arg, char *file) -{ - pid_t pid; - int isdraft, vecp; - char *vec[MAXARGS]; - - context_save(); /* save the context file */ - fflush(stdout); - - /* - * If you have your lproc listed as "mhl", - * then really invoked the mhlproc instead - * (which is usually mhl anyway). - */ - if (!strcmp (r1bindex (lproc, '/'), "mhl")) - lproc = mhlproc; - - switch (pid = vfork()) { - case -1: - /* fork error */ - advise ("fork", "unable to"); - return 1; - - case 0: - /* child */ - vecp = 0; - vec[vecp++] = r1bindex (lproc, '/'); - isdraft = 1; - if (arg) { - while (*arg) { - if (**arg != '-') - isdraft = 0; - vec[vecp++] = *arg++; - } - } - if (isdraft) { - if (!strcmp (vec[0], "show")) - vec[vecp++] = "-file"; - vec[vecp++] = file; - } - vec[vecp] = NULL; - - execvp (lproc, vec); - fprintf (stderr, "unable to exec "); - perror (lproc); - _exit (-1); - - default: - /* parent */ - return (pidwait (pid, -1) & 0377 ? 1 : 0); - } - - return 1; /* NOT REACHED */ -} diff --git a/sbr/sigmsg.awk b/sbr/sigmsg.awk index 88beac1..699302c 100755 --- a/sbr/sigmsg.awk +++ b/sbr/sigmsg.awk @@ -1,4 +1,4 @@ -# +# # sigmsg.awk -- awk/nawk/gawk script to generate sigmsg.h # # provided by Geoff Wing @@ -6,80 +6,80 @@ # On SunOS 4.1.3 - user-functions don't work properly, also \" problems # Without 0 + hacks some nawks compare numbers as strings # -/^[\t ]*#[\t ]*define[\t _]*SIG[A-Z][A-Z0-9]*[\t ]*[1-9][0-9]*/ { - sigindex = index($0, "SIG") - sigtail = substr($0, sigindex, 80) - split(sigtail, tmp) - signam = substr(tmp[1], 4, 20) - signum = tmp[2] - if (sig[signum] == "") { - sig[signum] = signam - if (0 + max < 0 + signum && signum < 60) - max = signum - if (signam == "ABRT") { msg[signum] = "abort" } - if (signam == "ALRM") { msg[signum] = "alarm" } - if (signam == "BUS") { msg[signum] = "bus error" } - if (signam == "CHLD") { msg[signum] = "death of child" } - if (signam == "CLD") { msg[signum] = "death of child" } - if (signam == "CONT") { msg[signum] = "continued" } - if (signam == "EMT") { msg[signum] = "EMT instruction" } - if (signam == "FPE") { msg[signum] = "floating point exception" } - if (signam == "HUP") { msg[signum] = "hangup" } - if (signam == "ILL") { msg[signum] = "illegal hardware instruction" } - if (signam == "INFO") { msg[signum] = "status request from keyboard" } - if (signam == "INT") { msg[signum] = "interrupt" } - if (signam == "IO") { msg[signum] = "i/o ready" } - if (signam == "IOT") { msg[signum] = "IOT instruction" } - if (signam == "KILL") { msg[signum] = "killed" } - if (signam == "LOST") { msg[signum] = "resource lost" } - if (signam == "PIPE") { msg[signum] = "broken pipe" } - if (signam == "POLL") { msg[signum] = "pollable event occurred" } - if (signam == "PROF") { msg[signum] = "profile signal" } - if (signam == "PWR") { msg[signum] = "power fail" } - if (signam == "QUIT") { msg[signum] = "quit" } - if (signam == "SEGV") { msg[signum] = "segmentation fault" } - if (signam == "SYS") { msg[signum] = "invalid system call" } - if (signam == "TERM") { msg[signum] = "terminated" } - if (signam == "TRAP") { msg[signum] = "trace trap" } - if (signam == "URG") { msg[signum] = "urgent condition" } - if (signam == "USR1") { msg[signum] = "user-defined signal 1" } - if (signam == "USR2") { msg[signum] = "user-defined signal 2" } - if (signam == "VTALRM") { msg[signum] = "virtual time alarm" } - if (signam == "WINCH") { msg[signum] = "window size changed" } - if (signam == "XCPU") { msg[signum] = "cpu limit exceeded" } - if (signam == "XFSZ") { msg[signum] = "file size limit exceeded" } - } +/^[\t ]*#[\t ]*define[\t _]*SIG[A-Z][A-Z0-9]*[\t ]*[1-9][0-9]*/ { + sigindex = index($0, "SIG") + sigtail = substr($0, sigindex, 80) + split(sigtail, tmp) + signam = substr(tmp[1], 4, 20) + signum = tmp[2] + if (sig[signum] == "") { + sig[signum] = signam + if (0 + max < 0 + signum && signum < 60) + max = signum + if (signam == "ABRT") { msg[signum] = "abort" } + if (signam == "ALRM") { msg[signum] = "alarm" } + if (signam == "BUS") { msg[signum] = "bus error" } + if (signam == "CHLD") { msg[signum] = "death of child" } + if (signam == "CLD") { msg[signum] = "death of child" } + if (signam == "CONT") { msg[signum] = "continued" } + if (signam == "EMT") { msg[signum] = "EMT instruction" } + if (signam == "FPE") { msg[signum] = "floating point exception" } + if (signam == "HUP") { msg[signum] = "hangup" } + if (signam == "ILL") { msg[signum] = "illegal hardware instruction" } + if (signam == "INFO") { msg[signum] = "status request from keyboard" } + if (signam == "INT") { msg[signum] = "interrupt" } + if (signam == "IO") { msg[signum] = "i/o ready" } + if (signam == "IOT") { msg[signum] = "IOT instruction" } + if (signam == "KILL") { msg[signum] = "killed" } + if (signam == "LOST") { msg[signum] = "resource lost" } + if (signam == "PIPE") { msg[signum] = "broken pipe" } + if (signam == "POLL") { msg[signum] = "pollable event occurred" } + if (signam == "PROF") { msg[signum] = "profile signal" } + if (signam == "PWR") { msg[signum] = "power fail" } + if (signam == "QUIT") { msg[signum] = "quit" } + if (signam == "SEGV") { msg[signum] = "segmentation fault" } + if (signam == "SYS") { msg[signum] = "invalid system call" } + if (signam == "TERM") { msg[signum] = "terminated" } + if (signam == "TRAP") { msg[signum] = "trace trap" } + if (signam == "URG") { msg[signum] = "urgent condition" } + if (signam == "USR1") { msg[signum] = "user-defined signal 1" } + if (signam == "USR2") { msg[signum] = "user-defined signal 2" } + if (signam == "VTALRM") { msg[signum] = "virtual time alarm" } + if (signam == "WINCH") { msg[signum] = "window size changed" } + if (signam == "XCPU") { msg[signum] = "cpu limit exceeded" } + if (signam == "XFSZ") { msg[signum] = "file size limit exceeded" } + } } END { - ps = "%s" - ifdstr = sprintf("\t%cstopped%s%c,\n", 34, ps, 34) + ps = "%s" + ifdstr = sprintf("\t%cstopped%s%c,\n", 34, ps, 34) - print "\n/*" - print " * sigmsg.h -- architecture-customized signal messages for nmh" - print " *" - print " * automatically generated by sigmsg.awk" - print " */\n" - printf("%s %d\n\n", "#define SIGCOUNT", max) - print "char *sigmsg[SIGCOUNT+2] = {" - print "\tNULL," + print "\n/*" + print " * sigmsg.h -- architecture-customized signal messages for nmh" + print " *" + print " * automatically generated by sigmsg.awk" + print " */\n" + printf("%s %d\n\n", "#define SIGCOUNT", max) + print "char *sigmsg[SIGCOUNT+2] = {" + print "\tNULL," - for (i = 1; i <= 0 + max; i++) - if (msg[i] == "") { - if (sig[i] == "") - printf("\tNULL,\n") - else if (sig[i] == "STOP") - printf ifdstr, " (signal)", " (signal)" - else if (sig[i] == "TSTP") - printf ifdstr, "", "" - else if (sig[i] == "TTIN") - printf ifdstr, " (tty input)", " (tty input)" - else if (sig[i] == "TTOU") - printf ifdstr, " (tty output)", " (tty output)" - else - printf("\t%cSIG%s%c,\n", 34, sig[i], 34) - } else - printf("\t%c%s%c,\n", 34, msg[i], 34) - print "\tNULL" - print "};" + for (i = 1; i <= 0 + max; i++) + if (msg[i] == "") { + if (sig[i] == "") + printf("\tNULL,\n") + else if (sig[i] == "STOP") + printf ifdstr, " (signal)", " (signal)" + else if (sig[i] == "TSTP") + printf ifdstr, "", "" + else if (sig[i] == "TTIN") + printf ifdstr, " (tty input)", " (tty input)" + else if (sig[i] == "TTOU") + printf ifdstr, " (tty output)", " (tty output)" + else + printf("\t%cSIG%s%c,\n", 34, sig[i], 34) + } else + printf("\t%c%s%c,\n", 34, msg[i], 34) + print "\tNULL" + print "};" } diff --git a/sbr/signals.c b/sbr/signals.c index 919b8e0..5b55fc4 100644 --- a/sbr/signals.c +++ b/sbr/signals.c @@ -1,118 +1,78 @@ - /* - * signals.c -- general signals interface for nmh - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** signals.c -- general signals interface for nmh +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include -int -SIGPROCMASK (int how, const sigset_t *set, sigset_t *oset) -{ -#ifdef POSIX_SIGNALS - return sigprocmask(how, set, oset); -#else -# ifdef BSD_SIGNALS - switch(how) { - case SIG_BLOCK: - *oset = sigblock(*set); - break; - case SIG_UNBLOCK: - sigfillset(*oset); - *oset = sigsetmask(*oset); - sigsetmask(*oset & ~(*set)); - break; - case SIG_SETMASK: - *oset = sigsetmask(*set); - break; - default: - adios(NULL, "unknown flag in SIGPROCMASK"); - break; - } - return 0; -# endif -#endif -} - - /* - * A version of the function `signal' that uses reliable - * signals, if the machine supports them. Also, (assuming - * OS support), it restarts interrupted system calls for all - * signals except SIGALRM. - */ +** A version of the function `signal' that uses reliable +** signals, if the machine supports them. Also, (assuming +** OS support), it restarts interrupted system calls for all +** signals except SIGALRM. +** +** Since we are now assuming POSIX signal support everywhere, we always +** use reliable signals. +*/ SIGNAL_HANDLER -SIGNAL (int sig, SIGNAL_HANDLER func) +SIGNAL(int sig, SIGNAL_HANDLER func) { -#ifdef POSIX_SIGNALS - struct sigaction act, oact; + struct sigaction act, oact; - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; - if (sig == SIGALRM) { + if (sig == SIGALRM) { # ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; /* SunOS */ + act.sa_flags |= SA_INTERRUPT; /* SunOS */ # endif - } else { + } else { # ifdef SA_RESTART - act.sa_flags |= SA_RESTART; /* SVR4, BSD4.4 */ + act.sa_flags |= SA_RESTART; /* SVR4, BSD4.4 */ # endif - } - if (sigaction(sig, &act, &oact) < 0) - return (SIG_ERR); - return (oact.sa_handler); -#else - return signal (sig, func); -#endif + } + if (sigaction(sig, &act, &oact) < 0) + return (SIG_ERR); + return (oact.sa_handler); } /* - * A version of the function `signal' that will set - * the handler of `sig' to `func' if the signal is - * not currently set to SIG_IGN. Also uses reliable - * signals if available. - */ +** A version of the function `signal' that will set +** the handler of `sig' to `func' if the signal is +** not currently set to SIG_IGN. Also uses reliable +** signals if available. +*/ SIGNAL_HANDLER -SIGNAL2 (int sig, SIGNAL_HANDLER func) +SIGNAL2(int sig, SIGNAL_HANDLER func) { -#ifdef POSIX_SIGNALS - struct sigaction act, oact; + struct sigaction act, oact; - if (sigaction(sig, NULL, &oact) < 0) - return (SIG_ERR); - if (oact.sa_handler != SIG_IGN) { - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; + if (sigaction(sig, NULL, &oact) < 0) + return (SIG_ERR); + if (oact.sa_handler != SIG_IGN) { + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; - if (sig == SIGALRM) { + if (sig == SIGALRM) { # ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; /* SunOS */ + act.sa_flags |= SA_INTERRUPT; /* SunOS */ # endif - } else { + } else { # ifdef SA_RESTART - act.sa_flags |= SA_RESTART; /* SVR4, BSD4.4 */ + act.sa_flags |= SA_RESTART; /* SVR4, BSD4.4 */ # endif + } + if (sigaction(sig, &act, &oact) < 0) + return (SIG_ERR); } - if (sigaction(sig, &act, &oact) < 0) - return (SIG_ERR); - } - return (oact.sa_handler); -#else - SIGNAL_HANDLER ofunc; - - if ((ofunc = signal (sig, SIG_IGN)) != SIG_IGN) - signal (sig, func); - return ofunc; -#endif + return (oact.sa_handler); } - diff --git a/sbr/smatch.c b/sbr/smatch.c index 88a098b..5bee67f 100644 --- a/sbr/smatch.c +++ b/sbr/smatch.c @@ -1,11 +1,10 @@ - /* - * smatch.c -- match a switch (option) - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** smatch.c -- match a switch (option) +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include @@ -13,35 +12,35 @@ int smatch(char *string, struct swit *swp) { - char *sp, *tcp; - int firstone, len; - struct swit *tp; - - firstone = UNKWNSW; - - if (!string) - return firstone; - len = strlen(string); - - for (tp = swp; tp->sw; tp++) { - tcp = tp->sw; - if (len < abs(tp->minchars)) - continue; /* no match */ - for (sp = string; *sp == *tcp++;) { - if (*sp++ == '\0') - return (tp - swp); /* exact match */ - } - if (*sp) { - if (*sp != ' ') - continue; /* no match */ - if (*--tcp == '\0') - return (tp - swp); /* exact match */ + char *sp, *tcp; + int firstone, len; + struct swit *tp; + + firstone = UNKWNSW; + + if (!string) + return firstone; + len = strlen(string); + + for (tp = swp; tp->sw; tp++) { + tcp = tp->sw; + if (len < abs(tp->minchars)) + continue; /* no match */ + for (sp = string; *sp == *tcp++;) { + if (*sp++ == '\0') + return (tp - swp); /* exact match */ + } + if (*sp) { + if (*sp != ' ') + continue; /* no match */ + if (*--tcp == '\0') + return (tp - swp); /* exact match */ + } + if (firstone == UNKWNSW) + firstone = tp - swp; + else + firstone = AMBIGSW; } - if (firstone == UNKWNSW) - firstone = tp - swp; - else - firstone = AMBIGSW; - } - return (firstone); + return (firstone); } diff --git a/sbr/snprintb.c b/sbr/snprintb.c index 5f3f124..ce7bf8a 100644 --- a/sbr/snprintb.c +++ b/sbr/snprintb.c @@ -1,40 +1,38 @@ - /* - * snprintb.c -- snprintf a %b string - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** snprintb.c -- snprintf a %b string +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include char * -snprintb (char *buffer, size_t n, unsigned v, char *bits) +snprintb(char *buffer, size_t n, unsigned v, char *bits) { - register int i, j; - register char c, *bp; + register int i, j; + register char c, *bp; - snprintf (buffer, n, bits && *bits == 010 ? "0%o" : "0x%x", v); - bp = buffer + strlen(buffer); + snprintf(buffer, n, bits && *bits == 010 ? "0%o" : "0x%x", v); + bp = buffer + strlen(buffer); - if (bits && *++bits) { - j = 0; - *bp++ = '<'; - while ((i = *bits++)) - if (v & (1 << (i - 1))) { - if (j++) - *bp++ = ','; - for (; (c = *bits) > 32; bits++) - *bp++ = c; - } - else - for (; *bits > 32; bits++) - continue; - *bp++ = '>'; - *bp = 0; - } + if (bits && *++bits) { + j = 0; + *bp++ = '<'; + while ((i = *bits++)) + if (v & (1 << (i - 1))) { + if (j++) + *bp++ = ','; + for (; (c = *bits) > 32; bits++) + *bp++ = c; + } else + for (; *bits > 32; bits++) + continue; + *bp++ = '>'; + *bp = 0; + } - return buffer; + return buffer; } diff --git a/sbr/snprintf.c b/sbr/snprintf.c deleted file mode 100644 index efb6df0..0000000 --- a/sbr/snprintf.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * snprintf.c -- formatted output to a string - * - * This is an implementation of snprintf() and vsnprintf() - * taken from the Apache web server. This is only used on - * systems which do not have a native version. - */ - -/* ==================================================================== - * Copyright (c) 1995-1999 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see . - * - * This code is based on, and used with the permission of, the - * SIO stdio-replacement strx_* functions by Panos Tsirigotis - * for xinetd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { - NO = 0, YES = 1 -} boolean_e; - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif -#define NUL '\0' -#define INT_NULL ((int *)0) -#define WIDE_INT long - -typedef struct { - char *curpos; - char *endpos; -} ap_vformatter_buff; - -typedef WIDE_INT wide_int; -typedef unsigned WIDE_INT u_wide_int; -typedef int bool_int; - -#define S_NULL "(null)" -#define S_NULL_LEN 6 - -#define FLOAT_DIGITS 6 -#define EXPONENT_LENGTH 10 - -/* These macros allow correct support of 8-bit characters on systems which - * support 8-bit characters. Pretty dumb how the cast is required, but - * that's legacy libc for ya. These new macros do not support EOF like - * the standard macros do. Tough. - */ -#define ap_isalpha(c) (isalpha(((unsigned char)(c)))) -#define ap_isdigit(c) (isdigit(((unsigned char)(c)))) -#define ap_islower(c) (islower(((unsigned char)(c)))) - -/* - * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions - * - * XXX: this is a magic number; do not decrease it - */ -#define NUM_BUF_SIZE 512 - -/* - * cvt.c - IEEE floating point formatting routines for FreeBSD - * from GNU libc-4.6.27. Modified to be thread safe. - */ - -/* - * ap_ecvt converts to decimal - * the number of digits is specified by ndigit - * decpt is set to the position of the decimal point - * sign is set to 0 for positive, 1 for negative - */ - -#define NDIG 80 - -/* buf must have at least NDIG bytes */ -static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) -{ - register int r2; - double fi, fj; - register char *p, *p1; - - if (ndigits >= NDIG - 1) - ndigits = NDIG - 2; - r2 = 0; - *sign = 0; - p = &buf[0]; - if (arg < 0) { - *sign = 1; - arg = -arg; - } - arg = modf(arg, &fi); - p1 = &buf[NDIG]; - /* - * Do integer part - */ - if (fi != 0) { - p1 = &buf[NDIG]; - while (fi != 0) { - fj = modf(fi / 10, &fi); - *--p1 = (int) ((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[NDIG]) - *p++ = *p1++; - } - else if (arg > 0) { - while ((fj = arg * 10) < 1) { - arg = fj; - r2--; - } - } - p1 = &buf[ndigits]; - if (eflag == 0) - p1 += r2; - *decpt = r2; - if (p1 < &buf[0]) { - buf[0] = '\0'; - return (buf); - } - while (p <= p1 && p < &buf[NDIG]) { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int) fj + '0'; - } - if (p1 >= &buf[NDIG]) { - buf[NDIG - 1] = '\0'; - return (buf); - } - p = p1; - *p1 += 5; - while (*p1 > '9') { - *p1 = '0'; - if (p1 > buf) - ++ * --p1; - else { - *p1 = '1'; - (*decpt)++; - if (eflag == 0) { - if (p > buf) - *p = '0'; - p++; - } - } - } - *p = '\0'; - return (buf); -} - -static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 1, buf)); -} - -static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 0, buf)); -} - -/* - * ap_gcvt - Floating output conversion to - * minimal length string - */ - -static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform) -{ - int sign, decpt; - register char *p1, *p2; - register int i; - char buf1[NDIG]; - - p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1); - p2 = buf; - if (sign) - *p2++ = '-'; - for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) - ndigit--; - if ((decpt >= 0 && decpt - ndigit > 4) - || (decpt < 0 && decpt < -3)) { /* use E-style */ - decpt--; - *p2++ = *p1++; - *p2++ = '.'; - for (i = 1; i < ndigit; i++) - *p2++ = *p1++; - *p2++ = 'e'; - if (decpt < 0) { - decpt = -decpt; - *p2++ = '-'; - } - else - *p2++ = '+'; - if (decpt / 100 > 0) - *p2++ = decpt / 100 + '0'; - if (decpt / 10 > 0) - *p2++ = (decpt % 100) / 10 + '0'; - *p2++ = decpt % 10 + '0'; - } - else { - if (decpt <= 0) { - if (*p1 != '0') - *p2++ = '.'; - while (decpt < 0) { - decpt++; - *p2++ = '0'; - } - } - for (i = 1; i <= ndigit; i++) { - *p2++ = *p1++; - if (i == decpt) - *p2++ = '.'; - } - if (ndigit < decpt) { - while (ndigit++ < decpt) - *p2++ = '0'; - *p2++ = '.'; - } - } - if (p2[-1] == '.' && !altform) - p2--; - *p2 = '\0'; - return (buf); -} - -/* - * The INS_CHAR macro inserts a character in the buffer and writes - * the buffer back to disk if necessary - * It uses the char pointers sp and bep: - * sp points to the next available character in the buffer - * bep points to the end-of-buffer+1 - * While using this macro, note that the nextb pointer is NOT updated. - * - * NOTE: Evaluation of the c argument should not have any side-effects - */ -#define INS_CHAR(c, sp, bep, cc) \ - { \ - if (sp >= bep) { \ - vbuff->curpos = sp; \ - if (flush_func(vbuff)) \ - return -1; \ - sp = vbuff->curpos; \ - bep = vbuff->endpos; \ - } \ - *sp++ = (c); \ - cc++; \ - } - -#define NUM( c ) ( c - '0' ) - -#define STR_TO_DEC( str, num ) \ - num = NUM( *str++ ) ; \ - while ( ap_isdigit( *str ) ) \ - { \ - num *= 10 ; \ - num += NUM( *str++ ) ; \ - } - -/* - * This macro does zero padding so that the precision - * requirement is satisfied. The padding is done by - * adding '0's to the left of the string that is going - * to be printed. - */ -#define FIX_PRECISION( adjust, precision, s, s_len ) \ - if ( adjust ) \ - while ( s_len < precision ) \ - { \ - *--s = '0' ; \ - s_len++ ; \ - } - -/* - * Macro that does padding. The padding is done by printing - * the character ch. - */ -#define PAD( width, len, ch ) do \ - { \ - INS_CHAR( ch, sp, bep, cc ) ; \ - width-- ; \ - } \ - while ( width > len ) - -/* - * Prefix the character ch to the string str - * Increase length - * Set the has_prefix flag - */ -#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES - - -/* - * Convert num to its decimal format. - * Return value: - * - a pointer to a string containing the number (no sign) - * - len contains the length of the string - * - is_negative is set to TRUE or FALSE depending on the sign - * of the number (always set to FALSE if is_unsigned is TRUE) - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - */ -static char *conv_10(register wide_int num, register bool_int is_unsigned, - register bool_int *is_negative, char *buf_end, - register int *len) -{ - register char *p = buf_end; - register u_wide_int magnitude; - - if (is_unsigned) { - magnitude = (u_wide_int) num; - *is_negative = FALSE; - } - else { - *is_negative = (num < 0); - - /* - * On a 2's complement machine, negating the most negative integer - * results in a number that cannot be represented as a signed integer. - * Here is what we do to obtain the number's magnitude: - * a. add 1 to the number - * b. negate it (becomes positive) - * c. convert it to unsigned - * d. add 1 - */ - if (*is_negative) { - wide_int t = num + 1; - - magnitude = ((u_wide_int) -t) + 1; - } - else - magnitude = (u_wide_int) num; - } - - /* - * We use a do-while loop so that we write at least 1 digit - */ - do { - register u_wide_int new_magnitude = magnitude / 10; - - *--p = (char) (magnitude - new_magnitude * 10 + '0'); - magnitude = new_magnitude; - } - while (magnitude); - - *len = buf_end - p; - return (p); -} - - - -static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) -{ - unsigned addr = ntohl(ia->s_addr); - char *p = buf_end; - bool_int is_negative; - int sub_len; - - p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); - - *len = buf_end - p; - return (p); -} - - - -static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len) -{ - char *p = buf_end; - bool_int is_negative; - int sub_len; - - p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len); - *--p = ':'; - p = conv_in_addr(&si->sin_addr, p, &sub_len); - - *len = buf_end - p; - return (p); -} - - - -/* - * Convert a floating point number to a string formats 'f', 'e' or 'E'. - * The result is placed in buf, and len denotes the length of the string - * The sign is returned in the is_negative argument (and is not placed - * in buf). - */ -static char *conv_fp(register char format, register double num, - boolean_e add_dp, int precision, bool_int *is_negative, - char *buf, int *len) -{ - register char *s = buf; - register char *p; - int decimal_point; - char buf1[NDIG]; - - if (format == 'f') - p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1); - else /* either e or E format */ - p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); - - /* - * Check for Infinity and NaN - */ - if (ap_isalpha(*p)) { - *len = strlen(strcpy(buf, p)); - *is_negative = FALSE; - return (buf); - } - - if (format == 'f') { - if (decimal_point <= 0) { - *s++ = '0'; - if (precision > 0) { - *s++ = '.'; - while (decimal_point++ < 0) - *s++ = '0'; - } - else if (add_dp) - *s++ = '.'; - } - else { - while (decimal_point-- > 0) - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - } - else { - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - - /* - * copy the rest of p, the NUL is NOT copied - */ - while (*p) - *s++ = *p++; - - if (format != 'f') { - char temp[EXPONENT_LENGTH]; /* for exponent conversion */ - int t_len; - bool_int exponent_is_negative; - - *s++ = format; /* either e or E */ - decimal_point--; - if (decimal_point != 0) { - p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, - &temp[EXPONENT_LENGTH], &t_len); - *s++ = exponent_is_negative ? '-' : '+'; - - /* - * Make sure the exponent has at least 2 digits - */ - if (t_len == 1) - *s++ = '0'; - while (t_len--) - *s++ = *p++; - } - else { - *s++ = '+'; - *s++ = '0'; - *s++ = '0'; - } - } - - *len = s - buf; - return (buf); -} - - -/* - * Convert num to a base X number where X is a power of 2. nbits determines X. - * For example, if nbits is 3, we do base 8 conversion - * Return value: - * a pointer to a string containing the number - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - */ -static char *conv_p2(register u_wide_int num, register int nbits, - char format, char *buf_end, register int *len) -{ - register int mask = (1 << nbits) - 1; - register char *p = buf_end; - static const char low_digits[] = "0123456789abcdef"; - static const char upper_digits[] = "0123456789ABCDEF"; - register const char *digits = (format == 'X') ? upper_digits : low_digits; - - do { - *--p = digits[num & mask]; - num >>= nbits; - } - while (num); - - *len = buf_end - p; - return (p); -} - - -/* - * Do format conversion placing the output in buffer - */ -int ap_vformatter(int (*flush_func)(ap_vformatter_buff *), - ap_vformatter_buff *vbuff, const char *fmt, va_list ap) -{ - register char *sp; - register char *bep; - register int cc = 0; - register int i; - - register char *s = NULL; - char *q; - int s_len; - - register int min_width = 0; - int precision = 0; - enum { - LEFT, RIGHT - } adjust; - char pad_char; - char prefix_char; - - double fp_num; - wide_int i_num = (wide_int) 0; - u_wide_int ui_num; - - char num_buf[NUM_BUF_SIZE]; - char char_buf[2]; /* for printing %% and % */ - - /* - * Flag variables - */ - boolean_e is_long; - boolean_e alternate_form; - boolean_e print_sign; - boolean_e print_blank; - boolean_e adjust_precision; - boolean_e adjust_width; - bool_int is_negative; - - sp = vbuff->curpos; - bep = vbuff->endpos; - - while (*fmt) { - if (*fmt != '%') { - INS_CHAR(*fmt, sp, bep, cc); - } - else { - /* - * Default variable settings - */ - adjust = RIGHT; - alternate_form = print_sign = print_blank = NO; - pad_char = ' '; - prefix_char = NUL; - - fmt++; - - /* - * Try to avoid checking for flags, width or precision - */ - if (!ap_islower(*fmt)) { - /* - * Recognize flags: -, #, BLANK, + - */ - for (;; fmt++) { - if (*fmt == '-') - adjust = LEFT; - else if (*fmt == '+') - print_sign = YES; - else if (*fmt == '#') - alternate_form = YES; - else if (*fmt == ' ') - print_blank = YES; - else if (*fmt == '0') - pad_char = '0'; - else - break; - } - - /* - * Check if a width was specified - */ - if (ap_isdigit(*fmt)) { - STR_TO_DEC(fmt, min_width); - adjust_width = YES; - } - else if (*fmt == '*') { - min_width = va_arg(ap, int); - fmt++; - adjust_width = YES; - if (min_width < 0) { - adjust = LEFT; - min_width = -min_width; - } - } - else - adjust_width = NO; - - /* - * Check if a precision was specified - * - * XXX: an unreasonable amount of precision may be specified - * resulting in overflow of num_buf. Currently we - * ignore this possibility. - */ - if (*fmt == '.') { - adjust_precision = YES; - fmt++; - if (ap_isdigit(*fmt)) { - STR_TO_DEC(fmt, precision); - } - else if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - if (precision < 0) - precision = 0; - } - else - precision = 0; - } - else - adjust_precision = NO; - } - else - adjust_precision = adjust_width = NO; - - /* - * Modifier check - */ - if (*fmt == 'l') { - is_long = YES; - fmt++; - } - else { - if (*fmt == 'h') /* "short" backward compatibility */ - ++fmt; - is_long = NO; - } - - /* - * Argument extraction and printing. - * First we determine the argument type. - * Then, we convert the argument to a string. - * On exit from the switch, s points to the string that - * must be printed, s_len has the length of the string - * The precision requirements, if any, are reflected in s_len. - * - * NOTE: pad_char may be set to '0' because of the 0 flag. - * It is reset to ' ' by non-numeric formats - */ - switch (*fmt) { - case 'u': - if (is_long) - i_num = va_arg(ap, u_wide_int); - else - i_num = (wide_int) va_arg(ap, unsigned int); - s = conv_10(i_num, 1, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - break; - - case 'd': - case 'i': - if (is_long) - i_num = va_arg(ap, wide_int); - else - i_num = (wide_int) va_arg(ap, int); - s = conv_10(i_num, 0, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - break; - - - case 'o': - if (is_long) - ui_num = va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 3, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && *s != '0') { - *--s = '0'; - s_len++; - } - break; - - - case 'x': - case 'X': - if (is_long) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 4, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && i_num != 0) { - *--s = *fmt; /* 'x' or 'X' */ - *--s = '0'; - s_len += 2; - } - break; - - - case 's': - s = va_arg(ap, char *); - if (s != NULL) { - s_len = strlen(s); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - break; - - - case 'f': - case 'e': - case 'E': - fp_num = va_arg(ap, double); - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = conv_fp(*fmt, fp_num, alternate_form, - (adjust_precision == NO) ? FLOAT_DIGITS : precision, - &is_negative, &num_buf[1], &s_len); - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - break; - - - case 'g': - case 'G': - if (adjust_precision == NO) - precision = FLOAT_DIGITS; - else if (precision == 0) - precision = 1; - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1], - alternate_form); - if (*s == '-') - prefix_char = *s++; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - - s_len = strlen(s); - - if (alternate_form && (q = strchr(s, '.')) == NULL) { - s[s_len++] = '.'; - s[s_len] = '\0'; /* delimit for following strchr() */ - } - if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) - *q = 'E'; - break; - - - case 'c': - char_buf[0] = (char) (va_arg(ap, int)); - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case '%': - char_buf[0] = '%'; - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case 'n': - *(va_arg(ap, int *)) = cc; - break; - - /* - * This is where we extend the printf format, with a second - * type specifier - */ - case 'p': - switch(*++fmt) { - /* - * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise - * we print "%p" to indicate that we don't handle "%p". - */ - case 'p': - ui_num = (u_wide_int) va_arg(ap, void *); - - if (sizeof(char *) <= sizeof(u_wide_int)) - s = conv_p2(ui_num, 4, 'x', - &num_buf[NUM_BUF_SIZE], &s_len); - else { - s = "%p"; - s_len = 2; - prefix_char = NUL; - } - pad_char = ' '; - break; - - /* print a struct sockaddr_in as a.b.c.d:port */ - case 'I': - { - struct sockaddr_in *si; - - si = va_arg(ap, struct sockaddr_in *); - if (si != NULL) { - s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - } - break; - - /* print a struct in_addr as a.b.c.d */ - case 'A': - { - struct in_addr *ia; - - ia = va_arg(ap, struct in_addr *); - if (ia != NULL) { - s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - } - break; - - case NUL: - /* if %p ends the string, oh well ignore it */ - continue; - - default: - s = "bogus %p"; - s_len = 8; - prefix_char = NUL; - break; - } - break; - - case NUL: - /* - * The last character of the format string was %. - * We ignore it. - */ - continue; - - - /* - * The default case is for unrecognized %'s. - * We print % to help the user identify what - * option is not understood. - * This is also useful in case the user wants to pass - * the output of format_converter to another function - * that understands some other % (like syslog). - * Note that we can't point s inside fmt because the - * unknown could be preceded by width etc. - */ - default: - char_buf[0] = '%'; - char_buf[1] = *fmt; - s = char_buf; - s_len = 2; - pad_char = ' '; - break; - } - - if (prefix_char != NUL && s != S_NULL && s != char_buf) { - *--s = prefix_char; - s_len++; - } - - if (adjust_width && adjust == RIGHT && min_width > s_len) { - if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(*s, sp, bep, cc); - s++; - s_len--; - min_width--; - } - PAD(min_width, s_len, pad_char); - } - - /* - * Print the string s. - */ - for (i = s_len; i != 0; i--) { - INS_CHAR(*s, sp, bep, cc); - s++; - } - - if (adjust_width && adjust == LEFT && min_width > s_len) - PAD(min_width, s_len, pad_char); - } - fmt++; - } - vbuff->curpos = sp; - return cc; -} - - -static int snprintf_flush(ap_vformatter_buff *vbuff) -{ - /* if the buffer fills we have to abort immediately, there is no way - * to "flush" a snprintf... there's nowhere to flush it to. - */ - return -1; -} - - -int snprintf(char *buf, size_t len, const char *format,...) -{ - int cc; - va_list ap; - ap_vformatter_buff vbuff; - - if (len == 0) - return 0; - - /* save one byte for nul terminator */ - vbuff.curpos = buf; - vbuff.endpos = buf + len - 1; - va_start(ap, format); - cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); - va_end(ap); - *vbuff.curpos = '\0'; - return (cc == -1) ? len : cc; -} - - -int vsnprintf(char *buf, size_t len, const char *format, va_list ap) -{ - int cc; - ap_vformatter_buff vbuff; - - if (len == 0) - return 0; - - /* save one byte for nul terminator */ - vbuff.curpos = buf; - vbuff.endpos = buf + len - 1; - cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); - *vbuff.curpos = '\0'; - return (cc == -1) ? len : cc; -} diff --git a/sbr/ssequal.c b/sbr/ssequal.c deleted file mode 100644 index 5ccf28f..0000000 --- a/sbr/ssequal.c +++ /dev/null @@ -1,37 +0,0 @@ - -/* - * ssequal.c -- check if a string is a substring of another - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/* - * THIS CODE DOES NOT WORK AS ADVERTISED. - * It is actually checking if s1 is a PREFIX of s2. - * All calls to this function need to be checked to see - * if that needs to be changed. Prefix checking is cheaper, so - * should be kept if it's sufficient. - */ - -/* - * Check if s1 is a substring of s2. - * If yes, then return 1, else return 0. - */ - -int -ssequal (char *s1, char *s2) -{ - if (!s1) - s1 = ""; - if (!s2) - s2 = ""; - - while (*s1) - if (*s1++ != *s2++) - return 0; - return 1; -} diff --git a/sbr/strcasecmp.c b/sbr/strcasecmp.c index 04aad7d..608b4a5 100644 --- a/sbr/strcasecmp.c +++ b/sbr/strcasecmp.c @@ -1,55 +1,34 @@ - /* - * strcasecmp.c -- compare strings, ignoring case - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** strcasecmp.c -- compare strings, ignoring case +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * Our version of strcasecmp has to deal with NULL strings. - * Once that is fixed in the rest of the code, we can use the - * native version, instead of this one. - */ - -int -mh_strcasecmp (const char *s1, const char *s2) -{ - const unsigned char *us1, *us2; - - us1 = (const unsigned char *) s1, - us2 = (const unsigned char *) s2; - - if (!us1) - us1 = ""; - if (!us2) - us2 = ""; - - while (tolower(*us1) == tolower(*us2++)) - if (*us1++ == '\0') - return (0); - return (tolower(*us1) - tolower(*--us2)); -} - +** Our version of strcasecmp has to deal with NULL strings. +** Once that is fixed in the rest of the code, we can use the +** native version, instead of this one. +*/ int -mh_strncasecmp (const char *s1, const char *s2, size_t n) +mh_strcasecmp(const char *s1, const char *s2) { - const unsigned char *us1, *us2; + const unsigned char *us1, *us2; - if (n != 0) { us1 = (const unsigned char *) s1, us2 = (const unsigned char *) s2; - do { - if (tolower(*us1) != tolower(*us2++)) - return (tolower(*us1) - tolower(*--us2)); - if (*us1++ == '\0') - break; - } while (--n != 0); - } - return (0); + if (!us1) + us1 = ""; + if (!us2) + us2 = ""; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); } diff --git a/sbr/strdup.c b/sbr/strdup.c deleted file mode 100644 index 251145a..0000000 --- a/sbr/strdup.c +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * strdup.c -- duplicate a string - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - - -char * -strdup (const char *str) -{ - char *cp; - size_t len; - - if (!str) - return NULL; - - len = strlen(str) + 1; - cp = mh_xmalloc (len); - memcpy (cp, str, len); - return cp; -} diff --git a/sbr/strerror.c b/sbr/strerror.c deleted file mode 100644 index 476a574..0000000 --- a/sbr/strerror.c +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * strerror.c -- get error message string - */ - -#include - -extern int sys_nerr; -extern char *sys_errlist[]; - - -char * -strerror (int errnum) -{ - if (errnum > 0 && errnum < sys_nerr) - return sys_errlist[errnum]; - else - return NULL; -} diff --git a/sbr/strindex.c b/sbr/strindex.c index 9a1e4fe..2513b30 100644 --- a/sbr/strindex.c +++ b/sbr/strindex.c @@ -1,25 +1,24 @@ - /* - * strindex.c -- "unsigned" lexical index - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** strindex.c -- "unsigned" lexical index +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include int -stringdex (char *p1, char *p2) +stringdex(char *p1, char *p2) { - char *p; + char *p; - if (p1 == NULL || p2 == NULL) - return -1; + if (p1 == NULL || p2 == NULL) + return -1; - for (p = p2; *p; p++) - if (uprf (p, p1)) - return (p - p2); + for (p = p2; *p; p++) + if (uprf(p, p1)) + return (p - p2); - return -1; + return -1; } diff --git a/sbr/trimcpy.c b/sbr/trimcpy.c index b640ea6..64dd848 100644 --- a/sbr/trimcpy.c +++ b/sbr/trimcpy.c @@ -1,40 +1,39 @@ - /* - * trimcpy.c -- strip leading and trailing whitespace, - * -- replace internal whitespace with spaces, - * -- then return a copy. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** trimcpy.c -- strip leading and trailing whitespace, +** -- replace internal whitespace with spaces, +** -- then return a copy. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include char * -trimcpy (unsigned char *cp) +trimcpy(unsigned char *cp) { - unsigned char *sp; - - /* skip over leading whitespace */ - while (isspace(*cp)) - cp++; - - /* start at the end and zap trailing whitespace */ - for (sp = cp + strlen(cp) - 1; sp >= cp; sp--) { - if (isspace(*sp)) - *sp = '\0'; - else - break; - } - - /* replace remaining whitespace with spaces */ - for (sp = cp; *sp; sp++) { - if (isspace(*sp)) - *sp = ' '; - } - - /* now return a copy */ - return getcpy(cp); + unsigned char *sp; + + /* skip over leading whitespace */ + while (isspace(*cp)) + cp++; + + /* start at the end and zap trailing whitespace */ + for (sp = cp + strlen(cp) - 1; sp >= cp; sp--) { + if (isspace(*sp)) + *sp = '\0'; + else + break; + } + + /* replace remaining whitespace with spaces */ + for (sp = cp; *sp; sp++) { + if (isspace(*sp)) + *sp = ' '; + } + + /* now return a copy */ + return getcpy(cp); } diff --git a/sbr/uprf.c b/sbr/uprf.c index b3c81ff..f283a1b 100644 --- a/sbr/uprf.c +++ b/sbr/uprf.c @@ -1,41 +1,27 @@ - /* - * uprf.c -- "unsigned" lexical prefix - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** uprf.c -- "unsigned" lexical prefix +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#define TO_LOWER 040 -#define NO_MASK 000 - int -uprf (char *c1, char *c2) +uprf(char *c1, char *c2) { - int c, mask; + int c; - if (!(c1 && c2)) - return 0; + if (!(c1 && c2)) + return 0; - while ((c = *c2++)) - { -#ifdef LOCALE - c &= 0xff; - mask = *c1 & 0xff; - c = (isalpha(c) && isupper(c)) ? tolower(c) : c; - mask = (isalpha(mask) && isupper(mask)) ? tolower(mask) : mask; - if (c != mask) -#else - mask = (isalpha(c) && isalpha(*c1)) ? TO_LOWER : NO_MASK; - if ((c | mask) != (*c1 | mask)) -#endif - return 0; - else - c1++; - } - return 1; + while ((c = *c2++)) { + if (tolower(c &= 0xff) != tolower(*c1 & 0xff)) + return 0; + else + c1++; + } + return 1; } diff --git a/sbr/utils.c b/sbr/utils.c index 48969ab..297ad45 100644 --- a/sbr/utils.c +++ b/sbr/utils.c @@ -1,11 +1,10 @@ - /* - * utils.c -- various utility routines - * - * This code is Copyright (c) 2006, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** utils.c -- various utility routines +** +** This code is Copyright (c) 2006, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,215 +13,182 @@ #include /* - * We allocate space for messages (msgs array) - * this number of elements at a time. - */ +** We allocate space for messages (msgs array) +** this number of elements at a time. +*/ #define MAXMSGS 256 /* - * Safely call malloc - */ +** Safely call malloc +*/ void * mh_xmalloc(size_t size) { - void *memory; + void *memory; - if (size == 0) - adios(NULL, "Tried to malloc 0 bytes"); + if (size == 0) + adios(NULL, "Tried to malloc 0 bytes"); - memory = malloc(size); - if (!memory) - adios(NULL, "Malloc failed"); + memory = malloc(size); + if (!memory) + adios(NULL, "Malloc failed"); - return memory; + return memory; } /* - * Safely call realloc - */ +** Safely call realloc +*/ void * mh_xrealloc(void *ptr, size_t size) { - void *memory; + void *memory; - /* Some non-POSIX realloc()s don't cope with realloc(NULL,sz) */ - if (!ptr) - return mh_xmalloc(size); + /* Some non-POSIX realloc()s don't cope with realloc(NULL,sz) */ + if (!ptr) { + return mh_xmalloc(size); + } - if (size == 0) - adios(NULL, "Tried to realloc 0bytes"); + if (size == 0) + adios(NULL, "Tried to realloc 0 bytes"); - memory = realloc(ptr, size); - if (!memory) - adios(NULL, "Realloc failed"); + memory = realloc(ptr, size); + if (!memory) + adios(NULL, "Realloc failed"); - return memory; + return memory; } /* - * Return the present working directory, if the current directory does not - * exist, or is too long, make / the pwd. - */ +** Return the present working directory, if the current directory does not +** exist, or is too long, make / the pwd. +*/ char * pwd(void) { - register char *cp; - static char curwd[PATH_MAX]; - - if (!getcwd (curwd, PATH_MAX)) { - admonish (NULL, "unable to determine working directory"); - if (!mypath || !*mypath - || (strcpy (curwd, mypath), chdir (curwd)) == -1) { - strcpy (curwd, "/"); - chdir (curwd); - } - return curwd; - } - - if ((cp = curwd + strlen (curwd) - 1) > curwd && *cp == '/') - *cp = '\0'; - - return curwd; + register char *cp; + static char curwd[PATH_MAX]; + + if (!getcwd(curwd, PATH_MAX)) { + admonish(NULL, "unable to determine working directory"); + if (!mypath || !*mypath || + (strcpy(curwd, mypath), chdir(curwd)) == -1) { + strcpy(curwd, "/"); + chdir(curwd); + } + return curwd; + } + + if ((cp = curwd + strlen(curwd) - 1) > curwd && *cp == '/') { + /* strip trailing slash */ + *cp = '\0'; + } + + return curwd; } /* - * add -- If "s1" is NULL, this routine just creates a - * -- copy of "s2" into newly malloc'ed memory. - * -- - * -- If "s1" is not NULL, then copy the concatenation - * -- of "s1" and "s2" (note the order) into newly - * -- malloc'ed memory. Then free "s1". - */ +** add -- If "s1" is NULL, this routine just creates a +** -- copy of "s2" into newly malloc'ed memory. +** -- (use getcpy() instead in this case) +** -- +** -- If "s1" is not NULL, then copy the concatenation +** -- of "s1" and "s2" (note the order) into newly +** -- malloc'ed memory. Then free "s1". +*/ char * -add (char *s2, char *s1) +add(char *s2, char *s1) { - char *cp; - size_t len1 = 0, len2 = 0; + char *cp; + size_t len1 = 0, len2 = 0; - if (s1) - len1 = strlen (s1); - if (s2) - len2 = strlen (s2); + if (s1) + len1 = strlen(s1); + if (s2) + len2 = strlen(s2); - cp = mh_xmalloc (len1 + len2 + 1); + cp = mh_xmalloc(len1 + len2 + 1); - /* Copy s1 and free it */ - if (s1) { - memcpy (cp, s1, len1); - free (s1); - } + /* Copy s1 and free it */ + if (s1) { + memcpy(cp, s1, len1); + free(s1); + } - /* Copy s2 */ - if (s2) - memcpy (cp + len1, s2, len2); + /* Copy s2 */ + if (s2) + memcpy(cp + len1, s2, len2); - /* Now NULL terminate the string */ - cp[len1 + len2] = '\0'; + /* Now NULL terminate the string */ + cp[len1 + len2] = '\0'; - return cp; -} - -/* - * folder_exists - * Check to see if a folder exists. - */ -int folder_exists(char *folder) -{ - struct stat st; - int exists = 0; - - if (stat (folder, &st) == -1) { - /* The folder either doesn't exist, or we hit an error. Either way - * return a failure. - */ - exists = 0; - } else { - /* We can see a folder with the right name */ - exists = 1; - } - - return exists; + return cp; } /* - * create_folder - * Check to see if a folder exists, if not, prompt the user to create - * it. - */ -void create_folder(char *folder, int autocreate, void (*done_callback)(int)) +** create_folder +** Check to see if a folder exists, if not, prompt the user to create it. +*/ +void +create_folder(char *folder, int autocreate, void (*done_callback)(int)) { - struct stat st; - extern int errno; - char *cp; - - if (stat (folder, &st) == -1) { - if (errno != ENOENT) - adios (folder, "error on folder"); - if (autocreate == 0) { - /* ask before creating folder */ - cp = concat ("Create folder \"", folder, "\"? ", NULL); - if (!getanswer (cp)) - done_callback (1); - free (cp); - } else if (autocreate == -1) { - /* do not create, so exit */ - done_callback (1); - } - if (!makedir (folder)) - adios (NULL, "unable to create folder %s", folder); - } + struct stat st; + extern int errno; + char *cp; + + if (stat(folder, &st) == -1) { + if (errno != ENOENT) + adios(folder, "error on folder"); + if (autocreate == 0) { + /* ask before creating folder */ + cp = concat("Create folder \"", folder, "\"? ", NULL); + if (!getanswer(cp)) + done_callback(1); + free(cp); + } else if (autocreate == -1) { + /* do not create, so exit */ + done_callback(1); + } + if (!makedir(folder)) + adios(NULL, "unable to create folder %s", folder); + } } /* - * num_digits - * Return the number of digits in a nonnegative integer. - */ +** num_digits +** Return the number of digits in a nonnegative integer. +*/ int -num_digits (int n) +num_digits(int n) { - int ndigits = 0; + int ndigits = 0; - /* Sanity check */ - if (n < 0) - adios (NULL, "oops, num_digits called with negative value"); + /* Sanity check */ + if (n < 0) + adios(NULL, "oops, num_digits called with negative value"); - if (n == 0) - return 1; + if (n == 0) + return 1; - while (n) { - n /= 10; - ndigits++; - } + while (n) { + n /= 10; + ndigits++; + } - return ndigits; + return ndigits; } /* - * Append a message arg to an array of them, resizing it if necessary. - * The function is written to suit the arg parsing code it was extracted - * from, and will probably be changed when the other code is cleaned up. - */ +** Append a message arg to an array of them, resizing it if necessary. +** The function is written to suit the arg parsing code it was extracted +** from, and will probably be changed when the other code is cleaned up. +*/ void app_msgarg(struct msgs_array *msgs, char *cp) { if(msgs->size >= msgs->max) - msgs->msgs = mh_xrealloc(msgs->msgs, (msgs->max+=MAXMSGS)*sizeof(*msgs->msgs)); + msgs->msgs = mh_xrealloc(msgs->msgs, + (msgs->max+=MAXMSGS)*sizeof(*msgs->msgs)); msgs->msgs[msgs->size++] = cp; } - -/* Open a form or components file */ -int -open_form(char **form, char *def) -{ - int in; - if (*form) { - if ((in = open (etcpath (*form), O_RDONLY)) == NOTOK) - adios (*form, "unable to open form file"); - } else { - if ((in = open (etcpath (def), O_RDONLY)) == NOTOK) - adios (def, "unable to open default components file"); - *form = def; - } - return in; -} diff --git a/sbr/vfgets.c b/sbr/vfgets.c index 3a376e1..bd01a2c 100644 --- a/sbr/vfgets.c +++ b/sbr/vfgets.c @@ -1,72 +1,71 @@ - /* - * vfgets.c -- virtual fgets - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** vfgets.c -- virtual fgets +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include -#define QUOTE '\\' +#define QUOTE '\\' int -vfgets (FILE *in, char **bp) +vfgets(FILE *in, char **bp) { - int toggle; - char *cp, *dp, *ep, *fp; - static int len = 0; - static char *pp = NULL; + int toggle; + char *cp, *dp, *ep, *fp; + static int len = 0; + static char *pp = NULL; - if (pp == NULL) - pp = mh_xmalloc ((size_t) (len = BUFSIZ)); + if (pp == NULL) + pp = mh_xmalloc((size_t) (len = BUFSIZ)); - for (ep = (cp = pp) + len - 1;;) { - if (fgets (cp, ep - cp + 1, in) == NULL) { - if (cp != pp) { - *bp = pp; - return 0; - } - return (ferror (in) && !feof (in) ? -1 : 1); - } + for (ep = (cp = pp) + len - 1;;) { + if (fgets(cp, ep - cp + 1, in) == NULL) { + if (cp != pp) { + *bp = pp; + return 0; + } + return (ferror(in) && !feof(in) ? -1 : 1); + } - if ((dp = cp + strlen (cp) - 2) < cp || *dp != QUOTE) { + if ((dp = cp + strlen(cp) - 2) < cp || *dp != QUOTE) { wrong_guess: - if (cp > ++dp) - adios (NULL, "vfgets() botch -- you lose big"); - if (*dp == '\n') { - *bp = pp; - return 0; - } else { - cp = ++dp; - } - } else { - for (fp = dp - 1, toggle = 0; fp >= cp; fp--) { - if (*fp != QUOTE) - break; - else - toggle = !toggle; - } - if (toggle) - goto wrong_guess; + if (cp > ++dp) + adios(NULL, "vfgets() botch -- you lose big"); + if (*dp == '\n') { + *bp = pp; + return 0; + } else { + cp = ++dp; + } + } else { + for (fp = dp - 1, toggle = 0; fp >= cp; fp--) { + if (*fp != QUOTE) + break; + else + toggle = !toggle; + } + if (toggle) + goto wrong_guess; - if (*++dp == '\n') { - *--dp = 0; - cp = dp; - } else { - cp = ++dp; - } - } + if (*++dp == '\n') { + *--dp = 0; + cp = dp; + } else { + cp = ++dp; + } + } - if (cp >= ep) { - int curlen = cp - pp; + if (cp >= ep) { + int curlen = cp - pp; - dp = mh_xrealloc (pp, (size_t) (len += BUFSIZ)); - cp = dp + curlen; - ep = (pp = dp) + len - 1; + dp = mh_xrealloc(pp, (size_t) (len += BUFSIZ)); + cp = dp + curlen; + ep = (pp = dp) + len - 1; + } } - } } diff --git a/test/README b/test/README index c61647e..94b5ab1 100644 --- a/test/README +++ b/test/README @@ -1,5 +1,10 @@ nmh unit test suite. + + The testcases are not maintained in mmh, currently. + Thus, they likely are broken. --meillo 2012-04 + + The purpose of these tests is to verify the functionality of the nmh commands. The goal of the suite is to create an environment where testing nmh commands is easy and useful. Each test is a shell script, and is diff --git a/test/tests/bad-input/test-header b/test/tests/bad-input/test-header index b9e76a1..8d466ac 100644 --- a/test/tests/bad-input/test-header +++ b/test/tests/bad-input/test-header @@ -69,7 +69,7 @@ This is a multi-part message in MIME format. I am a stupid spammer. EOF -mhshow -nopause $msgnum > $actual 2>&1 +mhshow $msgnum > $actual 2>&1 check exit $failed diff --git a/test/tests/mhbuild/test-forw b/test/tests/mhbuild/test-forw index 1dece26..8e78374 100644 --- a/test/tests/mhbuild/test-forw +++ b/test/tests/mhbuild/test-forw @@ -18,8 +18,8 @@ check() { mkdraft() { cat > $draft < $expected < $expected < $actual 2>&1 +mhshow $msgnum > $actual 2>&1 diff -u $expected $actual diff --git a/test/tests/mhshow/test-qp b/test/tests/mhshow/test-qp index ae6ec05..74d70ee 100644 --- a/test/tests/mhshow/test-qp +++ b/test/tests/mhshow/test-qp @@ -59,5 +59,5 @@ just a newline =l = ^H (backspace) character, probably erased = in diff output EOF -mhshow -nopause $msgnum > $actual 2>&1 +mhshow $msgnum > $actual 2>&1 diff -u $expected $actual diff --git a/uip/Makefile.in b/uip/Makefile.in index 370fc15..bf23531 100644 --- a/uip/Makefile.in +++ b/uip/Makefile.in @@ -17,21 +17,18 @@ etcdir = @sysconfdir@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@ +INCLUDES = -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -MTSLIB = ../mts/libmts.a -NDBM_LIBS = @NDBM_LIBS@ -LOCALLIBS = ../config/version.o ../config/config.o $(MTSLIB) ../sbr/libmh.a +LOCALLIBS = ../config/version.o ../config/config.o ../sbr/libmh.a LINKLIBS = $(LOCALLIBS) $(LIBS) -LINT = @LINT@ +LINT = @LINT@ LINTFLAGS = @LINTFLAGS@ TERMLIB = @TERMLIB@ LEXLIB = @LEXLIB@ -POPLIB = @POPLIB@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) LINK = $(CC) $(LDFLAGS) -o $@ @@ -50,37 +47,33 @@ SETGID_MAIL = @SETGID_MAIL@ $(COMPILE) $< # commands to build -CMDS = ali anno burst comp dist flist folder forw install-mh mark mhbuild \ - mhlist mhmail mhn mhparam mhpath mhshow mhstore msgchk \ - msh new packf pick prompter refile repl rmf rmm scan send show \ - sortm whatnow whom - -## removed this from CMDS until I can fix it -## OTHERCMDS = vmh +CMDS = ali anno burst comp dist flist folder forw mmh mark \ + mhbuild mhl mhsign mhpgp \ + mhlist mhmail mhparam mhpath mhstore new packf pick \ + print-mimetype prompter rcvdist rcvpack rcvstore refile repl rmf \ + rmm scan send sendfiles show slocal sortm spost whatnow whom # commands that are links to other commands -LCMDS = flists folders next prev +LCMDS = flists folders next prev fnext fprev unseen # misc support binaries -MISC = ap conflict dp fmtdump mhl post rcvdist rcvpack \ - rcvstore rcvtty slocal spost viamail mhtest +MISC = ap dp fmtdump mhtest mmhwrap # commands with 'S'pecial installation needs SCMDS = inc # source files -SRCS = ali.c aliasbr.c anno.c annosbr.c ap.c burst.c comp.c \ - conflict.c dist.c distsbr.c dp.c dropsbr.c flist.c fmtdump.c \ - folder.c forw.c ftpsbr.c inc.c install-mh.c mark.c md5.c mhbuild.c \ - mhbuildsbr.c mhcachesbr.c mhfree.c mhl.c mhlist.c mhlistsbr.c \ - mhlsbr.c mhmail.c mhmisc.c mhn.c mhoutsbr.c mhparam.c mhparse.c \ - mhpath.c mhshow.c mhshowsbr.c mhstore.c mhstoresbr.c mhtest.c \ - msgchk.c msh.c mshcmds.c new.c packf.c pick.c picksbr.c popsbr.c \ - post.c prompter.c rcvdist.c rcvpack.c rcvstore.c rcvtty.c \ - refile.c repl.c replsbr.c rmf.c rmm.c scan.c scansbr.c send.c \ - sendsbr.c show.c slocal.c sortm.c spost.c termsbr.c viamail.c \ - vmh.c vmhsbr.c vmhtest.c whatnow.c whatnowproc.c whatnowsbr.c \ - whom.c wmh.c +SRCS = ali.c aliasbr.c anno.c ap.c burst.c comp.c \ + dist.c distsbr.c dp.c dropsbr.c flist.c fmtdump.c \ + folder.c forw.c inc.c mark.c mmh.sh mmhwrap.sh mhbuild.c \ + mhfree.c mhl.c mhlist.c mhlistsbr.c mhsign.sh mhpgp.sh \ + mhmail.c mhmisc.c mhoutsbr.c mhparam.c mhparse.c \ + mhpath.c mhshow.c mhshowsbr.c mhstore.c mhtest.c \ + new.c packf.c pick.c print-mimetype.sh \ + prompter.c rcvdist.c rcvpack.c rcvstore.c \ + refile.c repl.c rmf.c rmm.c scan.c scansbr.c send.c \ + sendfiles.sh slocal.c sortm.c spost.c termsbr.c \ + whatnow.c whatnowproc.c whom.c # auxiliary files AUX = Makefile.in @@ -97,26 +90,23 @@ all: $(CMDS) $(MISC) $(SCMDS) ali: ali.o aliasbr.o $(LOCALLIBS) $(LINK) ali.o aliasbr.o $(LINKLIBS) -ap: ap.o termsbr.o $(LOCALLIBS) - $(LINK) ap.o termsbr.o $(LINKLIBS) $(TERMLIB) +ap: ap.o $(LOCALLIBS) + $(LINK) ap.o $(LINKLIBS) -anno: anno.o annosbr.o $(LOCALLIBS) - $(LINK) anno.o annosbr.o $(LINKLIBS) +anno: anno.o $(LOCALLIBS) + $(LINK) anno.o $(LINKLIBS) burst: burst.o $(LOCALLIBS) $(LINK) burst.o $(LINKLIBS) -comp: comp.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) comp.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) - -conflict: conflict.o aliasbr.o $(LOCALLIBS) - $(LINK) conflict.o aliasbr.o $(LINKLIBS) +comp: comp.o whatnowproc.o $(LOCALLIBS) + $(LINK) comp.o whatnowproc.o $(LINKLIBS) -dist: dist.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) dist.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) +dist: dist.o whatnowproc.o $(LOCALLIBS) + $(LINK) dist.o whatnowproc.o $(LINKLIBS) -dp: dp.o termsbr.o $(LOCALLIBS) - $(LINK) dp.o termsbr.o $(LINKLIBS) $(TERMLIB) +dp: dp.o $(LOCALLIBS) + $(LINK) dp.o $(LINKLIBS) flist: flist.o $(LOCALLIBS) $(LINK) flist.o $(LINKLIBS) @@ -127,53 +117,57 @@ fmtdump: fmtdump.o $(LOCALLIBS) folder: folder.o $(LOCALLIBS) $(LINK) folder.o $(LINKLIBS) -forw: forw.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) forw.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) +forw: forw.o whatnowproc.o $(LOCALLIBS) + $(LINK) forw.o whatnowproc.o $(LINKLIBS) -inc: inc.o scansbr.o dropsbr.o termsbr.o $(POPLIB) $(LOCALLIBS) - $(LINK) inc.o scansbr.o dropsbr.o termsbr.o $(POPLIB) $(LINKLIBS) $(TERMLIB) - -install-mh: install-mh.o $(LOCALLIBS) - $(LINK) install-mh.o $(LINKLIBS) +inc: inc.o scansbr.o termsbr.o $(LOCALLIBS) + $(LINK) inc.o scansbr.o termsbr.o $(LINKLIBS) $(TERMLIB) mark: mark.o $(LOCALLIBS) $(LINK) mark.o $(LINKLIBS) -mhbuild: mhbuild.o mhbuildsbr.o mhcachesbr.o mhlistsbr.o mhoutsbr.o mhmisc.o mhfree.o mhparse.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhbuild.o mhbuildsbr.o mhcachesbr.o mhlistsbr.o mhoutsbr.o mhmisc.o mhfree.o mhparse.o ftpsbr.o md5.o $(LINKLIBS) $(TERMLIB) +mmh: mmh.sh + cp $(srcdir)/mmh.sh mmh + chmod +x mmh + +mmhwrap: mmhwrap.sh + sed "s,%bindir%,"$(bindir)"," $(srcdir)/mmhwrap.sh >mmhwrap + chmod +x mmhwrap + +mhsign: mhsign.sh + cp $(srcdir)/mhsign.sh mhsign + chmod +x mhsign + +mhpgp: mhpgp.sh + cp $(srcdir)/mhpgp.sh mhpgp + chmod +x mhpgp + +mhbuild: mhbuild.o mhoutsbr.o mhmisc.o mhfree.o mhparse.o termsbr.o $(LOCALLIBS) + $(LINK) mhbuild.o mhoutsbr.o mhmisc.o mhfree.o mhparse.o $(LINKLIBS) $(TERMLIB) -mhl: mhl.o mhlsbr.o termsbr.o $(LOCALLIBS) - $(LINK) mhl.o mhlsbr.o termsbr.o $(LINKLIBS) $(TERMLIB) +mhl: mhl.o termsbr.o $(LOCALLIBS) + $(LINK) mhl.o termsbr.o $(LINKLIBS) $(TERMLIB) -mhlist: mhlist.o mhparse.o mhcachesbr.o mhlistsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhlist.o mhparse.o mhcachesbr.o mhlistsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LINKLIBS) $(TERMLIB) +mhlist: mhlist.o mhparse.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LOCALLIBS) + $(LINK) mhlist.o mhparse.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LINKLIBS) $(TERMLIB) mhmail: mhmail.o $(LOCALLIBS) $(LINK) mhmail.o $(LINKLIBS) -mhn: mhn.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhstoresbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhn.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhstoresbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LINKLIBS) $(TERMLIB) - mhparam: mhparam.o $(LOCALLIBS) $(LINK) mhparam.o $(LINKLIBS) mhpath: mhpath.o $(LOCALLIBS) $(LINK) mhpath.o $(LINKLIBS) -mhshow: mhshow.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhshow.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LINKLIBS) $(TERMLIB) - -mhstore: mhstore.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhstoresbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhstore.o mhparse.o mhcachesbr.o mhshowsbr.o mhlistsbr.o mhstoresbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LINKLIBS) $(TERMLIB) - -mhtest: mhtest.o mhparse.o mhcachesbr.o mhoutsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LOCALLIBS) - $(LINK) mhtest.o mhparse.o mhcachesbr.o mhoutsbr.o mhmisc.o mhfree.o ftpsbr.o termsbr.o md5.o $(LINKLIBS) $(TERMLIB) +show: mhshow.o mhparse.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LOCALLIBS) + $(LINK) mhshow.o mhparse.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LINKLIBS) $(TERMLIB) -msgchk: msgchk.o $(POPLIB) $(LOCALLIBS) - $(LINK) msgchk.o $(POPLIB) $(LINKLIBS) +mhstore: mhstore.o mhparse.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LOCALLIBS) + $(LINK) mhstore.o mhparse.o mhshowsbr.o mhlistsbr.o mhmisc.o mhfree.o termsbr.o $(LINKLIBS) $(TERMLIB) -msh: msh.o mshcmds.o vmhsbr.o picksbr.o scansbr.o dropsbr.o mhlsbr.o termsbr.o $(LOCALLIBS) - $(LINK) msh.o mshcmds.o vmhsbr.o picksbr.o scansbr.o dropsbr.o mhlsbr.o termsbr.o $(LINKLIBS) $(TERMLIB) +mhtest: mhtest.o mhparse.o mhoutsbr.o mhmisc.o mhfree.o termsbr.o $(LOCALLIBS) + $(LINK) mhtest.o mhparse.o mhoutsbr.o mhmisc.o mhfree.o termsbr.o $(LINKLIBS) $(TERMLIB) new: new.o $(LOCALLIBS) $(LINK) new.o $(LINKLIBS) @@ -181,11 +175,12 @@ new: new.o $(LOCALLIBS) packf: packf.o dropsbr.o $(LOCALLIBS) $(LINK) packf.o dropsbr.o $(LINKLIBS) -pick: pick.o picksbr.o $(LOCALLIBS) - $(LINK) pick.o picksbr.o $(LINKLIBS) +pick: pick.o $(LOCALLIBS) + $(LINK) pick.o $(LINKLIBS) -post: post.o aliasbr.o $(LOCALLIBS) - $(LINK) post.o aliasbr.o $(LINKLIBS) +print-mimetype: print-mimetype.sh + cp $(srcdir)/print-mimetype.sh print-mimetype + chmod +x print-mimetype prompter: prompter.o $(LOCALLIBS) $(LINK) prompter.o $(LINKLIBS) @@ -199,14 +194,11 @@ rcvpack: rcvpack.o dropsbr.o $(LOCALLIBS) rcvstore: rcvstore.o $(LOCALLIBS) $(LINK) rcvstore.o $(LINKLIBS) -rcvtty: rcvtty.o scansbr.o termsbr.o $(LOCALLIBS) - $(LINK) rcvtty.o scansbr.o termsbr.o $(LINKLIBS) $(TERMLIB) - refile: refile.o $(LOCALLIBS) $(LINK) refile.o $(LINKLIBS) -repl: repl.o replsbr.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) repl.o replsbr.o whatnowproc.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) +repl: repl.o whatnowproc.o $(LOCALLIBS) + $(LINK) repl.o whatnowproc.o $(LINKLIBS) rmf: rmf.o $(LOCALLIBS) $(LINK) rmf.o $(LINKLIBS) @@ -217,14 +209,15 @@ rmm: rmm.o $(LOCALLIBS) scan: scan.o scansbr.o termsbr.o $(LOCALLIBS) $(LINK) scan.o scansbr.o termsbr.o $(LINKLIBS) $(TERMLIB) -send: send.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) send.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) +send: send.o distsbr.o $(LOCALLIBS) + $(LINK) send.o distsbr.o $(LINKLIBS) -show: show.o mhlsbr.o termsbr.o $(LOCALLIBS) - $(LINK) show.o mhlsbr.o termsbr.o $(LINKLIBS) $(TERMLIB) +sendfiles: sendfiles.sh + cp $(srcdir)/sendfiles.sh sendfiles + chmod +x sendfiles -slocal: slocal.o aliasbr.o dropsbr.o $(LOCALLIBS) - $(LINK) slocal.o aliasbr.o dropsbr.o $(NDBM_LIBS) $(LINKLIBS) +slocal: slocal.o $(LOCALLIBS) + $(LINK) slocal.o $(LINKLIBS) sortm: sortm.o $(LOCALLIBS) $(LINK) sortm.o $(LINKLIBS) @@ -232,17 +225,11 @@ sortm: sortm.o $(LOCALLIBS) spost: spost.o aliasbr.o $(LOCALLIBS) $(LINK) spost.o aliasbr.o $(LINKLIBS) -viamail: viamail.o mhmisc.o mhoutsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) viamail.o mhmisc.o mhoutsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) $(TERMLIB) - -vmh: vmh.o vmhsbr.o $(LOCALLIBS) - $(LINK) vmh.o vmhsbr.o $(LINKLIBS) $(TERMLIB) - -whatnow: whatnow.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LOCALLIBS) - $(LINK) whatnow.o whatnowsbr.o sendsbr.o annosbr.o distsbr.o $(LINKLIBS) +whatnow: whatnow.o $(LOCALLIBS) + $(LINK) whatnow.o $(LINKLIBS) -whom: whom.o distsbr.o $(LOCALLIBS) - $(LINK) whom.o distsbr.o $(LINKLIBS) +whom: whom.o $(LOCALLIBS) + $(LINK) whom.o $(LINKLIBS) # ========== DEPENDENCIES FOR INSTALLING ========== @@ -251,7 +238,7 @@ install: install-cmds install-misc install-lcmds install-scmds # install commands install-cmds: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + mkdir -p $(DESTDIR)$(bindir) for cmd in $(CMDS); do \ $(INSTALL_PROGRAM) $$cmd $(DESTDIR)$(bindir)/$$cmd; \ done @@ -265,7 +252,6 @@ install-lcmds: rm -f $(DESTDIR)$(bindir)/unseen rm -f $(DESTDIR)$(bindir)/prev rm -f $(DESTDIR)$(bindir)/next - rm -f $(DESTDIR)$(libdir)/install-mh $(LN) $(DESTDIR)$(bindir)/flist $(DESTDIR)$(bindir)/flists $(LN) $(DESTDIR)$(bindir)/folder $(DESTDIR)$(bindir)/folders $(LN) $(DESTDIR)$(bindir)/new $(DESTDIR)$(bindir)/fnext @@ -276,7 +262,7 @@ install-lcmds: # install misc support binaries install-misc: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir) + mkdir -p $(DESTDIR)$(libdir) for misc in $(MISC); do \ $(INSTALL_PROGRAM) $$misc $(DESTDIR)$(libdir)/$$misc; \ done @@ -320,7 +306,7 @@ superclean: realclean # ========== DEPENDENCIES FOR LINT ================ -lint: +lint: $(LINT) $(LINTFLAGS) $(INCLUDES) $(DEFS) $(SRCS) # ========== DEPENDENCIES FOR MAINTENANCE ========== @@ -331,7 +317,7 @@ Makefile: Makefile.in ../config.status cd .. && ./config.status $(subdir)/$@ distdir = ../`cat ../distname`/$(subdir) -nmhdist: $(DIST) +mmhdist: $(DIST) @echo "Copying distribution files in $(subdir)" @for file in $(DIST); do \ cp -p $(srcdir)/$$file $(distdir); \ diff --git a/uip/ali.c b/uip/ali.c index 41f92a6..2c80147 100644 --- a/uip/ali.c +++ b/uip/ali.c @@ -1,45 +1,41 @@ - /* - * ali.c -- list nmh mail aliases - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** ali.c -- list nmh mail aliases +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include /* - * maximum number of names - */ -#define NVEC 50 +** maximum number of names +*/ +#define NVEC 50 static struct swit switches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define NALIASW 1 - { "noalias", -7 }, -#define LISTSW 2 - { "list", 0 }, -#define NLISTSW 3 - { "nolist", 0 }, -#define NORMSW 4 - { "normalize", 0 }, -#define NNORMSW 5 - { "nonormalize", 0 }, -#define USERSW 6 - { "user", 0 }, -#define NUSERSW 7 - { "nouser", 0 }, -#define VERSIONSW 8 - { "version", 0 }, -#define HELPSW 9 - { "help", 0 }, - { NULL, 0 } +#define FILESW 0 + { "file aliasfile", 0 }, +#define LISTSW 1 + { "list", 0 }, +#define NLISTSW 2 + { "nolist", 2 }, +#define NORMSW 3 + { "normalize", 0 }, +#define NNORMSW 4 + { "nonormalize", 2 }, +#define USERSW 5 + { "user", 0 }, +#define NUSERSW 6 + { "nouser", 2 }, +#define VERSIONSW 7 + { "Version", 0 }, +#define HELPSW 8 + { "help", 0 }, + { NULL, 0 } }; static int pos = 1; @@ -47,212 +43,204 @@ static int pos = 1; extern struct aka *akahead; /* - * prototypes - */ -static void print_aka (char *, int, int); -static void print_usr (char *, int, int); +** prototypes +*/ +static void print_aka(char *, int, int); +static void print_usr(char *, int, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int i, vecp = 0, inverted = 0, list = 0; - int noalias = 0, normalize = AD_NHST; - char *cp, **ap, **argp, buf[BUFSIZ]; - char *vec[NVEC], **arguments; - struct aka *ak; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] aliases ...", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version (invo_name); - done (1); - - case ALIASW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((i = alias (cp)) != AK_OK) - adios (NULL, "aliasing error in %s - %s", cp, akerror (i)); - continue; - case NALIASW: - noalias++; - continue; - - case LISTSW: - list++; - continue; - case NLISTSW: - list = 0; - continue; - - case NORMSW: - normalize = AD_HOST; - continue; - case NNORMSW: - normalize = AD_NHST; - continue; - - case USERSW: - inverted++; - continue; - case NUSERSW: - inverted = 0; - continue; - } + int i, vecp = 0, inverted = 0, list = 0; + int deffiles = 1, normalize = AD_NHST; + char *cp, **ap, **argp, buf[BUFSIZ]; + char *vec[NVEC], **arguments; + struct aka *ak; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] aliases ...", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FILESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", argp[-2]); + if ((i = alias(cp)) != AK_OK) + adios(NULL, "aliasing error in %s: %s", cp, akerror(i)); + deffiles = 0; + continue; + + case LISTSW: + list++; + continue; + case NLISTSW: + list = 0; + continue; + + case NORMSW: + normalize = AD_HOST; + continue; + case NNORMSW: + normalize = AD_NHST; + continue; + + case USERSW: + inverted++; + continue; + case NUSERSW: + inverted = 0; + continue; + } + } + vec[vecp++] = cp; } - vec[vecp++] = cp; - } - - if (!noalias) { - /* allow Aliasfile: profile entry */ - if ((cp = context_find ("Aliasfile"))) { - char *dp = NULL; - - for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++) - if ((i = alias (*ap)) != AK_OK) - adios (NULL, "aliasing error in %s - %s", *ap, akerror (i)); - if (dp) - free(dp); + + /* process default Aliasfile: profile entry */ + if (deffiles && (cp = context_find("Aliasfile"))) { + char *dp = NULL; + + for (ap = brkstring(dp=getcpy(cp), " ", "\n"); + ap && *ap; ap++) { + if ((i = alias(etcpath(*ap))) != AK_OK) { + adios(NULL, "aliasing error in %s: %s", + *ap, akerror(i)); + } + } + if (dp) { + free(dp); + } } - alias (AliasFile); - } - - /* - * If -user is specified - */ - if (inverted) { - if (vecp == 0) - adios (NULL, "usage: %s -user addresses ... (you forgot the addresses)", - invo_name); - - for (i = 0; i < vecp; i++) - print_usr (vec[i], list, normalize); - - done (0); - } - - if (vecp) { - /* print specified aliases */ - for (i = 0; i < vecp; i++) - print_aka (akvalue (vec[i]), list, 0); - } else { - /* print them all */ - for (ak = akahead; ak; ak = ak->ak_next) { - printf ("%s: ", ak->ak_name); - pos += strlen (ak->ak_name) + 1; - print_aka (akresult (ak), list, pos); + + /* + ** If -user is specified + */ + if (inverted) { + if (vecp == 0) + adios(NULL, "usage: %s -user addresses ... (you forgot the addresses)", + invo_name); + + for (i = 0; i < vecp; i++) + print_usr(vec[i], list, normalize); + + done(0); + } + + if (vecp) { + /* print specified aliases */ + for (i = 0; i < vecp; i++) + print_aka(akvalue(vec[i]), list, 0); + } else { + /* print them all */ + for (ak = akahead; ak; ak = ak->ak_next) { + printf("%s: ", ak->ak_name); + pos += strlen(ak->ak_name) + 1; + print_aka(akresult(ak), list, pos); + } } - } - done (0); - return 1; + done(0); + return 1; } static void -print_aka (char *p, int list, int margin) +print_aka(char *p, int list, int margin) { - char c; - - if (p == NULL) { - printf ("\n"); - return; - } - - while ((c = *p++)) { - switch (c) { - case ',': - if (*p) { - if (list) - printf ("\n%*s", margin, ""); - else { - if (pos >= 68) { - printf (",\n "); - pos = 2; - } else { - printf (", "); - pos += 2; + char c; + + if (p == NULL) { + printf("\n"); + return; + } + + while ((c = *p++)) { + switch (c) { + case ',': + if (*p) { + if (list) + printf("\n%*s", margin, ""); + else { + if (pos >= 68) { + printf(",\n "); + pos = 2; + } else { + printf(", "); + pos += 2; + } + } } - } - } - case 0: - break; + case 0: + break; - default: - pos++; - putchar (c); + default: + pos++; + putchar(c); + } } - } - putchar ('\n'); - pos = 1; + putchar('\n'); + pos = 1; } static void -print_usr (char *s, int list, int norm) +print_usr(char *s, int list, int norm) { - register char *cp, *pp, *vp; - register struct aka *ak; - register struct mailname *mp, *np; - - if ((pp = getname (s)) == NULL) - adios (NULL, "no address in \"%s\"", s); - if ((mp = getm (pp, NULL, 0, norm, NULL)) == NULL) - adios (NULL, "bad address \"%s\"", s); - while (getname ("")) - continue; - - vp = NULL; - for (ak = akahead; ak; ak = ak->ak_next) { - pp = akresult (ak); - while ((cp = getname (pp))) { - if ((np = getm (cp, NULL, 0, norm, NULL)) == NULL) + register char *cp, *pp, *vp; + register struct aka *ak; + register struct mailname *mp, *np; + + if ((pp = getname(s)) == NULL) + adios(NULL, "no address in \"%s\"", s); + if ((mp = getm(pp, NULL, 0, norm, NULL)) == NULL) + adios(NULL, "bad address \"%s\"", s); + while (getname("")) continue; - if (!mh_strcasecmp (mp->m_host, np->m_host) - && !mh_strcasecmp (mp->m_mbox, np->m_mbox)) { - vp = vp ? add (ak->ak_name, add (",", vp)) - : getcpy (ak->ak_name); - mnfree (np); - while (getname ("")) - continue; - break; - } - mnfree (np); + + vp = NULL; + for (ak = akahead; ak; ak = ak->ak_next) { + pp = akresult(ak); + while ((cp = getname(pp))) { + if ((np = getm(cp, NULL, 0, norm, NULL)) == NULL) + continue; + if (!mh_strcasecmp(mp->m_host, np->m_host) + && !mh_strcasecmp(mp->m_mbox, np->m_mbox)) { + vp = vp ? add(ak->ak_name, add(",", vp)) + : getcpy(ak->ak_name); + mnfree(np); + while (getname("")) + continue; + break; + } + mnfree(np); + } } - } - mnfree (mp); - -#if 0 - printf ("%s: ", s); - print_aka (vp ? vp : s, list, pos += strlen (s) + 1); -#else - print_aka (vp ? vp : s, list, 0); -#endif - - if (vp) - free (vp); + mnfree(mp); + + print_aka(vp ? vp : s, list, 0); + + if (vp) + free(vp); } diff --git a/uip/aliasbr.c b/uip/aliasbr.c index b1a7e61..8b32826 100644 --- a/uip/aliasbr.c +++ b/uip/aliasbr.c @@ -1,11 +1,10 @@ - /* - * aliasbr.c -- new aliasing mechanism - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** aliasbr.c -- new aliasing mechanism +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -23,574 +22,519 @@ struct home *homehead = NULL; struct home *hometail = NULL; /* - * prototypes - */ -int alias (char *); -int akvisible (void); -void init_pw (void); -char *akresult (struct aka *); -char *akvalue (char *); -char *akerror (int); - -static char *akval (struct aka *, char *); -static int aleq (char *, char *); -static char *scanp (unsigned char *); -static char *getp (char *); -static char *seekp (char *, char *, char **); -static int addfile (struct aka *, char *); -static int addgroup (struct aka *, char *); -static int addmember (struct aka *, char *); -static int addall (struct aka *); -static char *getalias (char *); -static void add_aka (struct aka *, char *); -static struct aka *akalloc (char *); -static struct home *hmalloc (struct passwd *); -struct home *seek_home (char *); +** prototypes +*/ +int alias(char *); +int akvisible(void); +void init_pw(void); +char *akresult(struct aka *); +char *akvalue(char *); +char *akerror(int); + +static char *akval(struct aka *, char *); +static int aleq(char *, char *); +static char *scanp(unsigned char *); +static char *getp(char *); +static char *seekp(char *, char *, char **); +static int addfile(struct aka *, char *); +static int addgroup(struct aka *, char *); +static int addmember(struct aka *, char *); +static char *getalias(char *); +static void add_aka(struct aka *, char *); +static struct aka *akalloc(char *); +static struct home *hmalloc(struct passwd *); +struct home *seek_home(char *); /* Do mh alias substitution on 's' and return the results. */ char * -akvalue (char *s) +akvalue(char *s) { - register char *v; - - if (akahead == NULL) - alias (AliasFile); + register char *v; - akvis = -1; - v = akval (akahead, s); - if (akvis == -1) - akvis = 0; - return v; + akvis = -1; + v = akval(akahead, s); + if (akvis == -1) + akvis = 0; + return v; } int -akvisible (void) +akvisible(void) { - return akvis; + return akvis; } char * -akresult (struct aka *ak) +akresult(struct aka *ak) { - register char *cp = NULL, *dp, *pp; - register struct adr *ad; - - for (ad = ak->ak_addr; ad; ad = ad->ad_next) { - pp = ad->ad_local ? akval (ak->ak_next, ad->ad_text) - : getcpy (ad->ad_text); - - if (cp) { - dp = cp; - cp = concat (cp, ",", pp, NULL); - free (dp); - free (pp); + register char *cp = NULL, *dp, *pp; + register struct adr *ad; + + for (ad = ak->ak_addr; ad; ad = ad->ad_next) { + pp = ad->ad_local ? akval(ak->ak_next, ad->ad_text) + : getcpy(ad->ad_text); + + if (cp) { + dp = cp; + cp = concat(cp, ",", pp, NULL); + free(dp); + free(pp); + } else + cp = pp; } - else - cp = pp; - } - if (akvis == -1) - akvis = ak->ak_visible; - return cp; + if (akvis == -1) + akvis = ak->ak_visible; + return cp; } -static char * -akval (struct aka *ak, char *s) +static char * +akval(struct aka *ak, char *s) { - if (!s) - return s; /* XXX */ + if (!s) + return s; /* XXX */ - for (; ak; ak = ak->ak_next) - if (aleq (s, ak->ak_name)) - return akresult (ak); + for (; ak; ak = ak->ak_next) + if (aleq(s, ak->ak_name)) + return akresult(ak); - return getcpy (s); + return getcpy(s); } static int -aleq (char *string, char *aliasent) +aleq(char *string, char *aliasent) { - register char c; + register char c; - while ((c = *string++)) - if (*aliasent == '*') - return 1; - else - if ((c | 040) != (*aliasent | 040)) - return 0; - else - aliasent++; + while ((c = *string++)) + if (*aliasent == '*') + return 1; + else if ((c | 040) != (*aliasent | 040)) + return 0; + else + aliasent++; - return (*aliasent == 0 || *aliasent == '*'); + return (*aliasent == 0 || *aliasent == '*'); } +/* +** file needs to be absolute or relative to cwd +*/ int -alias (char *file) +alias(char *file) { - int i; - register char *bp, *cp, *pp; - char lc, *ap; - register struct aka *ak = NULL; - register FILE *fp; - - if (*file != '/' - && (strncmp (file, "./", 2) && strncmp (file, "../", 3))) - file = etcpath (file); - if ((fp = fopen (file, "r")) == NULL) { - akerrst = file; - return AK_NOFILE; - } - - while (vfgets (fp, &ap) == OK) { - bp = ap; - switch (*(pp = scanp (bp))) { - case '<': /* recurse a level */ - if (!*(cp = getp (pp + 1))) { - akerrst = "'<' without alias-file"; - fclose (fp); - return AK_ERROR; - } - if ((i = alias (cp)) != AK_OK) { - fclose (fp); - return i; - } - - case ':': /* comment */ - case ';': - case '#': - case 0: - continue; + int i; + register char *bp, *cp, *pp; + char lc, *ap; + register struct aka *ak = NULL; + register FILE *fp; + + if ((fp = fopen(file, "r")) == NULL) { + akerrst = file; + return AK_NOFILE; } - akerrst = bp; - if (!*(cp = seekp (pp, &lc, &ap))) { - fclose (fp); - return AK_ERROR; - } - if (!(ak = akalloc (cp))) { - fclose (fp); - return AK_LIMIT; - } - switch (lc) { - case ':': - ak->ak_visible = 0; - break; - - case ';': - ak->ak_visible = 1; - break; - - default: - fclose (fp); - return AK_ERROR; - } - - switch (*(pp = scanp (ap))) { - case 0: /* EOL */ - fclose (fp); - return AK_ERROR; - - case '<': /* read values from file */ - if (!*(cp = getp (pp + 1))) { - fclose (fp); - return AK_ERROR; - } - if (!addfile (ak, cp)) { - fclose (fp); - return AK_NOFILE; + while (vfgets(fp, &ap) == OK) { + bp = ap; + switch (*(pp = scanp(bp))) { + case '<': /* recurse a level */ + if (!*(cp = getp(pp + 1))) { + akerrst = "'<' without alias-file"; + fclose(fp); + return AK_ERROR; + } + if ((i = alias(cp)) != AK_OK) { + fclose(fp); + return i; + } + + case ':': /* comment */ + case ';': + case '#': + case 0: + continue; } - break; - case '=': /* UNIX group */ - if (!*(cp = getp (pp + 1))) { - fclose (fp); - return AK_ERROR; + akerrst = bp; + if (!*(cp = seekp(pp, &lc, &ap))) { + fclose(fp); + return AK_ERROR; } - if (!addgroup (ak, cp)) { - fclose (fp); - return AK_NOGROUP; + if (!(ak = akalloc(cp))) { + fclose(fp); + return AK_LIMIT; } - break; - - case '+': /* UNIX group members */ - if (!*(cp = getp (pp + 1))) { - fclose (fp); - return AK_ERROR; - } - if (!addmember (ak, cp)) { - fclose (fp); - return AK_NOGROUP; + switch (lc) { + case ':': + ak->ak_visible = 0; + break; + + case ';': + ak->ak_visible = 1; + break; + + default: + fclose(fp); + return AK_ERROR; } - break; - case '*': /* Everyone */ - addall (ak); - break; - - default: /* list */ - while ((cp = getalias (pp))) - add_aka (ak, cp); - break; + switch (*(pp = scanp(ap))) { + case 0: /* EOL */ + fclose(fp); + return AK_ERROR; + + case '<': /* read values from file */ + if (!*(cp = getp(pp + 1))) { + fclose(fp); + return AK_ERROR; + } + if (!addfile(ak, cp)) { + fclose(fp); + return AK_NOFILE; + } + break; + + case '=': /* UNIX group */ + if (!*(cp = getp(pp + 1))) { + fclose(fp); + return AK_ERROR; + } + if (!addgroup(ak, cp)) { + fclose(fp); + return AK_NOGROUP; + } + break; + + case '+': /* UNIX group members */ + if (!*(cp = getp(pp + 1))) { + fclose(fp); + return AK_ERROR; + } + if (!addmember(ak, cp)) { + fclose(fp); + return AK_NOGROUP; + } + break; + + default: /* list */ + while ((cp = getalias(pp))) + add_aka(ak, cp); + break; + } } - } - fclose (fp); - return AK_OK; + fclose(fp); + return AK_OK; } char * -akerror (int i) +akerror(int i) { - static char buffer[BUFSIZ]; + static char buffer[BUFSIZ]; - switch (i) { - case AK_NOFILE: - snprintf (buffer, sizeof(buffer), "unable to read '%s'", akerrst); - break; + switch (i) { + case AK_NOFILE: + snprintf(buffer, sizeof(buffer), "unable to read '%s'", + akerrst); + break; - case AK_ERROR: - snprintf (buffer, sizeof(buffer), "error in line '%s'", akerrst); - break; + case AK_ERROR: + snprintf(buffer, sizeof(buffer), "error in line '%s'", + akerrst); + break; - case AK_LIMIT: - snprintf (buffer, sizeof(buffer), "out of memory while on '%s'", akerrst); - break; + case AK_LIMIT: + snprintf(buffer, sizeof(buffer), "out of memory while on '%s'", + akerrst); + break; - case AK_NOGROUP: - snprintf (buffer, sizeof(buffer), "no such group as '%s'", akerrst); - break; + case AK_NOGROUP: + snprintf(buffer, sizeof(buffer), "no such group as '%s'", + akerrst); + break; - default: - snprintf (buffer, sizeof(buffer), "unknown error (%d)", i); - break; - } + default: + snprintf(buffer, sizeof(buffer), "unknown error (%d)", i); + break; + } - return buffer; + return buffer; } static char * -scanp (unsigned char *p) +scanp(unsigned char *p) { - while (isspace (*p)) - p++; - return p; + while (isspace(*p)) + p++; + return p; } static char * -getp (char *p) +getp(char *p) { - register unsigned char *cp = scanp (p); + register unsigned char *cp = scanp(p); - p = cp; - while (!isspace (*cp) && *cp) - cp++; - *cp = 0; + p = cp; + while (!isspace(*cp) && *cp) + cp++; + *cp = 0; - return p; + return p; } static char * -seekp (char *p, char *c, char **a) +seekp(char *p, char *c, char **a) { - register unsigned char *cp; + register unsigned char *cp; - p = cp = scanp (p); - while (!isspace (*cp) && *cp && *cp != ':' && *cp != ';') - cp++; - *c = *cp; - *cp++ = 0; - *a = cp; + p = cp = scanp(p); + while (!isspace(*cp) && *cp && *cp != ':' && *cp != ';') + cp++; + *c = *cp; + *cp++ = 0; + *a = cp; - return p; + return p; } static int -addfile (struct aka *ak, char *file) +addfile(struct aka *ak, char *file) { - register char *cp; - char buffer[BUFSIZ]; - register FILE *fp; + register char *cp; + char buffer[BUFSIZ]; + register FILE *fp; - if (!(fp = fopen (etcpath (file), "r"))) { - akerrst = file; - return 0; - } + if (!(fp = fopen(etcpath(file), "r"))) { + akerrst = file; + return 0; + } - while (fgets (buffer, sizeof buffer, fp)) - while ((cp = getalias (buffer))) - add_aka (ak, cp); + while (fgets(buffer, sizeof buffer, fp)) + while ((cp = getalias(buffer))) + add_aka(ak, cp); - fclose (fp); - return 1; + fclose(fp); + return 1; } static int -addgroup (struct aka *ak, char *grp) +addgroup(struct aka *ak, char *grp) { - register char *gp; - register struct group *gr = getgrnam (grp); - register struct home *hm = NULL; - - if (!gr) - gr = getgrgid (atoi (grp)); - if (!gr) { - akerrst = grp; - return 0; - } - -#ifndef DBMPWD - if (homehead == NULL) - init_pw (); -#endif /* DBMPWD */ - - while ((gp = *gr->gr_mem++)) -#ifdef DBMPWD - { - struct passwd *pw; -#endif /* DBMPWD */ - for (hm = homehead; hm; hm = hm->h_next) - if (!strcmp (hm->h_name, gp)) { - add_aka (ak, hm->h_name); - break; - } -#ifdef DBMPWD - if ((pw = getpwnam(gp))) + register char *gp; + register struct group *gr = getgrnam(grp); + register struct home *hm = NULL; + + if (!gr) + gr = getgrgid(atoi(grp)); + if (!gr) { + akerrst = grp; + return 0; + } + + while ((gp = *gr->gr_mem++)) { - hmalloc(pw); - add_aka (ak, gp); + struct passwd *pw; + for (hm = homehead; hm; hm = hm->h_next) + if (strcmp(hm->h_name, gp)==0) { + add_aka(ak, hm->h_name); + break; + } + if ((pw = getpwnam(gp))) { + hmalloc(pw); + add_aka(ak, gp); + } } - } -#endif /* DBMPWD */ - return 1; + return 1; } static int -addmember (struct aka *ak, char *grp) +addmember(struct aka *ak, char *grp) { - gid_t gid; - register struct group *gr = getgrnam (grp); - register struct home *hm = NULL; - - if (gr) - gid = gr->gr_gid; - else { - gid = atoi (grp); - gr = getgrgid (gid); - } - if (!gr) { - akerrst = grp; - return 0; - } - -#ifndef DBMPWD - if (homehead == NULL) -#endif /* DBMPWD */ - init_pw (); - - for (hm = homehead; hm; hm = hm->h_next) - if (hm->h_gid == gid) - add_aka (ak, hm->h_name); - - return 1; -} + gid_t gid; + register struct group *gr = getgrnam(grp); + register struct home *hm = NULL; + + if (gr) + gid = gr->gr_gid; + else { + gid = atoi(grp); + gr = getgrgid(gid); + } + if (!gr) { + akerrst = grp; + return 0; + } + init_pw(); -static int -addall (struct aka *ak) -{ - int noshell = NoShell == NULL || *NoShell == 0; - register struct home *hm; - -#ifndef DBMPWD - if (homehead == NULL) -#endif /* DBMPWD */ - init_pw (); - if (Everyone < 0) - Everyone = EVERYONE; - - for (hm = homehead; hm; hm = hm->h_next) - if (hm->h_uid > Everyone - && (noshell || strcmp (hm->h_shell, NoShell))) - add_aka (ak, hm->h_name); - - return homehead != NULL; + for (hm = homehead; hm; hm = hm->h_next) + if (hm->h_gid == gid) + add_aka(ak, hm->h_name); + + return 1; } static char * -getalias (char *addrs) +getalias(char *addrs) { - register unsigned char *pp, *qp; - static char *cp = NULL; - - if (cp == NULL) - cp = addrs; - else - if (*cp == 0) - return (cp = NULL); - - for (pp = cp; isspace (*pp); pp++) - continue; - if (*pp == 0) - return (cp = NULL); - for (qp = pp; *qp != 0 && *qp != ','; qp++) - continue; - if (*qp == ',') - *qp++ = 0; - for (cp = qp, qp--; qp > pp; qp--) - if (*qp != 0) { - if (isspace (*qp)) - *qp = 0; - else - break; - } + register unsigned char *pp, *qp; + static char *cp = NULL; + + if (cp == NULL) + cp = addrs; + else + if (*cp == 0) + return (cp = NULL); + + for (pp = cp; isspace(*pp); pp++) + continue; + if (*pp == 0) + return (cp = NULL); + for (qp = pp; *qp != 0 && *qp != ','; qp++) + continue; + if (*qp == ',') + *qp++ = 0; + for (cp = qp, qp--; qp > pp; qp--) + if (*qp != 0) { + if (isspace(*qp)) + *qp = 0; + else + break; + } - return pp; + return pp; } static void -add_aka (struct aka *ak, char *pp) +add_aka(struct aka *ak, char *pp) { - register struct adr *ad, *ld; - - for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next) - if (!strcmp (pp, ad->ad_text)) - return; - - ad = (struct adr *) mh_xmalloc (sizeof(*ad)); - ad->ad_text = getcpy (pp); - ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL; - ad->ad_next = NULL; - if (ak->ak_addr) - ld->ad_next = ad; - else - ak->ak_addr = ad; + register struct adr *ad, *ld; + + for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next) + if (strcmp(pp, ad->ad_text)==0) + return; + + ad = (struct adr *) mh_xmalloc(sizeof(*ad)); + ad->ad_text = getcpy(pp); + ad->ad_local = strchr(pp, '@') == NULL; + ad->ad_next = NULL; + if (ak->ak_addr) + ld->ad_next = ad; + else + ak->ak_addr = ad; } void -init_pw (void) +init_pw(void) { - register struct passwd *pw; -#ifdef DBMPWD - static int init; - - if (!init) - { - /* if the list has yet to be initialized */ - /* zap the list, and rebuild from scratch */ - homehead=NULL; - hometail=NULL; - init++; -#endif /* DBMPWD */ - - setpwent (); - - while ((pw = getpwent ())) - if (!hmalloc (pw)) - break; - - endpwent (); -#ifdef DBMPWD - } -#endif /* DBMPWD */ + register struct passwd *pw; + static int init = 0; + + if (!init) { + /* read the passwd database and build a list */ + setpwent(); + while ((pw = getpwent())) { + if (!hmalloc(pw)) { + break; + } + } + endpwent(); + + init++; /* now we're initialized */ + } } static struct aka * -akalloc (char *id) +akalloc(char *id) { - register struct aka *p; + register struct aka *p; - p = (struct aka *) mh_xmalloc (sizeof(*p)); + p = (struct aka *) mh_xmalloc(sizeof(*p)); - p->ak_name = getcpy (id); - p->ak_visible = 0; - p->ak_addr = NULL; - p->ak_next = NULL; - if (akatail != NULL) - akatail->ak_next = p; - if (akahead == NULL) - akahead = p; - akatail = p; + p->ak_name = getcpy(id); + p->ak_visible = 0; + p->ak_addr = NULL; + p->ak_next = NULL; + if (akatail != NULL) + akatail->ak_next = p; + if (akahead == NULL) + akahead = p; + akatail = p; - return p; + return p; } static struct home * -hmalloc (struct passwd *pw) +hmalloc(struct passwd *pw) { - register struct home *p; - - p = (struct home *) mh_xmalloc (sizeof(*p)); - - p->h_name = getcpy (pw->pw_name); - p->h_uid = pw->pw_uid; - p->h_gid = pw->pw_gid; - p->h_home = getcpy (pw->pw_dir); - p->h_shell = getcpy (pw->pw_shell); - p->h_ngrps = 0; - p->h_next = NULL; - if (hometail != NULL) - hometail->h_next = p; - if (homehead == NULL) - homehead = p; - hometail = p; - - return p; + register struct home *p; + + p = (struct home *) mh_xmalloc(sizeof(*p)); + + p->h_name = getcpy(pw->pw_name); + p->h_uid = pw->pw_uid; + p->h_gid = pw->pw_gid; + p->h_home = getcpy(pw->pw_dir); + p->h_shell = getcpy(pw->pw_shell); + p->h_ngrps = 0; + p->h_next = NULL; + /* append to end */ + if (!homehead) + homehead = p; + if (hometail) + hometail->h_next = p; + hometail = p; + + return p; } struct home * -seek_home (char *name) +seek_home(char *name) { - register struct home *hp; -#ifdef DBMPWD - struct passwd *pw; - char lname[32]; - unsigned char *c; - char *c1; -#else /* DBMPWD */ - - if (homehead == NULL) - init_pw (); -#endif /* DBMPWD */ - - for (hp = homehead; hp; hp = hp->h_next) - if (!mh_strcasecmp (name, hp->h_name)) - return hp; - -#ifdef DBMPWD - /* - * The only place where there might be problems. - * This assumes that ALL usernames are kept in lowercase. - */ - for (c = name, c1 = lname; *c && (c1 - lname < sizeof(lname) - 1); c++, c1++) { - if (isalpha(*c) && isupper(*c)) - *c1 = tolower (*c); - else - *c1 = *c; - } - *c1 = '\0'; - if ((pw = getpwnam(lname))) - return(hmalloc(pw)); -#endif /* DBMPWD */ - - return NULL; + register struct home *hp; + struct passwd *pw; + char lname[32]; + unsigned char *c; + char *c1; + + for (hp = homehead; hp; hp = hp->h_next) + if (!mh_strcasecmp(name, hp->h_name)) + return hp; + + /* + ** The only place where there might be problems. + ** This assumes that ALL usernames are kept in lowercase. + */ + for (c = name, c1 = lname; *c && (c1 - lname < (int)sizeof(lname) - 1); + c++, c1++) { + if (isalpha(*c) && isupper(*c)) + *c1 = tolower(*c); + else + *c1 = *c; + } + *c1 = '\0'; + if ((pw = getpwnam(lname))) + return(hmalloc(pw)); + + return NULL; } diff --git a/uip/anno.c b/uip/anno.c index 41716f7..2647d97 100644 --- a/uip/anno.c +++ b/uip/anno.c @@ -1,318 +1,641 @@ - /* - * anno.c -- annotate messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - * - * Four new options have been added: delete, list, number, and draft. - * Message header fields are used by the new MIME attachment code in - * the send command. Adding features to generalize the anno command - * seemed to be a better approach than the creation of a new command - * whose features would overlap with those of the anno command. - * - * The -draft option causes anno to operate on the current draft file - * instead of on a message sequence. - * - * The -delete option deletes header elements that match the -component - * field name. If -delete is used without the -text option, the first - * header field whose field name matches the component name is deleted. - * If the -delete is used with the -text option, and the -text argument - * begins with a /, the first header field whose field name matches the - * component name and whose field body matches the text is deleted. If - * the -text argument does not begin with a /, then the text is assumed - * to be the last component of a path name, and the first header field - * whose field name matches the component name and a field body whose - * last path name component matches the text is deleted. If the -delete - * option is used with the new -number option described below, the nth - * header field whose field name matches the component name is deleted. - * No header fields are deleted if none of the above conditions are met. - * - * The -list option outputs the field bodies from each header field whose - * field name matches the component name, one per line. If no -text - * option is specified, only the last path name component of each field - * body is output. The entire field body is output if the -text option - * is used; the contents of the -text argument are ignored. If the -list - * option is used in conjuction with the new -number option described - * below, each line is numbered starting with 1. A tab separates the - * number from the field body. - * - * The -number option works with both the -delete and -list options as - * described above. The -number option takes an optional argument. A - * value of 1 is assumed if this argument is absent. - */ +** anno.c -- annotate messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** Three new options have been added: delete, list, and number. Adding +** features to generalize the anno command seemed to be a better approach +** than the creation of a new command whose features would overlap with +** those of the anno command. +*/ #include #include +#include +#include +#include +#include + +static enum { MODE_ADD, MODE_DEL, MODE_LIST } mode = MODE_ADD; static struct swit switches[] = { -#define COMPSW 0 - { "component field", 0 }, -#define INPLSW 1 - { "inplace", 0 }, -#define NINPLSW 2 - { "noinplace", 0 }, -#define DATESW 3 - { "date", 0 }, -#define NDATESW 4 - { "nodate", 0 }, -#define TEXTSW 5 - { "text body", 0 }, -#define VERSIONSW 6 - { "version", 0 }, -#define HELPSW 7 - { "help", 0 }, -#define DRFTSW 8 - { "draft", 2 }, -#define LISTSW 9 - { "list", 1 }, -#define DELETESW 10 - { "delete", 2 }, -#define NUMBERSW 11 - { "number", 2 }, -#define APPENDSW 12 - { "append", 1 }, -#define PRESERVESW 13 - { "preserve", 1 }, -#define NOPRESERVESW 14 - { "nopreserve", 3 }, - { NULL, 0 } +#define COMPSW 0 + { "component field", 0 }, +#define DATESW 1 + { "date", 0 }, +#define NDATESW 2 + { "nodate", 2 }, +#define TEXTSW 3 + { "text body", 0 }, +#define VERSIONSW 4 + { "Version", 0 }, +#define HELPSW 5 + { "help", 0 }, +#define LISTSW 6 + { "list", 0 }, +#define DELETESW 7 + { "delete", 0 }, +#define NUMBERSW 8 + { "number", 0 }, +#define APPENDSW 9 + { "append", 0 }, +#define PRESERVESW 10 + { "preserve", 0 }, +#define NOPRESERVESW 11 + { "nopreserve", 2 }, + { NULL, 0 } }; /* - * static prototypes - */ -static void make_comp (unsigned char **); +** static prototypes +*/ +static void make_comp(unsigned char **); +static int annotate(char *, unsigned char *, char *, int, int, int, int); +static void annolist(char *, unsigned char *, int); +static void dodel(int, unsigned char *, char *, FILE *, int); +static void doadd(int, unsigned char *, char *, FILE *, int, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int inplace = 1, datesw = 1; - int msgnum; - char *cp, *maildir; - unsigned char *comp = NULL; - char *text = NULL, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - int append = 0; /* append annotations instead of default prepend */ - int delete = -2; /* delete header element if set */ - char *draft = (char *)0; /* draft file name */ - int isdf = 0; /* return needed for m_draft() */ - int list = 0; /* list header elements if set */ - int number = 0; /* delete specific number of like elements if set */ - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case COMPSW: - if (comp) - adios (NULL, "only one component at a time!"); - if (!(comp = *argp++) || *comp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case DATESW: - datesw++; - continue; - case NDATESW: - datesw = 0; - continue; - - case INPLSW: - inplace++; - continue; - case NINPLSW: - inplace = 0; - continue; - - case TEXTSW: - if (text) - adios (NULL, "only one body at a time!"); - if (!(text = *argp++) || *text == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case DELETESW: /* delete annotations */ - delete = 0; - continue; - - case DRFTSW: /* draft message specified */ - draft = ""; - continue; - - case LISTSW: /* produce a listing */ - list = 1; - continue; - - case NUMBERSW: /* number listing or delete by number */ - if (number != 0) - adios (NULL, "only one number at a time!"); - - if (argp - arguments == argc - 1 || **argp == '-') - number = 1; - - else { - if (strcmp(*argp, "all") == 0) - number = -1; - - else if (!(number = atoi(*argp))) - adios (NULL, "missing argument to %s", argp[-2]); - - argp++; - } - - delete = number; - continue; - - case APPENDSW: /* append annotations instead of default prepend */ - append = 1; - continue; - - case PRESERVESW: /* preserve access and modification times on annotated message */ - annopreserve(1); - continue; - - case NOPRESERVESW: /* don't preserve access and modification times on annotated message (default) */ - annopreserve(0); - continue; - } + int datesw = 1; + int preserve = 0; + int msgnum; + char *cp, *maildir; + unsigned char *comp = NULL; + char *text = NULL, *folder = NULL, buf[BUFSIZ]; + char *file = NULL; + char **argp, **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + int append = 0; /* append annotations instead of default prepend */ + int number = 0; /* delete specific number of like elements if set */ + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [+folder] [msgs] [switches]", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case DELETESW: /* delete annotations */ + mode = MODE_DEL; + continue; + + case LISTSW: /* produce a listing */ + mode = MODE_LIST; + continue; + + case COMPSW: + if (comp) + adios(NULL, "only one component at a time!"); + if (!(comp = *argp++) || *comp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case TEXTSW: + if (text) + adios(NULL, "only one body at a time!"); + if (!(text = *argp++) || *text == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case NUMBERSW: /* number listing or delete by number */ + if (mode == MODE_ADD) { + adios(NULL, "-number switch must appear after -list or -delete, only."); + } + if (mode == MODE_LIST) { + number = 1; + continue; + } + /* MODE_DEL */ + if (number) { + adios(NULL, "only one number at a time!"); + } + if (*argp && strcmp(*argp, "all")==0) { + number = -1; + argp++; + continue; + } + if (!*argp || !(number = atoi(*argp))) { + adios(NULL, "missing argument to %s", + argp[-1]); + } + if (number < 0) { + adios(NULL, "invalid number (%d).", + number); + } + argp++; + continue; + + case DATESW: + datesw++; + continue; + case NDATESW: + datesw = 0; + continue; + + case APPENDSW: + append = 1; + continue; + + case PRESERVESW: + preserve = 1; + continue; + + case NOPRESERVESW: + preserve = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else if (*cp == '/' || *cp == '.') { + if (file) + adios(NULL, "only one file at a time!"); + file = cp; + } else { + app_msgarg(&msgs, cp); + } } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* - * We're dealing with the draft message instead of message numbers. - * Get the name of the draft and deal with it just as we do with - * message numbers below. - */ - - if (draft != (char *)0) { - if (msgs.size != 0) - adios(NULL, "can only have message numbers or -draft."); - - draft = getcpy(m_draft(folder, (char *)0, 1, &isdf)); - make_comp(&comp); + if (file && (folder || msgs.size)) { + adios(NULL, "Don't intermix files and messages."); + } + if (!datesw && !text) { + adios(NULL, "-nodate without -text is a no-op."); + } + if (number && text) { + adios(NULL, "Don't combine -number with -text."); + } - if (list) - annolist(draft, comp, text, number); - else - annotate (draft, comp, text, inplace, datesw, delete, append); + if (file) { + if (mode == MODE_LIST) + annolist(file, comp, number); + else + annotate(file, comp, text, datesw, number, + append, preserve); + done(0); + } + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + + /* annotate all the SELECTED messages */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if (mode == MODE_LIST) + annolist(m_name(msgnum), comp, number); + else + annotate(m_name(msgnum), comp, text, datesw, + number, append, preserve); + } + } + + context_replace(curfolder, folder); + seq_setcur(mp, mp->lowsel); + seq_save(mp); + folder_free(mp); + context_save(); done(0); return 1; - } - -#ifdef UCI - if (strcmp(invo_name, "fanno") == 0) /* ugh! */ - datesw = 0; -#endif /* UCI */ - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - - make_comp (&comp); - - /* annotate all the SELECTED messages */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - if (list) - annolist(m_name(msgnum), comp, text, number); - else - annotate (m_name (msgnum), comp, text, inplace, datesw, delete, append); +} + +static void +make_comp(unsigned char **ap) +{ + unsigned char *cp; + char buffer[BUFSIZ]; + + if (!*ap) { + printf("Enter component name: "); + fflush(stdout); + + if (!fgets(buffer, sizeof buffer, stdin)) { + done(1); + } + *ap = trimcpy(buffer); } - } - - context_replace (pfolder, folder); /* update current folder */ - seq_setcur (mp, mp->lowsel); /* update current message */ - seq_save (mp); /* synchronize message sequences */ - folder_free (mp); /* free folder/message structure */ - context_save (); /* save the context file */ - done (0); - return 1; + + if ((cp = *ap + strlen(*ap) - 1) > *ap && *cp == ':') + *cp = '\0'; + if (strlen(*ap) == 0) + adios(NULL, "null component name"); + if (**ap == '-') + adios(NULL, "invalid component name %s", *ap); + if (strlen(*ap) >= NAMESZ) + adios(NULL, "too large component name %s", *ap); + + for (cp = *ap; *cp; cp++) + if (!isalnum(*cp) && *cp != '-') + adios(NULL, "invalid component name %s", *ap); } + +/* +** Produce a listing of all header fields (annotations) whose field +** name matches comp. Number the listing if number is set. +*/ static void -make_comp (unsigned char **ap) +annolist(char *file, unsigned char *comp, int number) { - register unsigned char *cp; - char buffer[BUFSIZ]; - - if (*ap == NULL) { - printf ("Enter component name: "); - fflush (stdout); - - if (fgets (buffer, sizeof buffer, stdin) == NULL) - done (1); - *ap = trimcpy (buffer); - } - - if ((cp = *ap + strlen (*ap) - 1) > *ap && *cp == ':') - *cp = 0; - if (strlen (*ap) == 0) - adios (NULL, "null component name"); - if (**ap == '-') - adios (NULL, "invalid component name %s", *ap); - if (strlen (*ap) >= NAMESZ) - adios (NULL, "too large component name %s", *ap); - - for (cp = *ap; *cp; cp++) - if (!isalnum (*cp) && *cp != '-') - adios (NULL, "invalid component name %s", *ap); + int c; + int count = 1; /* header field (annotation) counter */ + char *cp; + char *field; + int field_size; + FILE *fp; + int length; + int n; /* number of bytes written */ + + if ((fp = fopen(file, "r")) == NULL) { + adios(file, "unable to open"); + } + + /* We'll grow this buffer as needed. */ + field = (char *)mh_xmalloc(field_size = 256); + + make_comp(&comp); + length = strlen(comp); /* Convenience copy. */ + + do { + /* + ** Get a line from the input file, growing the field buffer + ** as needed. We do this so that we can fit an entire line + ** in the buffer making it easy to do a string comparison + ** on both the field name and the field body which might be + ** a long path name. + */ + for (n = 0, cp = field; (c = getc(fp)) != EOF; *cp++ = c) { + if (c == '\n' && (c = getc(fp)) != ' ' && c != '\t') { + ungetc(c, fp); + c = '\n'; + break; + } + if (++n >= field_size - 1) { + field = (char *)mh_xrealloc(field, + field_size += 256); + cp = field + n - 1; + } + } + *cp = '\0'; + + if (strncasecmp(field, comp, length)==0 && + field[length] == ':') { + for (cp = field + length + 1; + *cp == ' ' || *cp == '\t'; cp++) { + continue; + } + if (number) { + printf("%d\t", count++); + } + printf("%s\n", cp); + } + + } while (*field && *field != '-'); + + free(field); + fclose(fp); + + return; +} + + +static int +annotate(char *file, unsigned char *comp, char *text, int datesw, + int number, int append, int preserve) +{ + int fd; + struct utimbuf b; + int perms, tmpfd; + char tmpfil[BUFSIZ]; + struct stat st; + FILE *tmp; + + /* open and lock the file to be annotated */ + if ((fd = lkopen(file, O_RDWR, 0)) == NOTOK) { + switch (errno) { + case ENOENT: + break; + default: + admonish(file, "unable to lock and open"); + break; + } + return 1; + } + + if (stat(file, &st) == -1) { + advise("can't get access and modification times for %s", file); + preserve = 0; + } + b.actime = st.st_atime; + b.modtime = st.st_mtime; + + perms = fstat(fd, &st) != NOTOK ? + (int)(st.st_mode & 0777) : m_gmprot(); + + strncpy(tmpfil, m_mktemp2(file, "annotate", NULL, &tmp), + sizeof(tmpfil)); + chmod(tmpfil, perms); + + make_comp(&comp); + + if (mode == MODE_DEL) { + dodel(fd, comp, text, tmp, number); + } + if (mode == MODE_ADD) { + doadd(fd, comp, text, tmp, datesw, append); + } + + cpydata(fd, fileno(tmp), file, tmpfil); + fclose(tmp); + + if ((tmpfd = open(tmpfil, O_RDONLY)) == NOTOK) { + adios(tmpfil, "unable to open for re-reading"); + } + lseek(fd, (off_t) 0, SEEK_SET); + + /* + ** We're making the file shorter if we're deleting a header field + ** so the file has to be truncated or it will contain garbage. + */ + if (mode == MODE_DEL && ftruncate(fd, 0) == -1) { + adios(tmpfil, "unable to truncate."); + } + cpydata(tmpfd, fd, tmpfil, file); + close(tmpfd); + unlink(tmpfil); + + if (preserve && utime(file, &b) == -1) { + advise("can't set access and modification times for %s", file); + } + lkclose(fd, file); + return 0; +} + +/* +** We're trying to delete a header field (annotation). +** +** - If number is greater than zero, +** we're deleting the nth header field that matches +** the field (component) name. +** - If number is zero and text is NULL, +** we're deleting the first field in which the field name +** matches the component name. +** - If number is zero and text is set, +** we're deleting the first field in which both the field name +** matches the component name and the field body matches the text. +** - If number is -1, +** we delete all matching fields. +*/ +static void +dodel(int fd, unsigned char *comp, char *text, FILE *tmp, int number) +{ + int length = strlen(comp); /* convenience copy */ + int count = 1; /* Number of matching header line. */ + int c, n; + char *cp; + char *field = NULL; + int field_size = 256; + FILE *fp; + + /* + ** We're going to need to copy some of the message file to the + ** temporary file while examining the contents. Convert the + ** message file descriptor to a file pointer since it's a lot + ** easier and more efficient to use stdio for this. Also allocate + ** a buffer to hold the header components as they're read in. + ** This buffer is grown as needed later. + */ + if ((fp = fdopen(fd, "r")) == NULL) { + adios(NULL, "unable to fdopen file."); + } + field = (char *)mh_xmalloc(field_size); + + /* + ** Copy lines from the input file to the temporary file + ** until we either find the one that we're looking + ** for (which we don't copy) or we reach the end of + ** the headers. Both a blank line and a line beginning + ** with a - terminate the headers so that we can handle + ** both drafts and RFC-2822 format messages. + */ + do { + /* + ** Get a line from the input file, growing the + ** field buffer as needed. We do this so that + ** we can fit an entire line in the buffer making + ** it easy to do a string comparison on both the + ** field name and the field body which might be + ** a long path name. + */ + for (n=0, cp=field; (c=getc(fp)) != EOF; *cp++ = c) { + if (c == '\n' && (c = getc(fp)) != ' ' && + c != '\t') { + ungetc(c, fp); + c = '\n'; + break; + } + + if (++n >= field_size - 1) { + field = (char *) mh_xrealloc(field, + field_size *= 2); + cp = field + n - 1; + } + } + *cp = '\0'; + + if (strncasecmp(field, comp, length)==0 && + field[length] == ':') { + /* + ** This component matches and thus is a candidate. + ** We delete the line by not copying it to the + ** temporary file. Thus: + ** - Break if we've found the one to delete. + ** - Continue if this is one to delete, but + ** there'll be further ones. + */ + + if (!number && !text) { + /* this first one is it */ + break; + } + + if (number == -1) { + /* delete all of them */ + continue; + } else if (number == count++) { + /* delete this specific one */ + break; + } + + if (text) { + /* delete the first matching one */ + cp = field+length+1; + while (*cp==' ' || *cp=='\t') { + cp++; /* eat leading whitespace */ + } + if (*text == '/' && strcmp(text, cp)==0) { + break; /* full path matches */ + } else if (strcmp(text, mhbasename(cp))==0) { + break; /* basename matches */ + } + } + /* + ** Although the compoment name mached, it + ** wasn't the right one. + */ + } + + /* Copy it. */ + if ((n = fputs(field, tmp)) == EOF || + (c=='\n' && fputc('\n', tmp)==EOF)) { + adios(NULL, "unable to write temporary file."); + } + + } while (*field && *field != '-'); + + free(field); + + fflush(tmp); + fflush(fp); /* The underlying fd will be closed by lkclose() */ + + /* + ** We've been messing with the input file position. Move the + ** input file descriptor to the current place in the file + ** because the stock data copying routine uses the descriptor, + ** not the pointer. + */ + if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1) { + adios(NULL, "can't seek."); + } +} + + +static void +doadd(int fd, unsigned char *comp, char *text, FILE *tmp, int datesw, + int append) +{ + char *cp, *sp; + int c; + FILE *fp = NULL; + + if (append) { + /* + ** We're going to need to copy some of the message + ** file to the temporary file while examining the + ** contents. Convert the message file descriptor to + ** a file pointer since it's a lot easier and more + ** efficient to use stdio for this. Also allocate + ** a buffer to hold the header components as they're + ** read in. This buffer is grown as needed later. + */ + if ((fp = fdopen(fd, "r")) == NULL) { + adios(NULL, "unable to fdopen file."); + } + /* Find the end of the headers. */ + if ((c = getc(fp)) == '\n') { + /* Special check for no headers is needed. */ + rewind(fp); + } else { + /* + ** Copy lines from the input file to the + ** temporary file until we reach the end + ** of the headers. + */ + putc(c, tmp); + while ((c = getc(fp)) != EOF) { + putc(c, tmp); + if (c == '\n') { + ungetc(c = getc(fp), fp); + if (c == '\n' || c == '-') { + break; + } + } + } + } + } + + if (datesw) { + fprintf(tmp, "%s: %s\n", comp, dtimenow()); + } + if ((cp = text)) { + /* Add body text header */ + do { + while (*cp == ' ' || *cp == '\t') { + cp++; + } + sp = cp; + while (*cp && *cp++ != '\n') { + continue; + } + if (cp - sp) { + fprintf(tmp, "%s: %*.*s", comp, + (int)(cp - sp), + (int)(cp - sp), sp); + } + } while (*cp); + if (cp[-1] != '\n' && cp != text) { + putc('\n', tmp); + } + } + fflush(tmp); + + /* + ** We've been messing with the input file position. Move the + ** input file descriptor to the current place in the file + ** because the stock data copying routine uses the descriptor, + ** not the pointer. + */ + if (append) { + if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1) { + adios(NULL, "can't seek."); + } + } } diff --git a/uip/annosbr.c b/uip/annosbr.c deleted file mode 100644 index 87e9580..0000000 --- a/uip/annosbr.c +++ /dev/null @@ -1,447 +0,0 @@ - -/* - * annosbr.c -- prepend annotation to messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include - - -/* - * static prototypes - */ -static int annosbr (int, char *, char *, char *, int, int, int, int); - -/* - * This "local" global and the annopreserve() function are a hack that allows additional - * functionality to be added to anno without piling on yet another annotate() argument. - */ - -static int preserve_actime_and_modtime = 0; /* set to preserve access and modification times on annotated message */ - -int -annotate (char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) -{ - int i, fd; - struct utimbuf b; - struct stat s; - - /* open and lock the file to be annotated */ - if ((fd = lkopen (file, O_RDWR, 0)) == NOTOK) { - switch (errno) { - case ENOENT: - break; - - default: - admonish (file, "unable to lock and open"); - break; - } - return 1; - } - - if (stat(file, &s) == -1) { - advise("can't get access and modification times for %s", file); - preserve_actime_and_modtime = 0; - } - - b.actime = s.st_atime; - b.modtime = s.st_mtime; - - i = annosbr (fd, file, comp, text, inplace, datesw, delete, append); - - if (preserve_actime_and_modtime && utime(file, &b) == -1) - advise("can't set access and modification times for %s", file); - - lkclose (fd, file); - return i; -} - -/* - * Produce a listing of all header fields (annotations) whose field name matches - * comp. Number the listing if number is set. Treate the field bodies as path - * names and just output the last component unless text is non-NULL. We don't - * care what text is set to. - */ - -void -annolist(char *file, char *comp, char *text, int number) -{ - int c; /* current character */ - int count; /* header field (annotation) counter */ - char *cp; /* miscellaneous character pointer */ - char *field; /* buffer for header field */ - int field_size; /* size of field buffer */ - FILE *fp; /* file pointer made from locked file descriptor */ - int length; /* length of field name */ - int n; /* number of bytes written */ - char *sp; /* another miscellaneous character pointer */ - - if ((fp = fopen(file, "r")) == (FILE *)0) - adios(file, "unable to open"); - - /* - * Allocate a buffer to hold the header components as they're read in. - * This buffer might need to be quite large, so we grow it as needed. - */ - - field = (char *)mh_xmalloc(field_size = 256); - - /* - * Get the length of the field name since we use it often. - */ - - length = strlen(comp); - - count = 0; - - do { - /* - * Get a line from the input file, growing the field buffer as needed. We do this - * so that we can fit an entire line in the buffer making it easy to do a string - * comparison on both the field name and the field body which might be a long path - * name. - */ - - for (n = 0, cp = field; (c = getc(fp)) != EOF; *cp++ = c) { - if (c == '\n' && (c = getc(fp)) != ' ' && c != '\t') { - (void)ungetc(c, fp); - c = '\n'; - break; - } - - if (++n >= field_size - 1) { - field = (char *) mh_xrealloc((void *)field, field_size += 256); - - cp = field + n - 1; - } - } - - /* - * NUL-terminate the field.. - */ - - *cp = '\0'; - - if (strncasecmp(field, comp, length) == 0 && field[length] == ':') { - for (cp = field + length + 1; *cp == ' ' || *cp == '\t'; cp++) - ; - - if (number) - (void)printf("%d\t", ++count); - - if (text == (char *)0 && (sp = strrchr(cp, '/')) != (char *)0) - cp = sp + 1; - - (void)printf("%s\n", cp); - } - - } while (*field != '\0' && *field != '-'); - - /* - * Clean up. - */ - - free(field); - - (void)fclose(fp); - - return; -} - -/* - * Set the preserve-times flag. This hack eliminates the need for an additional argument to annotate(). - */ - -void -annopreserve(int preserve) -{ - preserve_actime_and_modtime = preserve; - return; -} - -static int -annosbr (int fd, char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) -{ - int mode, tmpfd; - char *cp, *sp; - char buffer[BUFSIZ], tmpfil[BUFSIZ]; - struct stat st; - FILE *tmp; - int c; /* current character */ - int count; /* header field (annotation) counter */ - char *field = NULL; /* buffer for header field */ - int field_size = 0; /* size of field buffer */ - FILE *fp = NULL; /* file pointer made from locked file descriptor */ - int length; /* length of field name */ - int n; /* number of bytes written */ - - mode = fstat (fd, &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot (); - - strncpy (tmpfil, m_mktemp2(file, "annotate", NULL, &tmp), sizeof(tmpfil)); - chmod (tmpfil, mode); - - /* - * We're going to need to copy some of the message file to the temporary - * file while examining the contents. Convert the message file descriptor - * to a file pointer since it's a lot easier and more efficient to use - * stdio for this. Also allocate a buffer to hold the header components - * as they're read in. This buffer is grown as needed later. - */ - - if (delete >= -1 || append != 0) { - if ((fp = fdopen(fd, "r")) == (FILE *)0) - adios(NULL, "unable to fdopen file."); - - field = (char *)mh_xmalloc(field_size = 256); - } - - /* - * We're trying to delete a header field (annotation )if the delete flag is - * not -2 or less. A value greater than zero means that we're deleting the - * nth header field that matches the field (component) name. A value of - * zero means that we're deleting the first field in which both the field - * name matches the component name and the field body matches the text. - * The text is matched in its entirety if it begins with a slash; otherwise - * the text is matched against whatever portion of the field body follows - * the last slash. This allows matching of both absolute and relative path - * names. This is because this functionality was added to support attachments. - * It might be worth having a separate flag to indicate path name matching to - * make it more general. A value of -1 means to delete all matching fields. - */ - - if (delete >= -1) { - /* - * Get the length of the field name since we use it often. - */ - - length = strlen(comp); - - /* - * Initialize the field counter. This is only used if we're deleting by - * number. - */ - - count = 0; - - /* - * Copy lines from the input file to the temporary file until we either find the one - * that we're looking for (which we don't copy) or we reach the end of the headers. - * Both a blank line and a line beginning with a - terminate the headers so that we - * can handle both drafts and RFC-2822 format messages. - */ - - do { - /* - * Get a line from the input file, growing the field buffer as needed. We do this - * so that we can fit an entire line in the buffer making it easy to do a string - * comparison on both the field name and the field body which might be a long path - * name. - */ - - for (n = 0, cp = field; (c = getc(fp)) != EOF; *cp++ = c) { - if (c == '\n' && (c = getc(fp)) != ' ' && c != '\t') { - (void)ungetc(c, fp); - c = '\n'; - break; - } - - if (++n >= field_size - 1) { - field = (char *) mh_xrealloc((void *)field, field_size *= 2); - - cp = field + n - 1; - } - } - - /* - * NUL-terminate the field.. - */ - - *cp = '\0'; - - /* - * Check for a match on the field name. We delete the line by not copying it to the - * temporary file if - * - * o The delete flag is 0, meaning that we're going to delete the first matching - * field, and the text is NULL meaning that we don't care about the field body. - * - * o The delete flag is 0, meaning that we're going to delete the first matching - * field, and the text begins with a / meaning that we're looking for a full - * path name, and the text matches the field body. - * - * o The delete flag is 0, meaning that we're going to delete the first matching - * field, the text does not begin with a / meaning that we're looking for the - * last path name component, and the last path name component matches the text. - * - * o The delete flag is positive meaning that we're going to delete the nth field - * with a matching field name, and this is the nth matching field name. - * - * o The delete flag is -1 meaning that we're going to delete all fields with a - * matching field name. - */ - - if (strncasecmp(field, comp, length) == 0 && field[length] == ':') { - if (delete == 0) { - if (text == (char *)0) - break; - - for (cp = field + length + 1; *cp == ' ' || *cp == '\t'; cp++) - ; - - if (*text == '/') { - if (strcmp(cp, text) == 0) - break; - } - else { - if ((sp = strrchr(cp, '/')) != (char *)0) - cp = sp + 1; - - if (strcmp(cp, text) == 0) - break; - } - } - - else if (delete == -1) - continue; - - else if (++count == delete) - break; - } - - /* - * This line wasn't a match so copy it to the temporary file. - */ - - if ((n = fputs(field, tmp)) == EOF || (c == '\n' && fputc('\n', tmp) == EOF)) - adios(NULL, "unable to write temporary file."); - - } while (*field != '\0' && *field != '-'); - - /* - * Get rid of the field buffer because we're done with it. - */ - - free((void *)field); - } - - else { - /* - * Find the end of the headers before adding the annotations if we're - * appending instead of the default prepending. A special check for - * no headers is needed if appending. - */ - - if (append) { - /* - * Copy lines from the input file to the temporary file until we - * reach the end of the headers. - */ - - if ((c = getc(fp)) == '\n') - rewind(fp); - - else { - (void)putc(c, tmp); - - while ((c = getc(fp)) != EOF) { - (void)putc(c, tmp); - - if (c == '\n') { - (void)ungetc(c = getc(fp), fp); - - if (c == '\n' || c == '-') - break; - } - } - } - } - - if (datesw) - fprintf (tmp, "%s: %s\n", comp, dtimenow (0)); - if ((cp = text)) { - do { - while (*cp == ' ' || *cp == '\t') - cp++; - sp = cp; - while (*cp && *cp++ != '\n') - continue; - if (cp - sp) - fprintf (tmp, "%s: %*.*s", comp, (int)(cp - sp), (int)(cp - sp), sp); - } while (*cp); - if (cp[-1] != '\n' && cp != text) - putc ('\n', tmp); - } - } - - fflush (tmp); - - /* - * We've been messing with the input file position. Move the input file - * descriptor to the current place in the file because the stock data - * copying routine uses the descriptor, not the pointer. - */ - - if (append || delete >= -1) { - if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1) - adios(NULL, "can't seek."); - } - - cpydata (fd, fileno (tmp), file, tmpfil); - fclose (tmp); - - if (inplace) { - if ((tmpfd = open (tmpfil, O_RDONLY)) == NOTOK) - adios (tmpfil, "unable to open for re-reading"); - - lseek (fd, (off_t) 0, SEEK_SET); - - /* - * We're making the file shorter if we're deleting a header field - * so the file has to be truncated or it will contain garbage. - */ - - if (delete >= -1 && ftruncate(fd, 0) == -1) - adios(tmpfil, "unable to truncate."); - - cpydata (tmpfd, fd, tmpfil, file); - close (tmpfd); - unlink (tmpfil); - } else { - strncpy (buffer, m_backup (file), sizeof(buffer)); - if (rename (file, buffer) == NOTOK) { - switch (errno) { - case ENOENT: /* unlinked early - no annotations */ - unlink (tmpfil); - break; - - default: - admonish (buffer, "unable to rename %s to", file); - break; - } - return 1; - } - if (rename (tmpfil, file) == NOTOK) { - admonish (file, "unable to rename %s to", tmpfil); - return 1; - } - } - - /* - * Close the delete file so that we don't run out of file pointers if - * we're doing piles of files. Note that this will make the close() in - * lkclose() fail, but that failure is ignored so it's not a problem. - */ - - if (delete >= -1) - (void)fclose(fp); - - return 0; -} diff --git a/uip/ap.c b/uip/ap.c index a0f7f77..c293a53 100644 --- a/uip/ap.c +++ b/uip/ap.c @@ -1,40 +1,31 @@ - /* - * ap.c -- parse addresses 822-style - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** ap.c -- parse addresses 822-style +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include - -#define NADDRS 100 -#define WIDTH 78 -#define WBUFSIZ BUFSIZ +#define NADDRS 100 -#define FORMAT "%<{error}%{error}: %{text}%|%(putstr(proper{text}))%>" +#define FORMAT "=%<{error}%{error}: %{text}%|%(putstr(proper{text}))%>" static struct swit switches[] = { -#define FORMSW 0 - { "form formatfile", 0 }, -#define FMTSW 1 - { "format string", 5 }, -#define NORMSW 2 - { "normalize", 0 }, -#define NNORMSW 3 - { "nonormalize", 0 }, -#define WIDTHSW 4 - { "width columns", 0 }, -#define VERSIONSW 5 - { "version", 0 }, -#define HELPSW 6 - { "help", 0 }, - { NULL, 0 } +#define FORMSW 0 + { "form formatfile", 0 }, +#define NORMSW 1 + { "normalize", 0 }, +#define NNORMSW 2 + { "nonormalize", 2 }, +#define VERSIONSW 3 + { "Version", 0 }, +#define HELPSW 4 + { "help", 0 }, + { NULL, 0 } }; static struct format *fmt; @@ -42,168 +33,140 @@ static struct format *fmt; static int dat[5]; /* - * prototypes - */ -int sc_width (void); /* from termsbr.c */ - -/* - * static prototypes - */ -static int process (char *, int, int); +** static prototypes +*/ +static int process(char *, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int addrp = 0, normalize = AD_HOST; - int width = 0, status = 0; - char *cp, *form = NULL, *format = NULL, *nfs; - char buf[BUFSIZ], **argp; - char **arguments, *addrs[NADDRS]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] addrs ...", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version (invo_name); - done (1); - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - width = atoi (cp); - continue; - - case NORMSW: - normalize = AD_HOST; - continue; - case NNORMSW: - normalize = AD_NHST; - continue; - } + int addrp = 0, normalize = AD_HOST; + int status = 0; + char *cp, *form = NULL, *fmtstr; + char buf[BUFSIZ], **argp; + char **arguments, *addrs[NADDRS]; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] addrs ...", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", argp[-2]); + continue; + + case NORMSW: + normalize = AD_HOST; + continue; + case NNORMSW: + normalize = AD_NHST; + continue; + } + } + if (addrp > NADDRS) + adios(NULL, "more than %d addresses", NADDRS); + else + addrs[addrp++] = cp; } - if (addrp > NADDRS) - adios (NULL, "more than %d addresses", NADDRS); - else - addrs[addrp++] = cp; - } - addrs[addrp] = NULL; - - if (addrp == 0) - adios (NULL, "usage: %s [switches] addrs ...", invo_name); - - /* get new format string */ - nfs = new_fs (form, format, FORMAT); - - if (width == 0) { - if ((width = sc_width ()) < WIDTH / 2) - width = WIDTH / 2; - width -= 2; - } - if (width > WBUFSIZ) - width = WBUFSIZ; - fmt_norm = normalize; - fmt_compile (nfs, &fmt); - - dat[0] = 0; - dat[1] = 0; - dat[2] = 0; - dat[3] = width; - dat[4] = 0; - - for (addrp = 0; addrs[addrp]; addrp++) - status += process (addrs[addrp], width, normalize); - - done (status); - return 1; + addrs[addrp] = NULL; + + if (addrp == 0) + adios(NULL, "usage: %s [switches] addrs ...", invo_name); + + /* get new format string */ + fmtstr = new_fs(form, FORMAT); + + fmt_norm = normalize; + fmt_compile(fmtstr, &fmt); + + dat[0] = 0; + dat[1] = 0; + dat[2] = 0; + dat[3] = BUFSIZ; + dat[4] = 0; + + for (addrp = 0; addrs[addrp]; addrp++) + status += process(addrs[addrp], normalize); + + done(status); + return 1; } struct pqpair { - char *pq_text; - char *pq_error; - struct pqpair *pq_next; + char *pq_text; + char *pq_error; + struct pqpair *pq_next; }; static int -process (char *arg, int length, int norm) +process(char *arg, int norm) { - int status = 0; - register char *cp; - char buffer[WBUFSIZ + 1], error[BUFSIZ]; - register struct comp *cptr; - register struct pqpair *p, *q; - struct pqpair pq; - register struct mailname *mp; - - (q = &pq)->pq_next = NULL; - while ((cp = getname (arg))) { - if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL) - adios (NULL, "unable to allocate pqpair memory"); - if ((mp = getm (cp, NULL, 0, norm, error)) == NULL) { - p->pq_text = getcpy (cp); - p->pq_error = getcpy (error); - status++; + int status = 0; + register char *cp; + char buffer[BUFSIZ + 1], error[BUFSIZ]; + register struct comp *cptr; + register struct pqpair *p, *q; + struct pqpair pq; + register struct mailname *mp; + + (q = &pq)->pq_next = NULL; + while ((cp = getname(arg))) { + if ((p = (struct pqpair *) + calloc((size_t) 1, sizeof(*p))) == NULL) + adios(NULL, "unable to allocate pqpair memory"); + if ((mp = getm(cp, NULL, 0, norm, error)) == NULL) { + p->pq_text = getcpy(cp); + p->pq_error = getcpy(error); + status++; + } else { + p->pq_text = getcpy(mp->m_text); + mnfree(mp); + } + q = (q->pq_next = p); } - else { - p->pq_text = getcpy (mp->m_text); - mnfree (mp); + + for (p = pq.pq_next; p; p = q) { + FINDCOMP(cptr, "text"); + if (cptr) + cptr->c_text = p->pq_text; + FINDCOMP(cptr, "error"); + if (cptr) + cptr->c_text = p->pq_error; + + fmt_scan(fmt, buffer, BUFSIZ, dat); + fputs(buffer, stdout); + + free(p->pq_text); + if (p->pq_error) + free(p->pq_error); + q = p->pq_next; + free((char *) p); } - q = (q->pq_next = p); - } - - for (p = pq.pq_next; p; p = q) { - FINDCOMP (cptr, "text"); - if (cptr) - cptr->c_text = p->pq_text; - FINDCOMP (cptr, "error"); - if (cptr) - cptr->c_text = p->pq_error; - - fmt_scan (fmt, buffer, length, dat); - fputs (buffer, stdout); - - free (p->pq_text); - if (p->pq_error) - free (p->pq_error); - q = p->pq_next; - free ((char *) p); - } - - return status; + + return status; } diff --git a/uip/burst.c b/uip/burst.c index fa3ac73..e657c33 100644 --- a/uip/burst.c +++ b/uip/burst.c @@ -1,443 +1,333 @@ - /* - * burst.c -- explode digests into individual messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** burst.c -- explode digests into individual messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include static struct swit switches[] = { -#define INPLSW 0 - { "inplace", 0 }, -#define NINPLSW 1 - { "noinplace", 0 }, -#define QIETSW 2 - { "quiet", 0 }, -#define NQIETSW 3 - { "noquiet", 0 }, -#define VERBSW 4 - { "verbose", 0 }, -#define NVERBSW 5 - { "noverbose", 0 }, -#define VERSIONSW 6 - { "version", 0 }, -#define HELPSW 7 - { "help", 0 }, - { NULL, 0 } +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, + { NULL, 0 } }; static char delim3[] = "-------"; struct smsg { - long s_start; - long s_stop; + long s_start; + long s_stop; }; /* - * static prototypes - */ -static int find_delim (int, struct smsg *); -static void burst (struct msgs **, int, struct smsg *, int, int, int, char *); -static void cpybrst (FILE *, FILE *, char *, char *, int); +** static prototypes +*/ +static int find_delim(int, struct smsg *); +static void burst(struct msgs **, int, struct smsg *, int, int, char *); +static void cpybrst(FILE *, FILE *, char *, char *, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int inplace = 0, quietsw = 0, verbosw = 0; - int msgp = 0, hi, msgnum, numburst; - char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments, *msgs[MAXARGS]; - struct smsg *smsgs; - struct msgs *mp; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case INPLSW: - inplace++; - continue; - case NINPLSW: - inplace = 0; - continue; - - case QIETSW: - quietsw++; - continue; - case NQIETSW: - quietsw = 0; - continue; - - case VERBSW: - verbosw++; - continue; - case NVERBSW: - verbosw = 0; - continue; - } + int verbosw = 0; + int msgp = 0, hi, msgnum, numburst; + char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; + char **argp, **arguments, *msgs[MAXARGS]; + struct smsg *smsgs; + struct msgs *mp; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case VERBSW: + verbosw++; + continue; + case NVERBSW: + verbosw = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + msgs[msgp++] = cp; + } } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - msgs[msgp++] = cp; + + if (!msgp) + msgs[msgp++] = seq_cur; + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgp; msgnum++) + if (!m_convert(mp, msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + smsgs = (struct smsg *) + calloc((size_t) (MAXFOLDER + 2), sizeof(*smsgs)); + if (smsgs == NULL) + adios(NULL, "unable to allocate burst storage"); + + hi = mp->hghmsg + 1; + + /* burst all the SELECTED messages */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if ((numburst = find_delim(msgnum, smsgs)) > 0) { + if (verbosw) + printf("%d message%s exploded from digest %d\n", numburst, numburst > 1 ? "s" : "", msgnum); + burst(&mp, msgnum, smsgs, numburst, verbosw, maildir); + } else if (numburst == 0) { + admonish(NULL, "message %d not in digest format", msgnum); + } else { + adios(NULL, "burst() botch -- you lose big"); + } + } } - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!msgp) - msgs[msgp++] = "cur"; - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - smsgs = (struct smsg *) - calloc ((size_t) (MAXFOLDER + 2), sizeof(*smsgs)); - if (smsgs == NULL) - adios (NULL, "unable to allocate burst storage"); - - hi = mp->hghmsg + 1; - - /* burst all the SELECTED messages */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - if ((numburst = find_delim (msgnum, smsgs)) >= 1) { - if (verbosw) - printf ("%d message%s exploded from digest %d\n", - numburst, numburst > 1 ? "s" : "", msgnum); - burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir); - } else { - if (numburst == 0) { - if (!quietsw) - admonish (NULL, "message %d not in digest format", - msgnum); - } /* this pair of braces was missing before 1999-07-15 */ - else - adios (NULL, "burst() botch -- you lose big"); - } + + free(smsgs); + context_replace(curfolder, folder); + + /* + ** The first message extracted from the first digest + ** becomes the current message. + */ + if (hi <= mp->hghmsg) { + seq_setcur(mp, hi); } - } - - free ((char *) smsgs); - context_replace (pfolder, folder); /* update current folder */ - - /* - * If -inplace is given, then the first message burst becomes - * the current message (which will now show a table of contents). - * Otherwise, the first message extracted from the first digest - * becomes the current message. - */ - if (inplace) { - if (mp->lowsel != mp->curmsg) - seq_setcur (mp, mp->lowsel); - } else { - if (hi <= mp->hghmsg) - seq_setcur (mp, hi); - } - - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; + + seq_save(mp); + context_save(); + folder_free(mp); + done(0); + return 1; } /* - * Scan the message and find the beginning and - * end of all the messages in the digest. - */ - +** Scan the message and find the beginning and +** end of all the messages in the digest. +*/ static int -find_delim (int msgnum, struct smsg *smsgs) +find_delim(int msgnum, struct smsg *smsgs) { - int ld3, wasdlm, msgp; - long pos; - char c, *msgnam; - int cc; - char buffer[BUFSIZ]; - FILE *in; - - ld3 = strlen (delim3); - - if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL) - adios (msgnam, "unable to read message"); - - for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) { - while (fgets (buffer, sizeof(buffer), in) && buffer[0] == '\n') - pos += (long) strlen (buffer); - if (feof (in)) - break; - fseek (in, pos, SEEK_SET); - smsgs[msgp].s_start = pos; - - for (c = 0; fgets (buffer, sizeof(buffer), in); c = buffer[0]) { - if (strncmp (buffer, delim3, ld3) == 0 - && (msgp == 1 || c == '\n') - && ((cc = peekc (in)) == '\n' || cc == EOF)) - break; - else - pos += (long) strlen (buffer); - } + int ld3, wasdlm, msgp; + long pos; + char c, *msgnam; + int cc; + char buffer[BUFSIZ]; + FILE *in; + + ld3 = strlen(delim3); + + if ((in = fopen(msgnam = m_name(msgnum), "r")) == NULL) + adios(msgnam, "unable to read message"); + + for (msgp = 0, pos = 0L; msgp <= MAXFOLDER; msgp++) { + while (fgets(buffer, sizeof(buffer), in) && buffer[0] == '\n') + pos += (long) strlen(buffer); + if (feof(in)) { + break; + } + fseek(in, pos, SEEK_SET); + smsgs[msgp].s_start = pos; + + for (c = 0; fgets(buffer, sizeof(buffer), in); c = buffer[0]) { + if (strncmp(buffer, delim3, ld3) == 0 + && (msgp == 1 || c == '\n')) { + cc = getc(in); + ungetc(cc, in); + if (cc == '\n' || cc == EOF) { + break; + } + } else + pos += (long) strlen(buffer); + } - wasdlm = strncmp (buffer, delim3, ld3) == 0; - if (smsgs[msgp].s_start != pos) - smsgs[msgp++].s_stop = (c == '\n' && wasdlm) ? pos - 1 : pos; - if (feof (in)) { -#if 0 - if (wasdlm) { - smsgs[msgp - 1].s_stop -= ((long) strlen (buffer) + 1); - msgp++; /* fake "End of XXX Digest" */ - } -#endif - break; + wasdlm = strncmp(buffer, delim3, ld3) == 0; + if (smsgs[msgp].s_start != pos) + smsgs[msgp].s_stop = (c == '\n' && wasdlm) ? + pos - 1 : pos; + if (feof(in)) { + break; + } + pos += (long) strlen(buffer); } - pos += (long) strlen (buffer); - } - fclose (in); - return (msgp - 1); /* toss "End of XXX Digest" */ + fclose(in); + return (msgp > 0) ? msgp-1 : 0; /* toss "End of XXX Digest" */ } /* - * Burst out the messages in the digest into the folder - */ - +** Burst out the messages in the digest into the folder +*/ static void -burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, - int inplace, int verbosw, char *maildir) +burst(struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, + int verbosw, char *maildir) { - int i, j, mode; - char *msgnam; - char f1[BUFSIZ], f2[BUFSIZ], f3[BUFSIZ]; - FILE *in, *out; - struct stat st; - struct msgs *mp; - - if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL) - adios (msgnam, "unable to read message"); - - mode = fstat (fileno(in), &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot(); - mp = *mpp; - - /* - * See if we have enough space in the folder - * structure for all the new messages. - */ - if ((mp->hghmsg + numburst > mp->hghoff) && - !(mp = folder_realloc (mp, mp->lowoff, mp->hghmsg + numburst))) - adios (NULL, "unable to allocate folder storage"); - *mpp = mp; - - j = mp->hghmsg; /* old value */ - mp->hghmsg += numburst; - mp->nummsg += numburst; - - /* - * If this is not the highest SELECTED message, then - * increment mp->hghsel by numburst, since the highest - * SELECTED is about to be slid down by that amount. - */ - if (msgnum < mp->hghsel) - mp->hghsel += numburst; - - /* - * If -inplace is given, renumber the messages after the - * source message, to make room for each of the messages - * contained within the digest. - * - * This is equivalent to refiling a message from the point - * of view of the external hooks. - */ - if (inplace) { - for (i = mp->hghmsg; j > msgnum; i--, j--) { - strncpy (f1, m_name (i), sizeof(f1)); - strncpy (f2, m_name (j), sizeof(f2)); - if (does_exist (mp, j)) { - if (verbosw) - printf ("message %d becomes message %d\n", j, i); - - if (rename (f2, f1) == NOTOK) - admonish (f1, "unable to rename %s to", f2); - - (void)snprintf(f1, sizeof (f1), "%s/%d", maildir, i); - (void)snprintf(f2, sizeof (f2), "%s/%d", maildir, j); - ext_hook("ref-hook", f1, f2); - - copy_msg_flags (mp, i, j); - clear_msg_flags (mp, j); + int i, j, mode; + char *msgnam; + char destfil[BUFSIZ]; + FILE *in, *out; + struct stat st; + struct msgs *mp; + + if ((in = fopen(msgnam = m_name(msgnum), "r")) == NULL) + adios(msgnam, "unable to read message"); + + mode = fstat(fileno(in), &st) != NOTOK ? + (int)(st.st_mode & 0777) : m_gmprot(); + mp = *mpp; + + /* + ** Ensure we have enough space in the folder + ** structure for all the new messages. + */ + if ((mp->hghmsg + numburst > mp->hghoff) && !(mp = folder_realloc(mp, + mp->lowoff, mp->hghmsg + numburst))) + adios(NULL, "unable to allocate folder storage"); + *mpp = mp; + + /* + ** At this point, there is an array of numburst smsgs, each + ** element of which contains the starting and stopping offsets + ** (seeks) of the message in the digest. Go through the message + ** numbers. Ignore smsgs[0], which is the table of contents. + */ + for (j=1, i=mp->hghmsg+1; j<=numburst; j++, i++) { + snprintf(destfil, sizeof destfil, "%s/%d", maildir, i); + if (!(out = fopen(destfil, "w"))) { + adios(destfil, "unable to open"); + } + if (verbosw) { + printf("message %d of digest %d becomes message %d\n", + j, msgnum, i); + } + chmod(destfil, mode); + fseek(in, smsgs[j].s_start, SEEK_SET); + cpybrst(in, out, msgnam, destfil, + (int) (smsgs[j].s_stop - smsgs[j].s_start)); + fclose(out); + mp->hghmsg++; + mp->nummsg++; + /* + ** Bursting each message is equivalent to adding a + ** new message from the point of view of the external hooks. + */ + ext_hook("add-hook", destfil, NULL); + copy_msg_flags(mp, i, msgnum); mp->msgflags |= SEQMOD; - } - } - } - - unset_selected (mp, msgnum); - - /* new hghmsg is hghmsg + numburst - * - * At this point, there is an array of numburst smsgs, each element of - * which contains the starting and stopping offsets (seeks) of the message - * in the digest. The inplace flag is set if the original digest is replaced - * by a message containing the table of contents. smsgs[0] is that table of - * contents. Go through the message numbers in reverse order (high to low). - * - * Set f1 to the name of the destination message, f2 to the name of a scratch - * file. Extract a message from the digest to the scratch file. Move the - * original message to a backup file if the destination message number is the - * same as the number of the original message, which only happens if the - * inplace flag is set. Then move the scratch file to the destination message. - * - * Moving the original message to the backup file is equivalent to deleting the - * message from the point of view of the external hooks. And bursting each - * message is equivalent to adding a new message. - */ - - i = inplace ? msgnum + numburst : mp->hghmsg; - for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) { - strncpy (f1, m_name (i), sizeof(f1)); - strncpy (f2, m_mktemp(invo_name, NULL, &out), sizeof(f2)); - - if (verbosw && i != msgnum) - printf ("message %d of digest %d becomes message %d\n", j, msgnum, i); - - chmod (f2, mode); - fseek (in, smsgs[j].s_start, SEEK_SET); - cpybrst (in, out, msgnam, f2, - (int) (smsgs[j].s_stop - smsgs[j].s_start)); - fclose (out); - - if (i == msgnum) { - strncpy (f3, m_backup (f1), sizeof(f3)); - if (rename (f1, f3) == NOTOK) - admonish (f3, "unable to rename %s to", f1); - - (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i); - ext_hook("del-hook", f3, (char *)0); } - if (rename (f2, f1) == NOTOK) - admonish (f1, "unable to rename %s to", f2); - - (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i); - ext_hook("add-hook", f3, (char *)0); - - copy_msg_flags (mp, i, msgnum); - mp->msgflags |= SEQMOD; - } - - fclose (in); + fclose(in); } -#define S1 0 -#define S2 1 -#define S3 2 - /* - * Copy a mesage which is being burst out of a digest. - * It will remove any "dashstuffing" in the message. - */ - +** Copy a message which is being burst out of a digest. +** It will remove any "dashstuffing" in the message. +*/ static void -cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len) +cpybrst(FILE *in, FILE *out, char *ifile, char *ofile, int len) { - register int c, state; - - for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) { - if (c == 0) - continue; - switch (state) { - case S1: - switch (c) { - case '-': - state = S3; - break; - - default: - state = S2; - case '\n': - fputc (c, out); + int c; + enum { S1, S2, S3 } state; + + for (state = S1; (c = fgetc(in)) != EOF && len > 0; len--) { + if (c == 0) + continue; + switch (state) { + case S1: + switch (c) { + case '-': + state = S3; + break; + + default: + state = S2; + case '\n': + fputc(c, out); + break; + } break; - } - break; - - case S2: - switch (c) { - case '\n': - state = S1; - default: - fputc (c, out); - break; - } - break; - case S3: - switch (c) { - case ' ': - state = S2; + case S2: + switch (c) { + case '\n': + state = S1; + default: + fputc(c, out); + break; + } break; - default: - state = (c == '\n') ? S1 : S2; - fputc ('-', out); - fputc (c, out); + case S3: + switch (c) { + case ' ': + state = S2; + break; + + default: + state = (c == '\n') ? S1 : S2; + fputc('-', out); + fputc(c, out); + break; + } break; } - break; } - } - if (ferror (in) && !feof (in)) - adios (ifile, "error reading"); - if (ferror (out)) - adios (ofile, "error writing"); + if (ferror(in) && !feof(in)) + adios(ifile, "error reading"); + if (ferror(out)) + adios(ofile, "error writing"); } diff --git a/uip/comp.c b/uip/comp.c index 5ebce6e..4768fc4 100644 --- a/uip/comp.c +++ b/uip/comp.c @@ -1,299 +1,167 @@ - /* - * comp.c -- compose a message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** comp.c -- compose a message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include static struct swit switches[] = { -#define DFOLDSW 0 - { "draftfolder +folder", 0 }, -#define DMSGSW 1 - { "draftmessage msg", 0 }, -#define NDFLDSW 2 - { "nodraftfolder", 0 }, -#define EDITRSW 3 - { "editor editor", 0 }, -#define NEDITSW 4 - { "noedit", 0 }, -#define FILESW 5 - { "file file", 0 }, -#define FORMSW 6 - { "form formfile", 0 }, -#define USESW 7 - { "use", 0 }, -#define NUSESW 8 - { "nouse", 0 }, -#define WHATSW 9 - { "whatnowproc program", 0 }, -#define NWHATSW 10 - { "nowhatnowproc", 0 }, -#define VERSIONSW 11 - { "version", 0 }, -#define HELPSW 12 - { "help", 0 }, - { NULL, 0 } -}; - -static struct swit aqrunl[] = { -#define NOSW 0 - { "quit", 0 }, -#define YESW 1 - { "replace", 0 }, -#define USELSW 2 - { "use", 0 }, -#define LISTDSW 3 - { "list", 0 }, -#define REFILSW 4 - { "refile +folder", 0 }, -#define NEWSW 5 - { "new", 0 }, - { NULL, 0 } -}; - -static struct swit aqrul[] = { - { "quit", 0 }, - { "replace", 0 }, - { "use", 0 }, - { "list", 0 }, - { "refile", 0 }, - { NULL, 0 } +#define EDITRSW 0 + { "editor editor", 0 }, +#define FORMSW 1 + { "form formfile", 0 }, +#define USESW 2 + { "use", 0 }, +#define NUSESW 3 + { "nouse", 2 }, +#define WHATSW 4 + { "whatnowproc program", 0 }, +#define VERSIONSW 5 + { "Version", 0 }, +#define HELPSW 6 + { "help", 0 }, + { NULL, 0 } }; int -main (int argc, char **argv) +main(int argc, char **argv) { - int use = NOUSE, nedit = 0, nwhat = 0; - int i, in, isdf = 0, out; - char *cp, *cwd, *maildir, *dfolder = NULL; - char *ed = NULL, *file = NULL, *form = NULL; - char *folder = NULL, *msg = NULL, buf[BUFSIZ]; - char drft[BUFSIZ], **argp, **arguments; - struct msgs *mp = NULL; - struct stat st; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case EDITRSW: - if (!(ed = *argp++) || *ed == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nedit = 0; - continue; - case NEDITSW: - nedit++; - continue; - - case WHATSW: - if (!(whatnowproc = *argp++) || *whatnowproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nwhat = 0; - continue; - case NWHATSW: - nwhat++; - continue; - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case USESW: - use++; - continue; - case NUSESW: - use = NOUSE; - continue; - - case FILESW: /* compatibility */ - if (file) - adios (NULL, "only one file at a time!"); - if (!(file = *argp++) || *file == '-') - adios (NULL, "missing argument to %s", argp[-2]); - isdf = NOTOK; - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (file) - adios (NULL, "only one draft message at a time!"); - if (!(file = *argp++) || *file == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - } + int use = NOUSE; + int in, out; + char *cp, *cwd, *maildir; + char *ed = NULL, *form = NULL; + char *folder = NULL, *msg = NULL, buf[BUFSIZ]; + char drft[BUFSIZ], **argp, **arguments; + struct msgs *mp = NULL; + char *fmtstr; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msg] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case EDITRSW: + if (!(ed = *argp++) || *ed == '-') + adios(NULL, "missing argument to %s", argp[-2]); + continue; + + case WHATSW: + if (!(whatnowproc = *argp++) || *whatnowproc == '-') + adios(NULL, "missing argument to %s", argp[-2]); + continue; + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", argp[-2]); + continue; + + case USESW: + use++; + continue; + case NUSESW: + use = NOUSE; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + if (msg) + adios(NULL, "only one message at a time!"); + else + msg = cp; + } } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - if (msg) - adios (NULL, "only one message at a time!"); - else - msg = cp; - } - } - - cwd = getcpy (pwd ()); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* - * Check if we are using a draft folder - * and have specified a message in it. - */ - if ((dfolder || context_find ("Draft-Folder")) && !folder && msg && !file) { - file = msg; - msg = NULL; - } - if (form && (folder || msg)) - adios (NULL, "can't mix forms and folders/msgs"); - - if (folder || msg) { - /* - * Use a message as the "form" for the new message. - */ - if (!msg) - msg = "cur"; - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - /* parse the message range/sequence/name and set SELECTED */ - if (!m_convert (mp, msg)) - done (1); - seq_setprev (mp); /* set the previous-sequence */ + cwd = getcpy(pwd()); + + if (form && (folder || msg)) + adios(NULL, "can't mix forms and folders/msgs"); + + if (use && folder) + adios(NULL, "can't mix -use and +folder"); + + if (use) { + /* Don't copy; the draft shall get removed in the end. */ + strncpy(drft, m_draft(msg ? msg : seq_cur), sizeof(drft)); + + } else if (folder || msg) { + /* Take a message as the "form" for the new message. */ + if (!msg) + msg = seq_cur; + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + /* parse the message range/sequence/name and set SELECTED */ + if (!m_convert(mp, msg)) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + if (mp->numsel > 1) + adios(NULL, "only one message at a time!"); + if ((in = open(form = getcpy(m_name(mp->lowsel)), + O_RDONLY)) == NOTOK) + adios(form, "unable to open message"); + + strncpy(drft, m_draft(seq_beyond), sizeof(drft)); + if ((out = creat(drft, m_gmprot())) == NOTOK) { + adios(drft, "unable to create"); + } + cpydata(in, out, form, drft); + close(in); + close(out); - if (mp->numsel > 1) - adios (NULL, "only one message at a time!"); - - if ((in = open (form = getcpy (m_name (mp->lowsel)), O_RDONLY)) == NOTOK) - adios (form, "unable to open message"); - } else - in = open_form(&form, components); - -try_it_again: - strncpy (drft, m_draft (dfolder, file, use, &isdf), sizeof(drft)); - - /* - * Check if we have an existing draft - */ - if ((out = open (drft, O_RDONLY)) != NOTOK) { - i = fdcompare (in, out); - close (out); - - /* - * If we have given -use flag, or if the - * draft is just the same as the components - * file, then no need to ask any questions. - */ - if (use || i) - goto edit_it; - - if (stat (drft, &st) == NOTOK) - adios (drft, "unable to stat"); - printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size); - for (i = LISTDSW; i != YESW;) { - if (!(argp = getans ("\nDisposition? ", isdf ? aqrunl : aqrul))) - done (1); - switch (i = smatch (*argp, isdf ? aqrunl : aqrul)) { - case NOSW: - done (0); - case NEWSW: - file = NULL; - use = NOUSE; - goto try_it_again; - case YESW: - break; - case USELSW: - use++; - goto edit_it; - case LISTDSW: - showfile (++argp, drft); - break; - case REFILSW: - if (refile (++argp, drft) == 0) - i = YESW; - break; - default: - advise (NULL, "say what?"); - break; - } + } else { + fmtstr = new_fs(form, components); + strncpy(drft, m_draft(seq_beyond), sizeof(drft)); + if ((out = creat(drft, m_gmprot())) == NOTOK) { + adios(drft, "unable to create"); + } + if (write(out, fmtstr, strlen(fmtstr)) != (int)strlen(fmtstr)) { + adios(drft, "error writing"); + } + close(out); } - } else { - if (use) - adios (drft, "unable to open"); - } - - if ((out = creat (drft, m_gmprot ())) == NOTOK) - adios (drft, "unable to create"); - cpydata (in, out, form, drft); - close (in); - close (out); - -edit_it: - context_save (); /* save the context file */ - if (nwhat) - done (0); - what_now (ed, nedit, use, drft, NULL, 0, NULLMP, NULL, 0, cwd); - done (1); - return 1; + context_save(); + what_now(ed, use, drft, NULL, 0, NULLMP, NULL, cwd); + done(1); + return 1; } diff --git a/uip/conflict.c b/uip/conflict.c deleted file mode 100644 index 07e77fc..0000000 --- a/uip/conflict.c +++ /dev/null @@ -1,547 +0,0 @@ - -/* - * conflict.c -- check for conflicts in mail system - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * maximum number of directories that can - * be specified using -search switch. - */ -#define NDIRS 100 - -/* - * Add space for group names, 100 at a time - */ -#define NGRPS 100 - -static struct swit switches[] = { -#define MAILSW 0 - { "mail name", 0 }, -#define SERCHSW 1 - { "search directory", 0 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, 0 } -}; - -static char *mail = NULL; -static char *dirs[NDIRS]; -static FILE *out = NULL; - -extern struct aka *akahead; -extern struct home *homehead; - -/* - * prototypes - */ -void alias_files (int, char **); -void pwd_names (void); -void grp_names (void); -void grp_members (void); -void grp_ids (void); -void maildrops (void); -void mdrop(char *); -int check (char *); -void setup (void); - - -int -main (int argc, char **argv) -{ - int akp = 0, dp = 0; - char *cp, **argp, **arguments; - char buf[BUFSIZ], *akv[50]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [aliasfiles ...]", - invo_name); - print_help (buf, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case MAILSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (mail) - adios (NULL, "mail to one address only"); - else - mail = cp; - continue; - - case SERCHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (dp >= NDIRS) - adios (NULL, "more than %d directories", NDIRS); - dirs[dp++] = cp; - continue; - } - } - akv[akp++] = cp; - } - - if (akp == 0) - akv[akp++] = AliasFile; - if (!homehead) - init_pw (); - if (!mail) - out = stdout; - dirs[dp] = NULL; - - alias_files (akp, akv); - pwd_names (); - grp_names (); - grp_members (); - grp_ids (); -#ifdef UCI - ldr_names (); - ldr_ship (); -#endif /* UCI */ - maildrops (); - - done (0); - return 1; -} - - -void -alias_files (int akp, char **akv) -{ - register int i, err; - - for (i = 0; i < akp; i++) - if ((err = alias (akv[i])) != AK_OK) { - setup (); - fprintf (out, "aliasing error in %s - %s\n", akv[i], akerror (err)); - } - else - if (out && !mail) - fprintf (out, "alias file %s is ok\n", akv[i]); -} - - -void -pwd_names (void) -{ - int hit = 0; - register struct home *hm, *lm; - - for (hm = homehead; hm; hm = hm->h_next) - for (lm = hm->h_next; lm; lm = lm->h_next) - if (strcmp (hm->h_name, lm->h_name) == 0) { - setup (); - fprintf (out, "duplicate user %s(uid=%d)\n", - lm->h_name, (int) lm->h_uid); - hit++; - } - - if (!hit && out && !mail) - fprintf (out, "no duplicate users\n"); -} - - -void -grp_names (void) -{ - int numgroups, maxgroups; - int i, hit = 0; - char **grps; - struct group *gr; - - /* allocate space NGRPS at a time */ - numgroups = 0; - maxgroups = NGRPS; - grps = (char **) mh_xmalloc((size_t) (maxgroups * sizeof(*grps))); - - setgrent (); - while ((gr = getgrent ())) { - for (i = 0; i < numgroups; i++) - if (!strcmp (grps[i], gr->gr_name)) { - setup (); - fprintf (out, "duplicate group %s(gid=%d)\n", - gr->gr_name, (int) gr->gr_gid); - hit++; - break; - } - if (i >= numgroups) { - if (numgroups >= maxgroups) { - maxgroups += NGRPS; - grps = (char **) mh_xrealloc(grps, - (size_t) (maxgroups * sizeof(*grps))); - } - grps[numgroups++] = getcpy (gr->gr_name); - } - } - endgrent (); - - for (i = 0; i < numgroups; i++) - free (grps[i]); - free (grps); - - if (!hit && out && !mail) - fprintf (out, "no duplicate groups\n"); -} - - -void -grp_members (void) -{ - register int hit = 0; - register char **cp, **dp; - register struct group *gr; - register struct home *hm; - - setgrent (); - while ((gr = getgrent ())) { - for (cp = gr->gr_mem; *cp; cp++) { - for (hm = homehead; hm; hm = hm->h_next) - if (!strcmp (*cp, hm->h_name)) - break; - if (hm == NULL) { - setup (); - fprintf (out, "group %s(gid=%d) has unknown member %s\n", - gr->gr_name, (int) gr->gr_gid, *cp); - hit++; - } else { - hm->h_ngrps++; - } - - for (dp = cp + 1; *dp; dp++) - if (strcmp (*cp, *dp) == 0) { - setup (); - fprintf (out, "group %s(gid=%d) has duplicate member %s\n", - gr->gr_name, (int) gr->gr_gid, *cp); - hit++; - } - } - } - endgrent (); - - for (hm = homehead; hm; hm = hm->h_next) - if (hm->h_ngrps > NGROUPS_MAX) { - setup (); - fprintf (out, "user %s is a member of %d groups (max %d)\n", - hm->h_name, hm->h_ngrps, NGROUPS_MAX); - hit++; - } - - if (!hit && out && !mail) - fprintf (out, "all group members accounted for\n"); -} - - -void -grp_ids (void) -{ /* -DRAND not implemented at most places */ - register int hit = 0; - register struct home *hm; - - for (hm = homehead; hm; hm = hm->h_next) - if (getgrgid (hm->h_gid) == NULL) { - setup (); - fprintf (out, "user %s(uid=%d) has unknown group-id %d\n", - hm->h_name, (int) hm->h_uid, (int) hm->h_gid); - hit++; - } - - if (!hit && out && !mail) - fprintf (out, "all group-id users accounted for\n"); -} - - -void -maildrops (void) -{ - register int i; - - if (mmdfldir && *mmdfldir) - mdrop (mmdfldir); - if (uucpldir && *uucpldir) - mdrop (uucpldir); - for (i = 0; dirs[i]; i++) - mdrop (dirs[i]); -} - - -void -mdrop(char *drop) -{ - register int hit = 0; - register struct dirent *dp; - register DIR *dd = opendir (drop); - - if (!dd) { - setup (); - fprintf (out, "unable to open maildrop area %s\n", drop); - return; - } - - while ((dp = readdir (dd))) - if (dp->d_name[0] != '.' && !check (dp->d_name)) { - setup (); - fprintf (out, - "there is a maildrop for the unknown user %s in %s\n", - dp->d_name, drop); - hit++; - } - - closedir (dd); - if (!hit && out && !mail) - fprintf (out, "all maildrops accounted for in %s\n", drop); -} - - -int -check (char *s) -{ - register struct home *hm; - - for (hm = homehead; hm; hm = hm->h_next) - if (!strcmp (s, hm->h_name)) - return 1; - return 0; -} - -void -setup (void) -{ - int fd, pd[2]; - - if (out) - return; - - if (mail) { - if (pipe (pd) == NOTOK) - adios ("pipe", "unable to"); - - switch (fork ()) { - case NOTOK: - adios ("fork", "unable to"); - - case OK: - close (pd[1]); - if (pd[0] != 0) { - dup2 (pd[0], 0); - close (pd[0]); - } - if ((fd = open ("/dev/null", O_WRONLY)) != NOTOK) - if (fd != 1) { - dup2 (fd, 1); - close (fd); - } - execlp (mailproc, r1bindex (mailproc, '/'), - mail, "-subject", invo_name, NULL); - adios (mailproc, "unable to exec "); - - default: - close (pd[0]); - out = fdopen (pd[1], "w"); - fprintf (out, "%s: the following is suspicious\n\n", - invo_name); - } - } -} - -#ifdef UCI -/* - * UCI specific stuff for conflict - */ - -/* taken from */ - -#define GLDRS "/admin/etc/GroupLeaders" - -struct grpldr { - char *gl_name; - char **gl_ldr; -}; - -int setglent (), endglent (); -struct grpldr *getglent (), *getglnam (); - - -/* taken from the getglent() routines */ - -#define MAXGLS 100 - -static FILE *glp = NULL; -static char line[BUFSIZ+1]; -static struct grpldr grpldr; -static char *gl_ldr[MAXGLS + 1]; - - -setglent() { - if (glp == NULL) - glp = fopen (GLDRS, "r"); - else - rewind (glp); - - return (glp != NULL); -} - - -endglent() { - if (glp != NULL) { - fclose (glp); - glp = NULL; - } - - return 1; -} - -struct grpldr *getglent () { - register char *cp, - **q; - - if (glp == NULL && !setglent ()) - return NULL; - if ((cp = fgets (line, BUFSIZ, glp)) == NULL) - return NULL; - - grpldr.gl_name = cp; - grpldr.gl_ldr = q = gl_ldr; - - while (*cp) { - while (*cp && !isspace (*cp)) - cp++; - while (*cp && isspace (*cp)) - *cp++ = '\0'; - if (*cp == '\0') - break; - if (q < gl_ldr + MAXGLS) - *q++ = cp; - else - break; - } - *q = NULL; - - return (&grpldr); -} - -struct grpldr *getglnam (name) -char *name; -{ - register struct grpldr *gl = NULL; - - setglent (); - while (gl = getglent ()) - if (strcmp (name, gl->gl_name) == 0) - break; - endglent (); - - return gl; -} - -ldr_names () { - register int gp, - hit = 0; - char *gldrs[NGRPS]; - register struct grpldr *gl; - - gldrs[0] = NULL; - setglent (); - while (gl = getglent ()) { - if (getgrnam (gl->gl_name) == NULL) { - setup (); - fprintf (out, "unknown group %s in group leaders file\n", - gl->gl_name); - hit++; - } - for (gp = 0; gldrs[gp]; gp++) - if (strcmp (gldrs[gp], gl->gl_name) == 0) { - setup (); - fprintf (out, "duplicate group %s in group leaders file\n", - gl->gl_name); - hit++; - break; - } - if (gldrs[gp] == NULL) - if (gp < NGRPS) { - gldrs[gp++] = getcpy (gl->gl_name); - gldrs[gp] = NULL; - } - else { - setup (); - fprintf (out, "more than %d groups in group leaders file%s\n", - " (time to recompile)", NGRPS - 1); - hit++; - } - } - endglent (); - - for (gp = 0; gldrs[gp]; gp++) - free (gldrs[gp]); - - if (!hit && out && !mail) - fprintf (out, "all groups in group leaders file accounted for\n"); -} - - -ldr_ship () { - register int hit = 0; - register char **cp, - **dp; - register struct grpldr *gl; - - setglent (); - while (gl = getglent ()) - for (cp = gl->gl_ldr; *cp; cp++) { - if (!check (*cp)) { - setup (); - fprintf (out, "group %s has unknown leader %s\n", - gl->gl_name, *cp); - hit++; - } - - for (dp = cp + 1; *dp; dp++) - if (strcmp (*cp, *dp) == 0) { - setup (); - fprintf (out, "group %s had duplicate leader %s\n", - gl->gl_name, *cp); - hit++; - } - } - endglent (); - - if (!hit && out && !mail) - fprintf (out, "all group leaders accounted for\n"); -} -#endif /* UCI */ diff --git a/uip/dist.c b/uip/dist.c index 4bad51a..c1f4f9d 100644 --- a/uip/dist.c +++ b/uip/dist.c @@ -1,288 +1,157 @@ - /* - * dist.c -- re-distribute a message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** dist.c -- re-distribute a message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include static struct swit switches[] = { -#define ANNOSW 0 - { "annotate", 0 }, -#define NANNOSW 1 - { "noannotate", 0 }, -#define DFOLDSW 2 - { "draftfolder +folder", 0 }, -#define DMSGSW 3 - { "draftmessage msg", 0 }, -#define NDFLDSW 4 - { "nodraftfolder", 0 }, -#define EDITRSW 5 - { "editor editor", 0 }, -#define NEDITSW 6 - { "noedit", 0 }, -#define FORMSW 7 - { "form formfile", 0 }, -#define INPLSW 8 - { "inplace", 0 }, -#define NINPLSW 9 - { "noinplace", 0 }, -#define WHATSW 10 - { "whatnowproc program", 0 }, -#define NWHATSW 11 - { "nowhatnowproc", 0 }, -#define VERSIONSW 12 - { "version", 0 }, -#define HELPSW 13 - { "help", 0 }, -#define FILESW 14 - { "file file", -4 }, /* interface from msh */ - { NULL, 0 } -}; - -static struct swit aqrnl[] = { -#define NOSW 0 - { "quit", 0 }, -#define YESW 1 - { "replace", 0 }, -#define LISTDSW 2 - { "list", 0 }, -#define REFILSW 3 - { "refile +folder", 0 }, -#define NEWSW 4 - { "new", 0 }, - { NULL, 0 } -}; - - -static struct swit aqrl[] = { - { "quit", 0 }, - { "replace", 0 }, - { "list", 0 }, - { "refile +folder", 0 }, - { NULL, 0 } +#define ANNOSW 0 + { "annotate", 0 }, +#define NANNOSW 1 + { "noannotate", 2 }, +#define EDITRSW 2 + { "editor editor", 0 }, +#define FORMSW 3 + { "form formfile", 0 }, +#define WHATSW 4 + { "whatnowproc program", 0 }, +#define VERSIONSW 5 + { "Version", 0 }, +#define HELPSW 6 + { "help", 0 }, + { NULL, 0 } }; int -main (int argc, char **argv) +main(int argc, char **argv) { - int anot = 0, inplace = 1, nedit = 0; - int nwhat = 0, i, in, isdf = 0, out; - char *cp, *cwd, *maildir, *msgnam, *dfolder = NULL; - char *dmsg = NULL, *ed = NULL, *file = NULL, *folder = NULL; - char *form = NULL, *msg = NULL, buf[BUFSIZ], drft[BUFSIZ]; - char **argp, **arguments; - struct msgs *mp = NULL; - struct stat st; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ANNOSW: - anot++; - continue; - case NANNOSW: - anot = 0; - continue; - - case EDITRSW: - if (!(ed = *argp++) || *ed == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nedit = 0; - continue; - case NEDITSW: - nedit++; - continue; - - case WHATSW: - if (!(whatnowproc = *argp++) || *whatnowproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nwhat = 0; - continue; - case NWHATSW: - nwhat++; - continue; - - case FILESW: - if (file) - adios (NULL, "only one file at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - file = path (cp, TFILE); - continue; - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case INPLSW: - inplace++; - continue; - case NINPLSW: - inplace = 0; - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - if (msg) - adios (NULL, "only one message at a time!"); - else - msg = cp; + int anot = 0; + int in, out; + char *cp, *cwd, *maildir, *msgnam; + char *ed = NULL, *folder = NULL; + char *form = NULL, *msg = NULL, buf[BUFSIZ], drft[BUFSIZ]; + char **argp, **arguments; + struct msgs *mp = NULL; + char *fmtstr; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msg] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case ANNOSW: + anot++; + continue; + case NANNOSW: + anot = 0; + continue; + + case EDITRSW: + if (!(ed = *argp++) || *ed == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WHATSW: + if (!(whatnowproc = *argp++) || *whatnowproc == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + if (msg) + adios(NULL, "only one message at a time!"); + else + msg = cp; + } } - } - - cwd = getcpy (pwd ()); - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (file && (msg || folder)) - adios (NULL, "can't mix files and folders/msgs"); + cwd = getcpy(pwd()); - in = open_form(&form, distcomps); + strncpy(drft, m_draft(seq_beyond), sizeof(drft)); + if ((out = creat(drft, m_gmprot())) == NOTOK) + adios(drft, "unable to create"); -try_it_again: - strncpy (drft, m_draft (dfolder, dmsg, NOUSE, &isdf), sizeof(drft)); - - /* Check if draft already exists */ - if (stat (drft, &st) != NOTOK) { - printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size); - for (i = LISTDSW; i != YESW;) { - if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl))) - done (1); - switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) { - case NOSW: - done (0); - case NEWSW: - dmsg = NULL; - goto try_it_again; - case YESW: - break; - case LISTDSW: - showfile (++argp, drft); - break; - case REFILSW: - if (refile (++argp, drft) == 0) - i = YESW; - break; - default: - advise (NULL, "say what?"); - break; - } + fmtstr = new_fs(form, distcomps); + if (write(out, fmtstr, strlen(fmtstr)) != (int)strlen(fmtstr)) { + adios(drft, "error writing"); } - } - if ((out = creat (drft, m_gmprot ())) == NOTOK) - adios (drft, "unable to create"); - - cpydata (in, out, form, drft); - close (in); - close (out); + close(out); - if (file) { - /* - * Dist a file - */ - anot = 0; /* don't want to annotate a file */ - } else { - /* - * Dist a message - */ if (!msg) - msg = "cur"; + msg = seq_cur; if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); + folder = getcurfol(); + maildir = toabsdir(folder); - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); /* check for empty folder */ if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); + adios(NULL, "no messages in %s", folder); /* parse the message range/sequence/name and set SELECTED */ - if (!m_convert (mp, msg)) - done (1); - seq_setprev (mp); /* set the previous-sequence */ + if (!m_convert(mp, msg)) + done(1); + seq_setprev(mp); if (mp->numsel > 1) - adios (NULL, "only one message at a time!"); - } + adios(NULL, "only one message at a time!"); - msgnam = file ? file : getcpy (m_name (mp->lowsel)); - if ((in = open (msgnam, O_RDONLY)) == NOTOK) - adios (msgnam, "unable to open message"); + msgnam = getcpy(m_name(mp->lowsel)); + if ((in = open(msgnam, O_RDONLY)) == NOTOK) + adios(msgnam, "unable to open message"); - if (!file) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->lowsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } + context_replace(curfolder, folder); + seq_setcur(mp, mp->lowsel); + seq_save(mp); /* synchronize sequences */ + context_save(); - if (nwhat) - done (0); - what_now (ed, nedit, NOUSE, drft, msgnam, 1, mp, - anot ? "Resent" : NULL, inplace, cwd); - done (1); - return 1; + what_now(ed, NOUSE, drft, msgnam, 1, mp, anot ? "Resent" : NULL, cwd); + done(1); + return 1; } diff --git a/uip/distsbr.c b/uip/distsbr.c index afd4e41..a9a52b1 100644 --- a/uip/distsbr.c +++ b/uip/distsbr.c @@ -1,11 +1,10 @@ - /* - * distsbr.c -- routines to do additional "dist-style" processing - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** distsbr.c -- routines to do additional "dist-style" processing +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,192 +13,205 @@ static int hdrfd = NOTOK; static int txtfd = NOTOK; -#define BADHDR "please re-edit %s to remove the ``%s'' header!" -#define BADTXT "please re-edit %s to consist of headers only!" -#define BADMSG "please re-edit %s to include a ``Resent-To:''!" -#define BADRFT "please re-edit %s and fix that header!" - /* - * static prototypes - */ +** static prototypes +*/ static void ready_msg(char *); int -distout (char *drft, char *msgnam, char *backup) +distout(char *drft, char *msgnam, char *backup) { - int state; - register unsigned char *dp; - register char *resent; - char name[NAMESZ], buffer[BUFSIZ]; - register FILE *ifp, *ofp; - - if (rename (drft, strcpy (backup, m_backup (drft))) == NOTOK) - adios (backup, "unable to rename %s to",drft); - if ((ifp = fopen (backup, "r")) == NULL) - adios (backup, "unable to read"); - - if ((ofp = fopen (drft, "w")) == NULL) - adios (drft, "unable to create temporary file"); - chmod (drft, m_gmprot ()); - - ready_msg (msgnam); - lseek (hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */ - cpydata (hdrfd, fileno (ofp), msgnam, drft); - - for (state = FLD, resent = NULL;;) - switch (state = - m_getfld (state, name, buffer, sizeof buffer, ifp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - if (uprf (name, "distribute-")) - snprintf (name, sizeof(name), "%s%s", "Resent", &name[10]); - if (uprf (name, "distribution-")) - snprintf (name, sizeof(name), "%s%s", "Resent", &name[12]); - if (!uprf (name, "resent")) { - advise (NULL, BADHDR, "draft", name); - goto leave_bad; + int state; + register unsigned char *dp; + register char *resent; + char name[NAMESZ], buffer[BUFSIZ]; + register FILE *ifp, *ofp; + + strcpy(backup, m_mktemp(toabsdir(invo_name), NULL, NULL)); + if (rename(drft, backup) == NOTOK) { + adios(backup, "unable to rename %s to",drft); + } + if (!(ifp = fopen(backup, "r"))) { + adios(backup, "unable to read"); + } + + if (!(ofp = fopen(drft, "w"))) { + adios(drft, "unable to create temporary file"); + } + chmod(drft, m_gmprot()); + + ready_msg(msgnam); + lseek(hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */ + cpydata(hdrfd, fileno(ofp), msgnam, drft); + + state = FLD; + resent = NULL; + while (1) { + switch (state = m_getfld(state, name, buffer, sizeof buffer, + ifp)) { + case FLD: + case FLDPLUS: + case FLDEOF: + if (!uprf(name, "resent")) { + advise(NULL, "Please re-edit draft to remove the ``%s'' header.", name); + goto leave_bad; + } + if (state == FLD) { + resent = add(":", add(name, resent)); + } + resent = add(buffer, resent); + fprintf(ofp, "%s: %s", name, buffer); + while (state == FLDPLUS) { + state = m_getfld(state, name, buffer, + sizeof buffer, ifp); + resent = add(buffer, resent); + fputs(buffer, ofp); + } + if (state == FLDEOF) { + goto process; + } + break; + + case BODY: + case BODYEOF: + for (dp = buffer; *dp; dp++) { + if (!isspace(*dp)) { + advise(NULL, "Please re-edit draft to consist of headers only."); + goto leave_bad; + } + } + + case FILEEOF: + goto process; + + case LENERR: + case FMTERR: + advise(NULL, "Please re-edit draft and fix that header."); +leave_bad: ; + fclose(ifp); + fclose(ofp); + unlink(drft); + if (rename(backup, drft) == NOTOK) { + adios(drft, "unable to rename %s to", backup); + } + return NOTOK; + + default: + adios(NULL, "getfld() returned %d", state); } - if (state == FLD) - resent = add (":", add (name, resent)); - resent = add (buffer, resent); - fprintf (ofp, "%s: %s", name, buffer); - while (state == FLDPLUS) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); - resent = add (buffer, resent); - fputs (buffer, ofp); + } + +process: ; + fclose(ifp); + fflush(ofp); + + if (!resent) { + advise(NULL, "Please re-edit draft to include a ``Resent-To:'' header."); + fclose(ofp); + unlink(drft); + if (rename(backup, drft) == NOTOK) { + adios(drft, "unable to rename %s to", backup); } - if (state == FLDEOF) - goto process; - break; - - case BODY: - case BODYEOF: - for (dp = buffer; *dp; dp++) - if (!isspace (*dp)) { - advise (NULL, BADTXT, "draft"); - goto leave_bad; - } - - case FILEEOF: - goto process; - - case LENERR: - case FMTERR: - advise (NULL, BADRFT, "draft"); - leave_bad: ; - fclose (ifp); - fclose (ofp); - unlink (drft); - if (rename (backup, drft) == NOTOK) - adios (drft, "unable to rename %s to", backup); return NOTOK; + } + free(resent); - default: - adios (NULL, "getfld() returned %d", state); + if (txtfd != NOTOK) { + lseek(txtfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */ + cpydata(txtfd, fileno(ofp), msgnam, drft); } -process: ; - fclose (ifp); - fflush (ofp); - - if (!resent) { - advise (NULL, BADMSG, "draft"); - fclose (ofp); - unlink (drft); - if (rename (backup, drft) == NOTOK) - adios (drft, "unable to rename %s to", backup); - return NOTOK; - } - free (resent); - - if (txtfd != NOTOK) { - lseek (txtfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */ - cpydata (txtfd, fileno (ofp), msgnam, drft); - } - - fclose (ofp); - - return OK; + + fclose(ofp); + + return OK; } static void -ready_msg (char *msgnam) +ready_msg(char *msgnam) { - int state, out; - char name[NAMESZ], buffer[BUFSIZ], tmpfil[BUFSIZ]; - register FILE *ifp, *ofp; - char *cp = NULL; - - if (hdrfd != NOTOK) - close (hdrfd), hdrfd = NOTOK; - if (txtfd != NOTOK) - close (txtfd), txtfd = NOTOK; - - if ((ifp = fopen (msgnam, "r")) == NULL) - adios (msgnam, "unable to open message"); - - cp = m_mktemp2(NULL, "dist", &hdrfd, NULL); - if (cp == NULL) { - adios("distsbr", "unable to create temporary file"); - } - fchmod(hdrfd, 0600); - strncpy(tmpfil, cp, sizeof(tmpfil)); - if ((out = dup (hdrfd)) == NOTOK - || (ofp = fdopen (out, "w")) == NULL) - adios (NULL, "no file descriptors -- you lose big"); - unlink (tmpfil); - - for (state = FLD;;) - switch (state = - m_getfld (state, name, buffer, sizeof buffer, ifp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - if (uprf (name, "resent")) - fprintf (ofp, "Prev-"); - fprintf (ofp, "%s: %s", name, buffer); - while (state == FLDPLUS) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); - fputs (buffer, ofp); - } - if (state == FLDEOF) - goto process; - break; - - case BODY: - case BODYEOF: - fclose (ofp); - - cp = m_mktemp2(NULL, "dist", &txtfd, NULL); - if (cp == NULL) { - adios("distsbr", "unable to create temporary file"); - } - fchmod(txtfd, 0600); - strncpy (tmpfil, cp, sizeof(tmpfil)); - if ((out = dup (txtfd)) == NOTOK - || (ofp = fdopen (out, "w")) == NULL) - adios (NULL, "no file descriptors -- you lose big"); - unlink (tmpfil); - fprintf (ofp, "\n%s", buffer); - while (state == BODY) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); - fputs (buffer, ofp); - } - case FILEEOF: - goto process; - - case LENERR: - case FMTERR: - adios (NULL, "format error in message %s", msgnam); + int state, out; + char name[NAMESZ], buffer[BUFSIZ], tmpfil[BUFSIZ]; + register FILE *ifp, *ofp; + char *cp = NULL; + + if (hdrfd != NOTOK) { + close(hdrfd); + hdrfd = NOTOK; + } + if (txtfd != NOTOK) { + close(txtfd); + txtfd = NOTOK; + } + if (!(ifp = fopen(msgnam, "r"))) { + adios(msgnam, "unable to open message"); + } - default: - adios (NULL, "getfld() returned %d", state); + cp = m_mktemp2(NULL, "dist", &hdrfd, NULL); + if (!cp) { + adios("distsbr", "unable to create temporary file"); + } + fchmod(hdrfd, 0600); + strncpy(tmpfil, cp, sizeof(tmpfil)); + if ((out = dup(hdrfd)) == NOTOK || !(ofp = fdopen(out, "w"))) { + adios(NULL, "no file descriptors -- you lose big"); + } + unlink(tmpfil); + + state = FLD; + while (1) { + state = m_getfld(state, name, buffer, sizeof buffer, ifp); + switch (state) { + case FLD: + case FLDPLUS: + case FLDEOF: + if (uprf(name, "resent")) { + fprintf(ofp, "Prev-"); + } + fprintf(ofp, "%s: %s", name, buffer); + while (state == FLDPLUS) { + state = m_getfld(state, name, buffer, + sizeof buffer, ifp); + fputs(buffer, ofp); + } + if (state == FLDEOF) { + goto process; + } + break; + + case BODY: + case BODYEOF: + fclose(ofp); + + cp = m_mktemp2(NULL, "dist", &txtfd, NULL); + if (!cp) { + adios("distsbr", "unable to create temp file"); + } + fchmod(txtfd, 0600); + strncpy(tmpfil, cp, sizeof(tmpfil)); + if ((out = dup(txtfd)) == NOTOK || + !(ofp = fdopen(out, "w"))) { + adios(NULL, "no file descriptors -- you lose"); + } + unlink(tmpfil); + fprintf(ofp, "\n%s", buffer); + while (state == BODY) { + state = m_getfld(state, name, buffer, + sizeof buffer, ifp); + fputs(buffer, ofp); + } + case FILEEOF: + goto process; + + case LENERR: + case FMTERR: + adios(NULL, "format error in message %s", msgnam); + + default: + adios(NULL, "getfld() returned %d", state); + } } process: ; - fclose (ifp); - fclose (ofp); + fclose(ifp); + fclose(ofp); } diff --git a/uip/dp.c b/uip/dp.c index c94c8ea..1a91678 100644 --- a/uip/dp.c +++ b/uip/dp.c @@ -1,35 +1,27 @@ - /* - * dp.c -- parse dates 822-style - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** dp.c -- parse dates 822-style +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#define NDATES 100 - -#define WIDTH 78 -#define WBUFSIZ BUFSIZ +#define NDATES 100 -#define FORMAT "%<(nodate{text})error: %{text}%|%(putstr(pretty{text}))%>" +#define FORMAT "=%<(nodate{text})error: %{text}%|%(putstr(pretty{text}))%>" static struct swit switches[] = { -#define FORMSW 0 - { "form formatfile", 0 }, -#define FMTSW 1 - { "format string", 5 }, -#define WIDTHSW 2 - { "width columns", 0 }, -#define VERSIONSW 3 - { "version", 0 }, -#define HELPSW 4 - { "help", 0 }, - { NULL, 0 } +#define FORMSW 0 + { "form formatfile", 0 }, +#define VERSIONSW 1 + { "Version", 0 }, +#define HELPSW 2 + { "help", 0 }, + { NULL, 0 } }; static struct format *fmt; @@ -37,120 +29,95 @@ static struct format *fmt; static int dat[5]; /* - * prototypes - */ -int sc_width (void); /* from termsbr.c */ - -/* - * static prototypes - */ -static int process (char *, int); +** static prototypes +*/ +static int process(char *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int datep = 0, width = 0, status = 0; - char *cp, *form = NULL, *format = NULL, *nfs; - char buf[BUFSIZ], **argp, **arguments; - char *dates[NDATES]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] dates ...", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - width = atoi (cp); - continue; - } + int datep = 0, status = 0; + char *cp, *form = NULL, *fmtstr; + char buf[BUFSIZ], **argp, **arguments; + char *dates[NDATES]; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] dates ...", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + } + } + if (datep > NDATES) + adios(NULL, "more than %d dates", NDATES); + else + dates[datep++] = cp; } - if (datep > NDATES) - adios (NULL, "more than %d dates", NDATES); - else - dates[datep++] = cp; - } - dates[datep] = NULL; - - if (datep == 0) - adios (NULL, "usage: %s [switches] dates ...", invo_name); - - /* get new format string */ - nfs = new_fs (form, format, FORMAT); - - if (width == 0) { - if ((width = sc_width ()) < WIDTH / 2) - width = WIDTH / 2; - width -= 2; - } - if (width > WBUFSIZ) - width = WBUFSIZ; - fmt_compile (nfs, &fmt); - - dat[0] = 0; - dat[1] = 0; - dat[2] = 0; - dat[3] = width; - dat[4] = 0; - - for (datep = 0; dates[datep]; datep++) - status += process (dates[datep], width); - - context_save (); /* save the context file */ - done (status); - return 1; + dates[datep] = NULL; + + if (datep == 0) + adios(NULL, "usage: %s [switches] dates ...", invo_name); + + /* get new format string */ + fmtstr = new_fs(form, FORMAT); + + fmt_compile(fmtstr, &fmt); + + dat[0] = 0; + dat[1] = 0; + dat[2] = 0; + dat[3] = BUFSIZ; + dat[4] = 0; + + for (datep = 0; dates[datep]; datep++) + status += process(dates[datep]); + + context_save(); /* save the context file */ + done(status); + return 1; } static int -process (char *date, int length) +process(char *date) { - int status = 0; - char buffer[WBUFSIZ + 1]; - register struct comp *cptr; + int status = 0; + char buffer[BUFSIZ + 1]; + register struct comp *cptr; - FINDCOMP (cptr, "text"); - if (cptr) - cptr->c_text = date; - fmt_scan (fmt, buffer, length, dat); - fputs (buffer, stdout); + FINDCOMP(cptr, "text"); + if (cptr) + cptr->c_text = date; + fmt_scan(fmt, buffer, BUFSIZ, dat); + fputs(buffer, stdout); - return status; + return status; } diff --git a/uip/dropsbr.c b/uip/dropsbr.c index 76bc00d..3c3e105 100644 --- a/uip/dropsbr.c +++ b/uip/dropsbr.c @@ -1,717 +1,198 @@ - /* - * dropsbr.c -- create/read/manipulate mail drops - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** dropsbr.c -- append to mbox files +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include -#include #include - -#ifdef HAVE_ERRNO_H -# include -#endif - -#ifdef NTOHLSWAP -# include -#else -# undef ntohl -# define ntohl(n) (n) -#endif - +#include #include -/* - * static prototypes - */ -static int mbx_chk_mbox (int); -static int mbx_chk_mmdf (int); -static int map_open (char *, int); - /* - * Main entry point to open/create and lock - * a file or maildrop. - */ - +** Main entry point to open/create and lock +** a file or maildrop. +*/ int -mbx_open (char *file, int mbx_style, uid_t uid, gid_t gid, mode_t mode) +mbox_open(char *file, uid_t uid, gid_t gid, mode_t mode) { - int j, count, fd; - struct stat st; + int i, count, fd; + struct stat st; - j = 0; + i = 0; - /* attempt to open and lock file */ - for (count = 4; count > 0; count--) { - if ((fd = lkopen (file, O_RDWR | O_CREAT | O_NONBLOCK, mode)) == NOTOK) { - switch (errno) { + /* attempt to open and lock file */ + for (count = 4; count > 0; count--) { + if ((fd = lkopen(file, O_RDWR | O_CREAT | O_NONBLOCK, mode)) + == NOTOK) { + switch (errno) { #if defined(FCNTL_LOCKING) || defined(LOCKF_LOCKING) - case EACCES: - case EAGAIN: + case EACCES: + case EAGAIN: #endif #ifdef FLOCK_LOCKING - case EWOULDBLOCK: + case EWOULDBLOCK: #endif - case ETXTBSY: - j = errno; - sleep (5); - break; - - default: - /* just return error */ - return NOTOK; - } - } - - /* good file descriptor */ - break; - } - - errno = j; - - /* - * Return if we still failed after 4 attempts, - * or we just want to skip the sanity checks. - */ - if (fd == NOTOK || mbx_style == OTHER_FORMAT) - return fd; - - /* - * Do sanity checks on maildrop. - */ - if (fstat (fd, &st) == NOTOK) { - /* - * The stat failed. So we make sure file - * has right ownership/modes - */ - chown (file, uid, gid); - chmod (file, mode); - } else if (st.st_size > (off_t) 0) { - int status; - - /* check the maildrop */ - switch (mbx_style) { - case MMDF_FORMAT: - default: - status = mbx_chk_mmdf (fd); - break; + case ETXTBSY: + i = errno; + sleep(5); + break; + + default: + /* just return error */ + return NOTOK; + } + } - case MBOX_FORMAT: - status = mbx_chk_mbox (fd); + /* good file descriptor */ break; } - /* if error, attempt to close it */ - if (status == NOTOK) { - close (fd); - return NOTOK; - } - } + errno = i; - return fd; -} - - -/* - * Check/prepare MBOX style maildrop for appending. - */ - -static int -mbx_chk_mbox (int fd) -{ - /* just seek to the end */ - if (lseek (fd, (off_t) 0, SEEK_END) == (off_t) NOTOK) - return NOTOK; - - return OK; -} - - -/* - * Check/prepare MMDF style maildrop for appending. - */ - -static int -mbx_chk_mmdf (int fd) -{ - size_t count; - char ldelim[BUFSIZ]; - - count = strlen (mmdlm2); - - /* casting -count to off_t, seem to break FreeBSD 2.2.6 */ - if (lseek (fd, (long) (-count), SEEK_END) == (off_t) NOTOK) - return NOTOK; - if (read (fd, ldelim, count) != count) - return NOTOK; - - ldelim[count] = 0; - - if (strcmp (ldelim, mmdlm2) - && write (fd, "\n", 1) != 1 - && write (fd, mmdlm2, count) != count) - return NOTOK; - - return OK; -} - - -int -mbx_read (FILE *fp, long pos, struct drop **drops, int noisy) -{ - register int len, size; - register long ld1, ld2; - register char *bp; - char buffer[BUFSIZ]; - register struct drop *cp, *dp, *ep, *pp; - - pp = (struct drop *) calloc ((size_t) (len = MAXFOLDER), sizeof(*dp)); - if (pp == NULL) { - if (noisy) - admonish (NULL, "unable to allocate drop storage"); - return NOTOK; - } - - ld1 = (long) strlen (mmdlm1); - ld2 = (long) strlen (mmdlm2); - - fseek (fp, pos, SEEK_SET); - for (ep = (dp = pp) + len - 1; fgets (buffer, sizeof(buffer), fp);) { - size = 0; - if (strcmp (buffer, mmdlm1) == 0) - pos += ld1, dp->d_start = (long) pos; - else { - dp->d_start = (long)pos , pos += (long) strlen (buffer); - for (bp = buffer; *bp; bp++, size++) - if (*bp == '\n') - size++; - } - - while (fgets (buffer, sizeof(buffer), fp) != NULL) - if (strcmp (buffer, mmdlm2) == 0) - break; - else { - pos += (long) strlen (buffer); - for (bp = buffer; *bp; bp++, size++) - if (*bp == '\n') - size++; - } - - if (dp->d_start != (long) pos) { - dp->d_id = 0; - dp->d_size = (long) size; - dp->d_stop = pos; - dp++; - } - pos += ld2; - - if (dp >= ep) { - register int curlen = dp - pp; + /* + ** Return if we still failed after 4 attempts, + ** or we just want to skip the sanity checks. + */ + if (fd == NOTOK) + return fd; + + /* Do sanity checks on maildrop. */ + if (fstat(fd, &st) == NOTOK) { + /* + ** The stat failed. So we make sure file + ** has right ownership/modes + */ + chown(file, uid, gid); + chmod(file, mode); + } else if (st.st_size > (off_t) 0) { + int status; + + /* Check/prepare MBOX style maildrop for appending. */ + if (lseek(fd, (off_t) 0, SEEK_END) == (off_t) NOTOK) { + status = NOTOK; + } else { + status = OK; + } - cp = (struct drop *) mh_xrealloc ((char *) pp, - (size_t) (len += MAXFOLDER) * sizeof(*pp)); - dp = cp + curlen, ep = (pp = cp) + len - 1; + /* if error, attempt to close it */ + if (status == NOTOK) { + close(fd); + return NOTOK; + } } - } - if (dp == pp) - free ((char *) pp); - else - *drops = pp; - return (dp - pp); -} - - -int -mbx_write(char *mailbox, int md, FILE *fp, int id, long last, - long pos, off_t stop, int mapping, int noisy) -{ - register int i, j, size; - off_t start; - long off; - register char *cp; - char buffer[BUFSIZ]; - - off = (long) lseek (md, (off_t) 0, SEEK_CUR); - j = strlen (mmdlm1); - if (write (md, mmdlm1, j) != j) - return NOTOK; - start = lseek (md, (off_t) 0, SEEK_CUR); - size = 0; - - fseek (fp, pos, SEEK_SET); - while (fgets (buffer, sizeof(buffer), fp) && (pos < stop)) { - i = strlen (buffer); - for (j = 0; (j = stringdex (mmdlm1, buffer)) >= 0; buffer[j]++) - continue; - for (j = 0; (j = stringdex (mmdlm2, buffer)) >= 0; buffer[j]++) - continue; - if (write (md, buffer, i) != i) - return NOTOK; - pos += (long) i; - if (mapping) - for (cp = buffer; i-- > 0; size++) - if (*cp++ == '\n') - size++; - } - - stop = lseek (md, (off_t) 0, SEEK_CUR); - j = strlen (mmdlm2); - if (write (md, mmdlm2, j) != j) - return NOTOK; - if (mapping) - map_write (mailbox, md, id, last, start, stop, off, size, noisy); - - return OK; + return fd; } /* - * Append message to end of file or maildrop. - */ - +** Append message to end of mbox. +*/ int -mbx_copy (char *mailbox, int mbx_style, int md, int fd, - int mapping, char *text, int noisy) +mbox_copy(int to, int from) { - int i, j, size; - off_t start, stop; - long pos; - char *cp, buffer[BUFSIZ]; - FILE *fp; - - pos = (long) lseek (md, (off_t) 0, SEEK_CUR); - size = 0; - - switch (mbx_style) { - case MMDF_FORMAT: - default: - j = strlen (mmdlm1); - if (write (md, mmdlm1, j) != j) - return NOTOK; - start = lseek (md, (off_t) 0, SEEK_CUR); + int i; + char buffer[BUFSIZ]; + FILE *fp; - if (text) { - i = strlen (text); - if (write (md, text, i) != i) - return NOTOK; - for (cp = text; *cp++; size++) - if (*cp == '\n') - size++; - } - - while ((i = read (fd, buffer, sizeof(buffer))) > 0) { - for (j = 0; - (j = stringdex (mmdlm1, buffer)) >= 0; - buffer[j]++) - continue; - for (j = 0; - (j = stringdex (mmdlm2, buffer)) >= 0; - buffer[j]++) - continue; - if (write (md, buffer, i) != i) - return NOTOK; - if (mapping) - for (cp = buffer; i-- > 0; size++) - if (*cp++ == '\n') - size++; - } - - stop = lseek (md, (off_t) 0, SEEK_CUR); - j = strlen (mmdlm2); - if (write (md, mmdlm2, j) != j) + if ((i = dup(from)) == NOTOK) return NOTOK; - if (mapping) - map_write (mailbox, md, 0, (long) 0, start, stop, pos, size, noisy); - - return (i != NOTOK ? OK : NOTOK); - - case MBOX_FORMAT: - if ((j = dup (fd)) == NOTOK) + if ((fp = fdopen(i, "r")) == NULL) { + close(i); return NOTOK; - if ((fp = fdopen (j, "r")) == NULL) { - close (j); - return NOTOK; - } - start = lseek (md, (off_t) 0, SEEK_CUR); - - /* If text is given, we add it to top of message */ - if (text) { - i = strlen (text); - if (write (md, text, i) != i) - return NOTOK; - for (cp = text; *cp++; size++) - if (*cp == '\n') - size++; - } - - for (j = 0; fgets (buffer, sizeof(buffer), fp) != NULL; j++) { + } + for (i = 0; fgets(buffer, sizeof(buffer), fp) != NULL; i++) { /* - * Check the first line, and make some changes. - */ - if (j == 0 && !text) { - /* - * Change the "Return-Path:" field (if in first line) - * back to "From ". - */ - if (!strncmp (buffer, "Return-Path:", 12)) { - char tmpbuffer[BUFSIZ]; - char *tp, *ep, *fp; - - strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); - ep = tmpbuffer + 13; - if (!(fp = strchr(ep + 1, ' '))) - fp = strchr(ep + 1, '\n'); - tp = dctime(dlocaltimenow()); - snprintf (buffer, sizeof(buffer), "From %.*s %s", - (int)(fp - ep), ep, tp); - } else if (!strncmp (buffer, "X-Envelope-From:", 16)) { - /* - * Change the "X-Envelope-From:" field - * (if first line) back to "From ". - */ - char tmpbuffer[BUFSIZ]; - char *ep; - - strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); - ep = tmpbuffer + 17; - snprintf (buffer, sizeof(buffer), "From %s", ep); - } else if (strncmp (buffer, "From ", 5)) { + ** Check the first line, and make some changes. + */ + if (i == 0) { /* - * If there is already a "From " line, - * then leave it alone. Else we add one. - */ - char tmpbuffer[BUFSIZ]; - char *tp, *ep; - - strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); - ep = "nobody@nowhere"; - tp = dctime(dlocaltimenow()); - snprintf (buffer, sizeof(buffer), "From %s %s%s", ep, tp, tmpbuffer); - } + ** Change the "Return-Path:" field + ** (if in first line) back to "From ". + */ + if (strncmp(buffer, "Return-Path:", 12)==0) { + char tmpbuffer[BUFSIZ]; + char *tp, *ep, *fp; + + strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); + ep = tmpbuffer + 13; + if (!(fp = strchr(ep + 1, ' '))) + fp = strchr(ep + 1, '\n'); + tp = dctime(dlocaltimenow()); + snprintf(buffer, sizeof(buffer), + "From %.*s %s", + (int)(fp-ep), ep, tp); + } else if (strncmp(buffer, "X-Envelope-From:", + 16)==0) { + /* + ** Change the "X-Envelope-From:" field + ** (if first line) back to "From ". + */ + char tmpbuffer[BUFSIZ]; + char *ep; + + strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); + ep = tmpbuffer + 17; + snprintf(buffer, sizeof(buffer), "From %s", + ep); + } else if (strncmp(buffer, "From ", 5)!=0) { + /* + ** If there is already a "From " line, + ** then leave it alone. Else we add one. + */ + char tmpbuffer[BUFSIZ]; + char *tp, *ep; + + strncpy(tmpbuffer, buffer, sizeof(tmpbuffer)); + ep = "nobody@nowhere"; + tp = dctime(dlocaltimenow()); + snprintf(buffer, sizeof(buffer), + "From %s %s%s", ep, tp, + tmpbuffer); + } } /* - * If this is not first line, and begins with - * "From ", then prepend line with ">". - */ - if (j != 0 && strncmp (buffer, "From ", 5) == 0) { - write (md, ">", 1); - size++; + ** If this is not first line, and begins with "From ", + ** then prepend line with ">". (`mboxo' format is used.) + */ + if (i != 0 && strncmp(buffer, "From ", 5) == 0) { + write(to, ">", 1); } - i = strlen (buffer); - if (write (md, buffer, i) != i) { - fclose (fp); - return NOTOK; + if (write(to, buffer, strlen(buffer)) != (int)strlen(buffer)) { + fclose(fp); + return NOTOK; } - if (mapping) - for (cp = buffer; i-- > 0; size++) - if (*cp++ == '\n') - size++; - } - if (write (md, "\n", 1) != 1) { - fclose (fp); - return NOTOK; - } - if (mapping) - size += 2; - - fclose (fp); - lseek (fd, (off_t) 0, SEEK_END); - stop = lseek (md, (off_t) 0, SEEK_CUR); - if (mapping) - map_write (mailbox, md, 0, (long) 0, start, stop, pos, size, noisy); - - return OK; - } -} - - -int -mbx_size (int md, off_t start, off_t stop) -{ - register int i, fd; - register long pos; - register FILE *fp; - - if ((fd = dup (md)) == NOTOK || (fp = fdopen (fd, "r")) == NULL) { - if (fd != NOTOK) - close (fd); - return NOTOK; - } - - fseek (fp, start, SEEK_SET); - for (i = 0, pos = stop - start; pos-- > 0; i++) - if (fgetc (fp) == '\n') - i++; - - fclose (fp); - return i; -} - - -/* - * Close and unlock file/maildrop. - */ - -int -mbx_close (char *mailbox, int md) -{ - if (lkclose (md, mailbox) == 0) - return OK; - return NOTOK; -} - - -/* - * This function is performed implicitly by getbbent.c: - * bb->bb_map = map_name (bb->bb_file); - */ - -char * -map_name (char *file) -{ - register char *cp, *dp; - static char buffer[BUFSIZ]; - - if ((dp = strchr(cp = r1bindex (file, '/'), '.')) == NULL) - dp = cp + strlen (cp); - if (cp == file) - snprintf (buffer, sizeof(buffer), ".%.*s%s", (int)(dp - cp), cp, ".map"); - else - snprintf (buffer, sizeof(buffer), "%.*s.%.*s%s", - (int)(cp - file), file, (int)(dp - cp), cp, ".map"); - - return buffer; -} - - -int -map_read (char *file, long pos, struct drop **drops, int noisy) -{ - register int i, md, msgp; - register char *cp; - struct drop d; - register struct drop *mp, *dp; - - if ((md = open (cp = map_name (file), O_RDONLY)) == NOTOK - || map_chk (cp, md, mp = &d, pos, noisy)) { - if (md != NOTOK) - close (md); - return 0; - } - - msgp = mp->d_id; - dp = (struct drop *) calloc ((size_t) (msgp + 1), sizeof(*dp)); - if (dp == NULL) { - close (md); - return 0; - } - - memcpy((char *) dp, (char *) mp, sizeof(*dp)); - - lseek (md, (off_t) sizeof(*mp), SEEK_SET); - if ((i = read (md, (char *) (dp + 1), msgp * sizeof(*dp))) < sizeof(*dp)) { - i = 0; - free ((char *) dp); - } else { -#ifdef NTOHLSWAP - register struct drop *tdp; - int j; - - for (j = 0, tdp = dp; j < i / sizeof(*dp); j++, tdp++) { - tdp->d_id = ntohl(tdp->d_id); - tdp->d_size = ntohl(tdp->d_size); - tdp->d_start = ntohl(tdp->d_start); - tdp->d_stop = ntohl(tdp->d_stop); } -#endif - *drops = dp; - } - - close (md); - - return (i / sizeof(*dp)); -} - - -int -map_write (char *mailbox, int md, int id, long last, off_t start, - off_t stop, long pos, int size, int noisy) -{ - register int i; - int clear, fd, td; - char *file; - register struct drop *dp; - struct drop d1, d2, *rp; - register FILE *fp; - struct stat st; - - if ((fd = map_open (file = map_name (mailbox), md)) == NOTOK) - return NOTOK; - if ((fstat (fd, &st) == OK) && (st.st_size > 0)) - clear = 0; - else - clear = 1; - - if (!clear && map_chk (file, fd, &d1, pos, noisy)) { - unlink (file); - mbx_close (file, fd); - if ((fd = map_open (file, md)) == NOTOK) - return NOTOK; - clear++; - } - - if (clear) { - if ((td = dup (md)) == NOTOK || (fp = fdopen (td, "r")) == NULL) { - if (noisy) - admonish (file, "unable to %s", td != NOTOK ? "fdopen" : "dup"); - if (td != NOTOK) - close (td); - mbx_close (file, fd); - return NOTOK; - } - - switch (i = mbx_read (fp, 0, &rp, noisy)) { - case NOTOK: - fclose (fp); - mbx_close (file, fd); + if (write(to, "\n", 1) != 1) { + fclose(fp); return NOTOK; - - case OK: - fclose (fp); - break; - - default: - d1.d_id = 0; - for (dp = rp; i-- >0; dp++) { - if (dp->d_start == start) - dp->d_id = id; - lseek (fd, (off_t) (++d1.d_id * sizeof(*dp)), SEEK_SET); - if (write (fd, (char *) dp, sizeof(*dp)) != sizeof(*dp)) { - if (noisy) - admonish (file, "write error"); - mbx_close (file, fd); - fclose (fp); - return NOTOK; - } - } - free ((char *) rp); - fclose (fp); - break; } - } - else { - if (last == 0) - last = d1.d_start; - dp = &d2; - dp->d_id = id; - dp->d_size = (long) (size ? size : mbx_size (fd, start, stop)); - dp->d_start = start; - dp->d_stop = stop; - lseek (fd, (off_t) (++d1.d_id * sizeof(*dp)), SEEK_SET); - if (write (fd, (char *) dp, sizeof(*dp)) != sizeof(*dp)) { - if (noisy) - admonish (file, "write error"); - mbx_close (file, fd); - return NOTOK; - } - } - - dp = &d1; - dp->d_size = DRVRSN; - dp->d_start = (long) last; - dp->d_stop = lseek (md, (off_t) 0, SEEK_CUR); - - lseek (fd, (off_t) 0, SEEK_SET); - if (write (fd, (char *) dp, sizeof(*dp)) != sizeof(*dp)) { - if (noisy) - admonish (file, "write error"); - mbx_close (file, fd); - return NOTOK; - } - - mbx_close (file, fd); + fclose(fp); + lseek(from, (off_t) 0, SEEK_END); - return OK; -} - - -static int -map_open (char *file, int md) -{ - mode_t mode; - struct stat st; - - mode = fstat (md, &st) != NOTOK ? (mode_t) (st.st_mode & 0777) : m_gmprot (); - return mbx_open (file, OTHER_FORMAT, st.st_uid, st.st_gid, mode); + return OK; } +/* +** Close and unlock file/maildrop. +*/ int -map_chk (char *file, int fd, struct drop *dp, long pos, int noisy) +mbox_close(char *mailbox, int md) { - long count; - struct drop d, tmpd; - register struct drop *dl; - - if (read (fd, (char *) &tmpd, sizeof(*dp)) != sizeof(*dp)) { -#ifdef notdef - admonish (NULL, "%s: missing or partial index", file); -#endif /* notdef */ - return NOTOK; - } -#ifndef NTOHLSWAP - *dp = tmpd; /* if ntohl(n)=(n), can use struct assign */ -#else - dp->d_id = ntohl(tmpd.d_id); - dp->d_size = ntohl(tmpd.d_size); - dp->d_start = ntohl(tmpd.d_start); - dp->d_stop = ntohl(tmpd.d_stop); -#endif - - if (dp->d_size != DRVRSN) { - if (noisy) - admonish (NULL, "%s: version mismatch (%d != %d)", file, - dp->d_size, DRVRSN); - return NOTOK; - } - - if (dp->d_stop != pos) { - if (noisy && pos != (long) 0) - admonish (NULL, - "%s: pointer mismatch or incomplete index (%ld!=%ld)", - file, dp->d_stop, (long) pos); + if (lkclose(md, mailbox) == 0) + return OK; return NOTOK; - } - - if ((long) ((dp->d_id + 1) * sizeof(*dp)) != (long) lseek (fd, (off_t) 0, SEEK_END)) { - if (noisy) - admonish (NULL, "%s: corrupt index(1)", file); - return NOTOK; - } - - dl = &d; - count = (long) strlen (mmdlm2); - lseek (fd, (off_t) (dp->d_id * sizeof(*dp)), SEEK_SET); - if (read (fd, (char *) dl, sizeof(*dl)) != sizeof(*dl) - || (ntohl(dl->d_stop) != dp->d_stop - && ntohl(dl->d_stop) + count != dp->d_stop)) { - if (noisy) - admonish (NULL, "%s: corrupt index(2)", file); - return NOTOK; - } - - return OK; } diff --git a/uip/flist.c b/uip/flist.c index e3da709..057d5f4 100644 --- a/uip/flist.c +++ b/uip/flist.c @@ -1,80 +1,73 @@ /* - * flist.c -- list nmh folders containing messages - * -- in a given sequence - * - * originally by - * David Nichols, Xerox-PARC, November, 1992 - * - * Copyright (c) 1994 Xerox Corporation. - * Use and copying of this software and preparation of derivative works based - * upon this software are permitted. Any distribution of this software or - * derivative works must comply with all applicable United States export - * control laws. This software is made available AS IS, and Xerox Corporation - * makes no warranty about the software, its performance or its conformity to - * any specification. - */ +** flist.c -- list nmh folders containing messages +** -- in a given sequence +** +** originally by +** David Nichols, Xerox-PARC, November, 1992 +** +** Copyright (c) 1994 Xerox Corporation. +** Use and copying of this software and preparation of derivative works based +** upon this software are permitted. Any distribution of this software or +** derivative works must comply with all applicable United States export +** control laws. This software is made available AS IS, and Xerox Corporation +** makes no warranty about the software, its performance or its conformity to +** any specification. +*/ #include #include -#define FALSE 0 -#define TRUE 1 - /* - * We allocate space to record the names of folders - * (foldersToDo array), this number of elements at a time. - */ +** We allocate space to record the names of folders +** (foldersToDo array), this number of elements at a time. +*/ #define MAXFOLDERS 100 static struct swit switches[] = { -#define SEQSW 0 - { "sequence name", 0 }, -#define ALLSW 1 - { "all", 0 }, -#define NOALLSW 2 - { "noall", 0 }, -#define RECURSE 3 - { "recurse", 0 }, -#define NORECURSE 4 - { "norecurse", 0 }, -#define SHOWZERO 5 - { "showzero", 0 }, -#define NOSHOWZERO 6 - { "noshowzero", 0 }, -#define ALPHASW 7 - { "alpha", 0 }, -#define NOALPHASW 8 - { "noalpha", 0 }, -#define FASTSW 9 - { "fast", 0 }, -#define NOFASTSW 10 - { "nofast", 0 }, -#define TOTALSW 11 - { "total", -5 }, -#define NOTOTALSW 12 - { "nototal", -7 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - { NULL, 0 } +#define SEQSW 0 + { "sequence name", 0 }, +#define ALLSW 1 + { "all", 0 }, +#define NOALLSW 2 + { "noall", 2 }, +#define RECURSE 3 + { "recurse", 0 }, +#define NORECURSE 4 + { "norecurse", 2 }, +#define SHOWZERO 5 + { "showzero", 0 }, +#define NOSHOWZERO 6 + { "noshowzero", 2 }, +#define ALPHASW 7 + { "alpha", 0 }, +#define NOALPHASW 8 + { "noalpha", 2 }, +#define FASTSW 9 + { "fast", 0 }, +#define NOFASTSW 10 + { "nofast", 2 }, +#define VERSIONSW 11 + { "Version", 0 }, +#define HELPSW 12 + { "help", 0 }, + { NULL, 0 } }; struct Folder { - char *name; /* name of folder */ - int priority; - int error; /* error == 1 for unreadable folder */ - int nMsgs; /* number of messages in folder */ - int nSeq[NUMATTRS]; /* number of messages in each sequence */ - int private[NUMATTRS]; /* is given sequence, public or private */ + char *name; /* name of folder */ + int priority; + int error; /* error == 1 for unreadable folder */ + int nMsgs; /* number of messages in folder */ + int nSeq[NUMATTRS]; /* number of messages in each sequence */ + int private[NUMATTRS]; /* is given sequence, public or private */ }; static struct Folder *orders = NULL; static int nOrders = 0; static int nOrdersAlloced = 0; static struct Folder *folders = NULL; -static int nFolders = 0; +static unsigned int nFolders = 0; static int nFoldersAlloced = 0; /* info on folders to search */ @@ -84,27 +77,27 @@ static int maxfolders; /* info on sequences to search for */ static char *sequencesToDo[NUMATTRS]; -static int numsequences; +static unsigned int numsequences; -static int all = FALSE; /* scan all folders in top level? */ -static int alphaOrder = FALSE; /* want alphabetical order only */ -static int recurse = FALSE; /* show nested folders? */ -static int showzero = TRUE; /* show folders even if no messages in seq? */ -static int Total = TRUE; /* display info on number of messages in * - * sequence found, and total num messages */ +static int all = FALSE; /* scan all folders in top level? */ +static int alphaOrder = FALSE; /* want alphabetical order only */ +static int recurse = FALSE; /* show nested folders? */ +static int showzero = TRUE; /* show folders even if no messages in seq? */ +static int fastsw = FALSE; /* display info on number of messages in + * sequence found, and total num messages */ -static char curfolder[BUFSIZ]; /* name of the current folder */ -static char *nmhdir; /* base nmh mail directory */ +static char curfol[BUFSIZ]; /* name of the current folder */ +static char *nmhdir; /* base nmh mail directory */ /* - * Type for a compare function for qsort. This keeps - * the compiler happy. - */ +** Type for a compare function for qsort. This keeps +** the compiler happy. +*/ typedef int (*qsort_comp) (const void *, const void *); /* - * prototypes - */ +** prototypes +*/ int CompareFolders(struct Folder *, struct Folder *); void GetFolderOrder(void); void ScanFolders(void); @@ -121,568 +114,571 @@ static void do_readonly_folders(void); int main(int argc, char **argv) { - char *cp, **argp; - char **arguments; - char buf[BUFSIZ]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex(argv[0], '/'); - - /* read user profile/context */ - context_read(); - - /* - * If program was invoked with name ending - * in `s', then add switch `-all'. - */ - if (argv[0][strlen (argv[0]) - 1] == 's') - all = TRUE; - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* allocate the initial space to record the folder names */ - numfolders = 0; - maxfolders = MAXFOLDERS; - foldersToDo = (char **) mh_xmalloc ((size_t) (maxfolders * sizeof(*foldersToDo))); - - /* no sequences yet */ - numsequences = 0; - - /* parse arguments */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch(++cp, switches)) { - case AMBIGSW: - ambigsw(cp, switches); - done(1); - case UNKWNSW: - adios(NULL, "-%s unknown", cp); - - case HELPSW: - snprintf(buf, sizeof(buf), "%s [+folder1 [+folder2 ...]][switches]", - invo_name); - print_help(buf, switches, 1); - done(1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case SEQSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - - /* check if too many sequences specified */ - if (numsequences >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) specified", NUMATTRS); - sequencesToDo[numsequences++] = cp; - break; - - case ALLSW: + char *cp, **argp; + char **arguments; + char buf[BUFSIZ]; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + /* + ** If program was invoked with name ending + ** in `s', then add switch `-all'. + */ + if (argv[0][strlen(argv[0]) - 1] == 's') all = TRUE; - break; - case NOALLSW: - all = FALSE; - break; - - case SHOWZERO: - showzero = TRUE; - break; - case NOSHOWZERO: - showzero = FALSE; - break; - - case ALPHASW: - alphaOrder = TRUE; - break; - case NOALPHASW: - alphaOrder = FALSE; - break; - - case NOFASTSW: - case TOTALSW: - Total = TRUE; - break; - - case FASTSW: - case NOTOTALSW: - Total = FALSE; - break; - - case RECURSE: - recurse = TRUE; - break; - case NORECURSE: - recurse = FALSE; - break; - } - } else { - /* - * Check if we need to allocate more space - * for folder names. - */ - if (numfolders >= maxfolders) { - maxfolders += MAXFOLDERS; - foldersToDo = (char **) mh_xrealloc (foldersToDo, - (size_t) (maxfolders * sizeof(*foldersToDo))); - } - if (*cp == '+' || *cp == '@') { - foldersToDo[numfolders++] = - pluspath (cp); - } else - foldersToDo[numfolders++] = cp; + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* allocate the initial space to record the folder names */ + numfolders = 0; + maxfolders = MAXFOLDERS; + foldersToDo = (char **) mh_xmalloc((size_t) + (maxfolders * sizeof(*foldersToDo))); + + /* no sequences yet */ + numsequences = 0; + + /* parse arguments */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder1 [+folder2 ...]][switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case SEQSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + + /* check if too many sequences specified */ + if (numsequences >= NUMATTRS) + adios(NULL, "too many sequences (more than %d) specified", NUMATTRS); + sequencesToDo[numsequences++] = cp; + break; + + case ALLSW: + all = TRUE; + break; + case NOALLSW: + all = FALSE; + break; + + case SHOWZERO: + showzero = TRUE; + break; + case NOSHOWZERO: + showzero = FALSE; + break; + + case ALPHASW: + alphaOrder = TRUE; + break; + case NOALPHASW: + alphaOrder = FALSE; + break; + + case FASTSW: + fastsw = TRUE; + break; + case NOFASTSW: + fastsw = FALSE; + break; + + case RECURSE: + recurse = TRUE; + break; + case NORECURSE: + recurse = FALSE; + break; + } + } else { + /* + ** Check if we need to allocate more space + ** for folder names. + */ + if (numfolders >= maxfolders) { + maxfolders += MAXFOLDERS; + foldersToDo = (char **) mh_xrealloc(foldersToDo, (size_t) (maxfolders * sizeof(*foldersToDo))); + } + if (*cp == '+' || *cp == '@') { + foldersToDo[numfolders++] = getcpy(expandfol(cp)); + } else + foldersToDo[numfolders++] = cp; + } } - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* get current folder */ - strncpy (curfolder, getfolder(1), sizeof(curfolder)); - - /* get nmh base directory */ - nmhdir = m_maildir (""); - - /* - * If we didn't specify any sequences, we search - * for the "Unseen-Sequence" profile entry and use - * all the sequences defined there. We check to - * make sure that the Unseen-Sequence entry doesn't - * contain more than NUMATTRS sequences. - */ - if (numsequences == 0) { - if ((cp = context_find(usequence)) && *cp) { - char **ap, *dp; - - dp = getcpy(cp); - ap = brkstring (dp, " ", "\n"); - for (; ap && *ap; ap++) { - if (numsequences >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) in %s profile entry", - NUMATTRS, usequence); - else - sequencesToDo[numsequences++] = *ap; - } - } else { - adios (NULL, "no sequence specified or %s profile entry found", usequence); + + /* get current folder */ + strncpy(curfol, getcurfol(), sizeof(curfol)); + + /* get nmh base directory */ + nmhdir = toabsdir("+"); + + /* + ** If no sequences specified, we use the `unseen' sequence(s) + ** We check to make sure that the Unseen-Sequence entry doesn't + ** contain too many sequences. + */ + if (numsequences == 0) { + char **ap, *dp; + + if ((cp = context_find(usequence))) { + if (!*cp) { + adios(NULL, "profile entry %s set, but empty, and no sequence given", usequence); + } + } else { + cp = seq_unseen; /* use default */ + } + dp = getcpy(cp); + ap = brkstring(dp, " ", "\n"); + for (; ap && *ap; ap++) { + if (numsequences >= NUMATTRS) { + adios(NULL, "too many sequences (more than %d) in %s profile entry", NUMATTRS, usequence); + } else { + sequencesToDo[numsequences++] = *ap; + } + } } - } - - GetFolderOrder(); - ScanFolders(); - qsort(folders, nFolders, sizeof(struct Folder), (qsort_comp) CompareFolders); - PrintFolders(); - done (0); - return 1; + + GetFolderOrder(); + ScanFolders(); + qsort(folders, nFolders, sizeof(struct Folder), + (qsort_comp) CompareFolders); + PrintFolders(); + done(0); + return 1; } /* - * Read the Flist-Order profile entry to determine - * how to sort folders for output. - */ +** Read the Flist-Order profile entry to determine +** how to sort folders for output. +*/ void GetFolderOrder(void) { - unsigned char *p, *s; - int priority = 1; - struct Folder *o; - - if (!(p = context_find("Flist-Order"))) - return; - for (;;) { - while (isspace(*p)) - ++p; - s = p; - while (*p && !isspace(*p)) - ++p; - if (p != s) { - /* Found one. */ - AllocFolders(&orders, &nOrdersAlloced, nOrders + 1); - o = &orders[nOrders++]; - o->priority = priority++; - o->name = (char *) mh_xmalloc(p - s + 1); - strncpy(o->name, s, p - s); - o->name[p - s] = 0; - } else - break; - } + unsigned char *p, *s; + int priority = 1; + struct Folder *o; + + if (!(p = context_find("Flist-Order"))) + return; + for (;;) { + while (isspace(*p)) + ++p; + s = p; + while (*p && !isspace(*p)) + ++p; + if (p != s) { + /* Found one. */ + AllocFolders(&orders, &nOrdersAlloced, nOrders + 1); + o = &orders[nOrders++]; + o->priority = priority++; + o->name = (char *) mh_xmalloc(p - s + 1); + strncpy(o->name, s, p - s); + o->name[p - s] = 0; + } else + break; + } } /* - * Scan all the necessary folders - */ +** Scan all the necessary folders +*/ void ScanFolders(void) { - int i; - - /* - * change directory to base of nmh directory - */ - if (chdir (nmhdir) == NOTOK) - adios (nmhdir, "unable to change directory to"); - - if (numfolders > 0) { - /* Update context */ - strncpy (curfolder, foldersToDo[numfolders - 1], sizeof(curfolder)); - context_replace (pfolder, curfolder);/* update current folder */ - context_save (); /* save the context file */ + int i; /* - * Scan each given folder. If -all is given, - * then also scan the 1st level subfolders under - * each given folder. + * change directory to base of nmh directory */ - for (i = 0; i < numfolders; ++i) - BuildFolderList(foldersToDo[i], all ? 1 : 0); - } else { - if (all) { - /* - * Do the readonly folders - */ - do_readonly_folders(); - - /* - * Now scan the entire nmh directory for folders - */ - BuildFolderList(".", 0); + if (chdir(nmhdir) == NOTOK) + adios(nmhdir, "unable to change directory to"); + + if (numfolders > 0) { + /* Update context */ + strncpy(curfol, foldersToDo[numfolders - 1], sizeof(curfol)); + context_replace(curfolder, curfol); /* update current folder */ + context_save(); /* save the context file */ + + /* + ** Scan each given folder. If -all is given, + ** then also scan the 1st level subfolders under + ** each given folder. + */ + for (i = 0; i < numfolders; ++i) + BuildFolderList(foldersToDo[i], all ? 1 : 0); } else { - /* - * Else scan current folder - */ - BuildFolderList(curfolder, 0); + if (all) { + /* Do the readonly folders */ + do_readonly_folders(); + + /* Now scan the entire nmh directory for folders */ + BuildFolderList(".", 0); + } else { + /* Else scan current folder */ + BuildFolderList(curfol, 0); + } } - } } /* - * Initial building of folder list for - * the top of our search tree. - */ +** Initial building of folder list for +** the top of our search tree. +*/ void BuildFolderList(char *dirName, int searchdepth) { - struct stat st; - - /* Make sure we have a directory */ - if ((stat(dirName, &st) == -1) || !S_ISDIR(st.st_mode)) - return; - - /* - * If base directory, don't add it to the - * folder list. We just recurse into it. - */ - if (!strcmp (dirName, ".")) { - BuildFolderListRecurse (".", &st, 0); - return; - } - - /* - * Add this folder to the list. - * If recursing and directory has subfolders, - * then build folder list for subfolders. - */ - if (AddFolder(dirName, showzero) && (recurse || searchdepth) && st.st_nlink > 2) - BuildFolderListRecurse(dirName, &st, searchdepth - 1); + struct stat st; + + /* Make sure we have a directory */ + if ((stat(dirName, &st) == -1) || !S_ISDIR(st.st_mode)) + return; + + /* + ** If base directory, don't add it to the + ** folder list. We just recurse into it. + */ + if (strcmp(dirName, ".")==0) { + BuildFolderListRecurse(".", &st, 0); + return; + } + + /* + ** Add this folder to the list. + ** If recursing and directory has subfolders, + ** then build folder list for subfolders. + */ + if (AddFolder(dirName, showzero) && (recurse || searchdepth) && + st.st_nlink > 2) + BuildFolderListRecurse(dirName, &st, searchdepth - 1); } /* - * Recursive building of folder list - */ +** Recursive building of folder list +*/ void BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) { - char *base, name[PATH_MAX]; - unsigned char *n; - int nlinks; - DIR *dir; - struct dirent *dp; - struct stat st; - - /* - * Keep track of number of directories we've seen so we can - * stop stat'ing entries in this directory once we've seen - * them all. This optimization will fail if you have extra - * directories beginning with ".", since we don't bother to - * stat them. But that shouldn't generally be a problem. - */ - nlinks = s->st_nlink; - - if (!(dir = opendir(dirName))) - adios(dirName, "can't open directory"); - - /* - * A hack so that we don't see a - * leading "./" in folder names. - */ - base = strcmp (dirName, ".") ? dirName : dirName + 1; - - while (nlinks && (dp = readdir(dir))) { - if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) { - nlinks--; - continue; - } - if (dp->d_name[0] == '.') - continue; - /* Check to see if the name of the file is a number - * if it is, we assume it's a mail file and skip it - */ - for (n = dp->d_name; *n && isdigit(*n); n++); - if (!*n) - continue; - strncpy (name, base, sizeof(name) - 2); - if (*base) - strcat(name, "/"); - strncat(name, dp->d_name, sizeof(name) - strlen(name) - 1); - if ((stat(name, &st) != -1) && S_ISDIR(st.st_mode)) { - /* - * Check if this was really a symbolic link pointing - * to a directory. If not, then decrement link count. - */ - if (lstat (name, &st) == -1) - nlinks--; - /* Add this folder to the list */ - if (AddFolder(name, showzero) && - (recurse || searchdepth) && st.st_nlink > 2) - BuildFolderListRecurse(name, &st, searchdepth - 1); + char *base, name[PATH_MAX]; + unsigned char *n; + int nlinks; + DIR *dir; + struct dirent *dp; + struct stat st; + + /* + ** Keep track of number of directories we've seen so we can + ** stop stat'ing entries in this directory once we've seen + ** them all. This optimization will fail if you have extra + ** directories beginning with ".", since we don't bother to + ** stat them. But that shouldn't generally be a problem. + */ + nlinks = s->st_nlink; + + if (!(dir = opendir(dirName))) + adios(dirName, "can't open directory"); + + /* + ** A hack so that we don't see a + ** leading "./" in folder names. + */ + base = (strcmp(dirName, ".")==0) ? dirName + 1 : dirName; + + while (nlinks && (dp = readdir(dir))) { + if (strcmp(dp->d_name, ".")==0 || + strcmp(dp->d_name, "..")==0) { + nlinks--; + continue; + } + if (dp->d_name[0] == '.') + continue; + /* Check to see if the name of the file is a number + ** if it is, we assume it's a mail file and skip it + */ + for (n = dp->d_name; *n && isdigit(*n); n++); + if (!*n) + continue; + strncpy(name, base, sizeof(name) - 2); + if (*base) + strcat(name, "/"); + strncat(name, dp->d_name, sizeof(name) - strlen(name) - 1); + if ((stat(name, &st) != -1) && S_ISDIR(st.st_mode)) { + /* + ** Check if this was really a symbolic link pointing + ** to a directory. If not, then decrement link count. + */ + if (lstat(name, &st) == -1) + nlinks--; + /* Add this folder to the list */ + if (AddFolder(name, showzero) && + (recurse || searchdepth) && + st.st_nlink > 2) + BuildFolderListRecurse(name, &st, + searchdepth - 1); + } } - } - closedir(dir); + closedir(dir); } /* - * Add this folder to our list, counting the total number of - * messages and the number of messages in each sequence. - */ +** Add this folder to our list, counting the total number of +** messages and the number of messages in each sequence. +*/ int AddFolder(char *name, int force) { - int i, msgnum, nonzero; - int seqnum[NUMATTRS], nSeq[NUMATTRS]; - struct Folder *f; - struct msgs *mp; - - /* Read folder and create message structure */ - if (!(mp = folder_read (name))) { - /* Oops, error occurred. Record it and continue. */ - AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); - f = &folders[nFolders++]; - f->name = getcpy(name); - f->error = 1; - f->priority = AssignPriority(f->name); - return 0; - } - - for (i = 0; i < numsequences; i++) { - /* Convert sequences to their sequence numbers */ - if (sequencesToDo[i]) - seqnum[i] = seq_getnum(mp, sequencesToDo[i]); - else - seqnum[i] = -1; - - /* Now count messages in this sequence */ - nSeq[i] = 0; - if (mp->nummsg > 0 && seqnum[i] != -1) { - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { - if (in_sequence(mp, seqnum[i], msgnum)) - nSeq[i]++; - } + unsigned int i; + int msgnum, nonzero; + int seqnum[NUMATTRS], nSeq[NUMATTRS]; + struct Folder *f; + struct msgs *mp; + + /* Read folder and create message structure */ + if (!(mp = folder_read(name))) { + /* Oops, error occurred. Record it and continue. */ + AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); + f = &folders[nFolders++]; + f->name = getcpy(name); + f->error = 1; + f->priority = AssignPriority(f->name); + return 0; } - } - - /* Check if any of the sequence checks were nonzero */ - nonzero = 0; - for (i = 0; i < numsequences; i++) { - if (nSeq[i] > 0) { - nonzero = 1; - break; + + for (i = 0; i < numsequences; i++) { + /* Convert sequences to their sequence numbers */ + if (sequencesToDo[i]) + seqnum[i] = seq_getnum(mp, sequencesToDo[i]); + else + seqnum[i] = -1; + + /* Now count messages in this sequence */ + nSeq[i] = 0; + if (mp->nummsg > 0 && seqnum[i] != -1) { + for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; + msgnum++) { + if (in_sequence(mp, seqnum[i], msgnum)) + nSeq[i]++; + } + } } - } - - if (nonzero || force) { - /* save general folder information */ - AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); - f = &folders[nFolders++]; - f->name = getcpy(name); - f->nMsgs = mp->nummsg; - f->error = 0; - f->priority = AssignPriority(f->name); - - /* record the sequence information */ + + /* Check if any of the sequence checks were nonzero */ + nonzero = 0; for (i = 0; i < numsequences; i++) { - f->nSeq[i] = nSeq[i]; - f->private[i] = (seqnum[i] != -1) ? is_seq_private(mp, seqnum[i]) : 0; + if (nSeq[i] > 0) { + nonzero = 1; + break; + } + } + + if (nonzero || force) { + /* save general folder information */ + AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); + f = &folders[nFolders++]; + f->name = getcpy(name); + f->nMsgs = mp->nummsg; + f->error = 0; + f->priority = AssignPriority(f->name); + + /* record the sequence information */ + for (i = 0; i < numsequences; i++) { + f->nSeq[i] = nSeq[i]; + f->private[i] = (seqnum[i] != -1) ? + is_seq_private(mp, seqnum[i]) : 0; + } } - } - folder_free (mp); /* free folder/message structure */ - return 1; + folder_free(mp); /* free folder/message structure */ + return 1; } /* - * Print the folder/sequence information - */ +** Print the folder/sequence information +*/ void PrintFolders(void) { - char tmpname[BUFSIZ]; - int i, j, len, has_private = 0; - int maxfolderlen = 0, maxseqlen = 0; - int maxnum = 0, maxseq = 0; - - if (!Total) { - for (i = 0; i < nFolders; i++) - printf("%s\n", folders[i].name); - return; - } - - /* - * Find the width we need for various fields - */ - for (i = 0; i < nFolders; ++i) { - /* find the length of longest folder name */ - len = strlen(folders[i].name); - if (len > maxfolderlen) - maxfolderlen = len; - - /* If folder had error, skip the rest */ - if (folders[i].error) - continue; - - /* find the maximum total messages */ - if (folders[i].nMsgs > maxnum) - maxnum = folders[i].nMsgs; - - for (j = 0; j < numsequences; j++) { - /* find maximum width of sequence name */ - len = strlen (sequencesToDo[j]); - if ((folders[i].nSeq[j] > 0 || showzero) && (len > maxseqlen)) - maxseqlen = len; - - /* find the maximum number of messages in sequence */ - if (folders[i].nSeq[j] > maxseq) - maxseq = folders[i].nSeq[j]; - - /* check if this sequence is private in any of the folders */ - if (folders[i].private[j]) - has_private = 1; + char tmpname[BUFSIZ]; + unsigned int i, j, len, has_private = 0; + unsigned int maxfolderlen = 0, maxseqlen = 0; + int maxnum = 0, maxseq = 0; + + if (fastsw) { + for (i = 0; i < nFolders; i++) + printf("%s\n", folders[i].name); + return; } - } - - /* Now print all the folder/sequence information */ - for (i = 0; i < nFolders; i++) { - for (j = 0; j < numsequences; j++) { - if (folders[i].nSeq[j] > 0 || showzero) { - /* Add `+' to end of name of current folder */ - if (strcmp(curfolder, folders[i].name)) - snprintf(tmpname, sizeof(tmpname), "%s", folders[i].name); - else - snprintf(tmpname, sizeof(tmpname), "%s+", folders[i].name); - if (folders[i].error) { - printf("%-*s is unreadable\n", maxfolderlen+1, tmpname); - continue; + /* + ** Find the width we need for various fields + */ + for (i = 0; i < nFolders; ++i) { + /* find the length of longest folder name */ + len = strlen(folders[i].name); + if (len > maxfolderlen) + maxfolderlen = len; + + /* If folder had error, skip the rest */ + if (folders[i].error) + continue; + + /* find the maximum total messages */ + if (folders[i].nMsgs > maxnum) + maxnum = folders[i].nMsgs; + + for (j = 0; j < numsequences; j++) { + /* find maximum width of sequence name */ + len = strlen(sequencesToDo[j]); + if ((folders[i].nSeq[j] > 0 || showzero) && + (len > maxseqlen)) + maxseqlen = len; + + /* find the maximum number of messages in sequence */ + if (folders[i].nSeq[j] > maxseq) + maxseq = folders[i].nSeq[j]; + + /* + ** check if this sequence is private in any of + ** the folders + */ + if (folders[i].private[j]) + has_private = 1; } + } - printf("%-*s has %*d in sequence %-*s%s; out of %*d\n", - maxfolderlen+1, tmpname, - num_digits(maxseq), folders[i].nSeq[j], - maxseqlen, sequencesToDo[j], - !has_private ? "" : folders[i].private[j] ? " (private)" : " ", - num_digits(maxnum), folders[i].nMsgs); - } + /* Now print all the folder/sequence information */ + for (i = 0; i < nFolders; i++) { + for (j = 0; j < numsequences; j++) { + if (folders[i].nSeq[j] > 0 || showzero) { + /* Add `+' to end of name of current folder */ + if (strcmp(curfol, folders[i].name)!=0) + snprintf(tmpname, sizeof(tmpname), + "%s", folders[i].name); + else + snprintf(tmpname, sizeof(tmpname), + "%s+", + folders[i].name); + + if (folders[i].error) { + printf("%-*s is unreadable\n", + maxfolderlen+1, + tmpname); + continue; + } + + printf("%-*s has %*d in sequence %-*s%s; out of %*d\n", maxfolderlen+1, tmpname, num_digits(maxseq), folders[i].nSeq[j], maxseqlen, sequencesToDo[j], !has_private ? "" : folders[i].private[j] ? " (private)" : " ", num_digits(maxnum), folders[i].nMsgs); + } + } } - } } /* - * Put them in priority order. - */ +** Put them in priority order. +*/ int CompareFolders(struct Folder *f1, struct Folder *f2) { - if (!alphaOrder && f1->priority != f2->priority) - return f1->priority - f2->priority; - else - return strcmp(f1->name, f2->name); + if (!alphaOrder && f1->priority != f2->priority) + return f1->priority - f2->priority; + else + return strcmp(f1->name, f2->name); } /* - * Make sure we have at least n folders allocated. - */ +** Make sure we have at least n folders allocated. +*/ void AllocFolders(struct Folder **f, int *nfa, int n) { - if (n <= *nfa) - return; - if (*f == NULL) { - *nfa = 10; - *f = (struct Folder *) mh_xmalloc (*nfa * (sizeof(struct Folder))); - } else { - *nfa *= 2; - *f = (struct Folder *) mh_xrealloc (*f, *nfa * (sizeof(struct Folder))); - } + if (n <= *nfa) + return; + if (*f == NULL) { + *nfa = 10; + *f = (struct Folder *) mh_xmalloc( + *nfa * (sizeof(struct Folder))); + } else { + *nfa *= 2; + *f = (struct Folder *) mh_xrealloc( + *f, *nfa * (sizeof(struct Folder))); + } } /* - * Return the priority for a name. The highest comes from an exact match. - * After that, the longest match (then first) assigns the priority. - */ +** Return the priority for a name. The highest comes from an exact match. +** After that, the longest match (then first) assigns the priority. +*/ int AssignPriority(char *name) { - int i, ol, nl; - int best = nOrders; - int bestLen = 0; - struct Folder *o; - - nl = strlen(name); - for (i = 0; i < nOrders; ++i) { - o = &orders[i]; - if (!strcmp(name, o->name)) - return o->priority; - ol = strlen(o->name); - if (nl < ol - 1) - continue; - if (ol < bestLen) - continue; - if (o->name[0] == '*' && !strcmp(o->name + 1, name + (nl - ol + 1))) { - best = o->priority; - bestLen = ol; - } else if (o->name[ol - 1] == '*' && strncmp(o->name, name, ol - 1) == 0) { - best = o->priority; - bestLen = ol; + int i, ol, nl; + int best = nOrders; + int bestLen = 0; + struct Folder *o; + + nl = strlen(name); + for (i = 0; i < nOrders; ++i) { + o = &orders[i]; + if (strcmp(name, o->name)==0) + return o->priority; + ol = strlen(o->name); + if (nl < ol - 1) + continue; + if (ol < bestLen) + continue; + if (o->name[0] == '*' && + strcmp(o->name + 1, name + (nl - ol + 1))==0) { + best = o->priority; + bestLen = ol; + } else if (o->name[ol - 1] == '*' && + strncmp(o->name, name, ol - 1) == 0) { + best = o->priority; + bestLen = ol; + } } - } - return best; + return best; } /* - * Do the read only folders - */ +** Do the read only folders +*/ static void -do_readonly_folders (void) +do_readonly_folders(void) { - int atrlen; - char atrcur[BUFSIZ]; - register struct node *np; - - snprintf (atrcur, sizeof(atrcur), "atr-%s-", current); - atrlen = strlen (atrcur); - - for (np = m_defs; np; np = np->n_next) - if (ssequal (atrcur, np->n_name) - && !ssequal (nmhdir, np->n_name + atrlen)) - BuildFolderList (np->n_name + atrlen, 0); + int atrlen; + char atrcur[BUFSIZ]; + register struct node *np; + + snprintf(atrcur, sizeof(atrcur), "atr-%s-", seq_cur); + atrlen = strlen(atrcur); + + for (np = m_defs; np; np = np->n_next) + if (strncmp(np->n_name, atrcur, atrlen)==0 + && strncmp(np->n_name+atrlen, nmhdir, strlen(nmhdir))!=0) + /* Why do we exclude absolute path names? --meillo */ + BuildFolderList(np->n_name + atrlen, 0); } diff --git a/uip/fmtdump.c b/uip/fmtdump.c index fff4502..a0e6e14 100644 --- a/uip/fmtdump.c +++ b/uip/fmtdump.c @@ -1,11 +1,10 @@ - /* - * fmtdump.c -- compile format file and dump out instructions - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmtdump.c -- compile format file and dump out instructions +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -13,15 +12,13 @@ #include static struct swit switches[] = { -#define FORMSW 0 - { "form formatfile", 0 }, -#define FMTSW 1 - { "format string", 5 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, 0 } +#define FORMSW 0 + { "form formatfile", 0 }, +#define VERSIONSW 1 + { "Version", 0 }, +#define HELPSW 2 + { "help", 0 }, + { NULL, 0 } }; /* for assignlabel */ @@ -29,9 +26,9 @@ static struct format *lvec[128]; static int lused = 0; /* - * static prototypes - */ -static void fmt_dump (struct format *); +** static prototypes +*/ +static void fmt_dump(struct format *); static void dumpone(struct format *); static int findlabel(struct format *); static void assignlabel(struct format *); @@ -43,73 +40,66 @@ static void litputc(char); int -main (int argc, char **argv) +main(int argc, char **argv) { - int ncomps; - char *cp, *form = NULL, *format = NULL; - char buf[BUFSIZ], *nfs, **argp, **arguments; - struct format *fmt; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - } + char *cp, *form = NULL; + char buf[BUFSIZ], *fmtstr, **argp, **arguments; + struct format *fmt; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches]", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + } + } + if (form) + adios(NULL, "only one form at a time!"); + else + form = cp; } - if (form) - adios (NULL, "only one form at a time!"); - else - form = cp; - } - - /* - * Get new format string. Must be before chdir(). - */ - nfs = new_fs (form, format, FORMAT); - ncomps = fmt_compile(nfs, &fmt); - - fmt_dump(fmt); - done(0); - return 1; + + /* + ** Get new format string. Must be before chdir(). + */ + fmtstr = new_fs(form, FORMAT); + fmt_compile(fmtstr, &fmt); + + fmt_dump(fmt); + done(0); + return 1; } static void -fmt_dump (struct format *fmth) +fmt_dump(struct format *fmth) { int i; register struct format *fmt, *addr; @@ -117,14 +107,10 @@ fmt_dump (struct format *fmth) /* Assign labels */ for (fmt = fmth; fmt; ++fmt) { i = fmt->f_type; - if (i == FT_IF_S || - i == FT_IF_S_NULL || - i == FT_IF_V_EQ || - i == FT_IF_V_NE || - i == FT_IF_V_GT || - i == FT_IF_MATCH || - i == FT_IF_AMATCH || - i == FT_GOTO) { + if (i == FT_IF_S || i == FT_IF_S_NULL || i == FT_IF_V_EQ || + i == FT_IF_V_NE || i == FT_IF_V_GT || + i == FT_IF_MATCH || i == FT_IF_AMATCH || + i == FT_GOTO) { addr = fmt + fmt->f_skip; if (findlabel(addr) < 0) assignlabel(addr); @@ -163,7 +149,8 @@ dumpone(struct format *fmt) if (fmt->f_comp->c_type) printf(", c_type %s", c_typestr(fmt->f_comp->c_type)); if (fmt->f_comp->c_flags) - printf(", c_flags %s", c_flagsstr(fmt->f_comp->c_flags)); + printf(", c_flags %s", + c_flagsstr(fmt->f_comp->c_flags)); break; case FT_LV_SEC: @@ -195,7 +182,8 @@ dumpone(struct format *fmt) if (fmt->f_comp->c_type) printf(", c_type %s", c_typestr(fmt->f_comp->c_type)); if (fmt->f_comp->c_flags) - printf(", c_flags %s", c_flagsstr(fmt->f_comp->c_flags)); + printf(", c_flags %s", + c_flagsstr(fmt->f_comp->c_flags)); break; case FT_LS_ADDR: @@ -217,7 +205,8 @@ dumpone(struct format *fmt) if (fmt->f_comp->c_type) printf(", c_type %s", c_typestr(fmt->f_comp->c_type)); if (fmt->f_comp->c_flags) - printf(", c_flags %s", c_flagsstr(fmt->f_comp->c_flags)); + printf(", c_flags %s", + c_flagsstr(fmt->f_comp->c_flags)); break; case FT_COMPF: @@ -228,7 +217,8 @@ dumpone(struct format *fmt) if (fmt->f_comp->c_type) printf(", c_type %s", c_typestr(fmt->f_comp->c_type)); if (fmt->f_comp->c_flags) - printf(", c_flags %s", c_flagsstr(fmt->f_comp->c_flags)); + printf(", c_flags %s", + c_flagsstr(fmt->f_comp->c_flags)); break; case FT_STRF: @@ -345,7 +335,7 @@ f_typestr(int t) case FT_COMPF: return("COMPF"); case FT_LIT: return("LIT"); case FT_LITF: return("LITF"); -#ifdef FT_LIT_FORCE +#ifdef FT_LIT_FORCE case FT_LIT_FORCE: return("LIT_FORCE"); #endif case FT_CHAR: return("CHAR"); @@ -410,11 +400,8 @@ f_typestr(int t) case FT_PARSEADDR: return("PARSEADDR"); case FT_FORMATADDR: return("FORMATADDR"); case FT_MYMBOX: return("MYMBOX"); -#ifdef FT_ADDTOSEQ - case FT_ADDTOSEQ: return("ADDTOSEQ"); -#endif case FT_SAVESTR: return("SAVESTR"); -#ifdef FT_PAUSE +#ifdef FT_PAUSE case FT_PAUSE: return ("PAUSE"); #endif case FT_DONE: return("DONE"); @@ -441,9 +428,9 @@ f_typestr(int t) } #define FNORD(v, s) if (t & (v)) { \ - if (i++ > 0) \ - strcat(buf, "|"); \ - strcat(buf, s); } + if (i++ > 0) \ + strcat(buf, "|"); \ + strcat(buf, s); } static char * c_typestr(int t) @@ -519,7 +506,8 @@ litputc(char c) putc('t', stdout); } else { putc('^', stdout); - putc(c ^ 0x40, stdout); /* DEL to ?, others to alpha */ + putc(c ^ 0x40, stdout); + /* DEL to ?, others to alpha */ } } else putc(c, stdout); diff --git a/uip/folder.c b/uip/folder.c index 3e7c85d..8638151 100644 --- a/uip/folder.c +++ b/uip/folder.c @@ -1,13 +1,12 @@ - /* - * folder(s).c -- set/list the current message and/or folder - * -- push/pop a folder onto/from the folder stack - * -- list the folder stack - * - * This code is Copyright (c) 2002, 2008, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** folder(s).c -- set/list the current message and/or folder +** -- push/pop a folder onto/from the folder stack +** -- list the folder stack +** +** This code is Copyright (c) 2002, 2008, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -15,641 +14,719 @@ #include static struct swit switches[] = { -#define ALLSW 0 - { "all", 0 }, -#define NALLSW 1 - { "noall", 0 }, -#define CREATSW 2 - { "create", 0 }, -#define NCREATSW 3 - { "nocreate", 0 }, -#define FASTSW 4 - { "fast", 0 }, -#define NFASTSW 5 - { "nofast", 0 }, -#define HDRSW 6 - { "header", 0 }, -#define NHDRSW 7 - { "noheader", 0 }, -#define PACKSW 8 - { "pack", 0 }, -#define NPACKSW 9 - { "nopack", 0 }, -#define VERBSW 10 - { "verbose", 0 }, -#define NVERBSW 11 - { "noverbose", 0 }, -#define RECURSW 12 - { "recurse", 0 }, -#define NRECRSW 13 - { "norecurse", 0 }, -#define TOTALSW 14 - { "total", 0 }, -#define NTOTLSW 15 - { "nototal", 0 }, -#define LISTSW 16 - { "list", 0 }, -#define NLISTSW 17 - { "nolist", 0 }, -#define PRNTSW 18 - { "print", 0 }, -#define NPRNTSW 19 - { "noprint", -4 }, -#define PUSHSW 20 - { "push", 0 }, -#define POPSW 21 - { "pop", 0 }, -#define VERSIONSW 22 - { "version", 0 }, -#define HELPSW 23 - { "help", 0 }, - { NULL, 0 } +#define ALLSW 0 + { "all", 0 }, +#define NALLSW 1 + { "noall", 2 }, +#define CREATSW 2 + { "create", 0 }, +#define NCREATSW 3 + { "nocreate", 2 }, +#define FASTSW 4 + { "fast", 0 }, +#define NFASTSW 5 + { "nofast", 2 }, +#define PACKSW 6 + { "pack", 0 }, +#define NPACKSW 7 + { "nopack", 2 }, +#define VERBSW 8 + { "verbose", 0 }, +#define NVERBSW 9 + { "noverbose", 2 }, +#define RECURSW 10 + { "recurse", 0 }, +#define NRECRSW 11 + { "norecurse", 2 }, +#define TOTALSW 12 + { "total", 0 }, +#define NTOTLSW 13 + { "nototal", 2 }, +#define LISTSW 14 + { "list", 0 }, +#define NLISTSW 15 + { "nolist", 2 }, +#define PRNTSW 16 + { "print", 0 }, +#define NPRNTSW 17 + { "noprint", -4 }, +#define PUSHSW 18 + { "push", 0 }, +#define POPSW 19 + { "pop", 0 }, +#define VERSIONSW 20 + { "Version", 0 }, +#define HELPSW 21 + { "help", 0 }, + { NULL, 0 } }; -static int fshort = 0; /* output only folder names */ -static int fcreat = 0; /* should we ask to create new folders? */ -static int fpack = 0; /* are we packing the folder? */ -static int fverb = 0; /* print actions taken while packing folder */ -static int fheader = 0; /* should we output a header? */ -static int frecurse = 0; /* recurse through subfolders */ -static int ftotal = 0; /* should we output the totals? */ -static int all = 0; /* should we output all folders */ +static int fshort = 0; /* output only folder names */ +static int fcreat = 0; /* should we ask to create new folders? */ +static int fpack = 0; /* are we packing the folder? */ +static int fverb = 0; /* print actions taken while packing folder */ +static int frecurse = 0; /* recurse through subfolders */ +static int ftotal = 0; /* should we output the totals? */ +static int all = 0; /* should we output all folders */ -static int total_folders = 0; /* total number of folders */ +static int total_folders = 0; /* total number of folders */ static char *nmhdir; static char *stack = "Folder-Stack"; static char folder[BUFSIZ]; /* - * Structure to hold information about - * folders as we scan them. - */ +** Structure to hold information about +** folders as we scan them. +*/ struct FolderInfo { - char *name; - int nummsg; - int curmsg; - int lowmsg; - int hghmsg; - int others; /* others == 1 if other files in folder */ - int error; /* error == 1 for unreadable folder */ + char *name; + int nummsg; + int curmsg; + int lowmsg; + int hghmsg; + int others; /* others == 1 if other files in folder */ + int error; /* error == 1 for unreadable folder */ }; /* - * Dynamically allocated space to hold - * all the folder information. - */ +** Dynamically allocated space to hold +** all the folder information. +*/ static struct FolderInfo *fi; static int maxFolderInfo; /* - * static prototypes - */ -static int get_folder_info (char *, char *); +** static prototypes +*/ +static int get_folder_info(char *, char *); static crawl_callback_t get_folder_info_callback; -static void print_folders (void); -static int sfold (struct msgs *, char *); -static void readonly_folders (void); +static void print_folders(void); +static int sfold(struct msgs *, char *); +static void readonly_folders(void); +static int folder_pack(struct msgs **, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int printsw = 0, listsw = 0; - int pushsw = 0, popsw = 0; - char *cp, *dp, *msg = NULL, *argfolder = NULL; - char **ap, **argp, buf[BUFSIZ], **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - /* - * If program was invoked with name ending - * in `s', then add switch `-all'. - */ - if (argv[0][strlen (argv[0]) - 1] == 's') - all = 1; - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ALLSW: - all = 1; - continue; - - case NALLSW: - all = 0; - continue; - - case CREATSW: - fcreat = 1; - continue; - case NCREATSW: - fcreat = -1; - continue; - - case FASTSW: - fshort++; - continue; - case NFASTSW: - fshort = 0; - continue; - - case HDRSW: - fheader = 1; - continue; - case NHDRSW: - fheader = -1; - continue; - - case PACKSW: - fpack++; - continue; - case NPACKSW: - fpack = 0; - continue; - - case VERBSW: - fverb++; - continue; - case NVERBSW: - fverb = 0; - continue; - - case RECURSW: - frecurse++; - continue; - case NRECRSW: - frecurse = 0; - continue; - - case TOTALSW: - ftotal = 1; - continue; - case NTOTLSW: - ftotal = -1; - continue; - - case PRNTSW: - printsw = 1; - continue; - case NPRNTSW: - printsw = 0; - continue; - - case LISTSW: - listsw = 1; - continue; - case NLISTSW: - listsw = 0; - continue; - - case PUSHSW: - pushsw = 1; - listsw = 1; - popsw = 0; - continue; - case POPSW: - popsw = 1; - listsw = 1; - pushsw = 0; - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (argfolder) - adios (NULL, "only one folder at a time!"); - else - argfolder = pluspath (cp); - } else { - if (msg) - adios (NULL, "only one (current) message at a time!"); - else - msg = cp; - } - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - nmhdir = concat (m_maildir (""), "/", NULL); - - /* - * If we aren't working with the folder stack - * (-push, -pop, -list) then the default is to print. - */ - if (pushsw == 0 && popsw == 0 && listsw == 0) - printsw++; - - /* Pushing a folder onto the folder stack */ - if (pushsw) { - if (!argfolder) { - /* If no folder is given, the current folder and */ - /* the top of the folder stack are swapped. */ - if ((cp = context_find (stack))) { - dp = getcpy (cp); - ap = brkstring (dp, " ", "\n"); - argfolder = getcpy(*ap++); - } else { - adios (NULL, "no other folder"); - } - for (cp = getcpy (getfolder (1)); *ap; ap++) - cp = add (*ap, add (" ", cp)); - free (dp); - context_replace (stack, cp); /* update folder stack */ - } else { - /* update folder stack */ - context_replace (stack, - (cp = context_find (stack)) - ? concat (getfolder (1), " ", cp, NULL) - : getcpy (getfolder (1))); + int printsw = 0, listsw = 0; + int pushsw = 0, popsw = 0; + char *cp, *dp, *msg = NULL, *argfolder = NULL; + char **ap, **argp, buf[BUFSIZ], **arguments; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + /* + ** If program was invoked with name ending + ** in `s', then add switch `-all'. + */ + if (argv[0][strlen(argv[0]) - 1] == 's') + all = 1; + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msg] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case ALLSW: + all = 1; + continue; + + case NALLSW: + all = 0; + continue; + + case CREATSW: + fcreat = 1; + continue; + case NCREATSW: + fcreat = -1; + continue; + + case FASTSW: + fshort++; + continue; + case NFASTSW: + fshort = 0; + continue; + + case PACKSW: + fpack++; + continue; + case NPACKSW: + fpack = 0; + continue; + + case VERBSW: + fverb++; + continue; + case NVERBSW: + fverb = 0; + continue; + + case RECURSW: + frecurse++; + continue; + case NRECRSW: + frecurse = 0; + continue; + + case TOTALSW: + ftotal = 1; + continue; + case NTOTLSW: + ftotal = -1; + continue; + + case PRNTSW: + printsw = 1; + continue; + case NPRNTSW: + printsw = 0; + continue; + + case LISTSW: + listsw = 1; + continue; + case NLISTSW: + listsw = 0; + continue; + + case PUSHSW: + pushsw = 1; + listsw = 1; + popsw = 0; + continue; + case POPSW: + popsw = 1; + listsw = 1; + pushsw = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (argfolder) + adios(NULL, "only one folder at a time!"); + else + argfolder = getcpy(expandfol(cp)); + } else { + if (msg) + adios(NULL, "only one (current) message at a time!"); + else + msg = cp; + } } - } - - /* Popping a folder off of the folder stack */ - if (popsw) { - if (argfolder) - adios (NULL, "sorry, no folders allowed with -pop"); - if ((cp = context_find (stack))) { - dp = getcpy (cp); - ap = brkstring (dp, " ", "\n"); - argfolder = getcpy(*ap++); - } else { - adios (NULL, "folder stack empty"); + + nmhdir = concat(toabsdir("+"), "/", NULL); + + /* + ** If we aren't working with the folder stack + ** (-push, -pop, -list) then the default is to print. + */ + if (pushsw == 0 && popsw == 0 && listsw == 0) + printsw++; + + /* Pushing a folder onto the folder stack */ + if (pushsw) { + if (!argfolder) { + /* If no folder is given, the current folder and */ + /* the top of the folder stack are swapped. */ + if ((cp = context_find(stack))) { + dp = getcpy(cp); + ap = brkstring(dp, " ", "\n"); + argfolder = getcpy(*ap++); + } else { + adios(NULL, "no other folder"); + } + for (cp = getcpy(getcurfol()); *ap; ap++) + cp = add(*ap, add(" ", cp)); + free(dp); + context_replace(stack, cp); /* update folder stack */ + } else { + /* update folder stack */ + context_replace(stack, (cp = context_find (stack)) ? + concat(getcurfol(), " ", cp, NULL) : + getcpy(getcurfol())); + } } - if (*ap) { - /* if there's anything left in the stack */ - cp = getcpy (*ap++); - for (; *ap; ap++) - cp = add (*ap, add (" ", cp)); - context_replace (stack, cp); /* update folder stack */ - } else { - context_del (stack); /* delete folder stack entry from context */ + + /* Popping a folder off of the folder stack */ + if (popsw) { + if (argfolder) + adios(NULL, "sorry, no folders allowed with -pop"); + if ((cp = context_find(stack))) { + dp = getcpy(cp); + ap = brkstring(dp, " ", "\n"); + argfolder = getcpy(*ap++); + } else { + adios(NULL, "folder stack empty"); + } + if (*ap) { + /* if there's anything left in the stack */ + cp = getcpy(*ap++); + for (; *ap; ap++) + cp = add(*ap, add(" ", cp)); + context_replace(stack, cp); /* update folder stack */ + } else { + /* delete folder stack entry from context */ + context_del(stack); + } + free(dp); } - free (dp); - } - if (pushsw || popsw) { - cp = m_maildir(argfolder); - if (access (cp, F_OK) == NOTOK) - adios (cp, "unable to find folder"); - context_replace (pfolder, argfolder); /* update current folder */ - context_save (); /* save the context file */ - argfolder = NULL; - } - - /* Listing the folder stack */ - if (listsw) { - printf ("%s", argfolder ? argfolder : getfolder (1)); - if ((cp = context_find (stack))) { - dp = getcpy (cp); - for (ap = brkstring (dp, " ", "\n"); *ap; ap++) - printf (" %s", *ap); - free (dp); + if (pushsw || popsw) { + cp = toabsdir(argfolder); + if (access(cp, F_OK) == NOTOK) + adios(cp, "unable to find folder"); + /* update current folder */ + context_replace(curfolder, argfolder); + context_save(); /* save the context file */ + argfolder = NULL; } - printf ("\n"); - if (!printsw) - done (0); - } + /* Listing the folder stack */ + if (listsw) { + printf("%s", argfolder ? argfolder : getcurfol()); + if ((cp = context_find(stack))) { + dp = getcpy(cp); + for (ap = brkstring(dp, " ", "\n"); *ap; ap++) + printf(" %s", *ap); + free(dp); + } + printf("\n"); + + if (!printsw) + done(0); + } - /* Allocate initial space to record folder information */ - maxFolderInfo = CRAWL_NUMFOLDERS; - fi = mh_xmalloc (maxFolderInfo * sizeof(*fi)); + /* Allocate initial space to record folder information */ + maxFolderInfo = CRAWL_NUMFOLDERS; + fi = mh_xmalloc(maxFolderInfo * sizeof(*fi)); - /* - * Scan the folders - */ - if (all || ftotal > 0) { /* - * If no folder is given, do them all - */ - /* change directory to base of nmh directory for crawl_folders */ - if (chdir (nmhdir) == NOTOK) - adios (nmhdir, "unable to change directory to"); - if (!argfolder) { - if (msg) - admonish (NULL, "no folder given for message %s", msg); - readonly_folders (); /* do any readonly folders */ - strncpy (folder, (cp = context_find (pfolder)) ? cp : "", sizeof(folder)); - crawl_folders (".", get_folder_info_callback, NULL); + ** Scan the folders + */ + if (all || ftotal > 0) { + /* + ** If no folder is given, do them all + */ + /* + ** change directory to base of nmh directory for + ** crawl_folders + */ + if (chdir(nmhdir) == NOTOK) + adios(nmhdir, "unable to change directory to"); + if (!argfolder) { + if (msg) + admonish(NULL, "no folder given for message %s", msg); + readonly_folders(); /* do any readonly folders */ + strncpy(folder, (cp = context_find(curfolder)) ? + cp : "", sizeof(folder)); + crawl_folders(".", get_folder_info_callback, NULL); + } else { + strncpy(folder, argfolder, sizeof(folder)); + if (get_folder_info(argfolder, msg)) { + /* update current folder */ + context_replace(curfolder, argfolder); + context_save(); + } + /* + ** Since recurse wasn't done in get_folder_info(), + ** we still need to list all level-1 sub-folders. + */ + if (!frecurse) + crawl_folders(folder, get_folder_info_callback, + NULL); + } } else { - strncpy (folder, argfolder, sizeof(folder)); - if (get_folder_info (argfolder, msg)) { - context_replace (pfolder, argfolder);/* update current folder */ - context_save (); /* save the context file */ - } - /* - * Since recurse wasn't done in get_folder_info(), - * we still need to list all level-1 sub-folders. - */ - if (!frecurse) - crawl_folders (folder, get_folder_info_callback, NULL); + strncpy(folder, argfolder ? argfolder : getcurfol(), + sizeof(folder)); + + /* + ** Check if folder exists. If not, then see if + ** we should create it, or just exit. + */ + create_folder(toabsdir(folder), fcreat, done); + + if (get_folder_info(folder, msg) && argfolder) { + /* update current folder */ + context_replace(curfolder, argfolder); + } } - } else { - strncpy (folder, argfolder ? argfolder : getfolder (1), sizeof(folder)); /* - * Check if folder exists. If not, then see if - * we should create it, or just exit. - */ - create_folder (m_maildir (folder), fcreat, done); - - if (get_folder_info (folder, msg) && argfolder) { - /* update current folder */ - context_replace (pfolder, argfolder); - } - } - - /* - * Print out folder information - */ - print_folders(); - - context_save (); /* save the context file */ - done (0); - return 1; + ** Print out folder information + */ + print_folders(); + + context_save(); + done(0); + return 1; } static int -get_folder_info_body (char *fold, char *msg, boolean *crawl_children) +get_folder_info_body(char *fold, char *msg, boolean *crawl_children) { - int i, retval = 1; - struct msgs *mp = NULL; - - i = total_folders++; - - /* - * if necessary, reallocate the space - * for folder information - */ - if (total_folders >= maxFolderInfo) { - maxFolderInfo += CRAWL_NUMFOLDERS; - fi = mh_xrealloc (fi, maxFolderInfo * sizeof(*fi)); - } - - fi[i].name = fold; - fi[i].nummsg = 0; - fi[i].curmsg = 0; - fi[i].lowmsg = 0; - fi[i].hghmsg = 0; - fi[i].others = 0; - fi[i].error = 0; - - if ((ftotal > 0) || !fshort || msg || fpack) { + int i, retval = 1; + struct msgs *mp = NULL; + + i = total_folders++; + /* - * create message structure and get folder info - */ - if (!(mp = folder_read (fold))) { - admonish (NULL, "unable to read folder %s", fold); - return 0; + ** if necessary, reallocate the space + ** for folder information + */ + if (total_folders >= maxFolderInfo) { + maxFolderInfo += CRAWL_NUMFOLDERS; + fi = mh_xrealloc(fi, maxFolderInfo * sizeof(*fi)); } - /* set the current message */ - if (msg && !sfold (mp, msg)) - retval = 0; + fi[i].name = fold; + fi[i].nummsg = 0; + fi[i].curmsg = 0; + fi[i].lowmsg = 0; + fi[i].hghmsg = 0; + fi[i].others = 0; + fi[i].error = 0; + + if ((ftotal > 0) || !fshort || msg || fpack) { + /* + ** create message structure and get folder info + */ + if (!(mp = folder_read(fold))) { + admonish(NULL, "unable to read folder %s", fold); + return 0; + } - if (fpack) { - if (folder_pack (&mp, fverb) == -1) - done (1); - seq_save (mp); /* synchronize the sequences */ - context_save (); /* save the context file */ - } + /* set the current message */ + if (msg && !sfold(mp, msg)) + retval = 0; - /* record info for this folder */ - if ((ftotal > 0) || !fshort) { - fi[i].nummsg = mp->nummsg; - fi[i].curmsg = mp->curmsg; - fi[i].lowmsg = mp->lowmsg; - fi[i].hghmsg = mp->hghmsg; - fi[i].others = other_files (mp); - } + if (fpack) { + if (folder_pack(&mp, fverb) == -1) + done(1); + seq_save(mp); /* synchronize the sequences */ + context_save(); /* save the context file */ + } + + /* record info for this folder */ + if ((ftotal > 0) || !fshort) { + fi[i].nummsg = mp->nummsg; + fi[i].curmsg = mp->curmsg; + fi[i].lowmsg = mp->lowmsg; + fi[i].hghmsg = mp->hghmsg; + fi[i].others = other_files(mp); + } - folder_free (mp); /* free folder/message structure */ - } + folder_free(mp); /* free folder/message structure */ + } - *crawl_children = (frecurse && (fshort || fi[i].others) - && (fi[i].error == 0)); - return retval; + *crawl_children = (frecurse && (fshort || fi[i].others) + && (fi[i].error == 0)); + return retval; } static boolean -get_folder_info_callback (char *fold, void *baton) +get_folder_info_callback(char *fold, void *baton) { - boolean crawl_children; - get_folder_info_body (fold, NULL, &crawl_children); - fflush (stdout); - return crawl_children; + boolean crawl_children; + get_folder_info_body(fold, NULL, &crawl_children); + fflush(stdout); + return crawl_children; } static int -get_folder_info (char *fold, char *msg) +get_folder_info(char *fold, char *msg) { - boolean crawl_children; - int retval; - - retval = get_folder_info_body (fold, msg, &crawl_children); + boolean crawl_children; + int retval; - if (crawl_children) { - crawl_folders (fold, get_folder_info_callback, NULL); - } + retval = get_folder_info_body(fold, msg, &crawl_children); - return retval; + if (crawl_children) { + crawl_folders(fold, get_folder_info_callback, NULL); + } +return retval; } /* - * Print folder information - */ +** Print folder information +*/ static void -print_folders (void) +print_folders(void) { - int i, len, hasempty = 0, curprinted; - int maxlen = 0, maxnummsg = 0, maxlowmsg = 0; - int maxhghmsg = 0, maxcurmsg = 0, total_msgs = 0; - int nummsgdigits, lowmsgdigits; - int hghmsgdigits, curmsgdigits; - char tmpname[BUFSIZ]; - - /* - * compute a few values needed to for - * printing various fields - */ - for (i = 0; i < total_folders; i++) { - /* length of folder name */ - len = strlen (fi[i].name); - if (len > maxlen) - maxlen = len; - - /* If folder has error, skip the rest */ - if (fi[i].error) - continue; - - /* calculate total number of messages */ - total_msgs += fi[i].nummsg; - - /* maximum number of messages */ - if (fi[i].nummsg > maxnummsg) - maxnummsg = fi[i].nummsg; - - /* maximum low message */ - if (fi[i].lowmsg > maxlowmsg) - maxlowmsg = fi[i].lowmsg; - - /* maximum high message */ - if (fi[i].hghmsg > maxhghmsg) - maxhghmsg = fi[i].hghmsg; - - /* maximum current message */ - if (fi[i].curmsg >= fi[i].lowmsg && - fi[i].curmsg <= fi[i].hghmsg && - fi[i].curmsg > maxcurmsg) - maxcurmsg = fi[i].curmsg; - - /* check for empty folders */ - if (fi[i].nummsg == 0) - hasempty = 1; - } - nummsgdigits = num_digits (maxnummsg); - lowmsgdigits = num_digits (maxlowmsg); - hghmsgdigits = num_digits (maxhghmsg); - curmsgdigits = num_digits (maxcurmsg); - - if (hasempty && nummsgdigits < 2) - nummsgdigits = 2; - - /* - * Print the header - */ - if (fheader > 0 || (all && !fshort && fheader >= 0)) - printf ("%-*s %*s %-*s; %-*s %*s\n", - maxlen+1, "FOLDER", - nummsgdigits + 13, "# MESSAGES", - lowmsgdigits + hghmsgdigits + 4, " RANGE", - curmsgdigits + 4, "CUR", - 9, "(OTHERS)"); - - /* - * Print folder information - */ - if (all || fshort || ftotal < 1) { + int i, len, hasempty = 0, curprinted; + int maxlen = 0, maxnummsg = 0, maxlowmsg = 0; + int maxhghmsg = 0, maxcurmsg = 0, total_msgs = 0; + int nummsgdigits, lowmsgdigits; + int hghmsgdigits, curmsgdigits; + char tmpname[BUFSIZ]; + + /* + ** compute a few values needed to for + ** printing various fields + */ for (i = 0; i < total_folders; i++) { - if (fshort) { - printf ("%s\n", fi[i].name); - continue; - } - - /* Add `+' to end of name, if folder is current */ - if (strcmp (folder, fi[i].name)) - snprintf (tmpname, sizeof(tmpname), "%s", fi[i].name); - else - snprintf (tmpname, sizeof(tmpname), "%s+", fi[i].name); - - if (fi[i].error) { - printf ("%-*s is unreadable\n", maxlen+1, tmpname); - continue; - } - - printf ("%-*s ", maxlen+1, tmpname); - - curprinted = 0; /* remember if we print cur */ - if (fi[i].nummsg == 0) { - printf ("has %*s messages%*s", - nummsgdigits, "no", - fi[i].others ? lowmsgdigits + hghmsgdigits + 5 : 0, ""); - } else { - printf ("has %*d message%s (%*d-%*d)", - nummsgdigits, fi[i].nummsg, - (fi[i].nummsg == 1) ? " " : "s", - lowmsgdigits, fi[i].lowmsg, - hghmsgdigits, fi[i].hghmsg); - if (fi[i].curmsg >= fi[i].lowmsg && fi[i].curmsg <= fi[i].hghmsg) { - curprinted = 1; - printf ("; cur=%*d", curmsgdigits, fi[i].curmsg); + /* length of folder name */ + len = strlen(fi[i].name); + if (len > maxlen) + maxlen = len; + + /* If folder has error, skip the rest */ + if (fi[i].error) + continue; + + /* calculate total number of messages */ + total_msgs += fi[i].nummsg; + + /* maximum number of messages */ + if (fi[i].nummsg > maxnummsg) + maxnummsg = fi[i].nummsg; + + /* maximum low message */ + if (fi[i].lowmsg > maxlowmsg) + maxlowmsg = fi[i].lowmsg; + + /* maximum high message */ + if (fi[i].hghmsg > maxhghmsg) + maxhghmsg = fi[i].hghmsg; + + /* maximum current message */ + if (fi[i].curmsg >= fi[i].lowmsg && + fi[i].curmsg <= fi[i].hghmsg && + fi[i].curmsg > maxcurmsg) + maxcurmsg = fi[i].curmsg; + + /* check for empty folders */ + if (fi[i].nummsg == 0) + hasempty = 1; + } + nummsgdigits = num_digits(maxnummsg); + lowmsgdigits = num_digits(maxlowmsg); + hghmsgdigits = num_digits(maxhghmsg); + curmsgdigits = num_digits(maxcurmsg); + + if (hasempty && nummsgdigits < 2) + nummsgdigits = 2; + + /* + ** Print folder information + */ + if (all || fshort || ftotal < 1) { + for (i = 0; i < total_folders; i++) { + if (fshort) { + printf("%s\n", fi[i].name); + continue; + } + + /* Add `+' to end of name, if folder is current */ + if (strcmp(folder, fi[i].name)!=0) + snprintf(tmpname, sizeof(tmpname), "%s", + fi[i].name); + else + snprintf(tmpname, sizeof(tmpname), "%s+", + fi[i].name); + + if (fi[i].error) { + printf("%-*s is unreadable\n", maxlen+1, + tmpname); + continue; + } + + printf("%-*s ", maxlen+1, tmpname); + + curprinted = 0; /* remember if we print cur */ + if (fi[i].nummsg == 0) { + printf("has %*s messages%*s", nummsgdigits, "no", fi[i].others ? lowmsgdigits + hghmsgdigits + 5 : 0, ""); + } else { + printf("has %*d message%s (%*d-%*d)", + nummsgdigits, fi[i].nummsg, + (fi[i].nummsg == 1) ? + " " : "s", + lowmsgdigits, fi[i].lowmsg, + hghmsgdigits, fi[i].hghmsg); + if (fi[i].curmsg >= fi[i].lowmsg && fi[i].curmsg <= fi[i].hghmsg) { + curprinted = 1; + printf("; cur=%*d", curmsgdigits, + fi[i].curmsg); + } + } + + if (fi[i].others) + printf(";%*s (others)", curprinted ? + 0 : curmsgdigits + 6, ""); + printf("\n"); } - } + } - if (fi[i].others) - printf (";%*s (others)", curprinted ? 0 : curmsgdigits + 6, ""); - printf (".\n"); + /* + ** Print folder/message totals + */ + if (ftotal > 0 || (all && !fshort && ftotal >= 0)) { + if (all) + printf("\n"); + printf("TOTAL = %d message%c in %d folder%s\n", + total_msgs, total_msgs != 1 ? 's' : ' ', + total_folders, total_folders != 1 ? "s" : ""); } - } - - /* - * Print folder/message totals - */ - if (ftotal > 0 || (all && !fshort && ftotal >= 0)) { - if (all) - printf ("\n"); - printf ("TOTAL = %d message%c in %d folder%s.\n", - total_msgs, total_msgs != 1 ? 's' : ' ', - total_folders, total_folders != 1 ? "s" : ""); - } - - fflush (stdout); + + fflush(stdout); } /* - * Set the current message and sychronize sequences - */ +** Set the current message and sychronize sequences +*/ static int -sfold (struct msgs *mp, char *msg) +sfold(struct msgs *mp, char *msg) { - /* parse the message range/sequence/name and set SELECTED */ - if (!m_convert (mp, msg)) - return 0; + /* parse the message range/sequence/name and set SELECTED */ + if (!m_convert(mp, msg)) + return 0; - if (mp->numsel > 1) { - admonish (NULL, "only one message at a time!"); - return 0; - } - seq_setprev (mp); /* set the previous-sequence */ - seq_setcur (mp, mp->lowsel);/* set current message */ - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ + if (mp->numsel > 1) { + admonish(NULL, "only one message at a time!"); + return 0; + } + seq_setprev(mp); /* set the previous-sequence */ + seq_setcur(mp, mp->lowsel); /* set current message */ + seq_save(mp); /* synchronize message sequences */ + context_save(); /* save the context file */ - return 1; + return 1; } /* - * Do the read only folders - */ +** Do the read only folders +*/ static void -readonly_folders (void) +readonly_folders(void) { - int atrlen; - char atrcur[BUFSIZ]; - register struct node *np; + int atrlen; + char atrcur[BUFSIZ]; + register struct node *np; + + snprintf(atrcur, sizeof(atrcur), "atr-%s-", seq_cur); + atrlen = strlen(atrcur); + + for (np = m_defs; np; np = np->n_next) + if (strncmp(np->n_name, atrcur, atrlen)==0 && + strncmp(np->n_name+atrlen, nmhdir, strlen(nmhdir))!=0) + /* Why do we exclude absolute path names? --meillo */ + get_folder_info(np->n_name + atrlen, NULL); +} - snprintf (atrcur, sizeof(atrcur), "atr-%s-", current); - atrlen = strlen (atrcur); - for (np = m_defs; np; np = np->n_next) - if (ssequal (atrcur, np->n_name) - && !ssequal (nmhdir, np->n_name + atrlen)) - get_folder_info (np->n_name + atrlen, NULL); +/* +** pack (renumber) the messages in a folder +** into a contiguous range from 1 to n. +** Return -1 if error, else return 0. +*/ +static int +folder_pack(struct msgs **mpp, int verbose) +{ + int hole, msgnum, newcurrent = 0; + char newmsg[BUFSIZ], oldmsg[BUFSIZ]; + struct msgs *mp; + + mp = *mpp; + + /* + ** Just return if folder is empty. + */ + if (mp->nummsg == 0) + return 0; + + /* + ** Make sure we have message status space allocated + ** for all numbers from 1 to current high message. + */ + if (mp->lowoff > 1) { + if ((mp = folder_realloc(mp, 1, mp->hghmsg))) + *mpp = mp; + else { + advise(NULL, "unable to allocate folder storage"); + return -1; + } + } + + for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) { + if (does_exist(mp, msgnum)) { + if (msgnum != hole) { + strncpy(newmsg, m_name(hole), sizeof(newmsg)); + strncpy(oldmsg, m_name(msgnum), sizeof(oldmsg)); + if (verbose) + printf("message %s becomes %s\n", oldmsg, newmsg); + + /* + ** Invoke the external refile hook for each + ** message being renamed. This is done + ** before the file is renamed so that the + ** old message file is around for the hook. + */ + + snprintf(oldmsg, sizeof (oldmsg), "%s/%d", + mp->foldpath, msgnum); + snprintf(newmsg, sizeof (newmsg), "%s/%d", + mp->foldpath, hole); + ext_hook("ref-hook", oldmsg, newmsg); + + /* move the message file */ + if (rename(oldmsg, newmsg) == -1) { + advise(newmsg, "unable to rename %s to", oldmsg); + return -1; + } + + /* check if this is the current message */ + if (msgnum == mp->curmsg) + newcurrent = hole; + + /* copy the attribute flags for this message */ + copy_msg_flags(mp, hole, msgnum); + + if (msgnum == mp->lowsel) + mp->lowsel = hole; + if (msgnum == mp->hghsel) + mp->hghsel = hole; + + /* + ** mark that sequence information has + ** been modified + */ + mp->msgflags |= SEQMOD; + } + hole++; + } + } + + /* record the new number for the high/low message */ + mp->lowmsg = 1; + mp->hghmsg = hole - 1; + + if (newcurrent) + seq_setcur(mp, newcurrent); + + return 0; } diff --git a/uip/forw.c b/uip/forw.c index ac0c4c5..54b7c07 100644 --- a/uip/forw.c +++ b/uip/forw.c @@ -1,11 +1,10 @@ - /* - * forw.c -- forward a message, or group of messages. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** forw.c -- forward a message, or group of messages. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,680 +13,321 @@ #include -#define IFORMAT "digest-issue-%s" -#define VFORMAT "digest-volume-%s" +#define IFORMAT "digest-issue-%s" +#define VFORMAT "digest-volume-%s" static struct swit switches[] = { -#define ANNOSW 0 - { "annotate", 0 }, -#define NANNOSW 1 - { "noannotate", 0 }, -#define DFOLDSW 2 - { "draftfolder +folder", 0 }, -#define DMSGSW 3 - { "draftmessage msg", 0 }, -#define NDFLDSW 4 - { "nodraftfolder", 0 }, -#define EDITRSW 5 - { "editor editor", 0 }, -#define NEDITSW 6 - { "noedit", 0 }, -#define FILTSW 7 - { "filter filterfile", 0 }, -#define FORMSW 8 - { "form formfile", 0 }, -#define FRMTSW 9 - { "format", 5 }, -#define NFRMTSW 10 - { "noformat", 7 }, -#define INPLSW 11 - { "inplace", 0 }, -#define NINPLSW 12 - { "noinplace", 0 }, -#define MIMESW 13 - { "mime", 0 }, -#define NMIMESW 14 - { "nomime", 0 }, -#define DGSTSW 15 - { "digest list", 0 }, -#define ISSUESW 16 - { "issue number", 0 }, -#define VOLUMSW 17 - { "volume number", 0 }, -#define WHATSW 18 - { "whatnowproc program", 0 }, -#define NWHATSW 19 - { "nowhatnowproc", 0 }, -#define BITSTUFFSW 20 - { "dashstuffing", 0 }, /* interface to mhl */ -#define NBITSTUFFSW 21 - { "nodashstuffing", 0 }, -#define VERSIONSW 22 - { "version", 0 }, -#define HELPSW 23 - { "help", 0 }, -#define FILESW 24 - { "file file", 4 }, /* interface from msh */ - -#ifdef MHE -#define BILDSW 25 - { "build", 5 }, /* interface from mhe */ -#endif /* MHE */ - - { NULL, 0 } -}; - -static struct swit aqrnl[] = { -#define NOSW 0 - { "quit", 0 }, -#define YESW 1 - { "replace", 0 }, -#define LISTDSW 2 - { "list", 0 }, -#define REFILSW 3 - { "refile +folder", 0 }, -#define NEWSW 4 - { "new", 0 }, - { NULL, 0 } -}; - -static struct swit aqrl[] = { - { "quit", 0 }, - { "replace", 0 }, - { "list", 0 }, - { "refile +folder", 0 }, - { NULL, 0 } +#define ANNOSW 0 + { "annotate", 0 }, +#define NANNOSW 1 + { "noannotate", 2 }, +#define EDITRSW 2 + { "editor editor", 0 }, +#define FORMSW 3 + { "form formfile", 0 }, +#define DGSTSW 4 + { "digest list", 0 }, +#define ISSUESW 5 + { "issue number", 0 }, +#define VOLUMSW 6 + { "volume number", 0 }, +#define WHATSW 7 + { "whatnowproc program", 0 }, +#define VERSIONSW 8 + { "Version", 0 }, +#define HELPSW 9 + { "help", 0 }, +#define BILDSW 10 + { "build", 5 }, /* interface from mhe */ + { NULL, 0 } }; static char drft[BUFSIZ]; - -static char delim3[] = - "\n------------------------------------------------------------\n\n"; -static char delim4[] = "\n------------------------------\n\n"; - - -static struct msgs *mp = NULL; /* used a lot */ +static struct msgs *mp = NULL; /* - * static prototypes - */ -static void mhl_draft (int, char *, int, int, char *, char *, int); -static void copy_draft (int, char *, char *, int, int, int); -static void copy_mime_draft (int); -static int build_form (char *, char *, int, int); +** static prototypes +*/ +static void add_forw_hdr(char *); +static int build_form(char *, char *, int, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgp = 0, anot = 0, inplace = 1, mime = 0; - int issue = 0, volume = 0, dashstuff = 0; - int nedit = 0, nwhat = 0, i, in; - int out, isdf = 0, msgnum; - char *cp, *cwd, *maildir, *dfolder = NULL; - char *dmsg = NULL, *digest = NULL, *ed = NULL; - char *file = NULL, *filter = NULL, *folder = NULL; - char *form = NULL, buf[BUFSIZ], value[10]; - char **argp, **arguments, *msgs[MAXARGS]; - struct stat st; - -#ifdef MHE - int buildsw = 0; -#endif /* MHE */ - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ANNOSW: - anot++; - continue; - case NANNOSW: - anot = 0; - continue; - - case EDITRSW: - if (!(ed = *argp++) || *ed == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nedit = 0; - continue; - case NEDITSW: - nedit++; - continue; - - case WHATSW: - if (!(whatnowproc = *argp++) || *whatnowproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nwhat = 0; - continue; -#ifdef MHE - case BILDSW: - buildsw++; /* fall... */ -#endif /* MHE */ - case NWHATSW: - nwhat++; - continue; - - case FILESW: - if (file) - adios (NULL, "only one file at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - file = path (cp, TFILE); - continue; - case FILTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - filter = getcpy (etcpath (cp)); - mime = 0; - continue; - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case FRMTSW: - filter = getcpy (etcpath (mhlforward)); - continue; - case NFRMTSW: - filter = NULL; - continue; - - case INPLSW: - inplace++; - continue; - case NINPLSW: - inplace = 0; - continue; - - case MIMESW: - mime++; - filter = NULL; - continue; - case NMIMESW: - mime = 0; - continue; - - case DGSTSW: - if (!(digest = *argp++) || *digest == '-') - adios (NULL, "missing argument to %s", argp[-2]); - mime = 0; - continue; - case ISSUESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((issue = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case VOLUMSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((volume = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - - case BITSTUFFSW: - dashstuff = 1; /* trinary logic */ - continue; - case NBITSTUFFSW: - dashstuff = -1; /* trinary logic */ - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - msgs[msgp++] = cp; - } - } - - cwd = getcpy (pwd ()); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (file && (msgp || folder)) - adios (NULL, "can't mix files and folders/msgs"); - -try_it_again: - -#ifdef MHE - strncpy (drft, buildsw ? m_maildir ("draft") - : m_draft (dfolder, NULL, NOUSE, &isdf), sizeof(drft)); - - /* Check if a draft already exists */ - if (!buildsw && stat (drft, &st) != NOTOK) { -#else - strncpy (drft, m_draft (dfolder, dmsg, NOUSE, &isdf), sizeof(drft)); - - /* Check if a draft already exists */ - if (stat (drft, &st) != NOTOK) { -#endif /* MHE */ - printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size); - for (i = LISTDSW; i != YESW;) { - if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl))) - done (1); - switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) { - case NOSW: - done (0); - case NEWSW: - dmsg = NULL; - goto try_it_again; - case YESW: - break; - case LISTDSW: - showfile (++argp, drft); - break; - case REFILSW: - if (refile (++argp, drft) == 0) - i = YESW; - break; - default: - advise (NULL, "say what?"); - break; - } + int msgp = 0, anot = 0; + int issue = 0, volume = 0; + int in; + int out, msgnum; + char *cp, *cwd, *maildir; + char *digest = NULL, *ed = NULL; + char *folder = NULL; + char *form = NULL, buf[BUFSIZ], value[10]; + char **argp, **arguments, *msgs[MAXARGS]; + char *fmtstr; + int buildsw = 0; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case ANNOSW: + anot++; + continue; + case NANNOSW: + anot = 0; + continue; + + case EDITRSW: + if (!(ed = *argp++) || *ed == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WHATSW: + if (!(whatnowproc = *argp++) || + *whatnowproc == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case BILDSW: + buildsw++; + continue; + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case DGSTSW: + if (!(digest = *argp++) || *digest == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + //mime = 0; + continue; + case ISSUESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if ((issue = atoi(cp)) < 1) + adios(NULL, "bad argument %s %s", + argp[-2], cp); + continue; + case VOLUMSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if ((volume = atoi(cp)) < 1) + adios(NULL, "bad argument %s %s", + argp[-2], cp); + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + msgs[msgp++] = cp; + } } - } - if (file) { + cwd = getcpy(pwd()); + strncpy(drft, buildsw ? toabsdir("draft") : m_draft(seq_beyond), + sizeof(drft)); /* - * Forwarding a file. - */ - anot = 0; /* don't want to annotate a file */ - } else { + ** FIXME: (concerning MHE support (buildsw) only) + ** There's no check if the draft already exists. mmh has removed + ** this case by having the draft folder. I won't add code only to + ** handle this legacy issue for MHE. -- meillo@marmaro.de 2012-05 + */ + /* - * Forwarding a message. - */ + ** Forwarding a message. + */ if (!msgp) - msgs[msgp++] = "cur"; + msgs[msgp++] = seq_cur; if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); + folder = getcurfol(); + maildir = toabsdir(folder); - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); /* check for empty folder */ if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); + adios(NULL, "no messages in %s", folder); /* parse all the message ranges/sequences and set SELECTED */ for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous sequence */ - } - - if (filter && access (filter, R_OK) == NOTOK) - adios (filter, "unable to read"); - - /* - * Open form (component) file. - */ - if (digest) { - if (issue == 0) { - snprintf (buf, sizeof(buf), IFORMAT, digest); - if (volume == 0 - && (cp = context_find (buf)) - && ((issue = atoi (cp)) < 0)) - issue = 0; - issue++; - } - if (volume == 0) - snprintf (buf, sizeof(buf), VFORMAT, digest); - if ((cp = context_find (buf)) == NULL || (volume = atoi (cp)) <= 0) - volume = 1; - if (!form) - form = digestcomps; - in = build_form (form, digest, volume, issue); - } else - in = open_form(&form, forwcomps); - - if ((out = creat (drft, m_gmprot ())) == NOTOK) - adios (drft, "unable to create"); - - /* - * copy the components into the draft - */ - cpydata (in, out, form, drft); - close (in); - - if (file) { - /* just copy the file into the draft */ - if ((in = open (file, O_RDONLY)) == NOTOK) - adios (file, "unable to open"); - cpydata (in, out, file, drft); - close (in); - close (out); - } else { - /* - * If filter file is defined, then format the - * messages into the draft using mhlproc. - */ - if (filter) - mhl_draft (out, digest, volume, issue, drft, filter, dashstuff); - else if (mime) - copy_mime_draft (out); - else - copy_draft (out, digest, drft, volume, issue, dashstuff); - close (out); + if (!m_convert(mp, msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous sequence */ + + if ((out = creat(drft, m_gmprot())) == NOTOK) + adios(drft, "unable to create"); + /* Open form (component) file. */ if (digest) { - snprintf (buf, sizeof(buf), IFORMAT, digest); - snprintf (value, sizeof(value), "%d", issue); - context_replace (buf, getcpy (value)); - snprintf (buf, sizeof(buf), VFORMAT, digest); - snprintf (value, sizeof(value), "%d", volume); - context_replace (buf, getcpy (value)); + if (issue == 0) { + snprintf(buf, sizeof(buf), IFORMAT, digest); + if (volume == 0 && (cp = context_find(buf)) + && ((issue = atoi(cp)) < 0)) + issue = 0; + issue++; + } + if (volume == 0) { + snprintf(buf, sizeof(buf), VFORMAT, digest); + if ((cp = context_find(buf)) == NULL || + (volume = atoi(cp)) <= 0) + volume = 1; + } + if (!form) + form = digestcomps; + in = build_form(form, digest, volume, issue); + cpydata(in, out, form, drft); + close(in); + } else { + fmtstr = new_fs(form, forwcomps); + if (write(out, fmtstr, strlen(fmtstr)) != (int)strlen(fmtstr)) { + adios(drft, "error writing"); + } } + close(out); - context_replace (pfolder, folder); /* update current folder */ - seq_setcur (mp, mp->lowsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - if (nwhat) - done (0); - what_now (ed, nedit, NOUSE, drft, NULL, 0, mp, - anot ? "Forwarded" : NULL, inplace, cwd); - done (1); - return 1; -} + add_forw_hdr(drft); + if (digest) { + snprintf(buf, sizeof(buf), IFORMAT, digest); + snprintf(value, sizeof(value), "%d", issue); + context_replace(buf, getcpy(value)); + snprintf(buf, sizeof(buf), VFORMAT, digest); + snprintf(value, sizeof(value), "%d", volume); + context_replace(buf, getcpy(value)); + } -/* - * Filter the messages you are forwarding, into the - * draft calling the mhlproc, and reading its output - * from a pipe. - */ - -static void -mhl_draft (int out, char *digest, int volume, int issue, - char *file, char *filter, int dashstuff) -{ - pid_t child_id; - int i, msgnum, pd[2]; - char *vec[MAXARGS]; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; - - if (pipe (pd) == NOTOK) - adios ("pipe", "unable to create"); - - vec[0] = r1bindex (mhlproc, '/'); - - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - adios ("fork", "unable to"); - - case OK: - close (pd[0]); - dup2 (pd[1], 1); - close (pd[1]); - - i = 1; - vec[i++] = "-forwall"; - vec[i++] = "-form"; - vec[i++] = filter; - - if (digest) { - vec[i++] = "-digest"; - vec[i++] = digest; - vec[i++] = "-issue"; - snprintf (buf1, sizeof(buf1), "%d", issue); - vec[i++] = buf1; - vec[i++] = "-volume"; - snprintf (buf2, sizeof(buf2), "%d", volume); - vec[i++] = buf2; - } - - /* - * Are we dashstuffing (quoting) the lines that begin - * with `-'. We use the mhl default (don't add any flag) - * unless the user has specified a specific flag. - */ - if (dashstuff > 0) - vec[i++] = "-dashstuffing"; - else if (dashstuff < 0) - vec[i++] = "-nodashstuffing"; - - if (mp->numsel >= MAXARGS - i) - adios (NULL, "more than %d messages for %s exec", - MAXARGS - i, vec[0]); - - /* - * Now add the message names to filter. We can only - * handle about 995 messages (because vec is fixed size), - * but that should be plenty. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel && i < sizeof(vec) - 1; - msgnum++) - if (is_selected (mp, msgnum)) - vec[i++] = getcpy (m_name (msgnum)); - vec[i] = NULL; - - execvp (mhlproc, vec); - fprintf (stderr, "unable to exec "); - perror (mhlproc); - _exit (-1); - - default: - close (pd[1]); - cpydata (pd[0], out, vec[0], file); - close (pd[0]); - pidXwait(child_id, mhlproc); - break; - } + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->lowsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ + + if (buildsw) + done(0); + what_now(ed, NOUSE, drft, NULL, 0, mp, + anot ? "Forwarded" : NULL, cwd); + done(1); + return 1; } /* - * Copy the messages into the draft. The messages are - * not filtered through the mhlproc. Do dashstuffing if - * necessary. - */ - +** Create an attachment header for the to be forward messages. +*/ static void -copy_draft (int out, char *digest, char *file, int volume, int issue, int dashstuff) +add_forw_hdr(char *draft) { - int fd,i, msgcnt, msgnum; - int len, buflen; - register char *bp, *msgnam; - char buffer[BUFSIZ]; - - msgcnt = 1; - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - if (digest) { - strncpy (buffer, msgnum == mp->lowsel ? delim3 : delim4, - sizeof(buffer)); - } else { - /* Get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - strncpy (bp, "\n-------", buflen); - len = strlen (bp); - bp += len; - buflen -= len; - - if (msgnum == mp->lowsel) { - snprintf (bp, buflen, " Forwarded Message%s", - mp->numsel > 1 ? "s" : ""); - } else { - snprintf (bp, buflen, " Message %d", msgcnt); + int msgnum; + char buffer[BUFSIZ]; + + snprintf(buffer, sizeof buffer, "anno -append -nodate '%s' " + "-comp '%s' -text '+%s", + draft, attach_hdr, mp->foldpath); + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (!is_selected(mp, msgnum)) { + continue; } - len = strlen (bp); - bp += len; - buflen -= len; - - strncpy (bp, "\n\n", buflen); - } - write (out, buffer, strlen (buffer)); - - if ((fd = open (msgnam = m_name (msgnum), O_RDONLY)) == NOTOK) { - admonish (msgnam, "unable to read message"); - continue; - } - - /* - * Copy the message. Add RFC934 quoting (dashstuffing) - * unless given the -nodashstuffing flag. - */ - if (dashstuff >= 0) - cpydgst (fd, out, msgnam, file); - else - cpydata (fd, out, msgnam, file); - - close (fd); - msgcnt++; + /* TODO: Check for buffer length! */ + strcat(buffer, " "); + strcat(buffer, m_name(msgnum)); } - } - - if (digest) { - strncpy (buffer, delim4, sizeof(buffer)); - } else { - snprintf (buffer, sizeof(buffer), "\n------- End of Forwarded Message%s\n\n", - mp->numsel > 1 ? "s" : ""); - } - write (out, buffer, strlen (buffer)); - - if (digest) { - snprintf (buffer, sizeof(buffer), "End of %s Digest [Volume %d Issue %d]\n", - digest, volume, issue); - i = strlen (buffer); - for (bp = buffer + i; i > 1; i--) - *bp++ = '*'; - *bp++ = '\n'; - *bp = 0; - write (out, buffer, strlen (buffer)); - } -} - - -/* - * Create a mhn composition file for forwarding message. - */ - -static void -copy_mime_draft (int out) -{ - int msgnum; - char buffer[BUFSIZ]; - - snprintf (buffer, sizeof(buffer), "#forw [forwarded message%s] +%s", - mp->numsel == 1 ? "" : "s", mp->foldpath); - write (out, buffer, strlen (buffer)); - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) { - snprintf (buffer, sizeof(buffer), " %s", m_name (msgnum)); - write (out, buffer, strlen (buffer)); + strcat(buffer, "'"); + /* TODO: This check is bad, but better than nothing */ + if (strlen(buffer) > BUFSIZ) { + adios(NULL, "Too long attachment header line. Forward less messages."); + } + if (system(buffer) != 0) { + advise(NULL, "unable to add attachment header"); } - write (out, "\n", 1); } static int -build_form (char *form, char *digest, int volume, int issue) +build_form(char *form, char *digest, int volume, int issue) { - int in; - int fmtsize; - register char *nfs; - char *line, tmpfil[BUFSIZ]; - FILE *tmp; - register struct comp *cptr; - struct format *fmt; - int dat[5]; - char *cp = NULL; - - /* Get new format string */ - nfs = new_fs (form, NULL, NULL); - fmtsize = strlen (nfs) + 256; - - /* Compile format string */ - fmt_compile (nfs, &fmt); - - FINDCOMP (cptr, "digest"); - if (cptr) - cptr->c_text = digest; - FINDCOMP (cptr, "date"); - if (cptr) - cptr->c_text = getcpy(dtimenow (0)); - - dat[0] = issue; - dat[1] = volume; - dat[2] = 0; - dat[3] = fmtsize; - dat[4] = 0; - - cp = m_mktemp2(NULL, invo_name, NULL, &tmp); - if (cp == NULL) adios("forw", "unable to create temporary file"); - strncpy (tmpfil, cp, sizeof(tmpfil)); - unlink (tmpfil); - if ((in = dup (fileno (tmp))) == NOTOK) - adios ("dup", "unable to"); - - line = mh_xmalloc ((unsigned) fmtsize); - fmt_scan (fmt, line, fmtsize, dat); - fputs (line, tmp); - free (line); - if (fclose (tmp)) - adios (tmpfil, "error writing"); - - lseek (in, (off_t) 0, SEEK_SET); - return in; + int in; + int fmtsize; + register char *fmtstr; + char *line, tmpfil[BUFSIZ]; + FILE *tmp; + register struct comp *cptr; + struct format *fmt; + int dat[5]; + char *cp = NULL; + + /* Get new format string */ + fmtstr = new_fs(form, NULL); + fmtsize = strlen(fmtstr) + 256; + + /* Compile format string */ + fmt_compile(fmtstr, &fmt); + + FINDCOMP(cptr, "digest"); + if (cptr) + cptr->c_text = digest; + FINDCOMP(cptr, "date"); + if (cptr) + cptr->c_text = getcpy(dtimenow()); + + dat[0] = issue; + dat[1] = volume; + dat[2] = 0; + dat[3] = fmtsize; + dat[4] = 0; + + cp = m_mktemp2(NULL, invo_name, NULL, &tmp); + if (cp == NULL) adios("forw", "unable to create temporary file"); + strncpy(tmpfil, cp, sizeof(tmpfil)); + unlink(tmpfil); + if ((in = dup(fileno(tmp))) == NOTOK) + adios("dup", "unable to"); + + line = mh_xmalloc((unsigned) fmtsize); + fmt_scan(fmt, line, fmtsize, dat); + fputs(line, tmp); + free(line); + if (fclose(tmp)) + adios(tmpfil, "error writing"); + + lseek(in, (off_t) 0, SEEK_SET); + return in; } diff --git a/uip/ftpsbr.c b/uip/ftpsbr.c deleted file mode 100644 index 57f25ba..0000000 --- a/uip/ftpsbr.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * ftpsbr.c -- simple FTP client library - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - -#ifdef HAVE_ARPA_FTP_H -# include -#endif - -#define v_debug debugsw -#define v_verbose verbosw - -static int ftp_fd = NOTOK; -static int data_fd = NOTOK; - -static int v_noise; - -extern int v_debug; -extern int v_verbose; - -#include -#include -#include -#include -#include - -#define start_tcp_client(res) \ - socket (res->ai_family, res->ai_socktype, res->ai_protocol) - -#define join_tcp_server(fd, sock, len) \ - connect ((fd), (struct sockaddr *) (sock), len) - -/* - * prototypes - */ -int ftp_get (char *, char *, char *, char *, char *, char *, int, int); -int ftp_trans (char *, char *, char *, char *, char *, char *, char *, int, int); - -/* - * static prototypes - */ -static int start_tcp_server (struct sockaddr_in *, int, int, int); -static void _asnprintf (char *, int, char *, va_list); -static int ftp_quit (void); -static int ftp_read (char *, char *, char *, int); -static int initconn (void); -static int dataconn (void); -static int command (int arg1, ...); -static int vcommand (int, va_list); -static int getreply (int, int); - - -static int -start_tcp_server (struct sockaddr_in *sock, int backlog, int opt1, int opt2) -{ - int eindex, sd; - - if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK) - return NOTOK; - - if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) { - eindex = errno; - close (sd); - errno = eindex; - } else { - listen (sd, backlog); - } - - return sd; -} - - -static int __len__; - -#define join_tcp_client(fd,sock) \ - accept ((fd), (struct sockaddr *) (sock), \ - (__len__ = sizeof *(sock), &__len__)) - -#define read_tcp_socket read -#define write_tcp_socket write -#define close_tcp_socket close - -static void -_asnprintf (char *bp, int len_bp, char *what, va_list ap) -{ - int eindex, len; - char *fmt; - - eindex = errno; - - *bp = '\0'; - fmt = va_arg (ap, char *); - - if (fmt) { - vsnprintf(bp, len_bp, fmt, ap); - len = strlen(bp); - bp += len; - len_bp -= len; - } - - if (what) { - char *s; - - if (*what) { - snprintf (bp, len_bp, " %s: ", what); - len = strlen (bp); - bp += len; - len_bp -= len; - } - if ((s = strerror(eindex))) - strncpy (bp, s, len_bp); - else - snprintf (bp, len_bp, "Error %d", eindex); - bp += strlen (bp); - } - - errno = eindex; -} - - -int -ftp_get (char *host, char *user, char *password, char *cwd, - char *remote, char *local, int ascii, int stayopen) -{ - return ftp_trans (host, user, password, cwd, remote, local, - "RETR", ascii, stayopen); -} - - -int -ftp_trans (char *host, char *user, char *password, char *cwd, char *remote, - char *local, char *cmd, int ascii, int stayopen) -{ - int result; - - if (stayopen <= 0) { - result = ftp_quit (); - if (host == NULL) - return result; - } - - if (ftp_fd == NOTOK) { - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); -#ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; -#endif - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - - result = getaddrinfo(host, "ftp", &hints, &res); - - if (result) { - fprintf(stderr, "%s/ftp: %s\n", host, gai_strerror(result)); - return NOTOK; - } - - if ((ftp_fd = start_tcp_client (res)) == NOTOK) { - perror (host); - freeaddrinfo(res); - return NOTOK; - } - if (join_tcp_server (ftp_fd, res->ai_addr, res->ai_addrlen) == NOTOK) { - perror (host); - freeaddrinfo(res); - close_tcp_socket (ftp_fd), ftp_fd = NOTOK; - return NOTOK; - } - freeaddrinfo(res); - getreply (1, 0); - - if (v_verbose) { - fprintf (stdout, "Connected to %s\n", host); - fflush (stdout); - } - - if (user) { - if ((result = command (0, "USER %s", user)) == CONTINUE) - result = command (1, "PASS %s", password); - if (result != COMPLETE) { - result = NOTOK; - goto out; - } - } - - if (remote == NULL) - return OK; - } - - if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE - && result != CONTINUE)) { - result = NOTOK; - goto out; - } - - if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) { - result = NOTOK; - goto out; - } - - result = ftp_read (remote, local, cmd, ascii); - -out: ; - if (result != OK || !stayopen) - ftp_quit (); - - return result; -} - - -static int -ftp_quit (void) -{ - int n; - - if (ftp_fd == NOTOK) - return OK; - - n = command (1, "QUIT"); - close_tcp_socket (ftp_fd), ftp_fd = NOTOK; - return (n == 0 || n == COMPLETE ? OK : NOTOK); -} - -static int -ftp_read (char *remote, char *local, char *cmd, int ascii) -{ - int istdio = 0, istore; - register int cc; - int expectingreply = 0; - char buffer[BUFSIZ]; - FILE *fp = NULL; - - if (initconn () == NOTOK) - goto bad; - - v_noise = v_verbose; - if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM) - goto bad; - - expectingreply++; - if (dataconn () == NOTOK) { -bad: ; - if (fp && !istdio) - fclose (fp); - if (data_fd != NOTOK) - close_tcp_socket (data_fd), data_fd = NOTOK; - if (expectingreply) - getreply (-2, 0); - - return NOTOK; - } - - istore = !strcmp (cmd, "STOR"); - - if ((istdio = !strcmp (local, "-"))) - fp = istore ? stdin : stdout; - else - if ((fp = fopen (local, istore ? "r" : "w")) == NULL) { - perror (local); - goto bad; - } - - if (istore) { - if (ascii) { - int c; - FILE *out; - - if (!(out = fdopen (data_fd, "w"))) { - perror ("fdopen"); - goto bad; - } - - while ((c = getc (fp)) != EOF) { - if (c == '\n') - putc ('\r', out); - if (putc (c, out) == EOF) { - perror ("putc"); - fclose (out); - data_fd = NOTOK; - goto bad; - } - } - - fclose (out); - data_fd = NOTOK; - } - else { - while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) > 0) - if (write_tcp_socket (data_fd, buffer, cc) != cc) { - perror ("write_tcp_socket"); - goto bad; - } - - close_tcp_socket (data_fd), data_fd = NOTOK; - } - } - else { - if (ascii) { - int c; - FILE *in; - - if (!(in = fdopen (data_fd, "r"))) { - perror ("fdopen"); - goto bad; - } - - while ((c = getc (in)) != EOF) { - if (c == '\r') - switch (c = getc (in)) { - case EOF: - case '\0': - c = '\r'; - break; - - case '\n': - break; - - default: - putc ('\r', fp); - break; - } - - if (putc (c, fp) == EOF) { - perror ("putc"); - fclose (in); - data_fd = NOTOK; - goto bad; - } - } - - fclose (in); - data_fd = NOTOK; - } - else { - while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0) - if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) { - perror ("fwrite"); - goto bad; - } - if (cc < 0) { - perror ("read_tcp_socket"); - goto bad; - } - - close_tcp_socket (data_fd), data_fd = NOTOK; - } - } - - if (!istdio) - fclose (fp); - - v_noise = v_verbose; - return (getreply (1, 0) == COMPLETE ? OK : NOTOK); -} - - -#define UC(b) (((int) b) & 0xff) - -static int -initconn (void) -{ - int len; - register char *a, *p; - struct sockaddr_in in_socket; - - if (getsockname (ftp_fd, (struct sockaddr *) &in_socket, - (len = sizeof(in_socket), &len)) == NOTOK) { - perror ("getsockname"); - return NOTOK; - } - in_socket.sin_port = 0; - if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) { - perror ("start_tcp_server"); - return NOTOK; - } - - if (getsockname (data_fd, (struct sockaddr *) &in_socket, - (len = sizeof in_socket, &len)) == NOTOK) { - perror ("getsockname"); - return NOTOK; - } - - a = (char *) &in_socket.sin_addr; - p = (char *) &in_socket.sin_port; - - if (command (1, "PORT %d,%d,%d,%d,%d,%d", - UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(p[0]), UC(p[1])) == COMPLETE) - return OK; - - return NOTOK; -} - -static int -dataconn (void) -{ - int fd; - struct sockaddr_in in_socket; - - if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) { - perror ("join_tcp_client"); - return NOTOK; - } - close_tcp_socket (data_fd); - data_fd = fd; - - return OK; -} - - -static int -command (int arg1, ...) -{ - int val; - va_list ap; - - va_start (ap, arg1); - val = vcommand (arg1, ap); - va_end (ap); - - return val; -} - -static int -vcommand (int complete, va_list ap) -{ - int len; - char buffer[BUFSIZ]; - - if (ftp_fd == NOTOK) - return NOTOK; - - _asnprintf (buffer, sizeof(buffer), NULL, ap); - if (v_debug) - fprintf (stderr, "<--- %s\n", buffer); - - strcat (buffer, "\r\n"); - len = strlen (buffer); - - if (write_tcp_socket (ftp_fd, buffer, len) != len) { - perror ("write_tcp_socket"); - return NOTOK; - } - - return (getreply (complete, !strcmp (buffer, "QUIT"))); -} - - -static int -getreply (int complete, int expecteof) -{ - for (;;) { - register int code, dig, n; - int continuation; - register char *bp; - char buffer[BUFSIZ]; - - code = dig = n = continuation = 0; - bp = buffer; - - for (;;) { - unsigned char c; - - if (read_tcp_socket (ftp_fd, &c, 1) < 1) { - if (expecteof) - return OK; - - perror ("read_tcp_socket"); - return DONE; - } - if (c == '\n') - break; - *bp++ = c != '\r' ? c : '\0'; - - dig++; - if (dig < 4) { - if (isdigit(c)) - code = code * 10 + (c - '0'); - else /* XXX: naughty FTP... */ - if (isspace (c)) - continuation++; - } - else - if (dig == 4 && c == '-') - continuation++; - if (n == 0) - n = c; - } - - if (v_debug) - fprintf (stderr, "---> %s\n", buffer); - if (continuation) - continue; - - n -= '0'; - - if (v_noise) { - fprintf (stdout, "%s\n", buffer); - fflush (stdout); - v_noise = 0; - } - else - if ((complete == -1 && n != PRELIM) - || (complete == 0 && n != CONTINUE && n != COMPLETE) - || (complete == 1 && n != COMPLETE)) - fprintf (stderr, "%s\n", buffer); - - return n; - } -} diff --git a/uip/inc.c b/uip/inc.c index 8f99b7b..f737d69 100644 --- a/uip/inc.c +++ b/uip/inc.c @@ -1,169 +1,102 @@ - /* - * inc.c -- incorporate messages from a maildrop into a folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** inc.c -- incorporate messages from a maildrop into a folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #ifdef MAILGROUP -/* Revised: Sat Apr 14 17:08:17 PDT 1990 (marvit@hplabs) - * Added hpux hacks to set and reset gid to be "mail" as needed. The reset - * is necessary so inc'ed mail is the group of the inc'er, rather than - * "mail". We setgid to egid only when [un]locking the mail file. This - * is also a major security precaution which will not be explained here. - * - * Fri Feb 7 16:04:57 PST 1992 John Romine - * NB: I'm not 100% sure that this setgid stuff is secure even now. - * - * See the *GROUPPRIVS() macros later. I'm reasonably happy with the setgid - * attribute. Running setuid root is probably not a terribly good idea, though. - * -- Peter Maydell , 04/1998 - * - * Peter Maydell's patch slightly modified for nmh 0.28-pre2. - * Ruud de Rooij Wed, 22 Jul 1998 13:24:22 +0200 - */ +/* +** Revised: Sat Apr 14 17:08:17 PDT 1990 (marvit@hplabs) +** Added hpux hacks to set and reset gid to be "mail" as needed. The reset +** is necessary so inc'ed mail is the group of the inc'er, rather than +** "mail". We setgid to egid only when [un]locking the mail file. This +** is also a major security precaution which will not be explained here. +** +** Fri Feb 7 16:04:57 PST 1992 John Romine +** NB: I'm not 100% sure that this setgid stuff is secure even now. +** +** See the *GROUPPRIVS() macros later. I'm reasonably happy with the setgid +** attribute. Running setuid root is probably not a terribly good idea, though. +** -- Peter Maydell , 04/1998 +** +** Peter Maydell's patch slightly modified for nmh 0.28-pre2. +** Ruud de Rooij Wed, 22 Jul 1998 13:24:22 +0200 +*/ #endif #include #include #include -#ifdef POP -# include -# include -#endif - #include #include #include #include -#include #include #include -#ifndef POP -# define POPminc(a) (a) -#else -# define POPminc(a) 0 -#endif - -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else -# define SASLminc(a) 0 -#endif - static struct swit switches[] = { -#define AUDSW 0 - { "audit audit-file", 0 }, -#define NAUDSW 1 - { "noaudit", 0 }, -#define CHGSW 2 - { "changecur", 0 }, -#define NCHGSW 3 - { "nochangecur", 0 }, -#define FILESW 4 - { "file name", 0 }, -#define FORMSW 5 - { "form formatfile", 0 }, -#define FMTSW 6 - { "format string", 5 }, -#define HOSTSW 7 - { "host hostname", POPminc (-4) }, -#define USERSW 8 - { "user username", POPminc (-4) }, -#define PACKSW 9 - { "pack file", POPminc (-4) }, -#define NPACKSW 10 - { "nopack", POPminc (-6) }, -#define PORTSW 11 - { "port name/number", POPminc (-4) }, -#define SILSW 12 - { "silent", 0 }, -#define NSILSW 13 - { "nosilent", 0 }, -#define TRNCSW 14 - { "truncate", 0 }, -#define NTRNCSW 15 - { "notruncate", 0 }, -#define WIDTHSW 16 - { "width columns", 0 }, -#define VERSIONSW 17 - { "version", 0 }, -#define HELPSW 18 - { "help", 0 }, -#define SNOOPSW 19 - { "snoop", -5 }, -#define SASLSW 20 - { "sasl", SASLminc(-4) }, -#define SASLMECHSW 21 - { "saslmech", SASLminc(-8) }, -#define PROXYSW 22 - { "proxy command", POPminc(-5) }, - { NULL, 0 } +#define AUDSW 0 + { "audit audit-file", 0 }, +#define NAUDSW 1 + { "noaudit", 2 }, +#define CHGSW 2 + { "changecur", 0 }, +#define NCHGSW 3 + { "nochangecur", 2 }, +#define FILESW 4 + { "file name", 0 }, +#define FORMSW 5 + { "form formatfile", 0 }, +#define SILSW 6 + { "silent", 0 }, +#define NSILSW 7 + { "nosilent", 2 }, +#define TRNCSW 8 + { "truncate", 0 }, +#define NTRNCSW 9 + { "notruncate", 2 }, +#define WIDTHSW 10 + { "width columns", 0 }, +#define VERSIONSW 11 + { "Version", 0 }, +#define HELPSW 12 + { "help", 0 }, + { NULL, 0 }, }; /* - * flags for the mail source - */ -#define INC_FILE 0 -#define INC_POP 1 - -static int inc_type; -static int snoop = 0; - -#ifdef POP -extern char response[]; - -static char *packfile = NULL; -static int size; -static long pos; -static long start; -static long stop; - -static int mbx_style = MMDF_FORMAT; -static int pd = NOTOK; -static FILE *pf = NULL; -#endif /* POP */ - -/* This is an attempt to simplify things by putting all the - * privilege ops into macros. - * *GROUPPRIVS() is related to handling the setgid MAIL property, - * and only applies if MAILGROUP is defined. - * *USERPRIVS() is related to handling the setuid root property, - * and only applies if POP is defined [why does POP => setuid root?] - * Basically, SAVEGROUPPRIVS() is called right at the top of main() - * to initialise things, and then DROPGROUPPRIVS() and GETGROUPPRIVS() - * do the obvious thing. TRYDROPGROUPPRIVS() has to be safe to call - * before DROPUSERPRIVS() is called [this is needed because setgid() - * sets both effective and real uids if euid is root.] - * - * There's probably a better implementation if we're allowed to use - * BSD-style setreuid() rather than using POSIX saved-ids. - * Anyway, if you're euid root it's a bit pointless to drop the group - * permissions... - * - * I'm pretty happy that the security is good provided we aren't setuid root. - * The only things we trust with group=mail privilege are lkfopen() - * and lkfclose(). - */ +** This is an attempt to simplify things by putting all the +** privilege ops into macros. +** *GROUPPRIVS() is related to handling the setgid MAIL property, +** and only applies if MAILGROUP is defined. +** Basically, SAVEGROUPPRIVS() is called right at the top of main() +** to initialise things, and then DROPGROUPPRIVS() and GETGROUPPRIVS() +** do the obvious thing. TRYDROPGROUPPRIVS() has to be safe to call +** before DROPUSERPRIVS() is called [this is needed because setgid() +** sets both effective and real uids if euid is root.] +** +** There's probably a better implementation if we're allowed to use +** BSD-style setreuid() rather than using POSIX saved-ids. +** Anyway, if you're euid root it's a bit pointless to drop the group +** permissions... +** +** I'm pretty happy that the security is good provided we aren't setuid root. +** The only things we trust with group=mail privilege are lkfopen() +** and lkfclose(). +*/ /* - * For setting and returning to "mail" gid - */ +** For setting and returning to "mail" gid +*/ #ifdef MAILGROUP static int return_gid; -#ifndef POP -/* easy case; we're not setuid root, so can drop group privs - * immediately. - */ +/* +** easy case; we're not setuid root, so can drop group privs immediately. +*/ #define TRYDROPGROUPPRIVS() DROPGROUPPRIVS() -#else /* POP ie we are setuid root */ -#define TRYDROPGROUPPRIVS() \ -if (geteuid() != 0) DROPGROUPPRIVS() -#endif #define DROPGROUPPRIVS() setgid(getgid()) #define GETGROUPPRIVS() setgid(return_gid) #define SAVEGROUPPRIVS() return_gid = getegid() @@ -175,814 +108,389 @@ if (geteuid() != 0) DROPGROUPPRIVS() #define SAVEGROUPPRIVS() #endif /* not MAILGROUP */ -/* these variables have to be globals so that done() can correctly clean up the lockfile */ +/* +** these variables have to be globals so that done() can correctly clean +** up the lockfile +*/ static int locked = 0; static char *newmail; static FILE *in; /* - * prototypes - */ -char *map_name(char *); - +** prototypes +*/ static void inc_done(int) NORETURN; -#ifdef POP -static int pop_action(char *); -static int pop_pack(char *); -static int map_count(void); -#endif int -main (int argc, char **argv) +main(int argc, char **argv) { - int chgflag = 1, trnflag = 1; - int noisy = 1, width = 0; - int hghnum = 0, msgnum = 0; - int sasl = 0; - int incerr = 0; /* <0 if inc hits an error which means it should not truncate mailspool */ - char *cp, *maildir = NULL, *folder = NULL; - char *format = NULL, *form = NULL; - char *host = NULL, *port = NULL, *user = NULL, *proxy = NULL; - char *audfile = NULL, *from = NULL, *saslmech = NULL; - char buf[BUFSIZ], **argp, *nfs, **arguments; - struct msgs *mp = NULL; - struct stat st, s1; - FILE *aud = NULL; - char b[MAXPATHLEN + 1]; - char *maildir_copy = NULL; /* copy of mail directory because the static gets overwritten */ - -#ifdef POP - int nmsgs, nbytes; - char *pass = NULL; - char *MAILHOST_env_variable; -#endif - -#ifdef MHE - FILE *mhe = NULL; -#endif - - done=inc_done; + int chgflag = 1, trnflag = 1; + int noisy = 1, width = 0; + int hghnum = 0, msgnum = 0; + int incerr = 0; /* + ** <0 if inc hits an error which means it should + ** not truncate mailspool + */ + char *cp, *maildir = NULL, *folder = NULL; + char *form = NULL; + char *audfile = NULL, *from = NULL; + char buf[BUFSIZ], **argp, *fmtstr, **arguments; + struct msgs *mp = NULL; + struct stat st, s1; + FILE *aud = NULL; + char b[MAXPATHLEN + 1]; + /* copy of mail directory because the static gets overwritten */ + char *maildir_copy = NULL; + + done=inc_done; -/* absolutely the first thing we do is save our privileges, - * and drop them if we can. - */ - SAVEGROUPPRIVS(); - TRYDROPGROUPPRIVS(); - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - -#ifdef POP - /* - * Scheme is: - * use MAILHOST environment variable if present, - * else try Hesiod. - * If that fails, use the default (if any) - * provided by mts.conf in mts_init() - */ - if ((MAILHOST_env_variable = getenv("MAILHOST")) != NULL) - pophost = MAILHOST_env_variable; - /* - * If there is a valid "pophost" entry in mts.conf, - * then use it as the default host. - */ - if (pophost && *pophost) - host = pophost; - - if ((cp = getenv ("MHPOPDEBUG")) && *cp) - snoop++; -#endif /* POP */ - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [switches]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case AUDSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - audfile = getcpy (m_maildir (cp)); - continue; - case NAUDSW: - audfile = NULL; - continue; - - case CHGSW: - chgflag++; - continue; - case NCHGSW: - chgflag = 0; - continue; - - /* - * The flag `trnflag' has the value: - * - * 2 if -truncate is given - * 1 by default (truncating is default) - * 0 if -notruncate is given - */ - case TRNCSW: - trnflag = 2; - continue; - case NTRNCSW: - trnflag = 0; - continue; - - case FILESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - from = path (cp, TFILE); - - /* - * If the truncate file is in default state, - * change to not truncate. - */ - if (trnflag == 1) - trnflag = 0; - continue; - - case SILSW: - noisy = 0; - continue; - case NSILSW: - noisy++; - continue; - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - width = atoi (cp); - continue; - - case HOSTSW: - if (!(host = *argp++) || *host == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PORTSW: - if (!(host = *argp++) || *port == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case USERSW: - if (!(user = *argp++) || *user == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PACKSW: -#ifndef POP - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); -#else /* POP */ - if (!(packfile = *argp++) || *packfile == '-') - adios (NULL, "missing argument to %s", argp[-2]); -#endif /* POP */ - continue; - case NPACKSW: -#ifdef POP - packfile = NULL; -#endif /* POP */ - continue; - - case SNOOPSW: - snoop++; - continue; - - case SASLSW: - sasl++; - continue; - - case SASLMECHSW: - if (!(saslmech = *argp++) || *saslmech == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case PROXYSW: - if (!(proxy = *argp++) || *proxy == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - adios (NULL, "usage: %s [+folder] [switches]", invo_name); +/* +** absolutely the first thing we do is save our privileges, +** and drop them if we can. +*/ + SAVEGROUPPRIVS(); + TRYDROPGROUPPRIVS(); + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case AUDSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", argp[-2]); + audfile = getcpy(expanddir(cp)); + continue; + case NAUDSW: + audfile = NULL; + continue; + + case CHGSW: + chgflag++; + continue; + case NCHGSW: + chgflag = 0; + continue; + + /* + ** The flag `trnflag' has the value: + ** + ** 2 if -truncate is given + ** 1 by default (truncating is default) + ** 0 if -notruncate is given + */ + case TRNCSW: + trnflag = 2; + continue; + case NTRNCSW: + trnflag = 0; + continue; + + case FILESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + from = getcpy(expanddir(cp)); + + /* + ** If the truncate file is in default state, + ** change to not truncate. + */ + if (trnflag == 1) + trnflag = 0; + continue; + + case SILSW: + noisy = 0; + continue; + case NSILSW: + noisy++; + continue; + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WIDTHSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + width = atoi(cp); + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + adios(NULL, "usage: %s [+folder] [switches]", + invo_name); + } } - } - - /* NOTE: above this point you should use TRYDROPGROUPPRIVS(), - * not DROPGROUPPRIVS(). - */ -#ifdef POP - if (host && !*host) - host = NULL; -#endif /* POP */ - - /* guarantee dropping group priveleges; we might not have done so earlier */ - DROPGROUPPRIVS(); - - /* - * Where are we getting the new mail? - */ - if (from) - inc_type = INC_FILE; -#ifdef POP - else if (host) - inc_type = INC_POP; -#endif - else - inc_type = INC_FILE; - -#ifdef POP - /* - * Are we getting the mail from - * a POP server? - */ - if (inc_type == INC_POP) { - if (user == NULL) - user = getusername (); - if (sasl) - pass = getusername (); - else - ruserpass (host, &user, &pass); /* - * initialize POP connection - */ - if (pop_init (host, port, user, pass, proxy, snoop, sasl, - saslmech) == NOTOK) - adios (NULL, "%s", response); - - /* Check if there are any messages */ - if (pop_stat (&nmsgs, &nbytes) == NOTOK) - adios (NULL, "%s", response); - - if (nmsgs == 0) { - pop_quit(); - adios (NULL, "no mail to incorporate"); - } - } -#endif /* POP */ - - /* - * We will get the mail from a file - * (typically the standard maildrop) - */ + ** NOTE: above this point you should use TRYDROPGROUPPRIVS(), + ** not DROPGROUPPRIVS(). + */ + /* guarantee dropping group priveleges; we might not have done so earlier */ + DROPGROUPPRIVS(); - if (inc_type == INC_FILE) { + /* + ** We will get the mail from a file + ** (typically the standard maildrop) + */ if (from) - newmail = from; - else if ((newmail = getenv ("MAILDROP")) && *newmail) - newmail = m_mailpath (newmail); - else if ((newmail = context_find ("maildrop")) && *newmail) - newmail = m_mailpath (newmail); + newmail = from; + else if ((newmail = getenv("MAILDROP")) && *newmail) + newmail = toabsdir(newmail); + else if ((newmail = context_find("maildrop")) && *newmail) + newmail = toabsdir(newmail); else { - newmail = concat (MAILDIR, "/", MAILFIL, NULL); + newmail = concat(mailspool, "/", getusername(), NULL); } - if (stat (newmail, &s1) == NOTOK || s1.st_size == 0) - adios (NULL, "no mail to incorporate"); + if (stat(newmail, &s1) == NOTOK || s1.st_size == 0) + adios(NULL, "no mail to incorporate"); - if ((cp = strdup(newmail)) == (char *)0) - adios (NULL, "error allocating memory to copy newmail"); + if ((cp = strdup(newmail)) == NULL) + adios(NULL, "error allocating memory to copy newmail"); newmail = cp; - } - -#ifdef POP - /* skip the folder setup */ - if ((inc_type == INC_POP) && packfile) - goto go_to_it; -#endif /* POP */ - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!folder) - folder = getfolder (0); - maildir = m_maildir (folder); - - if ((maildir_copy = strdup(maildir)) == (char *)0) - adios (maildir, "error allocating memory to copy maildir"); - - if (!folder_exists(maildir)) { - /* If the folder doesn't exist, and we're given the -silent flag, - * just fail. - */ - if (noisy) - create_folder(maildir, 0, done); - else - done (1); - } - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - -#ifdef POP -go_to_it: -#endif /* POP */ - - if (inc_type == INC_FILE) { - if (access (newmail, W_OK) != NOTOK) { - locked++; - if (trnflag) { - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); - } - - GETGROUPPRIVS(); /* Reset gid to lock mail file */ - in = lkfopen (newmail, "r"); - DROPGROUPPRIVS(); - if (in == NULL) - adios (NULL, "unable to lock and fopen %s", newmail); - fstat (fileno(in), &s1); - } else { - trnflag = 0; - if ((in = fopen (newmail, "r")) == NULL) - adios (newmail, "unable to read"); - } - } - - /* This shouldn't be necessary but it can't hurt. */ - DROPGROUPPRIVS(); - - if (audfile) { - int i; - if ((i = stat (audfile, &st)) == NOTOK) - advise (NULL, "Creating Receive-Audit: %s", audfile); - if ((aud = fopen (audfile, "a")) == NULL) - adios (audfile, "unable to append to"); - else if (i == NOTOK) - chmod (audfile, m_gmprot ()); - -#ifdef POP - fprintf (aud, from ? "<> %s -ms %s\n" - : host ? "<> %s -host %s -user %s\n" - : "<> %s\n", - dtimenow (0), from ? from : host, user); -#else /* POP */ - fprintf (aud, from ? "<> %s -ms %s\n" : "<> %s\n", - dtimenow (0), from); -#endif /* POP */ - } - -#ifdef MHE - if (context_find ("mhe")) { - int i; - cp = concat (maildir, "/++", NULL); - i = stat (cp, &st); - if ((mhe = fopen (cp, "a")) == NULL) - admonish (cp, "unable to append to"); - else - if (i == NOTOK) - chmod (cp, m_gmprot ()); - free (cp); - } -#endif /* MHE */ - - /* Get new format string */ - nfs = new_fs (form, format, FORMAT); - - if (noisy) { - printf ("Incorporating new mail into %s...\n\n", folder); - fflush (stdout); - } - -#ifdef POP - /* - * Get the mail from a POP server - */ - if (inc_type == INC_POP) { - int i; - if (packfile) { - packfile = path (packfile, TFILE); - if (stat (packfile, &st) == NOTOK) { - if (errno != ENOENT) - adios (packfile, "error on file"); - cp = concat ("Create file \"", packfile, "\"? ", NULL); - if (noisy && !getanswer (cp)) - done (1); - free (cp); - } - msgnum = map_count (); - if ((pd = mbx_open (packfile, mbx_style, getuid(), getgid(), m_gmprot())) - == NOTOK) - adios (packfile, "unable to open"); - if ((pf = fdopen (pd, "w+")) == NULL) - adios (NULL, "unable to fdopen %s", packfile); - } else { - hghnum = msgnum = mp->hghmsg; - /* - * Check if we have enough message space for all the new - * messages. If not, then realloc the folder and add enough - * space for all new messages plus 10 additional slots. - */ - if (mp->hghmsg + nmsgs >= mp->hghoff - && !(mp = folder_realloc (mp, mp->lowoff, mp->hghmsg + nmsgs + 10))) - adios (NULL, "unable to allocate folder storage"); - } - for (i = 1; i <= nmsgs; i++) { - msgnum++; - if (packfile) { - fseek (pf, 0L, SEEK_CUR); - pos = ftell (pf); - size = 0; - fwrite (mmdlm1, 1, strlen (mmdlm1), pf); - start = ftell (pf); - - if (pop_retr (i, pop_pack) == NOTOK) - adios (NULL, "%s", response); - - fseek (pf, 0L, SEEK_CUR); - stop = ftell (pf); - if (fflush (pf)) - adios (packfile, "write error on"); - fseek (pf, start, SEEK_SET); - } else { - cp = getcpy (m_name (msgnum)); - if ((pf = fopen (cp, "w+")) == NULL) - adios (cp, "unable to write"); - chmod (cp, m_gmprot ()); - start = stop = 0L; - - if (pop_retr (i, pop_action) == NOTOK) - adios (NULL, "%s", response); - - if (fflush (pf)) - adios (cp, "write error on"); - fseek (pf, 0L, SEEK_SET); - } - switch (incerr = scan (pf, msgnum, 0, nfs, width, - packfile ? 0 : msgnum == mp->hghmsg + 1 && chgflag, - 1, NULL, stop - start, noisy)) { - case SCNEOF: - printf ("%*d empty\n", DMAXFOLDER, msgnum); - break; + if (!folder) + folder = getdeffol(); + maildir = toabsdir(folder); - case SCNFAT: - trnflag = 0; - noisy++; - /* advise (cp, "unable to read"); already advised */ - /* fall thru */ + if ((maildir_copy = strdup(maildir)) == NULL) + adios(maildir, "error allocating memory to copy maildir"); - case SCNERR: - case SCNNUM: - break; + create_folder(maildir, noisy ? 0 : 1, done); - case SCNMSG: - case SCNENC: - default: - if (aud) - fputs (scanl, aud); -# ifdef MHE - if (mhe) - fputs (scanl, mhe); -# endif /* MHE */ - if (noisy) - fflush (stdout); - if (!packfile) { - clear_msg_flags (mp, msgnum); - set_exists (mp, msgnum); - set_unseen (mp, msgnum); - mp->msgflags |= SEQMOD; - } - break; - } - if (packfile) { - fseek (pf, stop, SEEK_SET); - fwrite (mmdlm2, 1, strlen (mmdlm2), pf); - if (fflush (pf) || ferror (pf)) { - int e = errno; - pop_quit (); - errno = e; - adios (packfile, "write error on"); - } - map_write (packfile, pd, 0, 0L, start, stop, pos, size, noisy); - } else { - if (ferror(pf) || fclose (pf)) { - int e = errno; - unlink (cp); - pop_quit (); - errno = e; - adios (cp, "write error on"); + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + if (access(newmail, W_OK) != NOTOK) { + locked++; + if (trnflag) { + SIGNAL(SIGHUP, SIG_IGN); + SIGNAL(SIGINT, SIG_IGN); + SIGNAL(SIGQUIT, SIG_IGN); + SIGNAL(SIGTERM, SIG_IGN); } - free (cp); - } - if (trnflag && pop_dele (i) == NOTOK) - adios (NULL, "%s", response); + GETGROUPPRIVS(); /* Reset gid to lock mail file */ + in = lkfopen(newmail, "r"); + DROPGROUPPRIVS(); + if (in == NULL) + adios(NULL, "unable to lock and fopen %s", newmail); + fstat(fileno(in), &s1); + } else { + trnflag = 0; + if ((in = fopen(newmail, "r")) == NULL) + adios(newmail, "unable to read"); } - if (pop_quit () == NOTOK) - adios (NULL, "%s", response); - if (packfile) { - mbx_close (packfile, pd); - pd = NOTOK; + /* This shouldn't be necessary but it can't hurt. */ + DROPGROUPPRIVS(); + + if (audfile) { + int i; + if ((i = stat(audfile, &st)) == NOTOK) + advise(NULL, "Creating Receive-Audit: %s", audfile); + if ((aud = fopen(audfile, "a")) == NULL) + adios(audfile, "unable to append to"); + else if (i == NOTOK) + chmod(audfile, m_gmprot()); + + fprintf(aud, from ? "<> %s -ms %s\n" : "<> %s\n", + dtimenow(), from); } - } -#endif /* POP */ - - /* - * Get the mail from file (usually mail spool) - */ - if (inc_type == INC_FILE) { - m_unknown (in); /* the MAGIC invocation... */ - hghnum = msgnum = mp->hghmsg; - for (;;) { - /* - * Check if we need to allocate more space for message status. - * If so, then add space for an additional 100 messages. - */ - if (msgnum >= mp->hghoff - && !(mp = folder_realloc (mp, mp->lowoff, mp->hghoff + 100))) { - advise (NULL, "unable to allocate folder storage"); - incerr = NOTOK; - break; - } - -#if 0 - /* copy file from spool to tmp file */ - tmpfilenam = m_scratch ("", invo_name); - if ((fd = creat (tmpfilenam, m_gmprot ())) == NOTOK) - adios (tmpfilenam, "unable to create"); - chmod (tmpfilenam, m_gmprot ()); - if (!(in2 = fdopen (fd, "r+"))) - adios (tmpfilenam, "unable to access"); - cpymsg (in, in2); - - /* link message into folder */ - newmsg = folder_addmsg(mp, tmpfilenam); -#endif - /* create scanline for new message */ - switch (incerr = scan (in, msgnum + 1, msgnum + 1, nfs, width, - msgnum == hghnum && chgflag, 1, NULL, 0L, noisy)) { - case SCNFAT: - case SCNEOF: - break; - case SCNERR: - if (aud) - fputs ("inc aborted!\n", aud); - advise (NULL, "aborted!"); /* doesn't clean up locks! */ - break; + /* Get new format string */ + fmtstr = new_fs(form, FORMAT); - case SCNNUM: - advise (NULL, "BUG in %s, number out of range", invo_name); - break; + if (noisy) { + printf("Incorporating new mail into %s...\n\n", folder); + fflush(stdout); + } - default: - advise (NULL, "BUG in %s, scan() botch (%d)", invo_name, incerr); - break; + /* + ** Get the mail from file (usually mail spool) + */ + thisisanmbox(in); + hghnum = msgnum = mp->hghmsg; + for (;;) { + /* + ** Check if we need to allocate more space for message status. + ** If so, then add space for an additional 100 messages. + */ + if (msgnum >= mp->hghoff && !(mp = folder_realloc(mp, mp->lowoff, mp->hghoff + 100))) { + advise(NULL, "unable to allocate folder storage"); + incerr = NOTOK; + break; + } - case SCNMSG: - case SCNENC: + /* create scanline for new message */ + switch (incerr = scan(in, msgnum + 1, msgnum + 1, + noisy ? fmtstr : NULL, width, + msgnum == hghnum && chgflag, 1)) { + case SCNFAT: + case SCNEOF: + break; + + case SCNERR: + if (aud) + fputs("inc aborted!\n", aud); + /* doesn't clean up locks! */ + advise(NULL, "aborted!"); + break; + + case SCNNUM: + advise(NULL, "BUG in %s, number out of range", + invo_name); + break; + + default: + advise(NULL, "BUG in %s, scan() botch (%d)", + invo_name, incerr); + break; + + case SCNMSG: + /* + ** Run the external program hook on the message. + */ + + snprintf(b, sizeof (b), "%s/%d", maildir_copy, + msgnum + 1); + ext_hook("add-hook", b, NULL); + + if (aud) + fputs(scanl, aud); + if (noisy) + fflush(stdout); + msgnum++; + mp->hghmsg++; + mp->nummsg++; + if (mp->lowmsg == 0) + mp->lowmsg = 1; + clear_msg_flags(mp, msgnum); + set_exists(mp, msgnum); + set_unseen(mp, msgnum); + mp->msgflags |= SEQMOD; + continue; + } /* - * Run the external program hook on the message. - */ - - (void)snprintf(b, sizeof (b), "%s/%d", maildir_copy, msgnum + 1); - (void)ext_hook("add-hook", b, (char *)0); - - if (aud) - fputs (scanl, aud); -#ifdef MHE - if (mhe) - fputs (scanl, mhe); -#endif /* MHE */ - if (noisy) - fflush (stdout); - - msgnum++; - mp->hghmsg++; - mp->nummsg++; - if (mp->lowmsg == 0) mp->lowmsg = 1; - - clear_msg_flags (mp, msgnum); - set_exists (mp, msgnum); - set_unseen (mp, msgnum); - mp->msgflags |= SEQMOD; - continue; - } - /* If we get here there was some sort of error from scan(), - * so stop processing anything more from the spool. - */ - break; + ** If we get here there was some sort of error from scan(), + ** so stop processing anything more from the spool. + */ + break; } - } - - if (incerr < 0) { /* error */ - if (locked) { - GETGROUPPRIVS(); /* Be sure we can unlock mail file */ - (void) lkfclose (in, newmail); in = NULL; - DROPGROUPPRIVS(); /* And then return us to normal privileges */ - } else { - fclose (in); in = NULL; + free(maildir_copy); + + if (incerr < 0) { /* error */ + if (locked) { + GETGROUPPRIVS(); /* Be sure we can unlock mail file */ + lkfclose(in, newmail); in = NULL; + DROPGROUPPRIVS(); /* + ** And then return us to normal + ** privileges + */ + } else { + fclose(in); in = NULL; + } + adios(NULL, "failed"); } - adios (NULL, "failed"); - } - - if (aud) - fclose (aud); -#ifdef MHE - if (mhe) - fclose (mhe); -#endif /* MHE */ + if (aud) + fclose(aud); - if (noisy) - fflush (stdout); + if (noisy) + fflush(stdout); -#ifdef POP - if ((inc_type == INC_POP) && packfile) - done (0); -#endif /* POP */ - - /* - * truncate file we are incorporating from - */ - if (inc_type == INC_FILE) { + /* + ** truncate file we are incorporating from + */ if (trnflag) { - if (stat (newmail, &st) != NOTOK && s1.st_mtime != st.st_mtime) - advise (NULL, "new messages have arrived!\007"); - else { - int newfd; - if ((newfd = creat (newmail, 0600)) != NOTOK) - close (newfd); - else - admonish (newmail, "error zero'ing"); - unlink(map_name(newmail)); - } + if (stat(newmail, &st) != NOTOK && s1.st_mtime != st.st_mtime) + advise(NULL, "new messages have arrived!\007"); + else { + int newfd; + if ((newfd = creat(newmail, 0600)) != NOTOK) + close(newfd); + else + admonish(newmail, "error zero'ing"); + } + } else if (noisy) { + printf("%s not zero'd\n", newmail); + } + + if (msgnum == hghnum) { + admonish(NULL, "no messages incorporated"); } else { - if (noisy) - printf ("%s not zero'd\n", newmail); + context_replace(curfolder, folder); /* update current folder */ + if (chgflag) + mp->curmsg = hghnum + 1; + mp->hghmsg = msgnum; + if (mp->lowmsg == 0) + mp->lowmsg = 1; + if (chgflag) /* sigh... */ + seq_setcur(mp, mp->curmsg); } - } - - if (msgnum == hghnum) { - admonish (NULL, "no messages incorporated"); - } else { - context_replace (pfolder, folder); /* update current folder */ - if (chgflag) - mp->curmsg = hghnum + 1; - mp->hghmsg = msgnum; - if (mp->lowmsg == 0) - mp->lowmsg = 1; - if (chgflag) /* sigh... */ - seq_setcur (mp, mp->curmsg); - } - - /* - * unlock the mail spool - */ - if (inc_type == INC_FILE) { + + /* + ** unlock the mail spool + */ if (locked) { - GETGROUPPRIVS(); /* Be sure we can unlock mail file */ - (void) lkfclose (in, newmail); in = NULL; - DROPGROUPPRIVS(); /* And then return us to normal privileges */ + GETGROUPPRIVS(); /* Be sure we can unlock mail file */ + lkfclose(in, newmail); in = NULL; + DROPGROUPPRIVS(); /* And then return us to normal privileges */ } else { - fclose (in); in = NULL; + fclose(in); in = NULL; } - } - - seq_setunseen (mp, 0); /* set the Unseen-Sequence */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - done (0); - return 1; -} - -#if 0 - -/* - * Copy message message from spool into - * temporary file. Massage the "From " line - * while copying. - */ - -cpymsg (FILE *in, FILE *out) -{ - int state; - char *tmpbuf, name[NAMESZ]; - - for (;;) { - state = m_getfld (state, name, tmpbuf, rlwidth, in); - switch (state) { - case FLD: - case FLDPLUS: - break; - case BODY: - break; - case LENERR: - case FMTERR: - break; - case FILEEOF: - break; - default: - } - } + seq_setunseen(mp, 1); /* add new msgs to unseen sequences */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ + done(0); + return 1; } -#endif /* if 0 */ - static void -inc_done (int status) -{ -#ifdef POP - if (packfile && pd != NOTOK) - mbx_close (packfile, pd); -#endif /* POP */ - if (locked) - { - GETGROUPPRIVS(); - lkfclose(in, newmail); - DROPGROUPPRIVS(); - } - exit (status); -} - -#ifdef POP -static int -pop_action (char *s) -{ - fprintf (pf, "%s\n", s); - stop += strlen (s) + 1; - return 0; /* Is return value used? This was missing before 1999-07-15. */ -} - -static int -pop_pack (char *s) -{ - int j; - char buffer[BUFSIZ]; - - snprintf (buffer, sizeof(buffer), "%s\n", s); - for (j = 0; (j = stringdex (mmdlm1, buffer)) >= 0; buffer[j]++) - continue; - for (j = 0; (j = stringdex (mmdlm2, buffer)) >= 0; buffer[j]++) - continue; - fputs (buffer, pf); - size += strlen (buffer) + 1; - return 0; /* Is return value used? This was missing before 1999-07-15. */ -} - -static int -map_count (void) +inc_done(int status) { - int md; - char *cp; - struct drop d; - struct stat st; - - if (stat (packfile, &st) == NOTOK) - return 0; - if ((md = open (cp = map_name (packfile), O_RDONLY)) == NOTOK - || map_chk (cp, md, &d, (long) st.st_size, 1)) { - if (md != NOTOK) - close (md); - return 0; - } - close (md); - return (d.d_id); + if (locked) { + GETGROUPPRIVS(); + lkfclose(in, newmail); + DROPGROUPPRIVS(); + } + exit(status); } -#endif /* POP */ diff --git a/uip/install-mh.c b/uip/install-mh.c deleted file mode 100644 index c484771..0000000 --- a/uip/install-mh.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * install-mh.c -- initialize the nmh environment of a new user - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include /* mh internals */ -#include -#include /* structure for getpwuid() results */ - -static struct swit switches[] = { -#define AUTOSW 0 - { "auto", 0 }, -#define VERSIONSW 1 - { "version", 0 }, -#define HELPSW 2 - { "help", 0 }, -#define CHECKSW 3 - { "check", 1 }, - { NULL, 0 } -}; - -/* - * static prototypes - */ -static char *geta(void); - - -int -main (int argc, char **argv) -{ - int autof = 0; - char *cp, *pathname, buf[BUFSIZ]; - char *dp, **arguments, **argp; - struct node *np; - struct passwd *pw; - struct stat st; - FILE *in, *out; - int check; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - check = 0; - - while ((dp = *argp++)) { - if (*dp == '-') { - switch (smatch (++dp, switches)) { - case AMBIGSW: - ambigsw (dp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", dp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches]", invo_name); - print_help (buf, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case AUTOSW: - autof++; - continue; - - case CHECKSW: - check = 1; - continue; - } - } else { - adios (NULL, "%s is invalid argument", dp); - } - } - - /* - * Find user's home directory. Try the HOME environment variable first, - * the home directory field in the password file if that's not found. - */ - - if ((mypath = getenv("HOME")) == (char *)0) { - if ((pw = getpwuid(getuid())) == (struct passwd *)0 || *pw->pw_dir == '\0') - adios(NULL, "cannot determine your home directory"); - else - mypath = pw->pw_dir; - } - - /* - * Find the user's profile. Check for the existence of an MH environment - * variable first with non-empty contents. Convert any relative path name - * found there to an absolute one. Look for the profile in the user's home - * directory if the MH environment variable isn't set. - */ - - if ((cp = getenv("MH")) && *cp != '\0') - defpath = path(cp, TFILE); - else - defpath = concat(mypath, "/", mh_profile, NULL); - - /* - * Check for the existence of the profile file. It's an error if it exists and - * this isn't an installation check. An installation check fails if it does not - * exist, succeeds if it does. - */ - - if (stat (defpath, &st) != NOTOK) { - if (check) - done(0); - - else if (autof) - adios (NULL, "invocation error"); - else - adios (NULL, "You already have an nmh profile, use an editor to modify it"); - } - else if (check) { - done(1); - } - - if (!autof && gans ("Do you want help? ", anoyes)) { - (void)printf( - "\n" - "Prior to using nmh, it is necessary to have a file in your login\n" - "directory (%s) named %s which contains information\n" - "to direct certain nmh operations. The only item which is required\n" - "is the path to use for all nmh folder operations. The suggested nmh\n" - "path for you is %s/Mail...\n" - "\n", mypath, mh_profile, mypath); - } - - cp = concat (mypath, "/", "Mail", NULL); - if (stat (cp, &st) != NOTOK) { - if (S_ISDIR(st.st_mode)) { - cp = concat ("You already have the standard nmh directory \"", - cp, "\".\nDo you want to use it for nmh? ", NULL); - if (gans (cp, anoyes)) - pathname = "Mail"; - else - goto query; - } else { - goto query; - } - } else { - if (autof) - printf ("I'm going to create the standard nmh path for you.\n"); - else - cp = concat ("Do you want the standard nmh path \"", - mypath, "/", "Mail\"? ", NULL); - if (autof || gans (cp, anoyes)) - pathname = "Mail"; - else { -query: - if (gans ("Do you want a path below your login directory? ", - anoyes)) { - printf ("What is the path? %s/", mypath); - pathname = geta (); - } else { - printf ("What is the whole path? /"); - pathname = concat ("/", geta (), NULL); - } - } - } - - chdir (mypath); - if (chdir (pathname) == NOTOK) { - cp = concat ("\"", pathname, "\" doesn't exist; Create it? ", NULL); - if (autof || gans (cp, anoyes)) - if (makedir (pathname) == 0) - adios (NULL, "unable to create %s", pathname); - } else { - printf ("[Using existing directory]\n"); - } - - /* - * Add some initial elements to the profile/context list - */ - m_defs = (struct node *) mh_xmalloc (sizeof *np); - np = m_defs; - np->n_name = getcpy ("Path"); - np->n_field = getcpy (pathname); - np->n_context = 0; - np->n_next = NULL; - - /* - * If there is a default profile file in the - * nmh `etc' directory, then read it also. - */ - if ((in = fopen (mh_defaults, "r"))) { - readconfig (&np->n_next, in, mh_defaults, 0); - fclose (in); - } - - ctxpath = getcpy (m_maildir (context = "context")); - - /* Initialize current folder to default */ - context_replace (pfolder, defaultfolder); - context_save (); - - /* - * Now write out the initial .mh_profile - */ - if ((out = fopen (defpath, "w")) == NULL) - adios (defpath, "unable to write"); - for (np = m_defs; np; np = np->n_next) { - if (!np->n_context) - fprintf (out, "%s: %s\n", np->n_name, np->n_field); - } - fclose (out); - done (0); - return 1; -} - - -static char * -geta (void) -{ - char *cp; - static char line[BUFSIZ]; - - fflush(stdout); - if (fgets(line, sizeof(line), stdin) == NULL) - done (1); - if ((cp = strchr(line, '\n'))) - *cp = 0; - return line; -} diff --git a/uip/mark.c b/uip/mark.c index dd09b48..d4a3729 100644 --- a/uip/mark.c +++ b/uip/mark.c @@ -1,276 +1,270 @@ - /* - * mark.c -- add message(s) to sequences in given folder - * -- delete messages (s) from sequences in given folder - * -- list sequences in given folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mark.c -- add message(s) to sequences in given folder +** -- delete messages (s) from sequences in given folder +** -- list sequences in given folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include static struct swit switches[] = { -#define ADDSW 0 - { "add", 0 }, -#define DELSW 1 - { "delete", 0 }, -#define LSTSW 2 - { "list", 0 }, -#define SEQSW 3 - { "sequence name", 0 }, -#define PUBLSW 4 - { "public", 0 }, -#define NPUBLSW 5 - { "nopublic", 0 }, -#define ZEROSW 6 - { "zero", 0 }, -#define NZEROSW 7 - { "nozero", 0 }, -#define VERSIONSW 8 - { "version", 0 }, -#define HELPSW 9 - { "help", 0 }, -#define DEBUGSW 10 - { "debug", -5 }, - { NULL, 0 } +#define ADDSW 0 + { "add", 0 }, +#define DELSW 1 + { "delete", 0 }, +#define LSTSW 2 + { "list", 0 }, +#define SEQSW 3 + { "sequence name", 0 }, +#define PUBLSW 4 + { "public", 0 }, +#define NPUBLSW 5 + { "nopublic", 2 }, +#define ZEROSW 6 + { "zero", 0 }, +#define NZEROSW 7 + { "nozero", 2 }, +#define VERSIONSW 8 + { "Version", 0 }, +#define HELPSW 9 + { "help", 0 }, +#define DEBUGSW 10 + { "debug", -5 }, + { NULL, 0 } }; /* - * static prototypes - */ -static void print_debug (struct msgs *); -static void seq_printdebug (struct msgs *); +** static prototypes +*/ +static void print_debug(struct msgs *); +static void seq_printdebug(struct msgs *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int addsw = 0, deletesw = 0, debugsw = 0; - int listsw = 0, publicsw = -1, zerosw = 0; - int seqp = 0, msgnum; - char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments; - char *seqs[NUMATTRS + 1]; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ADDSW: - addsw++; - deletesw = listsw = 0; - continue; - case DELSW: - deletesw++; - addsw = listsw = 0; - continue; - case LSTSW: - listsw++; - addsw = deletesw = 0; - continue; - - case SEQSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - - /* check if too many sequences specified */ - if (seqp >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) specified", NUMATTRS); - seqs[seqp++] = cp; - continue; - - case PUBLSW: - publicsw = 1; - continue; - case NPUBLSW: - publicsw = 0; - continue; - - case DEBUGSW: - debugsw++; - continue; - - case ZEROSW: - zerosw++; - continue; - case NZEROSW: - zerosw = 0; - continue; - } + int addsw = 0, deletesw = 0, debugsw = 0; + int listsw = 0, publicsw = -1, zerosw = 0, msgnum; + unsigned int seqp = 0; + char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; + char **argp, **arguments; + char *seqs[NUMATTRS + 1]; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case ADDSW: + addsw++; + deletesw = listsw = 0; + continue; + case DELSW: + deletesw++; + addsw = listsw = 0; + continue; + case LSTSW: + listsw++; + addsw = deletesw = 0; + continue; + + case SEQSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + + /* check if too many sequences specified */ + if (seqp >= NUMATTRS) + adios(NULL, "too many sequences (more than %d) specified", NUMATTRS); + seqs[seqp++] = cp; + continue; + + case PUBLSW: + publicsw = 1; + continue; + case NPUBLSW: + publicsw = 0; + continue; + + case DEBUGSW: + debugsw++; + continue; + + case ZEROSW: + zerosw++; + continue; + case NZEROSW: + zerosw = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* - * If we haven't specified -add, -delete, or -list, - * then use -add if a sequence was specified, else - * use -list. - */ - if (!addsw && !deletesw && !listsw) { - if (seqp) - addsw++; - else - listsw++; - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!msgs.size) - app_msgarg(&msgs, listsw ? "all" :"cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* print some general debugging info */ - if (debugsw) - print_debug(mp); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - - if (publicsw == 1 && is_readonly(mp)) - adios (NULL, "folder %s is read-only, so -public not allowed", folder); - - /* - * Make sure at least one sequence has been - * specified if we are adding or deleting. - */ - if (seqp == 0 && (addsw || deletesw)) - adios (NULL, "-%s requires at least one -sequence argument", - addsw ? "add" : "delete"); - seqs[seqp] = NULL; - - /* Adding messages to sequences */ - if (addsw) { - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_addsel (mp, seqs[seqp], publicsw, zerosw)) - done (1); - } - - /* Deleting messages from sequences */ - if (deletesw) { - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_delsel (mp, seqs[seqp], publicsw, zerosw)) - done (1); - } - - /* Listing messages in sequences */ - if (listsw) { - if (seqp) { - /* print the sequences given */ - for (seqp = 0; seqs[seqp]; seqp++) - seq_print (mp, seqs[seqp]); - } else { - /* else print them all */ - seq_printall (mp); + + /* + ** If we haven't specified -add, -delete, or -list, + ** then use -add if a sequence was specified, else + ** use -list. + */ + if (!addsw && !deletesw && !listsw) { + if (seqp) + addsw++; + else + listsw++; } - /* print debugging info about SELECTED messages */ + if (!msgs.size) + app_msgarg(&msgs, listsw ? seq_all : seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* print some general debugging info */ if (debugsw) - seq_printdebug (mp); - } - - seq_save (mp); /* synchronize message sequences */ - context_replace (pfolder, folder); /* update current folder */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; + print_debug(mp); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + + if (publicsw == 1 && is_readonly(mp)) + adios(NULL, "folder %s is read-only, so -public not allowed", + folder); + + /* + ** Make sure at least one sequence has been + ** specified if we are adding or deleting. + */ + if (seqp == 0 && (addsw || deletesw)) + adios(NULL, "-%s requires at least one -sequence argument", + addsw ? "add" : "delete"); + seqs[seqp] = NULL; + + /* Adding messages to sequences */ + if (addsw) { + for (seqp = 0; seqs[seqp]; seqp++) + if (!seq_addsel(mp, seqs[seqp], publicsw, zerosw)) + done(1); + } + + /* Deleting messages from sequences */ + if (deletesw) { + for (seqp = 0; seqs[seqp]; seqp++) + if (!seq_delsel(mp, seqs[seqp], publicsw, zerosw)) + done(1); + } + + /* Listing messages in sequences */ + if (listsw) { + if (seqp) { + /* print the sequences given */ + for (seqp = 0; seqs[seqp]; seqp++) + seq_print(mp, seqs[seqp]); + } else { + /* else print them all */ + seq_printall(mp); + } + + /* print debugging info about SELECTED messages */ + if (debugsw) + seq_printdebug(mp); + } + + seq_save(mp); /* synchronize message sequences */ + context_replace(curfolder, folder); /* update current folder */ + context_save(); /* save the context file */ + folder_free(mp); /* free folder/message structure */ + done(0); + return 1; } /* - * Print general debugging info - */ +** Print general debugging info +*/ static void -print_debug (struct msgs *mp) +print_debug(struct msgs *mp) { - char buf[100]; - - printf ("invo_name = %s\n", invo_name); - printf ("mypath = %s\n", mypath); - printf ("defpath = %s\n", defpath); - printf ("ctxpath = %s\n", ctxpath); - printf ("context flags = %s\n", snprintb (buf, sizeof(buf), - (unsigned) ctxflags, DBITS)); - printf ("foldpath = %s\n", mp->foldpath); - printf ("folder flags = %s\n\n", snprintb(buf, sizeof(buf), - (unsigned) mp->msgflags, FBITS)); - printf ("lowmsg=%d hghmsg=%d nummsg=%d curmsg=%d\n", - mp->lowmsg, mp->hghmsg, mp->nummsg, mp->curmsg); - printf ("lowsel=%d hghsel=%d numsel=%d\n", - mp->lowsel, mp->hghsel, mp->numsel); - printf ("lowoff=%d hghoff=%d\n\n", mp->lowoff, mp->hghoff); + char buf[100]; + + printf("invo_name = %s\n", invo_name); + printf("mypath = %s\n", mypath); + printf("defpath = %s\n", defpath); + printf("ctxpath = %s\n", ctxpath); + printf("context flags = %s\n", snprintb(buf, sizeof(buf), + (unsigned) ctxflags, DBITS)); + printf("foldpath = %s\n", mp->foldpath); + printf("folder flags = %s\n\n", snprintb(buf, sizeof(buf), + (unsigned) mp->msgflags, FBITS)); + printf("lowmsg=%d hghmsg=%d nummsg=%d curmsg=%d\n", + mp->lowmsg, mp->hghmsg, mp->nummsg, mp->curmsg); + printf("lowsel=%d hghsel=%d numsel=%d\n", + mp->lowsel, mp->hghsel, mp->numsel); + printf("lowoff=%d hghoff=%d\n\n", mp->lowoff, mp->hghoff); } /* - * Print debugging info about all the SELECTED - * messages and the sequences they are in. - */ +** Print debugging info about all the SELECTED +** messages and the sequences they are in. +*/ static void -seq_printdebug (struct msgs *mp) +seq_printdebug(struct msgs *mp) { - int msgnum; - char buf[100]; - - printf ("\n"); - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) - printf ("%*d: %s\n", DMAXFOLDER, msgnum, - snprintb (buf, sizeof(buf), - (unsigned) mp->msgstats[msgnum - mp->lowoff], seq_bits (mp))); - } + int msgnum; + char buf[100]; + + printf("\n"); + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) + printf("%*d: %s\n", DMAXFOLDER, msgnum, snprintb(buf, sizeof(buf), (unsigned) mp->msgstats[msgnum - mp->lowoff], seq_bits(mp))); + } } diff --git a/uip/md5.c b/uip/md5.c deleted file mode 100644 index 5e0ab3b..0000000 --- a/uip/md5.c +++ /dev/null @@ -1,306 +0,0 @@ - -/* - * md5.c -- md5 message digest algorithm - * taken from RFC-1321/Appendix A.3 - */ - -/* - * MD5C.C -- RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* - * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All - * rights reserved. - * - * License to copy and use this software is granted provided that it - * is identified as the "RSA Data Security, Inc. MD5 Message-Digest - * Algorithm" in all material mentioning or referencing this software - * or this function. - * - * License is also granted to make and use derivative works provided - * that such works are identified as "derived from the RSA Data - * Security, Inc. MD5 Message-Digest Algorithm" in all material - * mentioning or referencing the derived work. - * - * RSA Data Security, Inc. makes no representations concerning either - * the merchantability of this software or the suitability of this - * software for any particular purpose. It is provided "as is" - * without express or implied warranty of any kind. - * - * These notices must be retained in any copies of any part of this - * documentation and/or software. - */ - -#include - -/* - * Constants for MD5Transform routine. - */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); -static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int)); -static void Decode PROTO_LIST ((UINT4 *, unsigned char *, unsigned int)); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -void MD5Init (context) -MD5_CTX *context; /* context */ -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. -*/ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -void MD5Update (context, input, inputLen) -MD5_CTX *context; /* context */ -unsigned char *input; /* input block */ -unsigned int inputLen; /* length of input block */ -{ - unsigned int i, index, partLen; - - /* Compute number of bytes mod 64 */ - index = (unsigned int)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - index; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) { - memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); - MD5Transform (context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform (context->state, &input[i]); - - index = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); -} - -/* - * MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -void MD5Final (digest, context) -unsigned char digest[16]; /* message digest */ -MD5_CTX *context; /* context */ -{ - unsigned char bits[8]; - unsigned int index, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. -*/ - index = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - MD5Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update (context, bits, 8); - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset ((POINTER)context, 0, sizeof(*context)); -} - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform (state, block) -UINT4 state[4]; -unsigned char block[64]; -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset ((POINTER)x, 0, sizeof(x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (output, input, len) -unsigned char *output; -UINT4 *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode (output, input, len) -UINT4 *output; -unsigned char *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} - diff --git a/uip/mhbuild.c b/uip/mhbuild.c index 1e86290..5ad0fc1 100644 --- a/uip/mhbuild.c +++ b/uip/mhbuild.c @@ -1,402 +1,1641 @@ +/* +** mhbuild.c -- expand/translate MIME composition files +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ /* - * mhbuild.c -- expand/translate MIME composition files - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** This code was originally part of mhn.c. I split it into +** a separate program (mhbuild.c). But the code still has some of +** the mhn.c code in it. This program needs additional +** streamlining and removal of unneeded code. +*/ #include #include #include -#include #include #include -#include #include #include #include -#include #include -#ifdef HAVE_SYS_WAIT_H -# include +#ifdef HAVE_SYS_TIME_H +# include #endif +#include static struct swit switches[] = { -#define CHECKSW 0 - { "check", 0 }, -#define NCHECKSW 1 - { "nocheck", 0 }, -#define EBCDICSW 2 - { "ebcdicsafe", 0 }, -#define NEBCDICSW 3 - { "noebcdicsafe", 0 }, -#define HEADSW 4 - { "headers", 0 }, -#define NHEADSW 5 - { "noheaders", 0 }, -#define LISTSW 6 - { "list", 0 }, -#define NLISTSW 7 - { "nolist", 0 }, -#define SIZESW 8 - { "realsize", 0 }, -#define NSIZESW 9 - { "norealsize", 0 }, -#define RFC934SW 10 - { "rfc934mode", 0 }, -#define NRFC934SW 11 - { "norfc934mode", 0 }, -#define VERBSW 12 - { "verbose", 0 }, -#define NVERBSW 13 - { "noverbose", 0 }, -#define RCACHESW 14 - { "rcache policy", 0 }, -#define WCACHESW 15 - { "wcache policy", 0 }, -#define CONTENTIDSW 16 - { "contentid", 0 }, -#define NCONTENTIDSW 17 - { "nocontentid", 0 }, -#define VERSIONSW 18 - { "version", 0 }, -#define HELPSW 19 - { "help", 0 }, -#define DEBUGSW 20 - { "debug", -5 }, - { NULL, 0 } +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, +#define DEBUGSW 4 + { "debug", -5 }, + { NULL, 0 } }; -/* mhbuildsbr.c */ -extern char *tmp; /* directory to place temp files */ +/* +** Directory to place tmp files. This must +** be set before these routines are called. +*/ +char *tmp; + +pid_t xpid = 0; + +static char prefix[] = "----- =_aaaaaaaaaa"; + + +/* +** prototypes +*/ + +/* mhmisc.c */ +int make_intermediates(char *); +void content_error(char *, CT, char *, ...); + +/* mhfree.c */ +void free_content(CT); +void free_ctinfo(CT); +void free_encoding(CT, int); + +/* +** static prototypes +*/ +static int init_decoded_content(CT); +static char *fgetstr(char *, int, FILE *); +static int user_content(FILE *, char *, char *, CT *); +static void set_id(CT, int); +static int compose_content(CT); +static int scan_content(CT); +static int build_headers(CT); +static CT build_mime(char *); -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; int debugsw = 0; int verbosw = 0; -int ebcdicsw = 0; -int listsw = 0; -int rfc934sw = 0; -int contentidsw = 1; - /* - * Temporary files - */ +** Temporary files +*/ static char infile[BUFSIZ]; static int unlink_infile = 0; static char outfile[BUFSIZ]; static int unlink_outfile = 0; -static void unlink_done (int) NORETURN; - -/* mhbuildsbr.c */ -CT build_mime (char *); -int output_message (CT, char *); -int output_message_fp (CT, FILE *, char*); +static void unlink_done(int) NORETURN; -/* mhlistsbr.c */ -int list_all_messages (CT *, int, int, int, int); +/* mhoutsbr.c */ +int output_message(CT, char *); +int output_message_fp(CT, FILE *, char*); /* mhmisc.c */ -void set_endian (void); +void set_endian(void); /* mhfree.c */ -void free_content (CT); +void free_content(CT); int -main (int argc, char **argv) +main(int argc, char **argv) { - int sizesw = 1, headsw = 1; - int *icachesw; - char *cp, buf[BUFSIZ]; - char buffer[BUFSIZ], *compfile = NULL; - char **argp, **arguments; - CT ct, cts[2]; - FILE *fp = NULL; - FILE *fp_out = NULL; - - done=unlink_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (cp[0] == '-' && cp[1] == '\0') { - if (compfile) - adios (NULL, "cannot specify both standard input and a file"); - else - compfile = cp; - listsw = 0; /* turn off -list if using standard in/out */ - verbosw = 0; /* turn off -verbose listings */ - break; - } - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; - do_cache: ; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); - default: - break; + char *cp, buf[BUFSIZ]; + char buffer[BUFSIZ], *compfile = NULL; + char **argp, **arguments; + CT ct, cts[2]; + FILE *fp = NULL; + FILE *fp_out = NULL; + + done = unlink_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (cp[0] == '-' && cp[1] == '\0') { + if (compfile) + adios(NULL, "cannot specify both standard input and a file"); + else + compfile = cp; + verbosw = 0; /* turn off -verbose listings */ + break; + } + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] file", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case VERBSW: + verbosw++; + continue; + case NVERBSW: + verbosw = 0; + continue; + case DEBUGSW: + debugsw = 1; + continue; + } } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case EBCDICSW: - ebcdicsw++; - continue; - case NEBCDICSW: - ebcdicsw = 0; - continue; - - case HEADSW: - headsw++; - continue; - case NHEADSW: - headsw = 0; - continue; - - case LISTSW: - listsw++; - continue; - case NLISTSW: - listsw = 0; - continue; - - case RFC934SW: - rfc934sw++; - continue; - case NRFC934SW: - rfc934sw = 0; - continue; - - case SIZESW: - sizesw++; - continue; - case NSIZESW: - sizesw = 0; - continue; - - case CONTENTIDSW: - contentidsw = 1; - continue; - case NCONTENTIDSW: - contentidsw = 0; - continue; - - case VERBSW: - verbosw++; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } - } - if (compfile) - adios (NULL, "only one composition file allowed"); + if (compfile) + adios(NULL, "only one composition file allowed"); + else + compfile = cp; + } + + set_endian(); + + /* + ** Check if we've specified an additional profile + */ + if ((cp = getenv("MHBUILD"))) { + if ((fp = fopen(cp, "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); + } else { + admonish("", "unable to read $MHBUILD profile (%s)", + cp); + } + } + + /* + ** Read the standard profile setup + */ + if ((fp = fopen(cp = etcpath("mhn.defaults"), "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); + } + + /* + ** Check for storage directory. If defined, we + ** will store temporary files there. Else we + ** store them in standard nmh directory. + */ + if ((cp = context_find(nmhstorage)) && *cp) + tmp = concat(cp, "/", invo_name, NULL); else - compfile = cp; - } + tmp = getcpy(toabsdir(invo_name)); - set_endian (); + /* Check if we have a file to process */ + if (!compfile) + adios(NULL, "need to specify a %s composition file", + invo_name); - if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1")) - listsw = 0; + /* + ** Process the composition file from standard input. + */ + if (compfile[0] == '-' && compfile[1] == '\0') { + /* copy standard input to temporary file */ + strncpy(infile, m_mktemp(invo_name, NULL, &fp), + sizeof(infile)); + while (fgets(buffer, BUFSIZ, stdin)) + fputs(buffer, fp); + fclose(fp); + unlink_infile = 1; - /* - * Check if we've specified an additional profile - */ - if ((cp = getenv ("MHBUILD"))) { - if ((fp = fopen (cp, "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } else { - admonish ("", "unable to read $MHBUILD profile (%s)", cp); - } - } - - /* - * Read the standard profile setup - */ - if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Check for storage directory. If defined, we - * will store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* Check if we have a file to process */ - if (!compfile) - adios (NULL, "need to specify a %s composition file", invo_name); - - /* - * Process the composition file from standard input. - */ - if (compfile[0] == '-' && compfile[1] == '\0') { - /* copy standard input to temporary file */ - strncpy (infile, m_mktemp(invo_name, NULL, &fp), sizeof(infile)); - while (fgets (buffer, BUFSIZ, stdin)) - fputs (buffer, fp); - fclose (fp); - unlink_infile = 1; + /* build the content structures for MIME message */ + ct = build_mime(infile); + cts[0] = ct; + cts[1] = NULL; + + /* output MIME message to this temporary file */ + strncpy(outfile, m_mktemp(invo_name, NULL, &fp_out), + sizeof(outfile)); + unlink_outfile = 1; + + /* output the message */ + output_message_fp(ct, fp_out, outfile); + fclose(fp_out); + + /* output the temp file to standard output */ + if ((fp = fopen(outfile, "r")) == NULL) + adios(outfile, "unable to open"); + while (fgets(buffer, BUFSIZ, fp)) + fputs(buffer, stdout); + fclose(fp); + + unlink(infile); + unlink_infile = 0; + + unlink(outfile); + unlink_outfile = 0; + + free_content(ct); + done(0); + } + + /* + ** Process the composition file from a file. + */ /* build the content structures for MIME message */ - ct = build_mime (infile); + ct = build_mime(compfile); cts[0] = ct; cts[1] = NULL; /* output MIME message to this temporary file */ - strncpy (outfile, m_mktemp(invo_name, NULL, &fp_out), sizeof(outfile)); + strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out), + sizeof(outfile)); unlink_outfile = 1; /* output the message */ - output_message_fp (ct, fp_out, outfile); - fclose(fp_out); - - /* output the temp file to standard output */ - if ((fp = fopen (outfile, "r")) == NULL) - adios (outfile, "unable to open"); - while (fgets (buffer, BUFSIZ, fp)) - fputs (buffer, stdout); - fclose (fp); + output_message_fp(ct, fp_out, outfile); + fclose(fp_out); - unlink (infile); - unlink_infile = 0; + /* Rename composition draft */ + snprintf(buffer, sizeof(buffer), "%s.orig", compfile); + if (rename(compfile, buffer) == NOTOK) { + adios(buffer, "unable to rename draft %s to", compfile); + } - unlink (outfile); + /* Rename output file to take its place */ + if (rename(outfile, compfile) == NOTOK) { + advise(compfile, "unable to rename output %s to", outfile); + rename(buffer, compfile); + done(1); + } unlink_outfile = 0; - free_content (ct); - done (0); - } - - /* - * Process the composition file from a file. - */ - - /* build the content structures for MIME message */ - ct = build_mime (compfile); - cts[0] = ct; - cts[1] = NULL; - - /* output MIME message to this temporary file */ - strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out), - sizeof(outfile)); - unlink_outfile = 1; - - /* output the message */ - output_message_fp (ct, fp_out, outfile); - fclose(fp_out); - - /* - * List the message info - */ - if (listsw) - list_all_messages (cts, headsw, sizesw, verbosw, debugsw); - - /* Rename composition draft */ - snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile)); - if (rename (compfile, buffer) == NOTOK) { - adios (compfile, "unable to rename comp draft %s to", buffer); - } - - /* Rename output file to take its place */ - if (rename (outfile, compfile) == NOTOK) { - advise (outfile, "unable to rename output %s to", compfile); - rename (buffer, compfile); - done (1); - } - unlink_outfile = 0; - - free_content (ct); - done (0); - return 1; + free_content(ct); + done(0); + return 1; +} + + +static void +unlink_done(int status) +{ + /* + ** Check if we need to remove stray temporary files. + */ + if (unlink_infile) + unlink(infile); + if (unlink_outfile) + unlink(outfile); + + exit(status); +} + +/* +** Main routine for translating composition file +** into valid MIME message. It translates the draft +** into a content structure (actually a tree of content +** structures). This message then can be manipulated +** in various ways, including being output via +** output_message(). +*/ +static CT +build_mime(char *infile) +{ + int compnum, state; + char buf[BUFSIZ], name[NAMESZ]; + char *cp, *np, *vp; + struct multipart *m; + struct part **pp; + CT ct; + FILE *in; + + umask(~m_gmprot()); + + /* open the composition draft */ + if ((in = fopen(infile, "r")) == NULL) + adios(infile, "unable to open for reading"); + + /* + ** Allocate space for primary (outside) content + */ + if ((ct = (CT) calloc(1, sizeof(*ct))) == NULL) + adios(NULL, "out of memory"); + + /* + ** Allocate structure for handling decoded content + ** for this part. We don't really need this, but + ** allocate it to remain consistent. + */ + init_decoded_content(ct); + + /* + ** Parse some of the header fields in the composition + ** draft into the linked list of header fields for + ** the new MIME message. + */ + for (compnum = 1, state = FLD;;) { + switch (state = m_getfld(state, name, buf, sizeof(buf), in)) { + case FLD: + case FLDPLUS: + case FLDEOF: + compnum++; + + /* abort if draft has Mime-Version header field */ + if (!mh_strcasecmp(name, VRSN_FIELD)) + adios(NULL, "draft shouldn't contain %s: field", VRSN_FIELD); + + /* + ** abort if draft has Content-Transfer-Encoding + ** header field + */ + if (!mh_strcasecmp(name, ENCODING_FIELD)) + adios(NULL, "draft shouldn't contain %s: field", ENCODING_FIELD); + + /* ignore any Content-Type fields in the header */ + if (!mh_strcasecmp(name, TYPE_FIELD)) { + while (state == FLDPLUS) + state = m_getfld(state, name, buf, + sizeof(buf), in); + goto finish_field; + } + + /* get copies of the buffers */ + np = getcpy(name); + vp = getcpy(buf); + + /* if necessary, get rest of field */ + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof(buf), in); + vp = add(buf, vp); /* add to prev value */ + } + + /* Now add the header data to the list */ + add_header(ct, np, vp); + +finish_field: + /* if this wasn't the last hdr field, then continue */ + if (state != FLDEOF) + continue; + /* else fall... */ + + case FILEEOF: + adios(NULL, "draft has empty body -- no directives!"); + /* NOTREACHED */ + + case BODY: + case BODYEOF: + fseek(in, (long) (-strlen(buf)), SEEK_CUR); + break; + + case LENERR: + case FMTERR: + adios(NULL, "message format error in component #%d", + compnum); + + default: + adios(NULL, "getfld() returned %d", state); + } + break; + } + + /* + ** Now add the MIME-Version header field + ** to the list of header fields. + */ + np = getcpy(VRSN_FIELD); + vp = concat(" ", VRSN_VALUE, "\n", NULL); + add_header(ct, np, vp); + + /* + ** We initally assume we will find multiple contents in the + ** draft. So create a multipart/mixed content to hold everything. + ** We can remove this later, if it is not needed. + */ + if (get_ctinfo("multipart/mixed", ct, 0) == NOTOK) + done(1); + ct->c_type = CT_MULTIPART; + ct->c_subtype = MULTI_MIXED; + ct->c_file = getcpy(infile); + + if ((m = (struct multipart *) calloc(1, sizeof(*m))) == NULL) + adios(NULL, "out of memory"); + ct->c_ctparams = (void *) m; + pp = &m->mp_parts; + + /* + ** read and parse the composition file + ** and the directives it contains. + */ + while (fgetstr(buf, sizeof(buf) - 1, in)) { + struct part *part; + CT p; + + if (user_content(in, infile, buf, &p) == DONE) { + admonish(NULL, "ignoring spurious #end"); + continue; + } + if (!p) + continue; + + if ((part = (struct part *) calloc(1, sizeof(*part))) == NULL) + adios(NULL, "out of memory"); + *pp = part; + pp = &part->mp_next; + part->mp_part = p; + } + + /* + ** close the composition draft since + ** it's not needed any longer. + */ + fclose(in); + + /* check if any contents were found */ + if (!m->mp_parts) + adios(NULL, "no content directives found"); + + /* + ** If only one content was found, then remove and + ** free the outer multipart content. + */ + if (!m->mp_parts->mp_next) { + CT p; + + p = m->mp_parts->mp_part; + m->mp_parts->mp_part = NULL; + + /* move header fields */ + p->c_first_hf = ct->c_first_hf; + p->c_last_hf = ct->c_last_hf; + ct->c_first_hf = NULL; + ct->c_last_hf = NULL; + + free_content(ct); + ct = p; + } else { + set_id(ct, 1); + } + + /* + ** Fill out, or expand directives. Parse and execute + ** commands specified by profile composition strings. + */ + compose_content(ct); + + if ((cp = strchr(prefix, 'a')) == NULL) + adios(NULL, "internal error(4)"); + + /* + ** Scan the contents. Choose a transfer encoding, and + ** check if prefix for multipart boundary clashes with + ** any of the contents. + */ + while (scan_content(ct) == NOTOK) { + if (*cp < 'z') { + (*cp)++; + } else { + if (*++cp == 0) + adios(NULL, "giving up trying to find a unique delimiter string"); + else + (*cp)++; + } + } + + /* Build the rest of the header field structures */ + build_headers(ct); + + return ct; +} + + +/* +** Set up structures for placing unencoded +** content when building parts. +*/ + +static int +init_decoded_content(CT ct) +{ + CE ce; + + if ((ce = (CE) calloc(1, sizeof(*ce))) == NULL) + adios(NULL, "out of memory"); + + ct->c_cefile = ce; + ct->c_ceopenfnx = open7Bit; /* since unencoded */ + ct->c_ceclosefnx = close_encoding; + ct->c_cesizefnx = NULL; /* since unencoded */ + + return OK; +} + + +static char * +fgetstr(char *s, int n, FILE *stream) +{ + char *cp, *ep; + + for (ep = (cp = s) + n; cp < ep; ) { + int i; + + if (!fgets(cp, n, stream)) + return (cp != s ? s : NULL); + if (cp == s && *cp != '#') + return s; + + cp += (i = strlen(cp)) - 1; + if (i <= 1 || *cp-- != '\n' || *cp != '\\') + break; + *cp = '\0'; + n -= (i - 2); + } + + return s; +} + + +/* +** Parse the composition draft for text and directives. +** Do initial setup of Content structure. +*/ + +static int +user_content(FILE *in, char *file, char *buf, CT *ctp) +{ + int vrsn; + unsigned char *cp; + char **ap; + char buffer[BUFSIZ]; + struct multipart *m; + struct part **pp; + struct str2init *s2i; + CI ci; + CT ct; + CE ce; + + if (buf[0] == '\n' || strcmp(buf, "#\n") == 0) { + *ctp = NULL; + return OK; + } + + /* allocate basic Content structure */ + if ((ct = (CT) calloc(1, sizeof(*ct))) == NULL) + adios(NULL, "out of memory"); + *ctp = ct; + + /* allocate basic structure for handling decoded content */ + init_decoded_content(ct); + ce = ct->c_cefile; + + ci = &ct->c_ctinfo; + set_id(ct, 0); + + /* + ** Handle inline text. Check if line + ** is one of the following forms: + ** + ** 1) doesn't begin with '#' (implicit directive) + ** 2) begins with "##" (implicit directive) + ** 3) begins with "#<" + */ + if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') { + int headers; + int inlineD; + long pos; + char content[BUFSIZ]; + FILE *out; + char *cp; + + cp = m_mktemp2(NULL, invo_name, NULL, &out); + if (cp == NULL) + adios("mhbuild", "unable to create temporary file"); + + /* use a temp file to collect the plain text lines */ + ce->ce_file = getcpy(cp); + ce->ce_unlink = 1; + + if (buf[0] == '#' && buf[1] == '<') { + strncpy(content, buf + 2, sizeof(content)); + inlineD = 1; + goto rock_and_roll; + } else { + inlineD = 0; + } + + /* the directive is implicit */ + strncpy(content, "text/plain", sizeof(content)); + headers = 0; + strncpy(buffer, buf[0] != '#' ? buf : buf + 1, sizeof(buffer)); + for (;;) { + int i; + + if (headers >= 0 && uprf(buffer, DESCR_FIELD) && + buffer[i=strlen(DESCR_FIELD)] == ':') { + headers = 1; + +again_descr: + ct->c_descr = add(buffer + i + 1, ct->c_descr); + if (!fgetstr(buffer, sizeof(buffer) - 1, in)) + adios(NULL, "end-of-file after %s: field in plaintext", DESCR_FIELD); + switch (buffer[0]) { + case ' ': + case '\t': + i = -1; + goto again_descr; + + case '#': + adios(NULL, "#-directive after %s: field in plaintext", DESCR_FIELD); + /* NOTREACHED */ + + default: + break; + } + } + + if (headers >= 0 && uprf(buffer, DISPO_FIELD) + && buffer[i = strlen(DISPO_FIELD)] == ':') { + headers = 1; + +again_dispo: + ct->c_dispo = add(buffer + i + 1, ct->c_dispo); + if (!fgetstr(buffer, sizeof(buffer) - 1, in)) + adios(NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); + switch (buffer[0]) { + case ' ': + case '\t': + i = -1; + goto again_dispo; + + case '#': + adios(NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); + /* NOTREACHED */ + + default: + break; + } + } + + if (headers != 1 || buffer[0] != '\n') + fputs(buffer, out); + +rock_and_roll: + headers = -1; + pos = ftell(in); + if ((cp = fgetstr(buffer, sizeof(buffer) - 1, in)) + == NULL) + break; + if (buffer[0] == '#') { + char *bp; + + if (buffer[1] != '#') + break; + for (cp = (bp = buffer) + 1; *cp; cp++) + *bp++ = *cp; + *bp = '\0'; + } + } + + fclose(out); + + /* parse content type */ + if (get_ctinfo(content, ct, inlineD) == NOTOK) + done(1); + + for (s2i = str2cts; s2i->si_key; s2i++) + if (!mh_strcasecmp(ci->ci_type, s2i->si_key)) + break; + if (!s2i->si_key && !uprf(ci->ci_type, "X-")) + s2i++; + + /* + ** check type specified (possibly implicitly) + */ + switch (ct->c_type = s2i->si_val) { + case CT_MESSAGE: + if (!mh_strcasecmp(ci->ci_subtype, "rfc822")) { + ct->c_encoding = CE_7BIT; + goto call_init; + } + /* else fall... */ + case CT_MULTIPART: + adios(NULL, "it doesn't make sense to define an in-line %s content", + ct->c_type == CT_MESSAGE ? "message" : + "multipart"); + /* NOTREACHED */ + + default: +call_init: + if ((ct->c_ctinitfnx = s2i->si_init)) + (*ct->c_ctinitfnx) (ct); + break; + } + + if (cp) + fseek(in, pos, SEEK_SET); + return OK; + } + + /* + ** If we've reached this point, the next line + ** must be some type of explicit directive. + */ + + if (buf[1] == '@') { + adios(NULL, "The #@ directive i.e. message/external-body " + "is not supported anymore."); + } + + /* parse directive */ + if (get_ctinfo(buf+1, ct, 1) == NOTOK) + done(1); + + /* check directive against the list of MIME types */ + for (s2i = str2cts; s2i->si_key; s2i++) + if (!mh_strcasecmp(ci->ci_type, s2i->si_key)) + break; + + /* + ** Check if the directive specified a valid type. + ** This will happen if it was one of the following forms: + ** + ** #type/subtype + */ + if (s2i->si_key) { + if (!ci->ci_subtype) + adios(NULL, "missing subtype in \"#%s\"", ci->ci_type); + + switch (ct->c_type = s2i->si_val) { + case CT_MULTIPART: + adios(NULL, "use \"#begin ... #end\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); + /* NOTREACHED */ + + case CT_MESSAGE: + if (!mh_strcasecmp(ci->ci_subtype, "partial") || + !mh_strcasecmp(ci->ci_subtype, + "external-body")) { + adios(NULL, "sorry, \"#%s/%s\" isn't supported", ci->ci_type, ci->ci_subtype); + } +use_forw: + adios(NULL, "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); + /* NOTREACHED */ + + default: + if ((ct->c_ctinitfnx = s2i->si_init)) + (*ct->c_ctinitfnx) (ct); + break; + } + + /* Handle [file] argument */ + if (ci->ci_magic) { + /* check if specifies command to execute */ + if (*ci->ci_magic == '|' || *ci->ci_magic == '!') { + for (cp = ci->ci_magic + 1; isspace(*cp); cp++) + continue; + if (!*cp) + adios(NULL, "empty pipe command for #%s directive", ci->ci_type); + cp = getcpy(cp); + free(ci->ci_magic); + ci->ci_magic = cp; + } else { + /* record filename of decoded contents */ + ce->ce_file = ci->ci_magic; + if (access(ce->ce_file, R_OK) == NOTOK) + adios("reading", "unable to access %s for", ce->ce_file); + ci->ci_magic = NULL; + } + return OK; + } + + /* + ** No [file] argument, so check profile for + ** method to compose content. + */ + snprintf(buffer, sizeof(buffer), "%s-compose-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) == NULL || *cp == '\0') { + snprintf(buffer, sizeof(buffer), "%s-compose-%s", + invo_name, ci->ci_type); + if ((cp = context_find(buffer)) == NULL || + *cp == '\0') { + content_error(NULL, ct, "don't know how to compose content"); + done(1); + } + } + ci->ci_magic = getcpy(cp); + return OK; + } + + /* + ** Message directive + ** #forw [+folder] [msgs] + */ + if (!mh_strcasecmp(ci->ci_type, "forw")) { + int msgnum; + char *folder, *arguments[MAXARGS]; + struct msgs *mp; + + if (ci->ci_magic) { + int i; + + ap = brkstring(ci->ci_magic, " ", "\n"); + for (i=0; ap[i] && inumsel > 1) { + /* we are forwarding multiple messages */ + if (get_ctinfo("multipart/digest", ct, 0) == NOTOK) + done(1); + ct->c_type = CT_MULTIPART; + ct->c_subtype = MULTI_DIGEST; + + if ((m = (struct multipart *) + calloc(1, sizeof(*m))) == NULL) + adios(NULL, "out of memory"); + ct->c_ctparams = (void *) m; + pp = &m->mp_parts; + + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + struct part *part; + CT p; + CE pe; + + if ((p = (CT) calloc(1, sizeof(*p))) + == NULL) + adios(NULL, "out of memory"); + init_decoded_content(p); + pe = p->c_cefile; + if (get_ctinfo("message/rfc822", p, 0) + == NOTOK) + done(1); + p->c_type = CT_MESSAGE; + p->c_subtype = MESSAGE_RFC822; + + snprintf(buffer, sizeof(buffer), + "%s/%d", mp->foldpath, + msgnum); + pe->ce_file = getcpy(buffer); + + if ((part = (struct part *) calloc(1, sizeof(*part))) == NULL) + adios(NULL, "out of memory"); + *pp = part; + pp = &part->mp_next; + part->mp_part = p; + } + } + } else { + /* we are forwarding one message */ + if (get_ctinfo("message/rfc822", ct, 0) == NOTOK) + done(1); + ct->c_type = CT_MESSAGE; + ct->c_subtype = MESSAGE_RFC822; + + msgnum = mp->lowsel; + snprintf(buffer, sizeof(buffer), "%s/%d", + mp->foldpath, msgnum); + ce->ce_file = getcpy(buffer); + } + + folder_free(mp); /* free folder/message structure */ + return OK; + } + + /* + ** #end + */ + if (!mh_strcasecmp(ci->ci_type, "end")) { + free_content(ct); + *ctp = NULL; + return DONE; + } + + /* + ** #begin [ alternative | parallel ] + */ + if (!mh_strcasecmp(ci->ci_type, "begin")) { + if (!ci->ci_magic) { + vrsn = MULTI_MIXED; + cp = SubMultiPart[vrsn - 1].kv_key; + } else if (!mh_strcasecmp(ci->ci_magic, "alternative")) { + vrsn = MULTI_ALTERNATE; + cp = SubMultiPart[vrsn - 1].kv_key; + } else if (!mh_strcasecmp(ci->ci_magic, "parallel")) { + vrsn = MULTI_PARALLEL; + cp = SubMultiPart[vrsn - 1].kv_key; + } else if (uprf(ci->ci_magic, "digest")) { + goto use_forw; + } else { + vrsn = MULTI_UNKNOWN; + cp = ci->ci_magic; + } + + free_ctinfo(ct); + snprintf(buffer, sizeof(buffer), "multipart/%s", cp); + if (get_ctinfo(buffer, ct, 0) == NOTOK) + done(1); + ct->c_type = CT_MULTIPART; + ct->c_subtype = vrsn; + + if ((m = (struct multipart *) calloc(1, sizeof(*m))) == NULL) + adios(NULL, "out of memory"); + ct->c_ctparams = (void *) m; + + pp = &m->mp_parts; + while (fgetstr(buffer, sizeof(buffer) - 1, in)) { + struct part *part; + CT p; + + if (user_content(in, file, buffer, &p) == DONE) { + if (!m->mp_parts) + adios(NULL, "empty \"#begin ... #end\" sequence"); + return OK; + } + if (!p) + continue; + + if ((part = (struct part *) + calloc(1, sizeof(*part))) == NULL) + adios(NULL, "out of memory"); + *pp = part; + pp = &part->mp_next; + part->mp_part = p; + } + admonish(NULL, "premature end-of-file, missing #end"); + return OK; + } + + /* + ** Unknown directive + */ + adios(NULL, "unknown directive \"#%s\"", ci->ci_type); + return NOTOK; /* NOT REACHED */ } static void -unlink_done (int status) +set_id(CT ct, int top) +{ + char msgid[BUFSIZ]; + static int partno; + static time_t clock = 0; + static char *msgfmt; + + if (clock == 0) { + time(&clock); + snprintf(msgid, sizeof(msgid), "<%d.%ld.%%d@%s>\n", + (int) getpid(), (long) clock, LocalName()); + partno = 0; + msgfmt = getcpy(msgid); + } + snprintf(msgid, sizeof(msgid), msgfmt, top ? 0 : ++partno); + ct->c_id = getcpy(msgid); +} + + +/* +** Fill out, or expand the various contents in the composition +** draft. Read-in any necessary files. Parse and execute any +** commands specified by profile composition strings. +*/ + +static int +compose_content(CT ct) +{ + CE ce = ct->c_cefile; + + switch (ct->c_type) { + case CT_MULTIPART: + { + int partnum; + char *pp; + char partnam[BUFSIZ]; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + + if (ct->c_partno) { + snprintf(partnam, sizeof(partnam), "%s.", + ct->c_partno); + pp = partnam + strlen(partnam); + } else { + pp = partnam; + } + + /* first, we call compose_content on all the subparts */ + for (part = m->mp_parts, partnum = 1; part; + part = part->mp_next, partnum++) { + CT p = part->mp_part; + + sprintf(pp, "%d", partnum); + p->c_partno = getcpy(partnam); + if (compose_content(p) == NOTOK) + return NOTOK; + } + } + break; + + case CT_MESSAGE: + /* Nothing to do for type message */ + break; + + /* + ** Discrete types (text/application/audio/image/video) + */ + default: + if (!ce->ce_file) { + pid_t child_id; + int xstdout, len, buflen; + char *bp, **ap, *cp; + char *vec[4], buffer[BUFSIZ]; + FILE *out; + CI ci = &ct->c_ctinfo; + char *tfile = NULL; + + if (!(cp = ci->ci_magic)) + adios(NULL, "internal error(5)"); + + tfile = m_mktemp2(NULL, invo_name, NULL, NULL); + if (tfile == NULL) { + adios("mhbuild", "unable to create temporary file"); + } + ce->ce_file = getcpy(tfile); + ce->ce_unlink = 1; + + xstdout = 0; + + /* Get buffer ready to go */ + bp = buffer; + bp[0] = '\0'; + buflen = sizeof(buffer); + + /* + ** Parse composition string into buffer + */ + for ( ; *cp; cp++) { + if (*cp == '%') { + switch (*++cp) { + case 'a': + { + /* + ** insert parameters from + ** directive + */ + char **ep; + char *s = ""; + + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { + snprintf(bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'F': + /* %f, and stdout is not-redirected */ + xstdout = 1; + /* and fall... */ + + case 'f': + /* + ** insert temporary filename + ** where content should be + ** written + */ + snprintf(bp, buflen, "%s", ce->ce_file); + break; + + case 's': + /* insert content subtype */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + len = strlen(bp); + bp += len; + buflen -= len; + } else { +raw: + *bp++ = *cp; + *bp = '\0'; + buflen--; + } + } + + if (verbosw) + printf("composing content %s/%s from command\n\t%s\n", ci->ci_type, ci->ci_subtype, buffer); + + fflush(stdout); /* not sure if need for -noverbose */ + + vec[0] = "/bin/sh"; + vec[1] = "-c"; + vec[2] = buffer; + vec[3] = NULL; + + if ((out = fopen(ce->ce_file, "w")) == NULL) + adios(ce->ce_file, "unable to open for writing"); + + switch (child_id = fork()) { + case NOTOK: + adios("fork", "unable to fork"); + /* NOTREACHED */ + + case OK: + if (!xstdout) + dup2(fileno(out), 1); + close(fileno(out)); + execvp("/bin/sh", vec); + fprintf(stderr, "unable to exec "); + perror("/bin/sh"); + _exit(-1); + /* NOTREACHED */ + + default: + fclose(out); + if (pidXwait(child_id, NULL)) + done(1); + break; + } + } + break; + } + + return OK; +} + + +/* +** Scan the content. +** +** 1) choose a transfer encoding. +** 2) check for clashes with multipart boundary string. +** 3) for text content, figure out which character set is being used. +** +** If there is a clash with one of the contents and the multipart boundary, +** this function will exit with NOTOK. This will cause the scanning process +** to be repeated with a different multipart boundary. It is possible +** (although highly unlikely) that this scan will be repeated multiple times. +*/ + +static int +scan_content(CT ct) +{ + int len; + int check8bit = 0, contains8bit = 0; /* check if contains 8bit data */ + int checklinelen = 0, linelen = 0; /* check for long lines */ + int checkboundary = 0, boundaryclash = 0; /* check if clashes with multipart boundary */ + int checklinespace = 0, linespace = 0; /* check if any line ends with space */ + unsigned char *cp = NULL, buffer[BUFSIZ]; + struct text *t = NULL; + FILE *in = NULL; + CE ce = ct->c_cefile; + + /* + ** handle multipart by scanning all subparts + ** and then checking their encoding. + */ + if (ct->c_type == CT_MULTIPART) { + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + + /* initially mark the domain of enclosing multipart as 7bit */ + ct->c_encoding = CE_7BIT; + + for (part = m->mp_parts; part; part = part->mp_next) { + CT p = part->mp_part; + + if (scan_content(p) == NOTOK) { + /* choose encoding for subpart */ + return NOTOK; + } + + /* + ** if necessary, enlarge encoding for enclosing + ** multipart + */ + if (p->c_encoding == CE_BINARY) + ct->c_encoding = CE_BINARY; + if (p->c_encoding == CE_8BIT && + ct->c_encoding != CE_BINARY) + ct->c_encoding = CE_8BIT; + } + + return OK; + } + + /* + ** Decide what to check while scanning this content. + */ + switch (ct->c_type) { + case CT_TEXT: + check8bit = 1; + checkboundary = 1; + if (ct->c_subtype == TEXT_PLAIN) { + checklinelen = 0; + checklinespace = 0; + } else { + checklinelen = 1; + checklinespace = 1; + } + break; + + case CT_APPLICATION: + check8bit = 1; + checklinelen = 1; + checklinespace = 1; + checkboundary = 1; + break; + + case CT_MESSAGE: + check8bit = 0; + checklinelen = 0; + checklinespace = 0; + checkboundary = 1; + break; + + case CT_AUDIO: + case CT_IMAGE: + case CT_VIDEO: + /* + ** Don't check anything for these types, + ** since we are forcing use of base64. + */ + check8bit = 0; + checklinelen = 0; + checklinespace = 0; + checkboundary = 0; + break; + } + + /* + ** Scan the unencoded content + */ + if (check8bit || checklinelen || checklinespace || checkboundary) { + if ((in = fopen(ce->ce_file, "r")) == NULL) + adios(ce->ce_file, "unable to open for reading"); + len = strlen(prefix); + + while (fgets(buffer, sizeof(buffer) - 1, in)) { + /* + ** Check for 8bit data. + */ + if (check8bit) { + for (cp = buffer; *cp; cp++) { + if (!isascii(*cp)) { + contains8bit = 1; + /* no need to keep checking */ + check8bit = 0; + } + } + } + + /* + ** Check line length. + */ + if (checklinelen && (strlen(buffer) > CPERLIN + 1)) { + linelen = 1; + checklinelen = 0; /* no need to keep checking */ + } + + /* + ** Check if line ends with a space. + */ + if (checklinespace && + (cp = buffer + strlen(buffer) - 2) > + buffer && isspace(*cp)) { + linespace = 1; + /* no need to keep checking */ + checklinespace = 0; + } + + /* + ** Check if content contains a line that clashes + ** with our standard boundary for multipart messages. + */ + if (checkboundary && buffer[0] == '-' && + buffer[1] == '-') { + for (cp = buffer + strlen(buffer) - 1; + cp >= buffer; cp--) + if (!isspace(*cp)) + break; + *++cp = '\0'; + if (strncmp(buffer + 2, prefix, len)==0 && + isdigit(buffer[2 + len])) { + boundaryclash = 1; + /* no need to keep checking */ + checkboundary = 0; + } + } + } + fclose(in); + } + + /* + ** Decide which transfer encoding to use. + */ + switch (ct->c_type) { + case CT_TEXT: + /* + ** If the text content didn't specify a character + ** set, we need to figure out which one was used. + */ + t = (struct text *) ct->c_ctparams; + if (t->tx_charset == CHARSET_UNSPECIFIED) { + CI ci = &ct->c_ctinfo; + char **ap, **ep; + + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) + continue; + + if (contains8bit) { + t->tx_charset = CHARSET_UNKNOWN; + *ap = concat("charset=", write_charset_8bit(), + NULL); + } else { + t->tx_charset = CHARSET_USASCII; + *ap = getcpy("charset=us-ascii"); + } + + cp = strchr(*ap++, '='); + *ap = NULL; + *cp++ = '\0'; + *ep = cp; + } + + if (contains8bit || linelen || linespace) + ct->c_encoding = CE_QUOTED; + else + ct->c_encoding = CE_7BIT; + break; + + case CT_APPLICATION: + /* For application type, use base64, except when postscript */ + if (contains8bit || linelen || linespace) + ct->c_encoding = (ct->c_subtype == + APPLICATION_POSTSCRIPT) ? + CE_QUOTED : CE_BASE64; + else + ct->c_encoding = CE_7BIT; + break; + + case CT_MESSAGE: + ct->c_encoding = CE_7BIT; + break; + + case CT_AUDIO: + case CT_IMAGE: + case CT_VIDEO: + /* For audio, image, and video contents, just use base64 */ + ct->c_encoding = CE_BASE64; + break; + } + + return (boundaryclash ? NOTOK : OK); +} + + +/* +** Scan the content structures, and build header +** fields that will need to be output into the +** message. +*/ + +static int +build_headers(CT ct) { - /* - * Check if we need to remove stray - * temporary files. - */ - if (unlink_infile) - unlink (infile); - if (unlink_outfile) - unlink (outfile); - - exit (status); + int cc, len; + char **ap, **ep; + char *np, *vp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* + ** If message is type multipart, then add the multipart + ** boundary to the list of attribute/value pairs. + */ + if (ct->c_type == CT_MULTIPART) { + char *cp; + static int level = 0; /* store nesting level */ + + ap = ci->ci_attrs; + ep = ci->ci_values; + snprintf(buffer, sizeof(buffer), "boundary=%s%d", + prefix, level++); + cp = strchr(*ap++ = getcpy(buffer), '='); + *ap = NULL; + *cp++ = '\0'; + *ep = cp; + } + + /* + ** output the content type and subtype + */ + np = getcpy(TYPE_FIELD); + vp = concat(" ", ci->ci_type, "/", ci->ci_subtype, NULL); + + /* keep track of length of line */ + len = strlen(TYPE_FIELD) + strlen(ci->ci_type) + + strlen(ci->ci_subtype) + 3; + + /* + ** Append the attribute/value pairs to + ** the end of the Content-Type line. + */ + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { + vp = add(";", vp); + len++; + + snprintf(buffer, sizeof(buffer), "%s=\"%s\"", *ap, *ep); + if (len + 1 + (cc = strlen(buffer)) >= CPERLIN) { + vp = add("\n\t", vp); + len = 8; + } else { + vp = add(" ", vp); + len++; + } + vp = add(buffer, vp); + len += cc; + } + + /* + ** Append any RFC-822 comment to the end of + ** the Content-Type line. + */ + if (ci->ci_comment) { + snprintf(buffer, sizeof(buffer), "(%s)", ci->ci_comment); + if (len + 1 + (cc = 2 + strlen(ci->ci_comment)) >= CPERLIN) { + vp = add("\n\t", vp); + len = 8; + } else { + vp = add(" ", vp); + len++; + } + vp = add(buffer, vp); + len += cc; + } + vp = add("\n", vp); + add_header(ct, np, vp); + + /* + ** output the Content-ID + */ + if (ct->c_id) { + np = getcpy(ID_FIELD); + vp = concat(" ", ct->c_id, NULL); + add_header(ct, np, vp); + } + + /* + ** output the Content-Description + */ + if (ct->c_descr) { + np = getcpy(DESCR_FIELD); + vp = concat(" ", ct->c_descr, NULL); + add_header(ct, np, vp); + } + + /* + ** output the Content-Disposition + */ + if (ct->c_dispo) { + np = getcpy(DISPO_FIELD); + vp = concat(" ", ct->c_dispo, NULL); + add_header(ct, np, vp); + } + + /* + ** output the Content-Transfer-Encoding + */ + switch (ct->c_encoding) { + case CE_7BIT: + /* Nothing to output */ + break; + + case CE_8BIT: + if (ct->c_type == CT_MESSAGE) + adios(NULL, "internal error, invalid encoding"); + + np = getcpy(ENCODING_FIELD); + vp = concat(" ", "8bit", "\n", NULL); + add_header(ct, np, vp); + break; + + case CE_QUOTED: + if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) + adios(NULL, "internal error, invalid encoding"); + + np = getcpy(ENCODING_FIELD); + vp = concat(" ", "quoted-printable", "\n", NULL); + add_header(ct, np, vp); + break; + + case CE_BASE64: + if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) + adios(NULL, "internal error, invalid encoding"); + + np = getcpy(ENCODING_FIELD); + vp = concat(" ", "base64", "\n", NULL); + add_header(ct, np, vp); + break; + + case CE_BINARY: + if (ct->c_type == CT_MESSAGE) + adios(NULL, "internal error, invalid encoding"); + + np = getcpy(ENCODING_FIELD); + vp = concat(" ", "binary", "\n", NULL); + add_header(ct, np, vp); + break; + + default: + adios(NULL, "unknown transfer encoding in content"); + break; + } + + /* + ** Additional content specific header processing + */ + switch (ct->c_type) { + case CT_MULTIPART: + { + struct multipart *m; + struct part *part; + + m = (struct multipart *) ct->c_ctparams; + for (part = m->mp_parts; part; part = part->mp_next) { + CT p; + + p = part->mp_part; + build_headers(p); + } + } + break; + + default: + /* Nothing to do */ + break; + } + + return OK; } diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c deleted file mode 100644 index f01abd5..0000000 --- a/uip/mhbuildsbr.c +++ /dev/null @@ -1,1695 +0,0 @@ - -/* - * mhbuildsbr.c -- routines to expand/translate MIME composition files - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* - * This code was originally part of mhn.c. I split it into - * a separate program (mhbuild.c) and then later split it - * again (mhbuildsbr.c). But the code still has some of - * the mhn.c code in it. This program needs additional - * streamlining and removal of unneeded code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - - -extern int debugsw; -extern int verbosw; - -extern int ebcdicsw; -extern int listsw; -extern int rfc934sw; -extern int contentidsw; - -extern int endian; /* mhmisc.c */ - -/* cache policies */ -extern int rcachesw; /* mhcachesbr.c */ -extern int wcachesw; /* mhcachesbr.c */ - -/* - * Directory to place tmp files. This must - * be set before these routines are called. - */ -char *tmp; - -pid_t xpid = 0; - -static char prefix[] = "----- =_aaaaaaaaaa"; - - -/* mhmisc.c */ -int make_intermediates (char *); -void content_error (char *, CT, char *, ...); - -/* mhcachesbr.c */ -int find_cache (CT, int, int *, char *, char *, int); - -/* ftpsbr.c */ -int ftp_get (char *, char *, char *, char *, char *, char *, int, int); - -/* mhfree.c */ -void free_content (CT); -void free_ctinfo (CT); -void free_encoding (CT, int); - -/* - * prototypes - */ -CT build_mime (char *); - -/* - * static prototypes - */ -static int init_decoded_content (CT); -static char *fgetstr (char *, int, FILE *); -static int user_content (FILE *, char *, char *, CT *); -static void set_id (CT, int); -static int compose_content (CT); -static int scan_content (CT); -static int build_headers (CT); -static char *calculate_digest (CT, int); - - -/* - * Main routine for translating composition file - * into valid MIME message. It translates the draft - * into a content structure (actually a tree of content - * structures). This message then can be manipulated - * in various ways, including being output via - * output_message(). - */ - -CT -build_mime (char *infile) -{ - int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; - char *cp, *np, *vp; - struct multipart *m; - struct part **pp; - CT ct; - FILE *in; - - umask (~m_gmprot ()); - - /* open the composition draft */ - if ((in = fopen (infile, "r")) == NULL) - adios (infile, "unable to open for reading"); - - /* - * Allocate space for primary (outside) content - */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) - adios (NULL, "out of memory"); - - /* - * Allocate structure for handling decoded content - * for this part. We don't really need this, but - * allocate it to remain consistent. - */ - init_decoded_content (ct); - - /* - * Parse some of the header fields in the composition - * draft into the linked list of header fields for - * the new MIME message. - */ - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), in)) { - case FLD: - case FLDPLUS: - case FLDEOF: - compnum++; - - /* abort if draft has Mime-Version header field */ - if (!mh_strcasecmp (name, VRSN_FIELD)) - adios (NULL, "draft shouldn't contain %s: field", VRSN_FIELD); - - /* abort if draft has Content-Transfer-Encoding header field */ - if (!mh_strcasecmp (name, ENCODING_FIELD)) - adios (NULL, "draft shouldn't contain %s: field", ENCODING_FIELD); - - /* ignore any Content-Type fields in the header */ - if (!mh_strcasecmp (name, TYPE_FIELD)) { - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), in); - goto finish_field; - } - - /* get copies of the buffers */ - np = add (name, NULL); - vp = add (buf, NULL); - - /* if necessary, get rest of field */ - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); - vp = add (buf, vp); /* add to previous value */ - } - - /* Now add the header data to the list */ - add_header (ct, np, vp); - -finish_field: - /* if this wasn't the last header field, then continue */ - if (state != FLDEOF) - continue; - /* else fall... */ - - case FILEEOF: - adios (NULL, "draft has empty body -- no directives!"); - /* NOTREACHED */ - - case BODY: - case BODYEOF: - fseek (in, (long) (-strlen (buf)), SEEK_CUR); - break; - - case LENERR: - case FMTERR: - adios (NULL, "message format error in component #%d", compnum); - - default: - adios (NULL, "getfld() returned %d", state); - } - break; - } - - /* - * Now add the MIME-Version header field - * to the list of header fields. - */ - np = add (VRSN_FIELD, NULL); - vp = concat (" ", VRSN_VALUE, "\n", NULL); - add_header (ct, np, vp); - - /* - * We initally assume we will find multiple contents in the - * draft. So create a multipart/mixed content to hold everything. - * We can remove this later, if it is not needed. - */ - if (get_ctinfo ("multipart/mixed", ct, 0) == NOTOK) - done (1); - ct->c_type = CT_MULTIPART; - ct->c_subtype = MULTI_MIXED; - ct->c_file = add (infile, NULL); - - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) m; - pp = &m->mp_parts; - - /* - * read and parse the composition file - * and the directives it contains. - */ - while (fgetstr (buf, sizeof(buf) - 1, in)) { - struct part *part; - CT p; - - if (user_content (in, infile, buf, &p) == DONE) { - admonish (NULL, "ignoring spurious #end"); - continue; - } - if (!p) - continue; - - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) - adios (NULL, "out of memory"); - *pp = part; - pp = &part->mp_next; - part->mp_part = p; - } - - /* - * close the composition draft since - * it's not needed any longer. - */ - fclose (in); - - /* check if any contents were found */ - if (!m->mp_parts) - adios (NULL, "no content directives found"); - - /* - * If only one content was found, then remove and - * free the outer multipart content. - */ - if (!m->mp_parts->mp_next) { - CT p; - - p = m->mp_parts->mp_part; - m->mp_parts->mp_part = NULL; - - /* move header fields */ - p->c_first_hf = ct->c_first_hf; - p->c_last_hf = ct->c_last_hf; - ct->c_first_hf = NULL; - ct->c_last_hf = NULL; - - free_content (ct); - ct = p; - } else { - set_id (ct, 1); - } - - /* - * Fill out, or expand directives. Parse and execute - * commands specified by profile composition strings. - */ - compose_content (ct); - - if ((cp = strchr(prefix, 'a')) == NULL) - adios (NULL, "internal error(4)"); - - /* - * Scan the contents. Choose a transfer encoding, and - * check if prefix for multipart boundary clashes with - * any of the contents. - */ - while (scan_content (ct) == NOTOK) { - if (*cp < 'z') { - (*cp)++; - } else { - if (*++cp == 0) - adios (NULL, "giving up trying to find a unique delimiter string"); - else - (*cp)++; - } - } - - /* Build the rest of the header field structures */ - build_headers (ct); - - return ct; -} - - -/* - * Set up structures for placing unencoded - * content when building parts. - */ - -static int -init_decoded_content (CT ct) -{ - CE ce; - - if ((ce = (CE) calloc (1, sizeof(*ce))) == NULL) - adios (NULL, "out of memory"); - - ct->c_cefile = ce; - ct->c_ceopenfnx = open7Bit; /* since unencoded */ - ct->c_ceclosefnx = close_encoding; - ct->c_cesizefnx = NULL; /* since unencoded */ - - return OK; -} - - -static char * -fgetstr (char *s, int n, FILE *stream) -{ - char *cp, *ep; - - for (ep = (cp = s) + n; cp < ep; ) { - int i; - - if (!fgets (cp, n, stream)) - return (cp != s ? s : NULL); - if (cp == s && *cp != '#') - return s; - - cp += (i = strlen (cp)) - 1; - if (i <= 1 || *cp-- != '\n' || *cp != '\\') - break; - *cp = '\0'; - n -= (i - 2); - } - - return s; -} - - -/* - * Parse the composition draft for text and directives. - * Do initial setup of Content structure. - */ - -static int -user_content (FILE *in, char *file, char *buf, CT *ctp) -{ - int extrnal, vrsn; - unsigned char *cp; - char **ap; - char buffer[BUFSIZ]; - struct multipart *m; - struct part **pp; - struct stat st; - struct str2init *s2i; - CI ci; - CT ct; - CE ce; - - if (buf[0] == '\n' || strcmp (buf, "#\n") == 0) { - *ctp = NULL; - return OK; - } - - /* allocate basic Content structure */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) - adios (NULL, "out of memory"); - *ctp = ct; - - /* allocate basic structure for handling decoded content */ - init_decoded_content (ct); - ce = ct->c_cefile; - - ci = &ct->c_ctinfo; - set_id (ct, 0); - - /* - * Handle inline text. Check if line - * is one of the following forms: - * - * 1) doesn't begin with '#' (implicit directive) - * 2) begins with "##" (implicit directive) - * 3) begins with "#<" - */ - if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') { - int headers; - int inlineD; - long pos; - char content[BUFSIZ]; - FILE *out; - char *cp; - - cp = m_mktemp2(NULL, invo_name, NULL, &out); - if (cp == NULL) adios("mhbuildsbr", "unable to create temporary file"); - - /* use a temp file to collect the plain text lines */ - ce->ce_file = add (cp, NULL); - ce->ce_unlink = 1; - - if (buf[0] == '#' && buf[1] == '<') { - strncpy (content, buf + 2, sizeof(content)); - inlineD = 1; - goto rock_and_roll; - } else { - inlineD = 0; - } - - /* the directive is implicit */ - strncpy (content, "text/plain", sizeof(content)); - headers = 0; - strncpy (buffer, buf[0] != '#' ? buf : buf + 1, sizeof(buffer)); - for (;;) { - int i; - - if (headers >= 0 && uprf (buffer, DESCR_FIELD) - && buffer[i = strlen (DESCR_FIELD)] == ':') { - headers = 1; - -again_descr: - ct->c_descr = add (buffer + i + 1, ct->c_descr); - if (!fgetstr (buffer, sizeof(buffer) - 1, in)) - adios (NULL, "end-of-file after %s: field in plaintext", DESCR_FIELD); - switch (buffer[0]) { - case ' ': - case '\t': - i = -1; - goto again_descr; - - case '#': - adios (NULL, "#-directive after %s: field in plaintext", DESCR_FIELD); - /* NOTREACHED */ - - default: - break; - } - } - - if (headers >= 0 && uprf (buffer, DISPO_FIELD) - && buffer[i = strlen (DISPO_FIELD)] == ':') { - headers = 1; - -again_dispo: - ct->c_dispo = add (buffer + i + 1, ct->c_dispo); - if (!fgetstr (buffer, sizeof(buffer) - 1, in)) - adios (NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); - switch (buffer[0]) { - case ' ': - case '\t': - i = -1; - goto again_dispo; - - case '#': - adios (NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); - /* NOTREACHED */ - - default: - break; - } - } - - if (headers != 1 || buffer[0] != '\n') - fputs (buffer, out); - -rock_and_roll: - headers = -1; - pos = ftell (in); - if ((cp = fgetstr (buffer, sizeof(buffer) - 1, in)) == NULL) - break; - if (buffer[0] == '#') { - char *bp; - - if (buffer[1] != '#') - break; - for (cp = (bp = buffer) + 1; *cp; cp++) - *bp++ = *cp; - *bp = '\0'; - } - } - - if (listsw) - ct->c_end = ftell (out); - fclose (out); - - /* parse content type */ - if (get_ctinfo (content, ct, inlineD) == NOTOK) - done (1); - - for (s2i = str2cts; s2i->si_key; s2i++) - if (!mh_strcasecmp (ci->ci_type, s2i->si_key)) - break; - if (!s2i->si_key && !uprf (ci->ci_type, "X-")) - s2i++; - - /* - * check type specified (possibly implicitly) - */ - switch (ct->c_type = s2i->si_val) { - case CT_MESSAGE: - if (!mh_strcasecmp (ci->ci_subtype, "rfc822")) { - ct->c_encoding = CE_7BIT; - goto call_init; - } - /* else fall... */ - case CT_MULTIPART: - adios (NULL, "it doesn't make sense to define an in-line %s content", - ct->c_type == CT_MESSAGE ? "message" : "multipart"); - /* NOTREACHED */ - - default: -call_init: - if ((ct->c_ctinitfnx = s2i->si_init)) - (*ct->c_ctinitfnx) (ct); - break; - } - - if (cp) - fseek (in, pos, SEEK_SET); - return OK; - } - - /* - * If we've reached this point, the next line - * must be some type of explicit directive. - */ - - /* check if directive is external-type */ - extrnal = (buf[1] == '@'); - - /* parse directive */ - if (get_ctinfo (buf + (extrnal ? 2 : 1), ct, 1) == NOTOK) - done (1); - - /* check directive against the list of MIME types */ - for (s2i = str2cts; s2i->si_key; s2i++) - if (!mh_strcasecmp (ci->ci_type, s2i->si_key)) - break; - - /* - * Check if the directive specified a valid type. - * This will happen if it was one of the following forms: - * - * #type/subtype (or) - * #@type/subtype - */ - if (s2i->si_key) { - if (!ci->ci_subtype) - adios (NULL, "missing subtype in \"#%s\"", ci->ci_type); - - switch (ct->c_type = s2i->si_val) { - case CT_MULTIPART: - adios (NULL, "use \"#begin ... #end\" instead of \"#%s/%s\"", - ci->ci_type, ci->ci_subtype); - /* NOTREACHED */ - - case CT_MESSAGE: - if (!mh_strcasecmp (ci->ci_subtype, "partial")) - adios (NULL, "sorry, \"#%s/%s\" isn't supported", - ci->ci_type, ci->ci_subtype); - if (!mh_strcasecmp (ci->ci_subtype, "external-body")) - adios (NULL, "use \"#@type/subtype ... [] ...\" instead of \"#%s/%s\"", - ci->ci_type, ci->ci_subtype); -use_forw: - adios (NULL, - "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", - ci->ci_type, ci->ci_subtype); - /* NOTREACHED */ - - default: - if ((ct->c_ctinitfnx = s2i->si_init)) - (*ct->c_ctinitfnx) (ct); - break; - } - - /* - * #@type/subtype (external types directive) - */ - if (extrnal) { - struct exbody *e; - CT p; - - if (!ci->ci_magic) - adios (NULL, "need external information for \"#@%s/%s\"", - ci->ci_type, ci->ci_subtype); - p = ct; - - snprintf (buffer, sizeof(buffer), "message/external-body; %s", ci->ci_magic); - free (ci->ci_magic); - ci->ci_magic = NULL; - - /* - * Since we are using the current Content structure to - * hold information about the type of the external - * reference, we need to create another Content structure - * for the message/external-body to wrap it in. - */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) - adios (NULL, "out of memory"); - *ctp = ct; - ci = &ct->c_ctinfo; - if (get_ctinfo (buffer, ct, 0) == NOTOK) - done (1); - ct->c_type = CT_MESSAGE; - ct->c_subtype = MESSAGE_EXTERNAL; - - if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) e; - - e->eb_parent = ct; - e->eb_content = p; - p->c_ctexbody = e; - - if (params_external (ct, 1) == NOTOK) - done (1); - - return OK; - } - - /* Handle [file] argument */ - if (ci->ci_magic) { - /* check if specifies command to execute */ - if (*ci->ci_magic == '|' || *ci->ci_magic == '!') { - for (cp = ci->ci_magic + 1; isspace (*cp); cp++) - continue; - if (!*cp) - adios (NULL, "empty pipe command for #%s directive", ci->ci_type); - cp = add (cp, NULL); - free (ci->ci_magic); - ci->ci_magic = cp; - } else { - /* record filename of decoded contents */ - ce->ce_file = ci->ci_magic; - if (access (ce->ce_file, R_OK) == NOTOK) - adios ("reading", "unable to access %s for", ce->ce_file); - if (listsw && stat (ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; - ci->ci_magic = NULL; - } - return OK; - } - - /* - * No [file] argument, so check profile for - * method to compose content. - */ - snprintf (buffer, sizeof(buffer), "%s-compose-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-compose-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - content_error (NULL, ct, "don't know how to compose content"); - done (1); - } - } - ci->ci_magic = add (cp, NULL); - return OK; - } - - if (extrnal) - adios (NULL, "external definition not allowed for \"#%s\"", ci->ci_type); - - /* - * Message directive - * #forw [+folder] [msgs] - */ - if (!mh_strcasecmp (ci->ci_type, "forw")) { - int msgnum; - char *folder, *arguments[MAXARGS]; - struct msgs *mp; - - if (ci->ci_magic) { - ap = brkstring (ci->ci_magic, " ", "\n"); - copyip (ap, arguments, MAXARGS); - } else { - arguments[0] = "cur"; - arguments[1] = NULL; - } - folder = NULL; - - /* search the arguments for a folder name */ - for (ap = arguments; *ap; ap++) { - cp = *ap; - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder per #forw directive"); - else - folder = pluspath (cp); - } - } - - /* else, use the current folder */ - if (!folder) - folder = add (getfolder (1), NULL); - - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - for (ap = arguments; *ap; ap++) { - cp = *ap; - if (*cp != '+' && *cp != '@') - if (!m_convert (mp, cp)) - done (1); - } - free (folder); - free_ctinfo (ct); - - /* - * If there is more than one message to include, make this - * a content of type "multipart/digest" and insert each message - * as a subpart. If there is only one message, then make this - * a content of type "message/rfc822". - */ - if (mp->numsel > 1) { - /* we are forwarding multiple messages */ - if (get_ctinfo ("multipart/digest", ct, 0) == NOTOK) - done (1); - ct->c_type = CT_MULTIPART; - ct->c_subtype = MULTI_DIGEST; - - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) m; - pp = &m->mp_parts; - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - struct part *part; - CT p; - CE pe; - - if ((p = (CT) calloc (1, sizeof(*p))) == NULL) - adios (NULL, "out of memory"); - init_decoded_content (p); - pe = p->c_cefile; - if (get_ctinfo ("message/rfc822", p, 0) == NOTOK) - done (1); - p->c_type = CT_MESSAGE; - p->c_subtype = MESSAGE_RFC822; - - snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - pe->ce_file = add (buffer, NULL); - if (listsw && stat (pe->ce_file, &st) != NOTOK) - p->c_end = (long) st.st_size; - - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) - adios (NULL, "out of memory"); - *pp = part; - pp = &part->mp_next; - part->mp_part = p; - } - } - } else { - /* we are forwarding one message */ - if (get_ctinfo ("message/rfc822", ct, 0) == NOTOK) - done (1); - ct->c_type = CT_MESSAGE; - ct->c_subtype = MESSAGE_RFC822; - - msgnum = mp->lowsel; - snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - ce->ce_file = add (buffer, NULL); - if (listsw && stat (ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; - } - - folder_free (mp); /* free folder/message structure */ - return OK; - } - - /* - * #end - */ - if (!mh_strcasecmp (ci->ci_type, "end")) { - free_content (ct); - *ctp = NULL; - return DONE; - } - - /* - * #begin [ alternative | parallel ] - */ - if (!mh_strcasecmp (ci->ci_type, "begin")) { - if (!ci->ci_magic) { - vrsn = MULTI_MIXED; - cp = SubMultiPart[vrsn - 1].kv_key; - } else if (!mh_strcasecmp (ci->ci_magic, "alternative")) { - vrsn = MULTI_ALTERNATE; - cp = SubMultiPart[vrsn - 1].kv_key; - } else if (!mh_strcasecmp (ci->ci_magic, "parallel")) { - vrsn = MULTI_PARALLEL; - cp = SubMultiPart[vrsn - 1].kv_key; - } else if (uprf (ci->ci_magic, "digest")) { - goto use_forw; - } else { - vrsn = MULTI_UNKNOWN; - cp = ci->ci_magic; - } - - free_ctinfo (ct); - snprintf (buffer, sizeof(buffer), "multipart/%s", cp); - if (get_ctinfo (buffer, ct, 0) == NOTOK) - done (1); - ct->c_type = CT_MULTIPART; - ct->c_subtype = vrsn; - - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) m; - - pp = &m->mp_parts; - while (fgetstr (buffer, sizeof(buffer) - 1, in)) { - struct part *part; - CT p; - - if (user_content (in, file, buffer, &p) == DONE) { - if (!m->mp_parts) - adios (NULL, "empty \"#begin ... #end\" sequence"); - return OK; - } - if (!p) - continue; - - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) - adios (NULL, "out of memory"); - *pp = part; - pp = &part->mp_next; - part->mp_part = p; - } - admonish (NULL, "premature end-of-file, missing #end"); - return OK; - } - - /* - * Unknown directive - */ - adios (NULL, "unknown directive \"#%s\"", ci->ci_type); - return NOTOK; /* NOT REACHED */ -} - - -static void -set_id (CT ct, int top) -{ - char msgid[BUFSIZ]; - static int partno; - static time_t clock = 0; - static char *msgfmt; - - if (clock == 0) { - time (&clock); - snprintf (msgid, sizeof(msgid), "<%d.%ld.%%d@%s>\n", - (int) getpid(), (long) clock, LocalName()); - partno = 0; - msgfmt = getcpy(msgid); - } - snprintf (msgid, sizeof(msgid), msgfmt, top ? 0 : ++partno); - ct->c_id = getcpy (msgid); -} - - -static char ebcdicsafe[0x100] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - - -/* - * Fill out, or expand the various contents in the composition - * draft. Read-in any necessary files. Parse and execute any - * commands specified by profile composition strings. - */ - -static int -compose_content (CT ct) -{ - CE ce = ct->c_cefile; - - switch (ct->c_type) { - case CT_MULTIPART: - { - int partnum; - char *pp; - char partnam[BUFSIZ]; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - - if (ct->c_partno) { - snprintf (partnam, sizeof(partnam), "%s.", ct->c_partno); - pp = partnam + strlen (partnam); - } else { - pp = partnam; - } - - /* first, we call compose_content on all the subparts */ - for (part = m->mp_parts, partnum = 1; part; part = part->mp_next, partnum++) { - CT p = part->mp_part; - - sprintf (pp, "%d", partnum); - p->c_partno = add (partnam, NULL); - if (compose_content (p) == NOTOK) - return NOTOK; - } - - /* - * If the -rfc934mode switch is given, then check all - * the subparts of a multipart/digest. If they are all - * message/rfc822, then mark this content and all - * subparts with the rfc934 compatibility mode flag. - */ - if (rfc934sw && ct->c_subtype == MULTI_DIGEST) { - int is934 = 1; - - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if (p->c_subtype != MESSAGE_RFC822) { - is934 = 0; - break; - } - } - ct->c_rfc934 = is934; - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if ((p->c_rfc934 = is934)) - p->c_end++; - } - } - - if (listsw) { - ct->c_end = (partnum = strlen (prefix) + 2) + 2; - if (ct->c_rfc934) - ct->c_end += 1; - - for (part = m->mp_parts; part; part = part->mp_next) - ct->c_end += part->mp_part->c_end + partnum; - } - } - break; - - case CT_MESSAGE: - /* Nothing to do for type message */ - break; - - /* - * Discrete types (text/application/audio/image/video) - */ - default: - if (!ce->ce_file) { - pid_t child_id; - int i, xstdout, len, buflen; - char *bp, **ap, *cp; - char *vec[4], buffer[BUFSIZ]; - FILE *out; - CI ci = &ct->c_ctinfo; - char *tfile = NULL; - - if (!(cp = ci->ci_magic)) - adios (NULL, "internal error(5)"); - - tfile = m_mktemp2(NULL, invo_name, NULL, NULL); - if (tfile == NULL) { - adios("mhbuildsbr", "unable to create temporary file"); - } - ce->ce_file = add (tfile, NULL); - ce->ce_unlink = 1; - - xstdout = 0; - - /* Get buffer ready to go */ - bp = buffer; - bp[0] = '\0'; - buflen = sizeof(buffer); - - /* - * Parse composition string into buffer - */ - for ( ; *cp; cp++) { - if (*cp == '%') { - switch (*++cp) { - case 'a': - { - /* insert parameters from directive */ - char **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; - } - } - break; - - case 'F': - /* %f, and stdout is not-redirected */ - xstdout = 1; - /* and fall... */ - - case 'f': - /* - * insert temporary filename where - * content should be written - */ - snprintf (bp, buflen, "%s", ce->ce_file); - break; - - case 's': - /* insert content subtype */ - strncpy (bp, ci->ci_subtype, buflen); - break; - - case '%': - /* insert character % */ - goto raw; - - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - } else { -raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; - } - } - - if (verbosw) - printf ("composing content %s/%s from command\n\t%s\n", - ci->ci_type, ci->ci_subtype, buffer); - - fflush (stdout); /* not sure if need for -noverbose */ - - vec[0] = "/bin/sh"; - vec[1] = "-c"; - vec[2] = buffer; - vec[3] = NULL; - - if ((out = fopen (ce->ce_file, "w")) == NULL) - adios (ce->ce_file, "unable to open for writing"); - - for (i = 0; (child_id = vfork()) == NOTOK && i > 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - adios ("fork", "unable to fork"); - /* NOTREACHED */ - - case OK: - if (!xstdout) - dup2 (fileno (out), 1); - close (fileno (out)); - execvp ("/bin/sh", vec); - fprintf (stderr, "unable to exec "); - perror ("/bin/sh"); - _exit (-1); - /* NOTREACHED */ - - default: - fclose (out); - if (pidXwait(child_id, NULL)) - done (1); - break; - } - } - - /* Check size of file */ - if (listsw && ct->c_end == 0L) { - struct stat st; - - if (stat (ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; - } - break; - } - - return OK; -} - - -/* - * Scan the content. - * - * 1) choose a transfer encoding. - * 2) check for clashes with multipart boundary string. - * 3) for text content, figure out which character set is being used. - * - * If there is a clash with one of the contents and the multipart boundary, - * this function will exit with NOTOK. This will cause the scanning process - * to be repeated with a different multipart boundary. It is possible - * (although highly unlikely) that this scan will be repeated multiple times. - */ - -static int -scan_content (CT ct) -{ - int len; - int check8bit = 0, contains8bit = 0; /* check if contains 8bit data */ - int checklinelen = 0, linelen = 0; /* check for long lines */ - int checkboundary = 0, boundaryclash = 0; /* check if clashes with multipart boundary */ - int checklinespace = 0, linespace = 0; /* check if any line ends with space */ - int checkebcdic = 0, ebcdicunsafe = 0; /* check if contains ebcdic unsafe characters */ - unsigned char *cp = NULL, buffer[BUFSIZ]; - struct text *t = NULL; - FILE *in = NULL; - CE ce = ct->c_cefile; - - /* - * handle multipart by scanning all subparts - * and then checking their encoding. - */ - if (ct->c_type == CT_MULTIPART) { - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - - /* initially mark the domain of enclosing multipart as 7bit */ - ct->c_encoding = CE_7BIT; - - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if (scan_content (p) == NOTOK) /* choose encoding for subpart */ - return NOTOK; - - /* if necessary, enlarge encoding for enclosing multipart */ - if (p->c_encoding == CE_BINARY) - ct->c_encoding = CE_BINARY; - if (p->c_encoding == CE_8BIT && ct->c_encoding != CE_BINARY) - ct->c_encoding = CE_8BIT; - } - - return OK; - } - - /* - * Decide what to check while scanning this content. - */ - switch (ct->c_type) { - case CT_TEXT: - check8bit = 1; - checkboundary = 1; - if (ct->c_subtype == TEXT_PLAIN) { - checkebcdic = 0; - checklinelen = 0; - checklinespace = 0; - } else { - checkebcdic = ebcdicsw; - checklinelen = 1; - checklinespace = 1; - } - break; - - case CT_APPLICATION: - check8bit = 1; - checkebcdic = ebcdicsw; - checklinelen = 1; - checklinespace = 1; - checkboundary = 1; - break; - - case CT_MESSAGE: - check8bit = 0; - checkebcdic = 0; - checklinelen = 0; - checklinespace = 0; - - /* don't check anything for message/external */ - if (ct->c_subtype == MESSAGE_EXTERNAL) - checkboundary = 0; - else - checkboundary = 1; - break; - - case CT_AUDIO: - case CT_IMAGE: - case CT_VIDEO: - /* - * Don't check anything for these types, - * since we are forcing use of base64. - */ - check8bit = 0; - checkebcdic = 0; - checklinelen = 0; - checklinespace = 0; - checkboundary = 0; - break; - } - - /* - * Scan the unencoded content - */ - if (check8bit || checklinelen || checklinespace || checkboundary) { - if ((in = fopen (ce->ce_file, "r")) == NULL) - adios (ce->ce_file, "unable to open for reading"); - len = strlen (prefix); - - while (fgets (buffer, sizeof(buffer) - 1, in)) { - /* - * Check for 8bit data. - */ - if (check8bit) { - for (cp = buffer; *cp; cp++) { - if (!isascii (*cp)) { - contains8bit = 1; - check8bit = 0; /* no need to keep checking */ - } - /* - * Check if character is ebcdic-safe. We only check - * this if also checking for 8bit data. - */ - if (checkebcdic && !ebcdicsafe[*cp & 0xff]) { - ebcdicunsafe = 1; - checkebcdic = 0; /* no need to keep checking */ - } - } - } - - /* - * Check line length. - */ - if (checklinelen && (strlen (buffer) > CPERLIN + 1)) { - linelen = 1; - checklinelen = 0; /* no need to keep checking */ - } - - /* - * Check if line ends with a space. - */ - if (checklinespace && (cp = buffer + strlen (buffer) - 2) > buffer && isspace (*cp)) { - linespace = 1; - checklinespace = 0; /* no need to keep checking */ - } - - /* - * Check if content contains a line that clashes - * with our standard boundary for multipart messages. - */ - if (checkboundary && buffer[0] == '-' && buffer[1] == '-') { - for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (!isspace (*cp)) - break; - *++cp = '\0'; - if (!strncmp(buffer + 2, prefix, len) && isdigit(buffer[2 + len])) { - boundaryclash = 1; - checkboundary = 0; /* no need to keep checking */ - } - } - } - fclose (in); - } - - /* - * Decide which transfer encoding to use. - */ - switch (ct->c_type) { - case CT_TEXT: - /* - * If the text content didn't specify a character - * set, we need to figure out which one was used. - */ - t = (struct text *) ct->c_ctparams; - if (t->tx_charset == CHARSET_UNSPECIFIED) { - CI ci = &ct->c_ctinfo; - char **ap, **ep; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) - continue; - - if (contains8bit) { - t->tx_charset = CHARSET_UNKNOWN; - *ap = concat ("charset=", write_charset_8bit(), NULL); - } else { - t->tx_charset = CHARSET_USASCII; - *ap = add ("charset=us-ascii", NULL); - } - - cp = strchr(*ap++, '='); - *ap = NULL; - *cp++ = '\0'; - *ep = cp; - } - - if (contains8bit || ebcdicunsafe || linelen || linespace || checksw) - ct->c_encoding = CE_QUOTED; - else - ct->c_encoding = CE_7BIT; - break; - - case CT_APPLICATION: - /* For application type, use base64, except when postscript */ - if (contains8bit || ebcdicunsafe || linelen || linespace || checksw) - ct->c_encoding = (ct->c_subtype == APPLICATION_POSTSCRIPT) - ? CE_QUOTED : CE_BASE64; - else - ct->c_encoding = CE_7BIT; - break; - - case CT_MESSAGE: - ct->c_encoding = CE_7BIT; - break; - - case CT_AUDIO: - case CT_IMAGE: - case CT_VIDEO: - /* For audio, image, and video contents, just use base64 */ - ct->c_encoding = CE_BASE64; - break; - } - - return (boundaryclash ? NOTOK : OK); -} - - -/* - * Scan the content structures, and build header - * fields that will need to be output into the - * message. - */ - -static int -build_headers (CT ct) -{ - int cc, mailbody, len; - char **ap, **ep; - char *np, *vp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* - * If message is type multipart, then add the multipart - * boundary to the list of attribute/value pairs. - */ - if (ct->c_type == CT_MULTIPART) { - char *cp; - static int level = 0; /* store nesting level */ - - ap = ci->ci_attrs; - ep = ci->ci_values; - snprintf (buffer, sizeof(buffer), "boundary=%s%d", prefix, level++); - cp = strchr(*ap++ = add (buffer, NULL), '='); - *ap = NULL; - *cp++ = '\0'; - *ep = cp; - } - - /* - * Skip the output of Content-Type, parameters, content - * description and disposition, and Content-ID if the - * content is of type "message" and the rfc934 compatibility - * flag is set (which means we are inside multipart/digest - * and the switch -rfc934mode was given). - */ - if (ct->c_type == CT_MESSAGE && ct->c_rfc934) - goto skip_headers; - - /* - * output the content type and subtype - */ - np = add (TYPE_FIELD, NULL); - vp = concat (" ", ci->ci_type, "/", ci->ci_subtype, NULL); - - /* keep track of length of line */ - len = strlen (TYPE_FIELD) + strlen (ci->ci_type) - + strlen (ci->ci_subtype) + 3; - - mailbody = ct->c_type == CT_MESSAGE - && ct->c_subtype == MESSAGE_EXTERNAL - && ((struct exbody *) ct->c_ctparams)->eb_body; - - /* - * Append the attribute/value pairs to - * the end of the Content-Type line. - */ - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (mailbody && !mh_strcasecmp (*ap, "body")) - continue; - - vp = add (";", vp); - len++; - - snprintf (buffer, sizeof(buffer), "%s=\"%s\"", *ap, *ep); - if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) { - vp = add ("\n\t", vp); - len = 8; - } else { - vp = add (" ", vp); - len++; - } - vp = add (buffer, vp); - len += cc; - } - - /* - * Append any RFC-822 comment to the end of - * the Content-Type line. - */ - if (ci->ci_comment) { - snprintf (buffer, sizeof(buffer), "(%s)", ci->ci_comment); - if (len + 1 + (cc = 2 + strlen (ci->ci_comment)) >= CPERLIN) { - vp = add ("\n\t", vp); - len = 8; - } else { - vp = add (" ", vp); - len++; - } - vp = add (buffer, vp); - len += cc; - } - vp = add ("\n", vp); - add_header (ct, np, vp); - - /* - * output the Content-ID, unless disabled by -nocontentid - */ - if (contentidsw && ct->c_id) { - np = add (ID_FIELD, NULL); - vp = concat (" ", ct->c_id, NULL); - add_header (ct, np, vp); - } - - /* - * output the Content-Description - */ - if (ct->c_descr) { - np = add (DESCR_FIELD, NULL); - vp = concat (" ", ct->c_descr, NULL); - add_header (ct, np, vp); - } - - /* - * output the Content-Disposition - */ - if (ct->c_dispo) { - np = add (DISPO_FIELD, NULL); - vp = concat (" ", ct->c_dispo, NULL); - add_header (ct, np, vp); - } - -skip_headers: - /* - * If this is the internal content structure for a - * "message/external", then we are done with the - * headers (since it has no body). - */ - if (ct->c_ctexbody) - return OK; - - /* - * output the Content-MD5 - */ - if (checksw) { - np = add (MD5_FIELD, NULL); - vp = calculate_digest (ct, (ct->c_encoding == CE_QUOTED) ? 1 : 0); - add_header (ct, np, vp); - } - - /* - * output the Content-Transfer-Encoding - */ - switch (ct->c_encoding) { - case CE_7BIT: - /* Nothing to output */ -#if 0 - np = add (ENCODING_FIELD, NULL); - vp = concat (" ", "7bit", "\n", NULL); - add_header (ct, np, vp); -#endif - break; - - case CE_8BIT: - if (ct->c_type == CT_MESSAGE) - adios (NULL, "internal error, invalid encoding"); - - np = add (ENCODING_FIELD, NULL); - vp = concat (" ", "8bit", "\n", NULL); - add_header (ct, np, vp); - break; - - case CE_QUOTED: - if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios (NULL, "internal error, invalid encoding"); - - np = add (ENCODING_FIELD, NULL); - vp = concat (" ", "quoted-printable", "\n", NULL); - add_header (ct, np, vp); - break; - - case CE_BASE64: - if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios (NULL, "internal error, invalid encoding"); - - np = add (ENCODING_FIELD, NULL); - vp = concat (" ", "base64", "\n", NULL); - add_header (ct, np, vp); - break; - - case CE_BINARY: - if (ct->c_type == CT_MESSAGE) - adios (NULL, "internal error, invalid encoding"); - - np = add (ENCODING_FIELD, NULL); - vp = concat (" ", "binary", "\n", NULL); - add_header (ct, np, vp); - break; - - default: - adios (NULL, "unknown transfer encoding in content"); - break; - } - - /* - * Additional content specific header processing - */ - switch (ct->c_type) { - case CT_MULTIPART: - { - struct multipart *m; - struct part *part; - - m = (struct multipart *) ct->c_ctparams; - for (part = m->mp_parts; part; part = part->mp_next) { - CT p; - - p = part->mp_part; - build_headers (p); - } - } - break; - - case CT_MESSAGE: - if (ct->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e; - - e = (struct exbody *) ct->c_ctparams; - build_headers (e->eb_content); - } - break; - - default: - /* Nothing to do */ - break; - } - - return OK; -} - - -static char nib2b64[0x40+1] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static char * -calculate_digest (CT ct, int asciiP) -{ - int cc; - char buffer[BUFSIZ], *vp, *op; - unsigned char *dp; - unsigned char digest[16]; - unsigned char outbuf[25]; - FILE *in; - MD5_CTX mdContext; - CE ce = ct->c_cefile; - - /* open content */ - if ((in = fopen (ce->ce_file, "r")) == NULL) - adios (ce->ce_file, "unable to open for reading"); - - /* Initialize md5 context */ - MD5Init (&mdContext); - - /* calculate md5 message digest */ - if (asciiP) { - while (fgets (buffer, sizeof(buffer) - 1, in)) { - char c, *cp; - - cp = buffer + strlen (buffer) - 1; - if ((c = *cp) == '\n') - *cp = '\0'; - - MD5Update (&mdContext, (unsigned char *) buffer, - (unsigned int) strlen (buffer)); - - if (c == '\n') - MD5Update (&mdContext, (unsigned char *) "\r\n", 2); - } - } else { - while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), in)) > 0) - MD5Update (&mdContext, (unsigned char *) buffer, (unsigned int) cc); - } - - /* md5 finalization. Write digest and zero md5 context */ - MD5Final (digest, &mdContext); - - /* close content */ - fclose (in); - - /* print debugging info */ - if (debugsw) { - unsigned char *ep; - - fprintf (stderr, "MD5 digest="); - for (ep = (dp = digest) + sizeof(digest) / sizeof(digest[0]); - dp < ep; dp++) - fprintf (stderr, "%02x", *dp & 0xff); - fprintf (stderr, "\n"); - } - - /* encode the digest using base64 */ - for (dp = digest, op = outbuf, cc = sizeof(digest) / sizeof(digest[0]); - cc > 0; cc -= 3, op += 4) { - unsigned long bits; - char *bp; - - bits = (*dp++ & 0xff) << 16; - if (cc > 1) { - bits |= (*dp++ & 0xff) << 8; - if (cc > 2) - bits |= *dp++ & 0xff; - } - - for (bp = op + 4; bp > op; bits >>= 6) - *--bp = nib2b64[bits & 0x3f]; - if (cc < 3) { - *(op + 3) = '='; - if (cc < 2) - *(op + 2) = '='; - } - } - - /* null terminate string */ - outbuf[24] = '\0'; - - /* now make copy and return string */ - vp = concat (" ", outbuf, "\n", NULL); - return vp; -} diff --git a/uip/mhcachesbr.c b/uip/mhcachesbr.c deleted file mode 100644 index 2223e80..0000000 --- a/uip/mhcachesbr.c +++ /dev/null @@ -1,455 +0,0 @@ - -/* - * mhcachesbr.c -- routines to manipulate the MIME content cache - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -extern int debugsw; - -extern pid_t xpid; /* mhshowsbr.c or mhbuildsbr.c */ - -/* cache policies */ -int rcachesw = CACHE_ASK; -int wcachesw = CACHE_ASK; - -/* - * Location of public and private cache. These must - * be set before these routines are called. - */ -char *cache_public; -char *cache_private; - - -/* mhparse.c (OR) mhbuildsbr.c */ -int pidcheck (int); - -/* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -int make_intermediates (char *); -void content_error (char *, CT, char *, ...); -void flush_errors (void); - -/* - * prototypes - */ -void cache_all_messages (CT *); -int find_cache (CT, int, int *, char *, char *, int); - -/* - * static prototypes - */ -static void cache_content (CT); -static int find_cache_aux (int, char *, char *, char *, int); -static int find_cache_aux2 (char *, char *, char *, int); - - -/* - * Top level entry point to cache content - * from a group of messages - */ - -void -cache_all_messages (CT *cts) -{ - CT ct, *ctp; - - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - if (type_ok (ct, 1)) { - cache_content (ct); - if (ct->c_fp) { - fclose (ct->c_fp); - ct->c_fp = NULL; - } - if (ct->c_ceclosefnx) - (*ct->c_ceclosefnx) (ct); - } - } - flush_errors (); -} - - -/* - * Entry point to cache content from external sources. - */ - -static void -cache_content (CT ct) -{ - int cachetype; - char *file, cachefile[BUFSIZ]; - CE ce = ct->c_cefile; - - if (!ct->c_id) { - advise (NULL, "no %s: field in %s", ID_FIELD, ct->c_file); - return; - } - - if (!ce) { - advise (NULL, "unable to decode %s", ct->c_file); - return; - } - -/* THIS NEEDS TO BE FIXED */ -#if 0 - if (ct->c_ceopenfnx == openMail) { - advise (NULL, "a radish may no know Greek, but I do..."); - return; - } -#endif - - if (find_cache (NULL, wcachesw != CACHE_NEVER ? wcachesw : CACHE_ASK, - &cachetype, ct->c_id, cachefile, sizeof(cachefile)) - == NOTOK) { - advise (NULL, "unable to cache %s's contents", ct->c_file); - return; - } - if (wcachesw != CACHE_NEVER && wcachesw != CACHE_ASK) { - fflush (stdout); - fprintf (stderr, "caching message %s as file %s\n", ct->c_file, - cachefile); - } - - if (ce->ce_file) { - int mask = umask (cachetype ? ~m_gmprot () : 0222); - FILE *fp; - - if (debugsw) - fprintf (stderr, "caching by copying %s...\n", ce->ce_file); - - file = NULL; - if ((*ct->c_ceopenfnx) (ct, &file) == NOTOK) - goto reset_umask; - - if ((fp = fopen (cachefile, "w"))) { - int cc; - char buffer[BUFSIZ]; - FILE *gp = ce->ce_fp; - - fseek (gp, 0L, SEEK_SET); - - while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) - > 0) - fwrite (buffer, sizeof(*buffer), cc, fp); - fflush (fp); - - if (ferror (gp)) { - admonish (ce->ce_file, "error reading"); - unlink (cachefile); - } else { - if (ferror (fp)) { - admonish (cachefile, "error writing"); - unlink (cachefile); - } - } - fclose (fp); - } else - content_error (cachefile, ct, "unable to fopen for writing"); -reset_umask: - umask (mask); - } else { - if (debugsw) - fprintf (stderr, "in place caching...\n"); - - file = cachefile; - if ((*ct->c_ceopenfnx) (ct, &file) != NOTOK) - chmod (cachefile, cachetype ? m_gmprot () : 0444); - } -} - - -int -find_cache (CT ct, int policy, int *writing, char *id, - char *buffer, int buflen) -{ - int status = NOTOK; - - if (id == NULL) - return NOTOK; - id = trimcpy (id); - - if (debugsw) - fprintf (stderr, "find_cache %s(%d) %s %s\n", caches[policy].sw, - policy, writing ? "writing" : "reading", id); - - switch (policy) { - case CACHE_NEVER: - default: - break; - - case CACHE_ASK: - case CACHE_PUBLIC: - if (cache_private - && !writing - && find_cache_aux (writing ? 2 : 0, cache_private, id, - buffer, buflen) == OK) { - if (access (buffer, R_OK) != NOTOK) { -got_private: - if (writing) - *writing = 1; -got_it: - status = OK; - break; - } - } - if (cache_public - && find_cache_aux (writing ? 1 : 0, cache_public, id, - buffer, buflen) == OK) { - if (writing || access (buffer, R_OK) != NOTOK) { - if (writing) - *writing = 0; - goto got_it; - } - } - break; - - case CACHE_PRIVATE: - if (cache_private - && find_cache_aux (writing ? 2 : 0, cache_private, id, - buffer, buflen) == OK) { - if (writing || access (buffer, R_OK) != NOTOK) - goto got_private; - } - break; - - } - - if (status == OK && policy == CACHE_ASK) { - int len, buflen; - char *bp, query[BUFSIZ]; - - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - - /* Get buffer ready to go */ - bp = query; - buflen = sizeof(query); - - /* Now, construct query */ - if (writing) { - snprintf (bp, buflen, "Make cached, publically-accessible copy"); - } else { - struct stat st; - - snprintf (bp, buflen, "Use cached copy"); - len = strlen (bp); - bp += len; - buflen -= len; - - if (ct->c_partno) { - snprintf (bp, buflen, " of content %s", ct->c_partno); - len = strlen (bp); - bp += len; - buflen -= len; - } - - stat (buffer, &st); - snprintf (bp, buflen, " (size %lu octets)", - (unsigned long) st.st_size); - } - len = strlen (bp); - bp += len; - buflen -= len; - - snprintf (bp, buflen, "\n in file %s? ", buffer); - - /* Now, check answer */ - if (!getanswer (query)) - status = NOTOK; - } - - if (status == OK && writing) { - if (*writing && strchr(buffer, '/')) - make_intermediates (buffer); - unlink (buffer); - } - - free (id); - return status; -} - - -static int -find_cache_aux (int writing, char *directory, char *id, - char *buffer, int buflen) -{ - int mask, usemap; - char mapfile[BUFSIZ], mapname[BUFSIZ]; - FILE *fp; - static int partno, pid; - static time_t clock = 0; - -#ifdef BSD42 - usemap = strchr (id, '/') ? 1 : 0; -#else - usemap = 1; -#endif - - if (debugsw) - fprintf (stderr, "find_cache_aux %s usemap=%d\n", directory, usemap); - - snprintf (mapfile, sizeof(mapfile), "%s/cache.map", directory); - if (find_cache_aux2 (mapfile, id, mapname, sizeof(mapname)) == OK) - goto done_map; - - if (!writing) { - if (usemap) - return NOTOK; - -use_raw: - snprintf (buffer, buflen, "%s/%s", directory, id); - return OK; - } - - if (!usemap && access (mapfile, W_OK) == NOTOK) - goto use_raw; - - if (clock != 0) { - time_t now; - - time (&now); - if (now > clock) - clock = 0; - } else { - pid = getpid (); - } - - if (clock == 0) { - time (&clock); - partno = 0; - } else { - if (partno > 0xff) { - clock++; - partno = 0; - } - } - - snprintf (mapname, sizeof(mapname), "%08x%04x%02x", - (unsigned int) (clock & 0xffffffff), - (unsigned int) (pid & 0xffff), - (unsigned int) (partno++ & 0xff)); - - if (debugsw) - fprintf (stderr, "creating mapping %s->%s\n", mapname, id); - - make_intermediates (mapfile); - mask = umask (writing == 2 ? 0077 : 0); - if (!(fp = lkfopen (mapfile, "a")) && errno == ENOENT) { - int fd; - - if ((fd = creat (mapfile, 0666)) != NOTOK) { - close (fd); - fp = lkfopen (mapfile, "a"); - } - } - umask (mask); - if (!fp) - return NOTOK; - fprintf (fp, "%s: %s\n", mapname, id); - lkfclose (fp, mapfile); - -done_map: - if (*mapname == '/') - strncpy (buffer, mapname, buflen); - else - snprintf (buffer, buflen, "%s/%s", directory, mapname); - if (debugsw) - fprintf (stderr, "use %s\n", buffer); - - return OK; -} - - -static int -find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen) -{ - int state; - char buf[BUFSIZ], name[NAMESZ]; - FILE *fp; - - if (!(fp = lkfopen (mapfile, "r"))) - return NOTOK; - - for (state = FLD;;) { - int result; - char *cp, *dp; - - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - strncpy (mapname, name, namelen); - if (state != FLDPLUS) - cp = buf; - else { - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); - cp = add (buf, cp); - } - } - dp = trimcpy (cp); - if (cp != buf) - free (cp); - if (debugsw) - fprintf (stderr, "compare %s to %s <- %s\n", id, dp, - mapname); - result = strcmp (id, dp); - free (dp); - if (result == 0) { - lkfclose (fp, mapfile); - return OK; - } - if (state != FLDEOF) - continue; - /* else fall... */ - - case BODY: - case BODYEOF: - case FILEEOF: - default: - break; - } - break; - } - - lkfclose (fp, mapfile); - return NOTOK; -} diff --git a/uip/mhfree.c b/uip/mhfree.c index 38b830e..bf3382c 100644 --- a/uip/mhfree.c +++ b/uip/mhfree.c @@ -1,12 +1,11 @@ - /* - * mhfree.c -- routines to free the data structures used to - * -- represent MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhfree.c -- routines to free the data structures used to +** -- represent MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -17,282 +16,258 @@ CT *cts = NULL; /* - * prototypes - */ -void free_content (CT); -void free_header (CT); -void free_ctinfo (CT); -void free_encoding (CT, int); -void freects_done (int); +** prototypes +*/ +void free_content(CT); +void free_header(CT); +void free_ctinfo(CT); +void free_encoding(CT, int); +void freects_done(int); /* - * static prototypes - */ -static void free_text (CT); -static void free_multi (CT); -static void free_partial (CT); -static void free_external (CT); +** static prototypes +*/ +static void free_text(CT); +static void free_multi(CT); +static void free_partial(CT); /* - * Primary routine to free a MIME content structure - */ +** Primary routine to free a MIME content structure +*/ void -free_content (CT ct) +free_content(CT ct) { - if (!ct) - return; + if (!ct) + return; - /* - * free all the header fields - */ - free_header (ct); + /* + ** free all the header fields + */ + free_header(ct); - if (ct->c_partno) - free (ct->c_partno); + if (ct->c_partno) + free(ct->c_partno); - if (ct->c_vrsn) - free (ct->c_vrsn); + if (ct->c_vrsn) + free(ct->c_vrsn); - if (ct->c_ctline) - free (ct->c_ctline); + if (ct->c_ctline) + free(ct->c_ctline); - free_ctinfo (ct); + free_ctinfo(ct); - /* - * some of the content types have extra - * parts which need to be freed. - */ - switch (ct->c_type) { + /* + ** some of the content types have extra + ** parts which need to be freed. + */ + switch (ct->c_type) { case CT_MULTIPART: - free_multi (ct); - break; + free_multi(ct); + break; case CT_MESSAGE: - switch (ct->c_subtype) { - case MESSAGE_PARTIAL: - free_partial (ct); - break; - - case MESSAGE_EXTERNAL: - free_external (ct); - break; - } - break; + if (ct->c_subtype == MESSAGE_PARTIAL) { + free_partial(ct); + } + break; case CT_TEXT: - free_text (ct); - break; - } - - if (ct->c_showproc) - free (ct->c_showproc); - if (ct->c_termproc) - free (ct->c_termproc); - if (ct->c_storeproc) - free (ct->c_storeproc); - - if (ct->c_celine) - free (ct->c_celine); - - /* free structures for content encodings */ - free_encoding (ct, 1); - - if (ct->c_id) - free (ct->c_id); - if (ct->c_descr) - free (ct->c_descr); - if (ct->c_dispo) - free (ct->c_dispo); - - if (ct->c_file) { - if (ct->c_unlink) - unlink (ct->c_file); - free (ct->c_file); - } - if (ct->c_fp) - fclose (ct->c_fp); - - if (ct->c_storage) - free (ct->c_storage); - if (ct->c_folder) - free (ct->c_folder); - - free (ct); + free_text(ct); + break; + } + + if (ct->c_charset) + free(ct->c_charset); + if (ct->c_showproc) + free(ct->c_showproc); + if (ct->c_storeproc) + free(ct->c_storeproc); + + if (ct->c_celine) + free(ct->c_celine); + + /* free structures for content encodings */ + free_encoding(ct, 1); + + if (ct->c_id) + free(ct->c_id); + if (ct->c_descr) + free(ct->c_descr); + if (ct->c_dispo) + free(ct->c_dispo); + + if (ct->c_file) { + if (ct->c_unlink) + unlink(ct->c_file); + free(ct->c_file); + } + if (ct->c_fp) + fclose(ct->c_fp); + + if (ct->c_storage) + free(ct->c_storage); + if (ct->c_folder) + free(ct->c_folder); + + free(ct); } /* - * Free the linked list of header fields - * for this content. - */ +** Free the linked list of header fields +** for this content. +*/ void -free_header (CT ct) +free_header(CT ct) { - HF hp1, hp2; + HF hp1, hp2; - hp1 = ct->c_first_hf; - while (hp1) { - hp2 = hp1->next; + hp1 = ct->c_first_hf; + while (hp1) { + hp2 = hp1->next; - free (hp1->name); - free (hp1->value); - free (hp1); + free(hp1->name); + free(hp1->value); + free(hp1); - hp1 = hp2; - } + hp1 = hp2; + } - ct->c_first_hf = NULL; - ct->c_last_hf = NULL; + ct->c_first_hf = NULL; + ct->c_last_hf = NULL; } void -free_ctinfo (CT ct) +free_ctinfo(CT ct) { - char **ap; - CI ci; - - ci = &ct->c_ctinfo; - if (ci->ci_type) { - free (ci->ci_type); - ci->ci_type = NULL; - } - if (ci->ci_subtype) { - free (ci->ci_subtype); - ci->ci_subtype = NULL; - } - for (ap = ci->ci_attrs; *ap; ap++) { - free (*ap); - *ap = NULL; - } - if (ci->ci_comment) { - free (ci->ci_comment); - ci->ci_comment = NULL; - } - if (ci->ci_magic) { - free (ci->ci_magic); - ci->ci_magic = NULL; - } + char **ap; + CI ci; + + ci = &ct->c_ctinfo; + if (ci->ci_type) { + free(ci->ci_type); + ci->ci_type = NULL; + } + if (ci->ci_subtype) { + free(ci->ci_subtype); + ci->ci_subtype = NULL; + } + for (ap = ci->ci_attrs; *ap; ap++) { + free(*ap); + *ap = NULL; + } + if (ci->ci_comment) { + free(ci->ci_comment); + ci->ci_comment = NULL; + } + if (ci->ci_magic) { + free(ci->ci_magic); + ci->ci_magic = NULL; + } } static void -free_text (CT ct) +free_text(CT ct) { - struct text *t; - - if (!(t = (struct text *) ct->c_ctparams)) - return; - - free ((char *) t); - ct->c_ctparams = NULL; -} + struct text *t; + if (!(t = (struct text *) ct->c_ctparams)) + return; -static void -free_multi (CT ct) -{ - struct multipart *m; - struct part *part, *next; - - if (!(m = (struct multipart *) ct->c_ctparams)) - return; - - if (m->mp_start) - free (m->mp_start); - if (m->mp_stop) - free (m->mp_stop); - - for (part = m->mp_parts; part; part = next) { - next = part->mp_next; - free_content (part->mp_part); - free ((char *) part); - } - m->mp_parts = NULL; - - free ((char *) m); - ct->c_ctparams = NULL; + free((char *) t); + ct->c_ctparams = NULL; } static void -free_partial (CT ct) +free_multi(CT ct) { - struct partial *p; - - if (!(p = (struct partial *) ct->c_ctparams)) - return; - - if (p->pm_partid) - free (p->pm_partid); - - free ((char *) p); - ct->c_ctparams = NULL; + struct multipart *m; + struct part *part, *next; + + if (!(m = (struct multipart *) ct->c_ctparams)) + return; + + if (m->mp_start) + free(m->mp_start); + if (m->mp_stop) + free(m->mp_stop); + + for (part = m->mp_parts; part; part = next) { + next = part->mp_next; + free_content(part->mp_part); + free((char *) part); + } + m->mp_parts = NULL; + + free((char *) m); + ct->c_ctparams = NULL; } static void -free_external (CT ct) +free_partial(CT ct) { - struct exbody *e; + struct partial *p; - if (!(e = (struct exbody *) ct->c_ctparams)) - return; + if (!(p = (struct partial *) ct->c_ctparams)) + return; - free_content (e->eb_content); - if (e->eb_body) - free (e->eb_body); + if (p->pm_partid) + free(p->pm_partid); - free ((char *) e); - ct->c_ctparams = NULL; + free((char *) p); + ct->c_ctparams = NULL; } /* - * Free data structures related to encoding/decoding - * Content-Transfer-Encodings. - */ +** Free data structures related to encoding/decoding +** Content-Transfer-Encodings. +*/ void -free_encoding (CT ct, int toplevel) +free_encoding(CT ct, int toplevel) { - CE ce; - - if (!(ce = ct->c_cefile)) - return; - - if (ce->ce_fp) { - fclose (ce->ce_fp); - ce->ce_fp = NULL; - } - - if (ce->ce_file) { - if (ce->ce_unlink) - unlink (ce->ce_file); - free (ce->ce_file); - ce->ce_file = NULL; - } - - if (toplevel) { - free ((char *) ce); - ct->c_cefile = NULL; - } else { - ct->c_ceopenfnx = NULL; - } + CE ce; + + if (!(ce = ct->c_cefile)) + return; + + if (ce->ce_fp) { + fclose(ce->ce_fp); + ce->ce_fp = NULL; + } + + if (ce->ce_file) { + if (ce->ce_unlink) + unlink(ce->ce_file); + free(ce->ce_file); + ce->ce_file = NULL; + } + + if (toplevel) { + free((char *) ce); + ct->c_cefile = NULL; + } else { + ct->c_ceopenfnx = NULL; + } } void -freects_done (int status) +freects_done(int status) { - CT *ctp; + CT *ctp; - if ((ctp = cts)) - for (; *ctp; ctp++) - free_content (*ctp); + if ((ctp = cts)) + for (; *ctp; ctp++) + free_content(*ctp); - exit (status); + exit(status); } diff --git a/uip/mhl.c b/uip/mhl.c index de12dde..fedf78f 100644 --- a/uip/mhl.c +++ b/uip/mhl.c @@ -1,38 +1,1148 @@ - /* - * mhl.c -- the nmh message listing program - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhl.c -- the nmh message listing program +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include +#include +#include +#include +#include +#include +#include +#include + +/* +** MAJOR BUG: +** for a component containing addresses, ADDRFMT, if COMPRESS is also +** set, then addresses get split wrong (not at the spaces between commas). +** To fix this correctly, putstr() should know about "atomic" strings that +** must NOT be broken across lines. That's too difficult for right now +** (it turns out that there are a number of degernate cases), so in +** oneline(), instead of +** +** (*onelp == '\n' && !onelp[1]) +** +** being a terminating condition, +** +** (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) +** +** is used instead. This cuts the line prematurely, and gives us a much +** better chance of getting things right. +*/ + +#define ONECOMP 0 +#define TWOCOMP 1 +#define BODYCOMP 2 + +#define QUOTE '\\' + +static struct swit switches[] = { +#define FORMSW 0 + { "form formfile", 0 }, +#define WIDTHSW 1 + { "width columns", 0 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, +#define FORW1SW 4 + { "forward", -7 }, +#define FORW2SW 5 + { "forwall", -7 }, +#define NBODYSW 6 + { "nobody", -6 }, + { NULL, 0 } +}; + +#define NOCOMPONENT 0x000001 /* don't show component name */ +#define UPPERCASE 0x000002 /* display in all upper case */ +#define CENTER 0x000004 /* center line */ +#define CLEARTEXT 0x000008 /* cleartext */ +#define EXTRA 0x000010 /* an "extra" component */ +#define HDROUTPUT 0x000020 /* already output */ +#define LEFTADJUST 0x000040 /* left justify multiple lines */ +#define COMPRESS 0x000080 /* compress text */ +#define ADDRFMT 0x000100 /* contains addresses */ +#define DATEFMT 0x000200 /* contains dates */ +#define FORMAT 0x000400 /* parse address/date/RFC-2047 field */ +#define INIT 0x000800 /* initialize component */ +#define SPLIT 0x001000 /* split headers (don't concatenate) */ +#define NONEWLINE 0x002000 /* don't write trailing newline */ +#define LBITS "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07LEFTADJUST\010COMPRESS\011ADDRFMT\012DATEFMT\013FORMAT\014INIT\015SPLIT\016NONEWLINE" +#define GFLAGS (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS | SPLIT) + +struct mcomp { + char *c_name; /* component name */ + char *c_text; /* component text */ + char *c_ovtxt; /* text overflow indicator */ + char *c_fstr; /* iff FORMAT */ + struct format *c_fmt; /* .. */ + int c_offset; /* left margin indentation */ + int c_ovoff; /* overflow indentation */ + int c_width; /* width of field */ + int c_cwidth; /* width of component */ + long c_flags; + struct mcomp *c_next; +}; + +static struct mcomp *msghd = NULL; +static struct mcomp *msgtl = NULL; +static struct mcomp *fmthd = NULL; +static struct mcomp *fmttl = NULL; + +static struct mcomp global = { + NULL, NULL, NULL, NULL, NULL, 0, -1, 80, -1, 0, NULL +}; + +static struct mcomp holder = { + NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NOCOMPONENT, NULL +}; + +struct pair { + char *p_name; + long p_flags; +}; + +static struct pair pairs[] = { + { "Date", DATEFMT }, + { "From", ADDRFMT }, + { "Sender", ADDRFMT }, + { "Reply-To", ADDRFMT }, + { "To", ADDRFMT }, + { "Cc", ADDRFMT }, + { "Bcc", ADDRFMT }, + { "Resent-Date", DATEFMT }, + { "Resent-From", ADDRFMT }, + { "Resent-Sender", ADDRFMT }, + { "Resent-Reply-To", ADDRFMT }, + { "Resent-To", ADDRFMT }, + { "Resent-Cc", ADDRFMT }, + { "Resent-Bcc", ADDRFMT }, + { NULL, 0 } +}; + +struct triple { + char *t_name; + long t_on; + long t_off; +}; + +static struct triple triples[] = { + { "nocomponent", NOCOMPONENT, 0 }, + { "uppercase", UPPERCASE, 0 }, + { "nouppercase", 0, UPPERCASE }, + { "center", CENTER, 0 }, + { "nocenter", 0, CENTER }, + { "leftadjust", LEFTADJUST, 0 }, + { "noleftadjust", 0, LEFTADJUST }, + { "compress", COMPRESS, 0 }, + { "nocompress", 0, COMPRESS }, + { "split", SPLIT, 0 }, + { "nosplit", 0, SPLIT }, + { "addrfield", ADDRFMT, DATEFMT }, + { "datefield", DATEFMT, ADDRFMT }, + { "newline", 0, NONEWLINE }, + { "nonewline", NONEWLINE, 0 }, + { NULL, 0, 0 } +}; + + +static int dobody = 1; +static int forwflg = 0; +static int forwall = 0; + +static int exitstat = 0; +static int mhldebug = 0; + +static unsigned int column; + +static int lm; +static int ovoff; +static int term; +static unsigned int wid; + +static char *ovtxt; + +static unsigned char *onelp; + +static char *parptr; + +static int num_ignores = 0; +static char *ignores[MAXARGS]; + +static jmp_buf env; +static jmp_buf mhlenv; -/* prototype from mhlsbr.c */ -int mhl (int, char **); +static FILE *(*mhl_action) () = (FILE *(*) ()) 0; + + +/* +** Redefine a couple of functions. +** These are undefined later in the code. +*/ +#define adios mhladios +#define done mhldone + +/* +** prototypes +*/ +static void mhl_format(char *, int); +static int evalvar(struct mcomp *); +static int ptoi(char *, int *); +static int ptos(char *, char **); +static char *parse(void); +static void process(char *, int, int); +static void mhlfile(FILE *, char *, int, int); +static int mcomp_flags(char *); +static char *mcomp_add(long, char *, char *); +static void mcomp_format(struct mcomp *, struct mcomp *); +static struct mcomp *add_queue(struct mcomp **, struct mcomp **, + char *, char *, int); +static void free_queue(struct mcomp **, struct mcomp **); +static void putcomp(struct mcomp *, struct mcomp *, int); +static char *oneline(char *, long); +static void putstr(char *); +static void putch(char); +static void intrser(int); +static void mhladios(char *, char *, ...); +static void mhldone(int); + +int sc_width(void); /* from termsbr.c */ int -main (int argc, char **argv) +main(int argc, char **argv) { -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - done (mhl (argc, argv)); - return 1; + int i, width = 0, vecp = 0; + char *cp, *form = NULL; + char buf[BUFSIZ], *files[MAXARGS]; + char **argp, **arguments; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + if ((cp = getenv("MHLDEBUG")) && *cp) + mhldebug++; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] [files ...]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WIDTHSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if ((width = atoi(cp)) < 1) + adios(NULL, "bad argument %s %s", + argp[-2], cp); + continue; + + case FORW2SW: + forwall++; /* fall */ + case FORW1SW: + forwflg++; + continue; + + case NBODYSW: + dobody = 0; + continue; + } + } + files[vecp++] = cp; + } + + mhl_format(form ? form : mhlformat, width); + + if (vecp == 0) { + process(NULL, 1, vecp = 1); + } else { + for (i = 0; i < vecp; i++) + process(files[i], i + 1, vecp); + } + + if (forwall) { + printf("\n------- End of Forwarded Message%s\n\n", + vecp > 1 ? "s" : ""); + } + + fflush(stdout); + if (ferror(stdout)) { + adios("output", "error writing"); + } + + return exitstat; } -/* - * Cheat: we are loaded with adrparse, which wants a routine called - * OfficialName(). We call adrparse:getm() with the correct arguments - * to prevent OfficialName() from being called. Hence, the following - * is to keep the loader happy. - */ +static void +mhl_format(char *file, int width) +{ + int i; + char *bp, *cp; + char *ap, buffer[BUFSIZ], name[NAMESZ]; + struct mcomp *c1; + struct stat st; + FILE *fp; + static dev_t dev = 0; + static ino_t ino = 0; + static time_t mtime = 0; + + if (fmthd != NULL) { + if (stat(etcpath(file), &st) != NOTOK + && mtime == st.st_mtime + && dev == st.st_dev + && ino == st.st_ino) + goto out; + else + free_queue(&fmthd, &fmttl); + } + + if ((fp = fopen(etcpath(file), "r")) == NULL) + adios(file, "unable to open format file"); + + if (fstat(fileno(fp), &st) != NOTOK) { + mtime = st.st_mtime; + dev = st.st_dev; + ino = st.st_ino; + } + + global.c_ovtxt = global.c_fstr = NULL; + global.c_fmt = NULL; + global.c_offset = 0; + global.c_ovoff = -1; + if ((i = sc_width()) > 5) + global.c_width = i; + global.c_cwidth = -1; + global.c_flags = 0; + *ignores = NULL; + + while (vfgets(fp, &ap) == OK) { + bp = ap; + if (*bp == ';') + continue; + + if ((cp = strchr(bp, '\n'))) + *cp = 0; + + if (*bp == ':') { + c1 = add_queue(&fmthd, &fmttl, NULL, bp + 1, + CLEARTEXT); + continue; + } + + parptr = bp; + strncpy(name, parse(), sizeof(name)); + switch(*parptr) { + case '\0': + case ',': + case '=': + /* + ** Split this list of fields to ignore, and copy + ** it to the end of the current "ignores" list. + */ + if (!mh_strcasecmp(name, "ignores")) { + char **tmparray; + int n = 0; + + /* split the fields */ + tmparray = brkstring(getcpy(++parptr), ",", + NULL); + /* + ** copy pointers to split fields + ** to ignores array + */ + while (tmparray[n] && num_ignoresc_fstr && global.c_fstr) { + if ((c1->c_flags & DATEFMT) && + (global.c_flags & DATEFMT)) { + c1->c_fstr = getcpy(global.c_fstr); + } else if ((c1->c_flags & ADDRFMT) && + (global.c_flags & ADDRFMT)) { + c1->c_fstr = getcpy(global.c_fstr); + } + } + continue; + + default: + adios(NULL, "format file syntax error: %s", bp); + } + } + fclose(fp); + + if (mhldebug) { + for (c1 = fmthd; c1; c1 = c1->c_next) { + fprintf(stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n", c1->c_name, c1->c_text, c1->c_ovtxt); + fprintf(stderr, "\tfstr=0x%x fmt=0x%x\n", (unsigned int)(unsigned long) c1->c_fstr, (unsigned int)(unsigned long) c1->c_fmt); + fprintf(stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d\n", c1->c_offset, c1->c_ovoff, c1->c_width, c1->c_cwidth); + fprintf (stderr, "\tflags=%s\n", snprintb(buffer, sizeof(buffer), (unsigned) c1->c_flags, LBITS)); + } + } + +out: + if (width) + global.c_width = width; + if (global.c_width < 5) + global.c_width = 10000; +} + + +static int +evalvar(struct mcomp *c1) +{ + char *cp, name[NAMESZ]; + struct triple *ap; + + if (!*parptr) + return 0; + strncpy(name, parse(), sizeof(name)); + + if (!mh_strcasecmp(name, "component")) { + if (ptos(name, &c1->c_text)) + return 1; + c1->c_flags &= ~NOCOMPONENT; + return 0; + } + + if (!mh_strcasecmp(name, "overflowtext")) + return ptos(name, &c1->c_ovtxt); + + if (!mh_strcasecmp(name, "formatfield")) { + char *fmtstr; + + if (ptos(name, &cp)) + return 1; + cp = concat("=", cp, NULL); + fmtstr = new_fs(cp, NULL); + free(cp); + c1->c_fstr = getcpy(fmtstr); + c1->c_flags |= FORMAT; + return 0; + } + + if (!mh_strcasecmp(name, "decode")) { + char *fmtstr; + + fmtstr = new_fs("=%(decode{text})", NULL); + c1->c_fstr = getcpy(fmtstr); + c1->c_flags |= FORMAT; + return 0; + } + + if (!mh_strcasecmp(name, "offset")) + return ptoi(name, &c1->c_offset); + if (!mh_strcasecmp(name, "overflowoffset")) + return ptoi(name, &c1->c_ovoff); + if (!mh_strcasecmp(name, "width")) + return ptoi(name, &c1->c_width); + if (!mh_strcasecmp(name, "compwidth")) + return ptoi(name, &c1->c_cwidth); + + for (ap = triples; ap->t_name; ap++) + if (!mh_strcasecmp(ap->t_name, name)) { + c1->c_flags |= ap->t_on; + c1->c_flags &= ~ap->t_off; + return 0; + } + + return 1; +} + + +static int +ptoi(char *name, int *i) +{ + char *cp; + + if (*parptr++ != '=' || !*(cp = parse())) { + advise(NULL, "missing argument to variable %s", name); + return 1; + } + + *i = atoi(cp); + return 0; +} + + +static int +ptos(char *name, char **s) +{ + char c, *cp; + + if (*parptr++ != '=') { + advise(NULL, "missing argument to variable %s", name); + return 1; + } + + if (*parptr != '"') { + for (cp = parptr; *parptr && *parptr != ':' && *parptr != ','; + parptr++) + continue; + } else { + for (cp = ++parptr; *parptr && *parptr != '"'; parptr++) + if (*parptr == QUOTE) + if (!*++parptr) + parptr--; + } + c = *parptr; + *parptr = 0; + *s = getcpy(cp); + if ((*parptr = c) == '"') + parptr++; + return 0; +} + + +static char * +parse(void) +{ + int c; + char *cp; + static char result[NAMESZ]; + + for (cp = result; *parptr && (cp - result < NAMESZ); parptr++) { + c = *parptr; + if (isalnum(c) + || c == '.' + || c == '-' + || c == '_' + || c == '[' + || c == ']') + *cp++ = c; + else + break; + } + *cp = '\0'; + + return result; +} + + +static void +process(char *fname, int ofilen, int ofilec) +{ + FILE *fp = NULL; + struct mcomp *c1; + + switch (setjmp(env)) { + case OK: + if (fname) { + fp = mhl_action ? (*mhl_action) (fname) : + fopen(fname, "r"); + if (fp == NULL) { + advise(fname, "unable to open"); + exitstat++; + return; + } + } else { + fname = "(stdin)"; + fp = stdin; + } + SIGNAL(SIGINT, intrser); + mhlfile(fp, fname, ofilen, ofilec); + /* FALL THROUGH! */ + default: + SIGNAL(SIGINT, SIG_IGN); + if (mhl_action == NULL && fp != stdin) + fclose(fp); + if (holder.c_text) { + free(holder.c_text); + holder.c_text = NULL; + } + free_queue(&msghd, &msgtl); + for (c1 = fmthd; c1; c1 = c1->c_next) + c1->c_flags &= ~HDROUTPUT; + break; + } +} + + +static void +mhlfile(FILE *fp, char *mname, int ofilen, int ofilec) +{ + int state; + struct mcomp *c1, *c2, *c3; + char **ip, name[NAMESZ], buf[BUFSIZ]; + + if (forwall) { + printf("\n-------"); + if (ofilen == 1) + printf(" Forwarded Message%s", ofilec > 1 ? "s" : ""); + else + printf(" Message %d", ofilen); + printf("\n\n"); + } else if (ofilec > 1) { + if (ofilen > 1) { + printf("\n\n\n"); + } + printf(">>> %s\n\n", mname); + } + + for (state = FLD;;) { + switch (state = m_getfld(state, name, buf, sizeof(buf), fp)) { + case FLD: + case FLDPLUS: + for (ip = ignores; *ip; ip++) + if (!mh_strcasecmp(name, *ip)) { + while (state == FLDPLUS) + state = m_getfld(state, name, buf, sizeof(buf), fp); + break; + } + if (*ip) + continue; + + for (c2 = fmthd; c2; c2 = c2->c_next) + if (!mh_strcasecmp(c2->c_name, name)) + break; + c1 = NULL; + if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT)) + for (c1 = msghd; c1; c1 = c1->c_next) + if (!mh_strcasecmp(c1->c_name, + c3->c_name)) { + c1->c_text = mcomp_add(c1->c_flags, buf, c1->c_text); + break; + } + if (c1 == NULL) + c1 = add_queue(&msghd, &msgtl, name, buf, 0); + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof(buf), fp); + c1->c_text = add(buf, c1->c_text); + } + if (c2 == NULL) + c1->c_flags |= EXTRA; + continue; + + case BODY: + case FILEEOF: + column = 0; + for (c1 = fmthd; c1; c1 = c1->c_next) { + if (c1->c_flags & CLEARTEXT) { + putcomp(c1, c1, ONECOMP); + continue; + } + if (!mh_strcasecmp(c1->c_name, "messagename")) { + holder.c_text = concat("(Message ", + mname, ")\n", NULL); + putcomp(c1, &holder, ONECOMP); + free(holder.c_text); + holder.c_text = NULL; + continue; + } + if (!mh_strcasecmp(c1->c_name, "extras")) { + for (c2 = msghd; c2; c2 = c2->c_next) + if (c2->c_flags & EXTRA) + putcomp(c1, c2, TWOCOMP); + continue; + } + if (dobody && !mh_strcasecmp(c1->c_name, "body")) { + holder.c_text = mh_xmalloc(sizeof(buf)); + strncpy(holder.c_text, buf, sizeof(buf)); + while (state == BODY) { + putcomp(c1, &holder, BODYCOMP); + state = m_getfld(state, name, holder.c_text, sizeof(buf), fp); + } + free(holder.c_text); + holder.c_text = NULL; + continue; + } + for (c2 = msghd; c2; c2 = c2->c_next) + if (!mh_strcasecmp(c2->c_name, + c1->c_name)) { + putcomp(c1, c2, ONECOMP); + if (!(c1->c_flags & SPLIT)) + break; + } + } + return; + + case LENERR: + case FMTERR: + advise(NULL, "format error in message %s", mname); + exitstat++; + return; + + default: + adios(NULL, "getfld() returned %d", state); + } + } +} + + +static int +mcomp_flags(char *name) +{ + struct pair *ap; + + for (ap = pairs; ap->p_name; ap++) + if (!mh_strcasecmp(ap->p_name, name)) + return (ap->p_flags); + + return 0; +} + + +static char * +mcomp_add(long flags, char *s1, char *s2) +{ + char *dp; + + if (!(flags & ADDRFMT)) + return add(s1, s2); + + if (s2 && *(dp = s2 + strlen(s2) - 1) == '\n') + *dp = 0; + + return add(s1, add(",\n", s2)); +} + + +struct pqpair { + char *pq_text; + char *pq_error; + struct pqpair *pq_next; +}; + + +static void +mcomp_format(struct mcomp *c1, struct mcomp *c2) +{ + int dat[5]; + char *ap, *cp; + char buffer[BUFSIZ], error[BUFSIZ]; + struct comp *cptr; + struct pqpair *p, *q; + struct pqpair pq; + struct mailname *mp; + + ap = c2->c_text; + c2->c_text = NULL; + dat[0] = 0; + dat[1] = 0; + dat[2] = 0; + dat[3] = sizeof(buffer) - 1; + dat[4] = 0; + fmt_compile(c1->c_fstr, &c1->c_fmt); + + if (!(c1->c_flags & ADDRFMT)) { + FINDCOMP(cptr, "text"); + if (cptr) + cptr->c_text = ap; + if ((cp = strrchr(ap, '\n'))) /* drop ending newline */ + if (!cp[1]) + *cp = 0; + + fmt_scan(c1->c_fmt, buffer, sizeof(buffer) - 1, dat); + /* Don't need to append a newline, dctime() already did */ + c2->c_text = getcpy(buffer); + + free(ap); + return; + } + + (q = &pq)->pq_next = NULL; + while ((cp = getname(ap))) { + if ((p = (struct pqpair *) + calloc((size_t) 1, sizeof(*p))) == NULL) + adios(NULL, "unable to allocate pqpair memory"); + + if ((mp = getm(cp, NULL, 0, AD_NAME, error)) == NULL) { + p->pq_text = getcpy(cp); + p->pq_error = getcpy(error); + } else { + p->pq_text = getcpy(mp->m_text); + mnfree(mp); + } + q = (q->pq_next = p); + } + + for (p = pq.pq_next; p; p = q) { + FINDCOMP(cptr, "text"); + if (cptr) + cptr->c_text = p->pq_text; + FINDCOMP(cptr, "error"); + if (cptr) + cptr->c_text = p->pq_error; + + fmt_scan(c1->c_fmt, buffer, sizeof(buffer) - 1, dat); + if (*buffer) { + if (c2->c_text) + c2->c_text = add(",\n", c2->c_text); + if (*(cp = buffer + strlen(buffer) - 1) == '\n') + *cp = 0; + c2->c_text = add(buffer, c2->c_text); + } + + free(p->pq_text); + if (p->pq_error) + free(p->pq_error); + q = p->pq_next; + free((char *) p); + } + + c2->c_text = add("\n", c2->c_text); + free (ap); +} + + +static struct mcomp * +add_queue(struct mcomp **head, struct mcomp **tail, char *name, + char *text, int flags) +{ + struct mcomp *c1; + + if ((c1 = (struct mcomp *) calloc((size_t) 1, sizeof(*c1))) == NULL) + adios(NULL, "unable to allocate comp memory"); + + c1->c_flags = flags & ~INIT; + if ((c1->c_name = name ? getcpy(name) : NULL)) + c1->c_flags |= mcomp_flags(c1->c_name); + c1->c_text = text ? getcpy(text) : NULL; + if (flags & INIT) { + if (global.c_ovtxt) + c1->c_ovtxt = getcpy(global.c_ovtxt); + c1->c_offset = global.c_offset; + c1->c_ovoff = global. c_ovoff; + c1->c_width = 0; + c1->c_cwidth = global.c_cwidth; + c1->c_flags |= global.c_flags & GFLAGS; + } + if (*head == NULL) + *head = c1; + if (*tail != NULL) + (*tail)->c_next = c1; + *tail = c1; + + return c1; +} + + +static void +free_queue(struct mcomp **head, struct mcomp **tail) +{ + struct mcomp *c1, *c2; + + for (c1 = *head; c1; c1 = c2) { + c2 = c1->c_next; + if (c1->c_name) + free(c1->c_name); + if (c1->c_text) + free(c1->c_text); + if (c1->c_ovtxt) + free(c1->c_ovtxt); + if (c1->c_fstr) + free(c1->c_fstr); + if (c1->c_fmt) + free((char *) c1->c_fmt); + free((char *) c1); + } + + *head = *tail = NULL; +} + + +static void +putcomp(struct mcomp *c1, struct mcomp *c2, int flag) +{ + int count, cchdr; + unsigned char *cp; + + cchdr = 0; + lm = 0; + wid = c1->c_width ? c1->c_width : global.c_width; + ovoff = (c1->c_ovoff >= 0 ? c1->c_ovoff : global.c_ovoff) + + c1->c_offset; + if ((ovtxt = c1->c_ovtxt ? c1->c_ovtxt : global.c_ovtxt) == NULL) + ovtxt = ""; + if (wid < ovoff + strlen(ovtxt) + 5) + adios(NULL, "component: %s width(%d) too small for overflow(%d)", c1->c_name, wid, ovoff + strlen(ovtxt) + 5); + onelp = NULL; + + if (c1->c_flags & CLEARTEXT) { + putstr(c1->c_text); + putstr("\n"); + return; + } + + if (c1->c_fstr && (c1->c_flags & (ADDRFMT | DATEFMT | FORMAT))) + mcomp_format(c1, c2); + + if (c1->c_flags & CENTER) { + count = (c1->c_width ? c1->c_width : global.c_width) + - c1->c_offset - strlen(c2->c_text); + if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) + count -= strlen(c1->c_text ? c1->c_text : c1->c_name) + + 2; + lm = c1->c_offset + (count / 2); + } else { + if (c1->c_offset) + lm = c1->c_offset; + } + + if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) { + if (c1->c_flags & UPPERCASE) /* uppercase component also */ + for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + putstr(c1->c_text ? c1->c_text : c1->c_name); + if (flag != BODYCOMP) { + putstr(": "); + if (!(c1->c_flags & SPLIT)) + c1->c_flags |= HDROUTPUT; + + cchdr++; + if ((count = c1->c_cwidth - + strlen(c1->c_text ? c1->c_text : c1->c_name) - 2) > 0) + while (count--) + putstr(" "); + } else + c1->c_flags |= HDROUTPUT; /* for BODYCOMP */ + } + + if (flag == TWOCOMP && !(c2->c_flags & HDROUTPUT) + && !(c2->c_flags & NOCOMPONENT)) { + if (c1->c_flags & UPPERCASE) + for (cp = c2->c_name; *cp; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + putstr(c2->c_name); + putstr(": "); + if (!(c1->c_flags & SPLIT)) + c2->c_flags |= HDROUTPUT; + + cchdr++; + if ((count = c1->c_cwidth - strlen(c2->c_name) - 2) > 0) + while (count--) + putstr(" "); + } + if (c1->c_flags & UPPERCASE) + for (cp = c2->c_text; *cp; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + + count = 0; + if (cchdr) { + if (flag == TWOCOMP) + count = (c1->c_cwidth >= 0) ? c1->c_cwidth : + (int)strlen(c2->c_name) + 2; + else + count = (c1->c_cwidth >= 0) ? (size_t)c1->c_cwidth : + strlen(c1->c_text ? + c1->c_text : c1->c_name) + 2; + } + count += c1->c_offset; + + if ((cp = oneline(c2->c_text, c1->c_flags))) + putstr(cp); + if (term == '\n') + putstr("\n"); + while ((cp = oneline(c2->c_text, c1->c_flags))) { + lm = count; + if (flag == BODYCOMP && !(c1->c_flags & NOCOMPONENT)) + putstr(c1->c_text ? c1->c_text : c1->c_name); + if (*cp) + putstr(cp); + if (term == '\n') + putstr("\n"); + } + if (flag == BODYCOMP && term == '\n') + c1->c_flags &= ~HDROUTPUT; /* Buffer ended on a newline */ +} + + +static char * +oneline(char *stuff, long flags) +{ + int spc; + char *cp, *ret; + + if (onelp == NULL) + onelp = stuff; + if (*onelp == 0) + return (onelp = NULL); + + ret = onelp; + term = 0; + if (flags & COMPRESS) { + for (spc = 1, cp = ret; *onelp; onelp++) + if (isspace(*onelp)) { + if (*onelp == '\n' && + (!onelp[1] || + (flags & ADDRFMT))) { + term = '\n'; + *onelp++ = 0; + break; + } else if (!spc) { + *cp++ = ' '; + spc++; + } + } else { + *cp++ = *onelp; + spc = 0; + } + + *cp = 0; + } else { + while (*onelp && *onelp != '\n') + onelp++; + if (*onelp == '\n') { + term = '\n'; + *onelp++ = 0; + } + if (flags & LEFTADJUST) + while (*ret == ' ' || *ret == '\t') + ret++; + } + if (*onelp == 0 && term == '\n' && (flags & NONEWLINE)) + term = 0; + + return ret; +} + + +static void +putstr(char *string) +{ + if (!column && lm > 0) { + while (lm > 0) + if (lm >= 8) { + putch('\t'); + lm -= 8; + } else { + putch(' '); + lm--; + } + } + lm = 0; + while (*string) + putch(*string++); +} + + +static void +putch(char ch) +{ + switch (ch) { + case '\t': + column |= 07; + column++; + break; + + case '\b': + column--; + break; + + case '\n': + case '\r': + column = 0; + break; + + default: + /* + ** If we are forwarding this message, and the first + ** column contains a dash, then add a dash and a space. + */ + if (column == 0 && forwflg && ch == '-') { + putchar('-'); + putchar(' '); + } + if (ch >= ' ') + column++; + break; + } + + if (column >= wid) { + putch('\n'); + if (ovoff > 0) + lm = ovoff; + putstr(ovtxt ? ovtxt : ""); + putch(ch); + return; + } + + putchar(ch); +} + + +static void +intrser(int i) +{ + discard(stdout); + putchar('\n'); + longjmp(env, DONE); +} + + +#undef adios +#undef done + +static void +mhladios(char *what, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + advertise(what, NULL, fmt, ap); + va_end(ap); + mhldone(1); +} + -char * -OfficialName(char *name) +static void +mhldone(int status) { - return name; + exitstat = status; + if (mhl_action) + longjmp(mhlenv, DONE); + else + done(exitstat); } diff --git a/uip/mhlist.c b/uip/mhlist.c index cb6a3cf..c66b7cf 100644 --- a/uip/mhlist.c +++ b/uip/mhlist.c @@ -1,78 +1,44 @@ - /* - * mhlist.c -- list the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhlist.c -- list the contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include -#include #include #include #include -#include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - static struct swit switches[] = { -#define CHECKSW 0 - { "check", 0 }, -#define NCHECKSW 1 - { "nocheck", 0 }, -#define HEADSW 2 - { "headers", 0 }, -#define NHEADSW 3 - { "noheaders", 0 }, -#define SIZESW 4 - { "realsize", 0 }, -#define NSIZESW 5 - { "norealsize", 0 }, -#define VERBSW 6 - { "verbose", 0 }, -#define NVERBSW 7 - { "noverbose", 0 }, -#define FILESW 8 /* interface from show */ - { "file file", 0 }, -#define PARTSW 9 - { "part number", 0 }, -#define TYPESW 10 - { "type content", 0 }, -#define RCACHESW 11 - { "rcache policy", 0 }, -#define WCACHESW 12 - { "wcache policy", 0 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - -/* - * switches for debugging - */ -#define DEBUGSW 15 - { "debug", -5 }, - { NULL, 0 } +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define FILESW 2 /* interface from show */ + { "file file", 0 }, +#define PARTSW 3 + { "part number", 0 }, +#define TYPESW 4 + { "type content", 0 }, +#define VERSIONSW 5 + { "Version", 0 }, +#define HELPSW 6 + { "help", 0 }, +#define DEBUGSW 7 + { "debug", -5 }, + { NULL, 0 } }; /* mhparse.c */ -extern char *tmp; /* directory to place temp files */ - -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; +extern char *tmp; /* directory to place temp files */ /* mhmisc.c */ extern int npart; @@ -82,309 +48,255 @@ extern char *types[NTYPES + 1]; extern int userrs; /* - * This is currently needed to keep mhparse happy. - * This needs to be changed. - */ +** This is currently needed to keep mhparse happy. +** This needs to be changed. +*/ pid_t xpid = 0; int debugsw = 0; int verbosw = 0; -#define quitser pipeser +#define quitser pipeser /* mhparse.c */ -CT parse_mime (char *); +CT parse_mime(char *); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void set_endian(void); +void flush_errors(void); /* mhlistsbr.c */ -void list_all_messages (CT *, int, int, int, int); +void list_all_messages(CT *, int, int); /* mhfree.c */ -void free_content (CT); +void free_content(CT); extern CT *cts; -void freects_done (int) NORETURN; +void freects_done(int) NORETURN; /* - * static prototypes - */ -static RETSIGTYPE pipeser (int); +** static prototypes +*/ +static void pipeser(int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int sizesw = 1, headsw = 1; - int msgnum, *icachesw; - char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp = NULL; - CT ct, *ctp; - - done=freects_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; -do_cache: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); - default: - break; + int msgnum; + char *cp, *file = NULL, *folder = NULL; + char *maildir, buf[100], **argp; + char **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp = NULL; + CT ct, *ctp; + + done=freects_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case PARTSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (npart >= NPARTS) + adios(NULL, "too many parts (starting with %s), %d max", cp, NPARTS); + parts[npart++] = cp; + continue; + + case TYPESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (ntype >= NTYPES) + adios(NULL, "too many types (starting with %s), %d max", cp, NTYPES); + types[ntype++] = cp; + continue; + + case FILESW: + if (!(cp = *argp++) || (*cp == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + file = *cp == '-' ? cp : getcpy(expanddir(cp)); + continue; + + case VERBSW: + verbosw = 1; + continue; + case NVERBSW: + verbosw = 0; + continue; + case DEBUGSW: + debugsw = 1; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + + /* null terminate the list of acceptable parts/types */ + parts[npart] = NULL; + types[ntype] = NULL; + + set_endian(); + + /* + ** Check for storage directory. If specified, + ** then store temporary files there. Else we + ** store them in standard nmh directory. + */ + if ((cp = context_find(nmhstorage)) && *cp) + tmp = concat(cp, "/", invo_name, NULL); + else + tmp = getcpy(toabsdir(invo_name)); + + if (file && msgs.size) + adios(NULL, "cannot specify msg and file at same time!"); + + /* + ** check if message is coming from file + */ + if (file) { + if (!(cts = (CT *) calloc((size_t) 2, sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + if ((ct = parse_mime(file))) + *ctp++ = ct; + } else { + /* + ** message(s) are coming from a folder + */ + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done (1); + seq_setprev(mp); /* set the previous-sequence */ + + if (!(cts = (CT *) calloc((size_t) (mp->numsel + 1), + sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + char *msgnam; + + msgnam = m_name(msgnum); + if ((ct = parse_mime(msgnam))) + *ctp++ = ct; + } } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case HEADSW: - headsw = 1; - continue; - case NHEADSW: - headsw = 0; - continue; - - case SIZESW: - sizesw = 1; - continue; - case NSIZESW: - sizesw = 0; - continue; - - case PARTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (npart >= NPARTS) - adios (NULL, "too many parts (starting with %s), %d max", - cp, NPARTS); - parts[npart++] = cp; - continue; - - case TYPESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (ntype >= NTYPES) - adios (NULL, "too many types (starting with %s), %d max", - cp, NTYPES); - types[ntype++] = cp; - continue; - - case FILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - file = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case VERBSW: - verbosw = 1; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* null terminate the list of acceptable parts/types */ - parts[npart] = NULL; - types[ntype] = NULL; - - set_endian (); - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Check for storage directory. If specified, - * then store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (file && msgs.size) - adios (NULL, "cannot specify msg and file at same time!"); - - /* - * check if message is coming from file - */ - if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - if ((ct = parse_mime (file))); - *ctp++ = ct; - } else { + + if (!*cts) + done(1); + + userrs = 1; + SIGNAL(SIGQUIT, quitser); + SIGNAL(SIGPIPE, pipeser); + /* - * message(s) are coming from a folder - */ - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - char *msgnam; - - msgnam = m_name (msgnum); - if ((ct = parse_mime (msgnam))) - *ctp++ = ct; - } + ** Get the associated umask for the relevant contents. + */ + for (ctp = cts; *ctp; ctp++) { + struct stat st; + + ct = *ctp; + if (type_ok(ct, 1) && !ct->c_umask) { + if (stat(ct->c_file, &st) != NOTOK) + ct->c_umask = ~(st.st_mode & 0777); + else + ct->c_umask = ~m_gmprot(); + } } - } - - if (!*cts) - done (1); - - userrs = 1; - SIGNAL (SIGQUIT, quitser); - SIGNAL (SIGPIPE, pipeser); - - /* - * Get the associated umask for the relevant contents. - */ - for (ctp = cts; *ctp; ctp++) { - struct stat st; - - ct = *ctp; - if (type_ok (ct, 1) && !ct->c_umask) { - if (stat (ct->c_file, &st) != NOTOK) - ct->c_umask = ~(st.st_mode & 0777); - else - ct->c_umask = ~m_gmprot(); + + /* + ** List the message content + */ + list_all_messages(cts, verbosw, debugsw); + + /* Now free all the structures for the content */ + for (ctp = cts; *ctp; ctp++) + free_content(*ctp); + + free((char *) cts); + cts = NULL; + + /* If reading from a folder, do some updating */ + if (mp) { + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->hghsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ } - } - - /* - * List the message content - */ - list_all_messages (cts, headsw, sizesw, verbosw, debugsw); - - /* Now free all the structures for the content */ - for (ctp = cts; *ctp; ctp++) - free_content (*ctp); - - free ((char *) cts); - cts = NULL; - - /* If reading from a folder, do some updating */ - if (mp) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - done (0); - return 1; + + done(0); + return 1; } -static RETSIGTYPE -pipeser (int i) +static void +pipeser(int i) { - if (i == SIGQUIT) { - unlink ("core"); - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - done (1); - /* NOTREACHED */ + if (i == SIGQUIT) { + unlink("core"); + fflush(stdout); + fprintf(stderr, "\n"); + fflush(stderr); + } + + done(1); + /* NOTREACHED */ } diff --git a/uip/mhlistsbr.c b/uip/mhlistsbr.c index 1aac74a..dc85bcc 100644 --- a/uip/mhlistsbr.c +++ b/uip/mhlistsbr.c @@ -1,431 +1,346 @@ - /* - * mhlistsbr.c -- routines to list information about the - * -- contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhlistsbr.c -- routines to list information about the +** -- contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include #include -#include #include #include #include #include /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void flush_errors(void); /* - * prototypes - */ -void list_all_messages (CT *, int, int, int, int); -int list_switch (CT, int, int, int, int); -int list_content (CT, int, int, int, int); +** prototypes +*/ +void list_all_messages(CT *, int, int); +int list_switch(CT, int, int, int); +int list_content(CT, int, int, int); /* - * static prototypes - */ -static void list_single_message (CT, int, int, int); -static int list_debug (CT); -static int list_multi (CT, int, int, int, int); -static int list_partial (CT, int, int, int, int); -static int list_external (CT, int, int, int, int); -static int list_application (CT, int, int, int, int); -static int list_encoding (CT); +** static prototypes +*/ +static void list_single_message(CT, int, int); +static int list_debug(CT); +static int list_multi(CT, int, int, int); +static int list_partial(CT, int, int, int); +static int list_encoding(CT); /* - * various formats for -list option - */ -#define LSTFMT1 "%4s %-5s %-24s %5s %-36s\n" -#define LSTFMT2a "%4d " -#define LSTFMT2b "%-5s %-24.24s " -#define LSTFMT2c1 "%5lu" -#define LSTFMT2c2 "%4lu%c" -#define LSTFMT2c3 "huge " -#define LSTFMT2c4 " " -#define LSTFMT2d1 " %-36.36s" -#define LSTFMT2d2 "\t %-65.65s\n" +** various formats for -list option +*/ +#define LSTFMT1 "%4s %-5s %-24s %5s %-36s\n" +#define LSTFMT2a "%4d " +#define LSTFMT2b "%-5s %-24.24s " +#define LSTFMT2c1 "%5lu" +#define LSTFMT2c2 "%4lu%c" +#define LSTFMT2c3 "huge " +#define LSTFMT2c4 " " +#define LSTFMT2d1 " %-36.36s" +#define LSTFMT2d2 "\t %-65.65s\n" /* - * Top level entry point to list group of messages - */ - +** Top level entry point to list group of messages +*/ void -list_all_messages (CT *cts, int headers, int realsize, int verbose, int debug) +list_all_messages(CT *cts, int verbose, int debug) { - CT ct, *ctp; - - if (headers) - printf (LSTFMT1, "msg", "part", "type/subtype", "size", "description"); - - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - list_single_message (ct, realsize, verbose, debug); - } + CT ct, *ctp; - flush_errors (); + printf(LSTFMT1, "msg", "part", "type/subtype", "size", "description"); + for (ctp = cts; *ctp; ctp++) { + ct = *ctp; + list_single_message(ct, verbose, debug); + } + flush_errors(); } /* - * Entry point to list a single message - */ - +** Entry point to list a single message +*/ static void -list_single_message (CT ct, int realsize, int verbose, int debug) +list_single_message(CT ct, int verbose, int debug) { - if (type_ok (ct, 1)) { - umask (ct->c_umask); - list_switch (ct, 1, realsize, verbose, debug); - if (ct->c_fp) { - fclose (ct->c_fp); - ct->c_fp = NULL; + if (type_ok(ct, 1)) { + umask(ct->c_umask); + list_switch(ct, 1, verbose, debug); + if (ct->c_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + if (ct->c_ceclosefnx) + (*ct->c_ceclosefnx) (ct); } - if (ct->c_ceclosefnx) - (*ct->c_ceclosefnx) (ct); - } } /* - * Primary switching routine to list information about a content - */ - +** Primary switching routine to list information about a content +*/ int -list_switch (CT ct, int toplevel, int realsize, int verbose, int debug) +list_switch(CT ct, int toplevel, int verbose, int debug) { - switch (ct->c_type) { + switch (ct->c_type) { case CT_MULTIPART: - return list_multi (ct, toplevel, realsize, verbose, debug); - break; + return list_multi(ct, toplevel, verbose, debug); + break; case CT_MESSAGE: - switch (ct->c_subtype) { - case MESSAGE_PARTIAL: - return list_partial (ct, toplevel, realsize, verbose, debug); - break; - - case MESSAGE_EXTERNAL: - return list_external (ct, toplevel, realsize, verbose, debug); - break; - - case MESSAGE_RFC822: - default: - return list_content (ct, toplevel, realsize, verbose, debug); - break; - } - break; + if (ct->c_subtype == MESSAGE_PARTIAL) { + return list_partial(ct, toplevel, verbose, debug); + } else { + return list_content(ct, toplevel, verbose, debug); + } + break; case CT_TEXT: case CT_AUDIO: case CT_IMAGE: case CT_VIDEO: - return list_content (ct, toplevel, realsize, verbose, debug); - break; - case CT_APPLICATION: - return list_application (ct, toplevel, realsize, verbose, debug); - break; + return list_content(ct, toplevel, verbose, debug); + break; default: - /* list_debug (ct); */ - adios (NULL, "unknown content type %d", ct->c_type); - break; - } + /* list_debug (ct); */ + adios(NULL, "unknown content type %d", ct->c_type); + break; + } - return 0; /* NOT REACHED */ + return 0; /* NOT REACHED */ } #define empty(s) ((s) ? (s) : "") /* - * Method for listing information about a simple/generic content - */ - +** Method for listing information about a simple/generic content +*/ int -list_content (CT ct, int toplevel, int realsize, int verbose, int debug) +list_content(CT ct, int toplevel, int verbose, int debug) { - unsigned long size; - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - printf (toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : " ", - atoi (r1bindex (empty (ct->c_file), '/'))); - snprintf (buffer, sizeof(buffer), "%s/%s", empty (ci->ci_type), - empty (ci->ci_subtype)); - printf (LSTFMT2b, empty (ct->c_partno), buffer); - - if (ct->c_cesizefnx && realsize) - size = (*ct->c_cesizefnx) (ct); - else - size = ct->c_end - ct->c_begin; - - /* find correct scale for size (Kilo/Mega/Giga/Tera) */ - for (cp = " KMGT"; size > 9999; size >>= 10) - if (!*++cp) - break; - - /* print size of this body part */ - switch (*cp) { - case ' ': - if (size > 0 || ct->c_encoding != CE_EXTERNAL) - printf (LSTFMT2c1, size); - else - printf (LSTFMT2c4); - break; + unsigned long size; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + printf(toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : " ", + atoi(mhbasename(empty(ct->c_file)))); + snprintf(buffer, sizeof(buffer), "%s/%s", empty(ci->ci_type), + empty(ci->ci_subtype)); + printf(LSTFMT2b, empty(ct->c_partno), buffer); + + if (ct->c_cesizefnx) + size = (*ct->c_cesizefnx) (ct); + else + size = ct->c_end - ct->c_begin; + + /* find correct scale for size (Kilo/Mega/Giga/Tera) */ + for (cp = " KMGT"; size > 9999; size >>= 10) + if (!*++cp) + break; + + /* print size of this body part */ + switch (*cp) { + case ' ': + if (size > 0 || ct->c_encoding != CE_EXTERNAL) + printf(LSTFMT2c1, size); + else + printf(LSTFMT2c4); + break; default: - printf (LSTFMT2c2, size, *cp); - break; + printf(LSTFMT2c2, size, *cp); + break; case '\0': - printf (LSTFMT2c3); - } - - /* print Content-Description */ - if (ct->c_descr) { - char *dp; - - dp = trimcpy (cp = add (ct->c_descr, NULL)); - free (cp); - printf (LSTFMT2d1, dp); - free (dp); - } - - printf ("\n"); - - /* - * If verbose, print any RFC-822 comments in the - * Content-Type line. - */ - if (verbose && ci->ci_comment) { - char *dp; - - dp = trimcpy (cp = add (ci->ci_comment, NULL)); - free (cp); - snprintf (buffer, sizeof(buffer), "(%s)", dp); - free (dp); - printf (LSTFMT2d2, buffer); - } - - if (debug) - list_debug (ct); - - return OK; + printf(LSTFMT2c3); + } + + /* print Content-Description */ + if (ct->c_descr) { + char *dp; + + dp = trimcpy(cp = getcpy(ct->c_descr)); + free(cp); + printf(LSTFMT2d1, dp); + free(dp); + } + + printf("\n"); + + if (verbose) { + char **ap, **ep; + CI ci = &ct->c_ctinfo; + + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { + printf("\t\t%s=\"%s\"\n", *ap, *ep); + } + + /* + ** If verbose, print any RFC-822 comments in the + ** Content-Type line. + */ + if (ci->ci_comment) { + char *dp; + + dp = trimcpy(cp = add(ci->ci_comment, NULL)); + free (cp); + snprintf(buffer, sizeof(buffer), "(%s)", dp); + free(dp); + printf(LSTFMT2d2, buffer); + } + } + + if (debug) + list_debug(ct); + + return OK; } /* - * Print debugging information about a content - */ - +** Print debugging information about a content +*/ static int -list_debug (CT ct) +list_debug(CT ct) { - char **ap, **ep; - CI ci = &ct->c_ctinfo; + char **ap, **ep; + CI ci = &ct->c_ctinfo; - fflush (stdout); - fprintf (stderr, " partno \"%s\"\n", empty (ct->c_partno)); + fflush(stdout); + fprintf(stderr, " partno \"%s\"\n", empty(ct->c_partno)); - /* print MIME-Version line */ - if (ct->c_vrsn) - fprintf (stderr, " %s:%s\n", VRSN_FIELD, ct->c_vrsn); + /* print MIME-Version line */ + if (ct->c_vrsn) + fprintf(stderr, " %s:%s\n", VRSN_FIELD, ct->c_vrsn); - /* print Content-Type line */ - if (ct->c_ctline) - fprintf (stderr, " %s:%s\n", TYPE_FIELD, ct->c_ctline); + /* print Content-Type line */ + if (ct->c_ctline) + fprintf(stderr, " %s:%s\n", TYPE_FIELD, ct->c_ctline); - /* print parsed elements of content type */ - fprintf (stderr, " type \"%s\"\n", empty (ci->ci_type)); - fprintf (stderr, " subtype \"%s\"\n", empty (ci->ci_subtype)); - fprintf (stderr, " comment \"%s\"\n", empty (ci->ci_comment)); - fprintf (stderr, " magic \"%s\"\n", empty (ci->ci_magic)); + /* print parsed elements of content type */ + fprintf(stderr, " type \"%s\"\n", empty(ci->ci_type)); + fprintf(stderr, " subtype \"%s\"\n", empty(ci->ci_subtype)); + fprintf(stderr, " comment \"%s\"\n", empty(ci->ci_comment)); + fprintf(stderr, " magic \"%s\"\n", empty(ci->ci_magic)); - /* print parsed parameters attached to content type */ - fprintf (stderr, " parameters\n"); - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) - fprintf (stderr, " %s=\"%s\"\n", *ap, *ep); + /* print parsed parameters attached to content type */ + fprintf(stderr, " parameters\n"); + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) + fprintf(stderr, " %s=\"%s\"\n", *ap, *ep); - /* print internal flags for type/subtype */ - fprintf (stderr, " type 0x%x subtype 0x%x params 0x%x\n", - ct->c_type, ct->c_subtype, - (unsigned int)(unsigned long) ct->c_ctparams); + /* print internal flags for type/subtype */ + fprintf(stderr, " type 0x%x subtype 0x%x params 0x%x\n", + ct->c_type, ct->c_subtype, + (unsigned int)(unsigned long) ct->c_ctparams); - fprintf (stderr, " showproc \"%s\"\n", empty (ct->c_showproc)); - fprintf (stderr, " termproc \"%s\"\n", empty (ct->c_termproc)); - fprintf (stderr, " storeproc \"%s\"\n", empty (ct->c_storeproc)); + fprintf(stderr, " charset \"%s\"\n", empty(ct->c_charset)); + fprintf(stderr, " showproc \"%s\"\n", empty(ct->c_showproc)); + fprintf(stderr, " storeproc \"%s\"\n", empty(ct->c_storeproc)); - /* print transfer encoding information */ - if (ct->c_celine) - fprintf (stderr, " %s:%s", ENCODING_FIELD, ct->c_celine); + /* print transfer encoding information */ + if (ct->c_celine) + fprintf(stderr, " %s:%s", ENCODING_FIELD, ct->c_celine); - /* print internal flags for transfer encoding */ - fprintf (stderr, " transfer encoding 0x%x params 0x%x\n", - ct->c_encoding, (unsigned int)(unsigned long) ct->c_cefile); + /* print internal flags for transfer encoding */ + fprintf(stderr, " transfer encoding 0x%x params 0x%x\n", + ct->c_encoding, + (unsigned int)(unsigned long) ct->c_cefile); - /* print Content-ID */ - if (ct->c_id) - fprintf (stderr, " %s:%s", ID_FIELD, ct->c_id); + /* print Content-ID */ + if (ct->c_id) + fprintf(stderr, " %s:%s", ID_FIELD, ct->c_id); - /* print Content-Description */ - if (ct->c_descr) - fprintf (stderr, " %s:%s", DESCR_FIELD, ct->c_descr); + /* print Content-Description */ + if (ct->c_descr) + fprintf(stderr, " %s:%s", DESCR_FIELD, ct->c_descr); - fprintf (stderr, " read fp 0x%x file \"%s\" begin %ld end %ld\n", - (unsigned int)(unsigned long) ct->c_fp, empty (ct->c_file), - ct->c_begin, ct->c_end); + fprintf(stderr, " read fp 0x%x file \"%s\" begin %ld end %ld\n", + (unsigned int)(unsigned long) ct->c_fp, + empty(ct->c_file), ct->c_begin, ct->c_end); - /* print more information about transfer encoding */ - list_encoding (ct); + /* print more information about transfer encoding */ + list_encoding(ct); - return OK; + return OK; } #undef empty /* - * list content information for type "multipart" - */ - +** list content information for type "multipart" +*/ static int -list_multi (CT ct, int toplevel, int realsize, int verbose, int debug) +list_multi(CT ct, int toplevel, int verbose, int debug) { - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; - /* list the content for toplevel of this multipart */ - list_content (ct, toplevel, realsize, verbose, debug); + /* list the content for toplevel of this multipart */ + list_content(ct, toplevel, verbose, debug); - /* now list for all the subparts */ - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; + /* now list for all the subparts */ + for (part = m->mp_parts; part; part = part->mp_next) { + CT p = part->mp_part; - if (part_ok (p, 1) && type_ok (p, 1)) - list_switch (p, 0, realsize, verbose, debug); - } - - return OK; -} - - -/* - * list content information for type "message/partial" - */ - -static int -list_partial (CT ct, int toplevel, int realsize, int verbose, int debug) -{ - struct partial *p = (struct partial *) ct->c_ctparams; - - list_content (ct, toplevel, realsize, verbose, debug); - if (verbose) { - printf ("\t [message %s, part %d", p->pm_partid, p->pm_partno); - if (p->pm_maxno) - printf (" of %d", p->pm_maxno); - printf ("]\n"); - } - - return OK; -} - - -/* - * list content information for type "message/external" - */ + if (part_ok(p, 1) && type_ok(p, 1)) + list_switch(p, 0, verbose, debug); + } -static int -list_external (CT ct, int toplevel, int realsize, int verbose, int debug) -{ - struct exbody *e = (struct exbody *) ct->c_ctparams; - - /* - * First list the information for the - * message/external content itself. - */ - list_content (ct, toplevel, realsize, verbose, debug); - - if (verbose) { - if (e->eb_name) - printf ("\t name=\"%s\"\n", e->eb_name); - if (e->eb_dir) - printf ("\t directory=\"%s\"\n", e->eb_dir); - if (e->eb_site) - printf ("\t site=\"%s\"\n", e->eb_site); - if (e->eb_server) - printf ("\t server=\"%s\"\n", e->eb_server); - if (e->eb_subject) - printf ("\t subject=\"%s\"\n", e->eb_subject); - - /* This must be defined */ - printf ("\t access-type=\"%s\"\n", e->eb_access); - - if (e->eb_mode) - printf ("\t mode=\"%s\"\n", e->eb_mode); - if (e->eb_permission) - printf ("\t permission=\"%s\"\n", e->eb_permission); - - if (e->eb_flags == NOTOK) - printf ("\t [service unavailable]\n"); - } - - /* - * Now list the information for the external content - * to which this content points. - */ - list_content (e->eb_content, 0, realsize, verbose, debug); - - return OK; + return OK; } /* - * list content information for type "application" - */ - +** list content information for type "message/partial" +*/ static int -list_application (CT ct, int toplevel, int realsize, int verbose, int debug) +list_partial(CT ct, int toplevel, int verbose, int debug) { - list_content (ct, toplevel, realsize, verbose, debug); - if (verbose) { - char **ap, **ep; - CI ci = &ct->c_ctinfo; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) - printf ("\t %s=\"%s\"\n", *ap, *ep); - } + struct partial *p = (struct partial *) ct->c_ctparams; + + list_content(ct, toplevel, verbose, debug); + if (verbose) { + printf("\t [message %s, part %d", + p->pm_partid, p->pm_partno); + if (p->pm_maxno) + printf(" of %d", p->pm_maxno); + printf("]\n"); + } - return OK; + return OK; } /* - * list information about the Content-Transfer-Encoding - * used by a content. - */ - +** list information about the Content-Transfer-Encoding +** used by a content. +*/ static int -list_encoding (CT ct) +list_encoding(CT ct) { - CE ce; + CE ce; - if ((ce = ct->c_cefile)) - fprintf (stderr, " decoded fp 0x%x file \"%s\"\n", - (unsigned int)(unsigned long) ce->ce_fp, - ce->ce_file ? ce->ce_file : ""); + if ((ce = ct->c_cefile)) + fprintf(stderr, " decoded fp 0x%x file \"%s\"\n", + (unsigned int)(unsigned long) ce->ce_fp, + ce->ce_file ? ce->ce_file : ""); - return OK; + return OK; } diff --git a/uip/mhlsbr.c b/uip/mhlsbr.c deleted file mode 100644 index 58b2978..0000000 --- a/uip/mhlsbr.c +++ /dev/null @@ -1,1821 +0,0 @@ - -/* - * mhlsbr.c -- main routines for nmh message lister - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * MAJOR BUG: - * for a component containing addresses, ADDRFMT, if COMPRESS is also - * set, then addresses get split wrong (not at the spaces between commas). - * To fix this correctly, putstr() should know about "atomic" strings that - * must NOT be broken across lines. That's too difficult for right now - * (it turns out that there are a number of degernate cases), so in - * oneline(), instead of - * - * (*onelp == '\n' && !onelp[1]) - * - * being a terminating condition, - * - * (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) - * - * is used instead. This cuts the line prematurely, and gives us a much - * better chance of getting things right. - */ - -#define ONECOMP 0 -#define TWOCOMP 1 -#define BODYCOMP 2 - -#define QUOTE '\\' - -static struct swit mhlswitches[] = { -#define BELLSW 0 - { "bell", 0 }, -#define NBELLSW 1 - { "nobell", 0 }, -#define CLRSW 2 - { "clear", 0 }, -#define NCLRSW 3 - { "noclear", 0 }, -#define FACESW 4 - { "faceproc program", 0 }, -#define NFACESW 5 - { "nofaceproc", 0 }, -#define FOLDSW 6 - { "folder +folder", 0 }, -#define FORMSW 7 - { "form formfile", 0 }, -#define PROGSW 8 - { "moreproc program", 0 }, -#define NPROGSW 9 - { "nomoreproc", 0 }, -#define LENSW 10 - { "length lines", 0 }, -#define WIDTHSW 11 - { "width columns", 0 }, -#define SLEEPSW 12 - { "sleep seconds", 0 }, -#define BITSTUFFSW 13 - { "dashstuffing", -12 }, /* interface from forw */ -#define NBITSTUFFSW 14 - { "nodashstuffing", -14 }, /* interface from forw */ -#define VERSIONSW 15 - { "version", 0 }, -#define HELPSW 16 - { "help", 0 }, -#define FORW1SW 17 - { "forward", -7 }, /* interface from forw */ -#define FORW2SW 18 - { "forwall", -7 }, /* interface from forw */ -#define DGSTSW 19 - { "digest list", -6 }, -#define VOLUMSW 20 - { "volume number", -6 }, -#define ISSUESW 21 - { "issue number", -5 }, -#define NBODYSW 22 - { "nobody", -6 }, - { NULL, 0 } -}; - -#define NOCOMPONENT 0x000001 /* don't show component name */ -#define UPPERCASE 0x000002 /* display in all upper case */ -#define CENTER 0x000004 /* center line */ -#define CLEARTEXT 0x000008 /* cleartext */ -#define EXTRA 0x000010 /* an "extra" component */ -#define HDROUTPUT 0x000020 /* already output */ -#define CLEARSCR 0x000040 /* clear screen */ -#define LEFTADJUST 0x000080 /* left justify multiple lines */ -#define COMPRESS 0x000100 /* compress text */ -#define ADDRFMT 0x000200 /* contains addresses */ -#define BELL 0x000400 /* sound bell at EOP */ -#define DATEFMT 0x000800 /* contains dates */ -#define FORMAT 0x001000 /* parse address/date/RFC-2047 field */ -#define INIT 0x002000 /* initialize component */ -#define FACEFMT 0x004000 /* contains face */ -#define FACEDFLT 0x008000 /* default for face */ -#define SPLIT 0x010000 /* split headers (don't concatenate) */ -#define NONEWLINE 0x020000 /* don't write trailing newline */ -#define LBITS "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT\017FACEFMT\020FACEDFLT\021SPLIT\022NONEWLINE" -#define GFLAGS (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS | SPLIT) - -struct mcomp { - char *c_name; /* component name */ - char *c_text; /* component text */ - char *c_ovtxt; /* text overflow indicator */ - char *c_nfs; /* iff FORMAT */ - struct format *c_fmt; /* .. */ - char *c_face; /* face designator */ - int c_offset; /* left margin indentation */ - int c_ovoff; /* overflow indentation */ - int c_width; /* width of field */ - int c_cwidth; /* width of component */ - int c_length; /* length in lines */ - long c_flags; - struct mcomp *c_next; -}; - -static struct mcomp *msghd = NULL; -static struct mcomp *msgtl = NULL; -static struct mcomp *fmthd = NULL; -static struct mcomp *fmttl = NULL; - -static struct mcomp global = { - NULL, NULL, "", NULL, NULL, 0, -1, 80, -1, 40, BELL, 0 -}; - -static struct mcomp holder = { - NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT, 0 -}; - -struct pair { - char *p_name; - long p_flags; -}; - -static struct pair pairs[] = { - { "Date", DATEFMT }, - { "From", ADDRFMT|FACEDFLT }, - { "Sender", ADDRFMT }, - { "Reply-To", ADDRFMT }, - { "To", ADDRFMT }, - { "cc", ADDRFMT }, - { "Bcc", ADDRFMT }, - { "Resent-Date", DATEFMT }, - { "Resent-From", ADDRFMT }, - { "Resent-Sender", ADDRFMT }, - { "Resent-Reply-To", ADDRFMT }, - { "Resent-To", ADDRFMT }, - { "Resent-cc", ADDRFMT }, - { "Resent-Bcc", ADDRFMT }, - { "Face", FACEFMT }, - { NULL, 0 } -}; - -struct triple { - char *t_name; - long t_on; - long t_off; -}; - -static struct triple triples[] = { - { "nocomponent", NOCOMPONENT, 0 }, - { "uppercase", UPPERCASE, 0 }, - { "nouppercase", 0, UPPERCASE }, - { "center", CENTER, 0 }, - { "nocenter", 0, CENTER }, - { "clearscreen", CLEARSCR, 0 }, - { "noclearscreen", 0, CLEARSCR }, - { "noclear", 0, CLEARSCR }, - { "leftadjust", LEFTADJUST, 0 }, - { "noleftadjust", 0, LEFTADJUST }, - { "compress", COMPRESS, 0 }, - { "nocompress", 0, COMPRESS }, - { "split", SPLIT, 0 }, - { "nosplit", 0, SPLIT }, - { "addrfield", ADDRFMT, DATEFMT }, - { "bell", BELL, 0 }, - { "nobell", 0, BELL }, - { "datefield", DATEFMT, ADDRFMT }, - { "newline", 0, NONEWLINE }, - { "nonewline", NONEWLINE, 0 }, - { NULL, 0, 0 } -}; - - -static int bellflg = 0; -static int clearflg = 0; -static int dashstuff = 0; -static int dobody = 1; -static int forwflg = 0; -static int forwall = 0; - -static int sleepsw = NOTOK; - -static char *digest = NULL; -static int volume = 0; -static int issue = 0; - -static int exitstat = 0; -static int mhldebug = 0; - -#define PITTY (-1) -#define NOTTY 0 -#define ISTTY 1 -static int ontty = NOTTY; - -static int row; -static int column; - -static int lm; -static int llim; -static int ovoff; -static int term; -static int wid; - -static char *ovtxt; - -static unsigned char *onelp; - -static char *parptr; - -static int num_ignores = 0; -static char *ignores[MAXARGS]; - -static jmp_buf env; -static jmp_buf mhlenv; - -static char delim3[] = /* from forw.c */ - "\n----------------------------------------------------------------------\n\n"; -static char delim4[] = "\n------------------------------\n\n"; - -static FILE *(*mhl_action) () = (FILE *(*) ()) 0; - - -/* - * Redefine a couple of functions. - * These are undefined later in the code. - */ -#define adios mhladios -#define done mhldone - -/* - * prototypes - */ -static void mhl_format (char *, int, int); -static int evalvar (struct mcomp *); -static int ptoi (char *, int *); -static int ptos (char *, char **); -static char *parse (void); -static void process (char *, char *, int, int); -static void mhlfile (FILE *, char *, int, int); -static int mcomp_flags (char *); -static char *mcomp_add (long, char *, char *); -static void mcomp_format (struct mcomp *, struct mcomp *); -static struct mcomp *add_queue (struct mcomp **, struct mcomp **, char *, char *, int); -static void free_queue (struct mcomp **, struct mcomp **); -static void putcomp (struct mcomp *, struct mcomp *, int); -static char *oneline (char *, long); -static void putstr (char *); -static void putch (char); -static RETSIGTYPE intrser (int); -static RETSIGTYPE pipeser (int); -static RETSIGTYPE quitser (int); -static void face_format (struct mcomp *); -static int doface (struct mcomp *); -static void mhladios (char *, char *, ...); -static void mhldone (int); -static void m_popen (char *); - -int mhl (int, char **); -int mhlsbr (int, char **, FILE *(*)()); -void m_pclose (void); - -void clear_screen (void); /* from termsbr.c */ -int SOprintf (char *, ...); /* from termsbr.c */ -int sc_width (void); /* from termsbr.c */ -int sc_length (void); /* from termsbr.c */ -int sc_hardcopy (void); /* from termsbr.c */ - - -int -mhl (int argc, char **argv) -{ - int length = 0, nomore = 0; - int i, width = 0, vecp = 0; - char *cp, *folder = NULL, *form = NULL; - char buf[BUFSIZ], *files[MAXARGS]; - char **argp, **arguments; - - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - if ((cp = getenv ("MHLDEBUG")) && *cp) - mhldebug++; - - if ((cp = getenv ("FACEPROC"))) - faceproc = cp; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, mhlswitches)) { - case AMBIGSW: - ambigsw (cp, mhlswitches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [files ...]", invo_name); - print_help (buf, mhlswitches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case BELLSW: - bellflg = 1; - continue; - case NBELLSW: - bellflg = -1; - continue; - - case CLRSW: - clearflg = 1; - continue; - case NCLRSW: - clearflg = -1; - continue; - - case FOLDSW: - if (!(folder = *argp++) || *folder == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case FACESW: - if (!(faceproc = *argp++) || *faceproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NFACESW: - faceproc = NULL; - continue; - case SLEEPSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - sleepsw = atoi (cp);/* ZERO ok! */ - continue; - - case PROGSW: - if (!(moreproc = *argp++) || *moreproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NPROGSW: - nomore++; - continue; - - case LENSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((length = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((width = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - - case DGSTSW: - if (!(digest = *argp++) || *digest == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case ISSUESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((issue = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case VOLUMSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((volume = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - - case FORW2SW: - forwall++; /* fall */ - case FORW1SW: - forwflg++; - clearflg = -1;/* XXX */ - continue; - - case BITSTUFFSW: - dashstuff = 1; /* trinary logic */ - continue; - case NBITSTUFFSW: - dashstuff = -1; /* trinary logic */ - continue; - - case NBODYSW: - dobody = 0; - continue; - } - } - files[vecp++] = cp; - } - - if (!folder) - folder = getenv ("mhfolder"); - - if (isatty (fileno (stdout))) { - if (!nomore && !sc_hardcopy() && moreproc && *moreproc != '\0') { - if (mhl_action) { - SIGNAL (SIGINT, SIG_IGN); - SIGNAL2 (SIGQUIT, quitser); - } - SIGNAL2 (SIGPIPE, pipeser); - m_popen (moreproc); - ontty = PITTY; - } else { - SIGNAL (SIGINT, SIG_IGN); - SIGNAL2 (SIGQUIT, quitser); - ontty = ISTTY; - } - } else { - ontty = NOTTY; - } - - mhl_format (form ? form : mhlformat, length, width); - - if (vecp == 0) { - process (folder, NULL, 1, vecp = 1); - } else { - for (i = 0; i < vecp; i++) - process (folder, files[i], i + 1, vecp); - } - - if (forwall) { - if (digest) { - printf ("%s", delim4); - if (volume == 0) { - snprintf (buf, sizeof(buf), "End of %s Digest\n", digest); - } else { - snprintf (buf, sizeof(buf), "End of %s Digest [Volume %d Issue %d]\n", - digest, volume, issue); - } - i = strlen (buf); - for (cp = buf + i; i > 1; i--) - *cp++ = '*'; - *cp++ = '\n'; - *cp = 0; - printf ("%s", buf); - } - else - printf ("\n------- End of Forwarded Message%s\n\n", - vecp > 1 ? "s" : ""); - } - - fflush(stdout); - if(ferror(stdout)){ - adios("output", "error writing"); - } - - if (clearflg > 0 && ontty == NOTTY) - clear_screen (); - - if (ontty == PITTY) - m_pclose (); - - return exitstat; -} - - -static void -mhl_format (char *file, int length, int width) -{ - int i; - char *bp, *cp, **ip; - char *ap, buffer[BUFSIZ], name[NAMESZ]; - struct mcomp *c1; - struct stat st; - FILE *fp; - static dev_t dev = 0; - static ino_t ino = 0; - static time_t mtime = 0; - - if (fmthd != NULL) { - if (stat (etcpath (file), &st) != NOTOK - && mtime == st.st_mtime - && dev == st.st_dev - && ino == st.st_ino) - goto out; - else - free_queue (&fmthd, &fmttl); - } - - if ((fp = fopen (etcpath (file), "r")) == NULL) - adios (file, "unable to open format file"); - - if (fstat (fileno (fp), &st) != NOTOK) { - mtime = st.st_mtime; - dev = st.st_dev; - ino = st.st_ino; - } - - global.c_ovtxt = global.c_nfs = NULL; - global.c_fmt = NULL; - global.c_offset = 0; - global.c_ovoff = -1; - if ((i = sc_width ()) > 5) - global.c_width = i; - global.c_cwidth = -1; - if ((i = sc_length ()) > 5) - global.c_length = i - 1; - global.c_flags = BELL; /* BELL is default */ - *(ip = ignores) = NULL; - - while (vfgets (fp, &ap) == OK) { - bp = ap; - if (*bp == ';') - continue; - - if ((cp = strchr(bp, '\n'))) - *cp = 0; - - if (*bp == ':') { - c1 = add_queue (&fmthd, &fmttl, NULL, bp + 1, CLEARTEXT); - continue; - } - - parptr = bp; - strncpy (name, parse(), sizeof(name)); - switch (*parptr) { - case '\0': - case ',': - case '=': - /* - * Split this list of fields to ignore, and copy - * it to the end of the current "ignores" list. - */ - if (!mh_strcasecmp (name, "ignores")) { - char **tmparray, **p; - int n = 0; - - /* split the fields */ - tmparray = brkstring (getcpy (++parptr), ",", NULL); - - /* count number of fields split */ - p = tmparray; - while (*p++) - n++; - - /* copy pointers to split fields to ignores array */ - ip = copyip (tmparray, ip, MAXARGS - num_ignores); - num_ignores += n; - continue; - } - parptr = bp; - while (*parptr) { - if (evalvar (&global)) - adios (NULL, "format file syntax error: %s", bp); - if (*parptr) - parptr++; - } - continue; - - case ':': - c1 = add_queue (&fmthd, &fmttl, name, NULL, INIT); - while (*parptr == ':' || *parptr == ',') { - parptr++; - if (evalvar (c1)) - adios (NULL, "format file syntax error: %s", bp); - } - if (!c1->c_nfs && global.c_nfs) { - if (c1->c_flags & DATEFMT) { - if (global.c_flags & DATEFMT) - c1->c_nfs = getcpy (global.c_nfs); - } - else - if (c1->c_flags & ADDRFMT) { - if (global.c_flags & ADDRFMT) - c1->c_nfs = getcpy (global.c_nfs); - } - } - continue; - - default: - adios (NULL, "format file syntax error: %s", bp); - } - } - fclose (fp); - - if (mhldebug) { - for (c1 = fmthd; c1; c1 = c1->c_next) { - fprintf (stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n", - c1->c_name, c1->c_text, c1->c_ovtxt); - fprintf (stderr, "\tnfs=0x%x fmt=0x%x\n", - (unsigned int)(unsigned long) c1->c_nfs, - (unsigned int)(unsigned long) c1->c_fmt); - fprintf (stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d length=%d\n", - c1->c_offset, c1->c_ovoff, c1->c_width, - c1->c_cwidth, c1->c_length); - fprintf (stderr, "\tflags=%s\n", - snprintb (buffer, sizeof(buffer), (unsigned) c1->c_flags, LBITS)); - } - } - -out: - if (clearflg == 1) { - global.c_flags |= CLEARSCR; - } else { - if (clearflg == -1) - global.c_flags &= ~CLEARSCR; - } - - switch (bellflg) { /* command line may override format file */ - case 1: - global.c_flags |= BELL; - break; - case -1: - global.c_flags &= ~BELL; - break; - } - - if (length) - global.c_length = length; - if (width) - global.c_width = width; - if (global.c_length < 5) - global.c_length = 10000; - if (global.c_width < 5) - global.c_width = 10000; -} - - -static int -evalvar (struct mcomp *c1) -{ - char *cp, name[NAMESZ]; - struct triple *ap; - - if (!*parptr) - return 0; - strncpy (name, parse(), sizeof(name)); - - if (!mh_strcasecmp (name, "component")) { - if (ptos (name, &c1->c_text)) - return 1; - c1->c_flags &= ~NOCOMPONENT; - return 0; - } - - if (!mh_strcasecmp (name, "overflowtext")) - return ptos (name, &c1->c_ovtxt); - - if (!mh_strcasecmp (name, "formatfield")) { - char *nfs; - - if (ptos (name, &cp)) - return 1; - nfs = new_fs (NULL, NULL, cp); - c1->c_nfs = getcpy (nfs); - c1->c_flags |= FORMAT; - return 0; - } - - if (!mh_strcasecmp (name, "decode")) { - char *nfs; - - nfs = new_fs (NULL, NULL, "%(decode{text})"); - c1->c_nfs = getcpy (nfs); - c1->c_flags |= FORMAT; - return 0; - } - - if (!mh_strcasecmp (name, "offset")) - return ptoi (name, &c1->c_offset); - if (!mh_strcasecmp (name, "overflowoffset")) - return ptoi (name, &c1->c_ovoff); - if (!mh_strcasecmp (name, "width")) - return ptoi (name, &c1->c_width); - if (!mh_strcasecmp (name, "compwidth")) - return ptoi (name, &c1->c_cwidth); - if (!mh_strcasecmp (name, "length")) - return ptoi (name, &c1->c_length); - if (!mh_strcasecmp (name, "nodashstuffing")) - return (dashstuff = -1); - - for (ap = triples; ap->t_name; ap++) - if (!mh_strcasecmp (ap->t_name, name)) { - c1->c_flags |= ap->t_on; - c1->c_flags &= ~ap->t_off; - return 0; - } - - return 1; -} - - -static int -ptoi (char *name, int *i) -{ - char *cp; - - if (*parptr++ != '=' || !*(cp = parse ())) { - advise (NULL, "missing argument to variable %s", name); - return 1; - } - - *i = atoi (cp); - return 0; -} - - -static int -ptos (char *name, char **s) -{ - char c, *cp; - - if (*parptr++ != '=') { - advise (NULL, "missing argument to variable %s", name); - return 1; - } - - if (*parptr != '"') { - for (cp = parptr; - *parptr && *parptr != ':' && *parptr != ','; - parptr++) - continue; - } else { - for (cp = ++parptr; *parptr && *parptr != '"'; parptr++) - if (*parptr == QUOTE) - if (!*++parptr) - parptr--; - } - c = *parptr; - *parptr = 0; - *s = getcpy (cp); - if ((*parptr = c) == '"') - parptr++; - return 0; -} - - -static char * -parse (void) -{ - int c; - char *cp; - static char result[NAMESZ]; - - for (cp = result; *parptr && (cp - result < NAMESZ); parptr++) { - c = *parptr; - if (isalnum (c) - || c == '.' - || c == '-' - || c == '_' - || c =='[' - || c == ']') - *cp++ = c; - else - break; - } - *cp = '\0'; - - return result; -} - - -static void -process (char *folder, char *fname, int ofilen, int ofilec) -{ - char *cp = NULL; - FILE *fp = NULL; - struct mcomp *c1; - - switch (setjmp (env)) { - case OK: - if (fname) { - fp = mhl_action ? (*mhl_action) (fname) : fopen (fname, "r"); - if (fp == NULL) { - advise (fname, "unable to open"); - exitstat++; - return; - } - } else { - fname = "(stdin)"; - fp = stdin; - } - cp = folder ? concat (folder, ":", fname, NULL) : getcpy (fname); - if (ontty != PITTY) - SIGNAL (SIGINT, intrser); - mhlfile (fp, cp, ofilen, ofilec); /* FALL THROUGH! */ - - default: - if (ontty != PITTY) - SIGNAL (SIGINT, SIG_IGN); - if (mhl_action == NULL && fp != stdin) - fclose (fp); - free (cp); - if (holder.c_text) { - free (holder.c_text); - holder.c_text = NULL; - } - free_queue (&msghd, &msgtl); - for (c1 = fmthd; c1; c1 = c1->c_next) - c1->c_flags &= ~HDROUTPUT; - break; - } -} - - -static void -mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) -{ - int state; - struct mcomp *c1, *c2, *c3; - char **ip, name[NAMESZ], buf[BUFSIZ]; - - if (forwall) { - if (digest) - printf ("%s", ofilen == 1 ? delim3 : delim4); - else { - printf ("\n-------"); - if (ofilen == 1) - printf (" Forwarded Message%s", ofilec > 1 ? "s" : ""); - else - printf (" Message %d", ofilen); - printf ("\n\n"); - } - } else { - switch (ontty) { - case PITTY: - if (ofilec > 1) { - if (ofilen > 1) { - if ((global.c_flags & CLEARSCR)) - clear_screen (); - else - printf ("\n\n\n"); - } - printf (">>> %s\n\n", mname); - } - break; - - case ISTTY: - strncpy (buf, "\n", sizeof(buf)); - if (ofilec > 1) { - if (SOprintf ("Press to list \"%s\"...", mname)) { - if (ofilen > 1) - printf ("\n\n\n"); - printf ("Press to list \"%s\"...", mname); - } - fflush (stdout); - buf[0] = 0; - read (fileno (stdout), buf, sizeof(buf)); - } - if (strchr(buf, '\n')) { - if ((global.c_flags & CLEARSCR)) - clear_screen (); - } - else - printf ("\n"); - break; - - default: - if (ofilec > 1) { - if (ofilen > 1) { - printf ("\n\n\n"); - if (clearflg > 0) - clear_screen (); - } - printf (">>> %s\n\n", mname); - } - break; - } - } - - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { - case FLD: - case FLDPLUS: - for (ip = ignores; *ip; ip++) - if (!mh_strcasecmp (name, *ip)) { - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); - break; - } - if (*ip) - continue; - - for (c2 = fmthd; c2; c2 = c2->c_next) - if (!mh_strcasecmp (c2->c_name, name)) - break; - c1 = NULL; - if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT)) - for (c1 = msghd; c1; c1 = c1->c_next) - if (!mh_strcasecmp (c1->c_name, c3->c_name)) { - c1->c_text = - mcomp_add (c1->c_flags, buf, c1->c_text); - break; - } - if (c1 == NULL) - c1 = add_queue (&msghd, &msgtl, name, buf, 0); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); - c1->c_text = add (buf, c1->c_text); - } - if (c2 == NULL) - c1->c_flags |= EXTRA; - continue; - - case BODY: - case FILEEOF: - row = column = 0; - for (c1 = fmthd; c1; c1 = c1->c_next) { - if (c1->c_flags & CLEARTEXT) { - putcomp (c1, c1, ONECOMP); - continue; - } - if (!mh_strcasecmp (c1->c_name, "messagename")) { - holder.c_text = concat ("(Message ", mname, ")\n", - NULL); - putcomp (c1, &holder, ONECOMP); - free (holder.c_text); - holder.c_text = NULL; - continue; - } - if (!mh_strcasecmp (c1->c_name, "extras")) { - for (c2 = msghd; c2; c2 = c2->c_next) - if (c2->c_flags & EXTRA) - putcomp (c1, c2, TWOCOMP); - continue; - } - if (dobody && !mh_strcasecmp (c1->c_name, "body")) { - holder.c_text = mh_xmalloc (sizeof(buf)); - strncpy (holder.c_text, buf, sizeof(buf)); - while (state == BODY) { - putcomp (c1, &holder, BODYCOMP); - state = m_getfld (state, name, holder.c_text, - sizeof(buf), fp); - } - free (holder.c_text); - holder.c_text = NULL; - continue; - } - for (c2 = msghd; c2; c2 = c2->c_next) - if (!mh_strcasecmp (c2->c_name, c1->c_name)) { - putcomp (c1, c2, ONECOMP); - if (!(c1->c_flags & SPLIT)) - break; - } - if (faceproc && c2 == NULL && (c1->c_flags & FACEFMT)) - for (c2 = msghd; c2; c2 = c2->c_next) - if (c2->c_flags & FACEDFLT) { - if (c2->c_face == NULL) - face_format (c2); - if ((holder.c_text = c2->c_face)) { - putcomp (c1, &holder, ONECOMP); - holder.c_text = NULL; - } - break; - } - } - return; - - case LENERR: - case FMTERR: - advise (NULL, "format error in message %s", mname); - exitstat++; - return; - - default: - adios (NULL, "getfld() returned %d", state); - } - } -} - - -static int -mcomp_flags (char *name) -{ - struct pair *ap; - - for (ap = pairs; ap->p_name; ap++) - if (!mh_strcasecmp (ap->p_name, name)) - return (ap->p_flags); - - return 0; -} - - -static char * -mcomp_add (long flags, char *s1, char *s2) -{ - char *dp; - - if (!(flags & ADDRFMT)) - return add (s1, s2); - - if (s2 && *(dp = s2 + strlen (s2) - 1) == '\n') - *dp = 0; - - return add (s1, add (",\n", s2)); -} - - -struct pqpair { - char *pq_text; - char *pq_error; - struct pqpair *pq_next; -}; - - -static void -mcomp_format (struct mcomp *c1, struct mcomp *c2) -{ - int dat[5]; - char *ap, *cp; - char buffer[BUFSIZ], error[BUFSIZ]; - struct comp *cptr; - struct pqpair *p, *q; - struct pqpair pq; - struct mailname *mp; - - ap = c2->c_text; - c2->c_text = NULL; - dat[0] = 0; - dat[1] = 0; - dat[2] = 0; - dat[3] = sizeof(buffer) - 1; - dat[4] = 0; - fmt_compile (c1->c_nfs, &c1->c_fmt); - - if (!(c1->c_flags & ADDRFMT)) { - FINDCOMP (cptr, "text"); - if (cptr) - cptr->c_text = ap; - if ((cp = strrchr(ap, '\n'))) /* drop ending newline */ - if (!cp[1]) - *cp = 0; - - fmt_scan (c1->c_fmt, buffer, sizeof(buffer) - 1, dat); - /* Don't need to append a newline, dctime() already did */ - c2->c_text = getcpy (buffer); - - free (ap); - return; - } - - (q = &pq)->pq_next = NULL; - while ((cp = getname (ap))) { - if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL) - adios (NULL, "unable to allocate pqpair memory"); - - if ((mp = getm (cp, NULL, 0, AD_NAME, error)) == NULL) { - p->pq_text = getcpy (cp); - p->pq_error = getcpy (error); - } else { - if ((c1->c_flags & FACEDFLT) && c2->c_face == NULL) { - char *h, *o; - if ((h = mp->m_host) == NULL) - h = LocalName (); - if ((o = OfficialName (h))) - h = o; - c2->c_face = concat ("address ", h, " ", mp->m_mbox, - NULL); - } - p->pq_text = getcpy (mp->m_text); - mnfree (mp); - } - q = (q->pq_next = p); - } - - for (p = pq.pq_next; p; p = q) { - FINDCOMP (cptr, "text"); - if (cptr) - cptr->c_text = p->pq_text; - FINDCOMP (cptr, "error"); - if (cptr) - cptr->c_text = p->pq_error; - - fmt_scan (c1->c_fmt, buffer, sizeof(buffer) - 1, dat); - if (*buffer) { - if (c2->c_text) - c2->c_text = add (",\n", c2->c_text); - if (*(cp = buffer + strlen (buffer) - 1) == '\n') - *cp = 0; - c2->c_text = add (buffer, c2->c_text); - } - - free (p->pq_text); - if (p->pq_error) - free (p->pq_error); - q = p->pq_next; - free ((char *) p); - } - - c2->c_text = add ("\n", c2->c_text); - free (ap); -} - - -static struct mcomp * -add_queue (struct mcomp **head, struct mcomp **tail, char *name, char *text, int flags) -{ - struct mcomp *c1; - - if ((c1 = (struct mcomp *) calloc ((size_t) 1, sizeof(*c1))) == NULL) - adios (NULL, "unable to allocate comp memory"); - - c1->c_flags = flags & ~INIT; - if ((c1->c_name = name ? getcpy (name) : NULL)) - c1->c_flags |= mcomp_flags (c1->c_name); - c1->c_text = text ? getcpy (text) : NULL; - if (flags & INIT) { - if (global.c_ovtxt) - c1->c_ovtxt = getcpy (global.c_ovtxt); - c1->c_offset = global.c_offset; - c1->c_ovoff = global. c_ovoff; - c1->c_width = c1->c_length = 0; - c1->c_cwidth = global.c_cwidth; - c1->c_flags |= global.c_flags & GFLAGS; - } - if (*head == NULL) - *head = c1; - if (*tail != NULL) - (*tail)->c_next = c1; - *tail = c1; - - return c1; -} - - -static void -free_queue (struct mcomp **head, struct mcomp **tail) -{ - struct mcomp *c1, *c2; - - for (c1 = *head; c1; c1 = c2) { - c2 = c1->c_next; - if (c1->c_name) - free (c1->c_name); - if (c1->c_text) - free (c1->c_text); - if (c1->c_ovtxt) - free (c1->c_ovtxt); - if (c1->c_nfs) - free (c1->c_nfs); - if (c1->c_fmt) - free ((char *) c1->c_fmt); - if (c1->c_face) - free (c1->c_face); - free ((char *) c1); - } - - *head = *tail = NULL; -} - - -static void -putcomp (struct mcomp *c1, struct mcomp *c2, int flag) -{ - int count, cchdr; - unsigned char *cp; - - cchdr = 0; - lm = 0; - llim = c1->c_length ? c1->c_length : -1; - wid = c1->c_width ? c1->c_width : global.c_width; - ovoff = (c1->c_ovoff >= 0 ? c1->c_ovoff : global.c_ovoff) - + c1->c_offset; - if ((ovtxt = c1->c_ovtxt ? c1->c_ovtxt : global.c_ovtxt) == NULL) - ovtxt = ""; - if (wid < ovoff + strlen (ovtxt) + 5) - adios (NULL, "component: %s width(%d) too small for overflow(%d)", - c1->c_name, wid, ovoff + strlen (ovtxt) + 5); - onelp = NULL; - - if (c1->c_flags & CLEARTEXT) { - putstr (c1->c_text); - putstr ("\n"); - return; - } - - if (c1->c_flags & FACEFMT) - switch (doface (c2)) { - case NOTOK: /* error */ - case OK: /* async faceproc */ - return; - - default: /* sync faceproc */ - break; - } - - if (c1->c_nfs && (c1->c_flags & (ADDRFMT | DATEFMT | FORMAT))) - mcomp_format (c1, c2); - - if (c1->c_flags & CENTER) { - count = (c1->c_width ? c1->c_width : global.c_width) - - c1->c_offset - strlen (c2->c_text); - if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) - count -= strlen (c1->c_text ? c1->c_text : c1->c_name) + 2; - lm = c1->c_offset + (count / 2); - } else { - if (c1->c_offset) - lm = c1->c_offset; - } - - if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) { - if (c1->c_flags & UPPERCASE) /* uppercase component also */ - for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); - putstr (c1->c_text ? c1->c_text : c1->c_name); - if (flag != BODYCOMP) { - putstr (": "); - if (!(c1->c_flags & SPLIT)) - c1->c_flags |= HDROUTPUT; - - cchdr++; - if ((count = c1->c_cwidth - - strlen (c1->c_text ? c1->c_text : c1->c_name) - 2) > 0) - while (count--) - putstr (" "); - } - else - c1->c_flags |= HDROUTPUT; /* for BODYCOMP */ - } - - if (flag == TWOCOMP - && !(c2->c_flags & HDROUTPUT) - && !(c2->c_flags & NOCOMPONENT)) { - if (c1->c_flags & UPPERCASE) - for (cp = c2->c_name; *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); - putstr (c2->c_name); - putstr (": "); - if (!(c1->c_flags & SPLIT)) - c2->c_flags |= HDROUTPUT; - - cchdr++; - if ((count = c1->c_cwidth - strlen (c2->c_name) - 2) > 0) - while (count--) - putstr (" "); - } - if (c1->c_flags & UPPERCASE) - for (cp = c2->c_text; *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); - - count = 0; - if (cchdr) { - if (flag == TWOCOMP) - count = (c1->c_cwidth >= 0) ? c1->c_cwidth - : strlen (c2->c_name) + 2; - else - count = (c1->c_cwidth >= 0) ? c1->c_cwidth - : strlen (c1->c_text ? c1->c_text : c1->c_name) + 2; - } - count += c1->c_offset; - - if ((cp = oneline (c2->c_text, c1->c_flags))) - putstr(cp); - if (term == '\n') - putstr ("\n"); - while ((cp = oneline (c2->c_text, c1->c_flags))) { - lm = count; - if (flag == BODYCOMP - && !(c1->c_flags & NOCOMPONENT)) - putstr (c1->c_text ? c1->c_text : c1->c_name); - if (*cp) - putstr (cp); - if (term == '\n') - putstr ("\n"); - } - if (flag == BODYCOMP && term == '\n') - c1->c_flags &= ~HDROUTPUT; /* Buffer ended on a newline */ -} - - -static char * -oneline (char *stuff, long flags) -{ - int spc; - char *cp, *ret; - - if (onelp == NULL) - onelp = stuff; - if (*onelp == 0) - return (onelp = NULL); - - ret = onelp; - term = 0; - if (flags & COMPRESS) { - for (spc = 1, cp = ret; *onelp; onelp++) - if (isspace (*onelp)) { - if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) { - term = '\n'; - *onelp++ = 0; - break; - } - else - if (!spc) { - *cp++ = ' '; - spc++; - } - } - else { - *cp++ = *onelp; - spc = 0; - } - - *cp = 0; - } - else { - while (*onelp && *onelp != '\n') - onelp++; - if (*onelp == '\n') { - term = '\n'; - *onelp++ = 0; - } - if (flags & LEFTADJUST) - while (*ret == ' ' || *ret == '\t') - ret++; - } - if (*onelp == 0 && term == '\n' && (flags & NONEWLINE)) - term = 0; - - return ret; -} - - -static void -putstr (char *string) -{ - if (!column && lm > 0) { - while (lm > 0) - if (lm >= 8) { - putch ('\t'); - lm -= 8; - } - else { - putch (' '); - lm--; - } - } - lm = 0; - while (*string) - putch (*string++); -} - - -static void -putch (char ch) -{ - char buf[BUFSIZ]; - - if (llim == 0) - return; - - switch (ch) { - case '\n': - if (llim > 0) - llim--; - column = 0; - row++; - if (ontty != ISTTY || row != global.c_length) - break; - if (global.c_flags & BELL) - putchar ('\007'); - fflush (stdout); - buf[0] = 0; - read (fileno (stdout), buf, sizeof(buf)); - if (strchr(buf, '\n')) { - if (global.c_flags & CLEARSCR) - clear_screen (); - row = 0; - } else { - putchar ('\n'); - row = global.c_length / 3; - } - return; - - case '\t': - column |= 07; - column++; - break; - - case '\b': - column--; - break; - - case '\r': - column = 0; - break; - - default: - /* - * If we are forwarding this message, and the first - * column contains a dash, then add a dash and a space. - */ - if (column == 0 && forwflg && (dashstuff >= 0) && ch == '-') { - putchar ('-'); - putchar (' '); - } - if (ch >= ' ') - column++; - break; - } - - if (column >= wid) { - putch ('\n'); - if (ovoff > 0) - lm = ovoff; - putstr (ovtxt ? ovtxt : ""); - putch (ch); - return; - } - - putchar (ch); -} - - -static RETSIGTYPE -intrser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGINT, intrser); -#endif - - discard (stdout); - putchar ('\n'); - longjmp (env, DONE); -} - - -static RETSIGTYPE -pipeser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGPIPE, pipeser); -#endif - - done (NOTOK); -} - - -static RETSIGTYPE -quitser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGQUIT, quitser); -#endif - - putchar ('\n'); - fflush (stdout); - done (NOTOK); -} - - -static void -face_format (struct mcomp *c1) -{ - char *cp; - struct mailname *mp; - - if ((cp = c1->c_text) == NULL) - return; - - if ((cp = getname (cp))) { - if ((mp = getm (cp, NULL, 0, AD_NAME, NULL))) { - char *h, *o; - if ((h = mp->m_host) == NULL) - h = LocalName (); - if ((o = OfficialName (h))) - h = o; - c1->c_face = concat ("address ", h, " ", mp->m_mbox, NULL); - } - - while ((cp = getname (cp))) - continue; - } -} - - -/* - * faceproc is two elements defining the image agent's location: - * Internet host - * UDP port - */ - -#include -#include -#include - -#ifdef HAVE_ARPA_INET_H -# include -#endif - -static int -doface (struct mcomp *c1) -{ - int result, sd; - static int inited = OK; - static struct sockaddr_storage ss; - static socklen_t socklen; - static int socktype; - static int protocol; - - if (inited == OK) { - char *cp; - char **ap = brkstring (cp = getcpy (faceproc), " ", "\n"); - struct addrinfo hints, *res; - - if (ap[0] == NULL || ap[1] == NULL) { -bad_faceproc: ; - free (cp); - return (inited = NOTOK); - } - - memset(&hints, 0, sizeof(hints)); -#ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; -#endif - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - - if (getaddrinfo(ap[0], ap[1], &hints, &res) != 0) - goto bad_faceproc; - - memcpy(&ss, res->ai_addr, res->ai_addrlen); - socklen = res->ai_addrlen; - socktype = res->ai_socktype; - protocol = res->ai_protocol; - freeaddrinfo(res); - - inited = DONE; - } - if (inited == NOTOK) - return NOTOK; - - if ((sd = socket (ss.ss_family, socktype, protocol)) == NOTOK) - return NOTOK; - - result = sendto (sd, c1->c_text, strlen (c1->c_text), 0, - (struct sockaddr *) &ss, socklen); - - close (sd); - - return (result != NOTOK ? OK : NOTOK); -} - -/* - * COMMENTED OUT - * This version doesn't use sockets - */ -#if 0 - -static int -doface (struct mcomp *c1) -{ - int i, len, vecp; - pid_t child_id; - int result, pdi[2], pdo[2]; - char *bp, *cp; - char buffer[BUFSIZ], *vec[10]; - - if (pipe (pdi) == NOTOK) - return NOTOK; - if (pipe (pdo) == NOTOK) { - close (pdi[0]); - close (pdi[1]); - return NOTOK; - } - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case NOTOK: - /* oops... fork error */ - return NOTOK; - - case OK: - /* child process */ - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - if (pdi[0] != fileno (stdin)) { - dup2 (pdi[0], fileno (stdin)); - close (pdi[0]); - } - close (pdi[1]); - close (pdo[0]); - if (pdo[1] != fileno (stdout)) { - dup2 (pdo[1], fileno (stdout)); - close (pdo[1]); - } - vecp = 0; - vec[vecp++] = r1bindex (faceproc, '/'); - vec[vecp++] = "-e"; - if (sleepsw != NOTOK) { - vec[vecp++] = "-s"; - snprintf (buffer, sizeof(buffer), "%d", sleepsw); - vec[vecp++] = buffer; - } - vec[vecp] = NULL; - execvp (faceproc, vec); - fprintf (stderr, "unable to exec "); - perror (faceproc); - _exit (-1); /* NOTREACHED */ - - default: - /* parent process */ - close (pdi[0]); - i = strlen (c1->c_text); - if (write (pdi[1], c1->c_text, i) != i) - adios ("pipe", "error writing to"); - free (c1->c_text), c1->c_text = NULL; - close (pdi[1]); - - close (pdo[1]); - cp = NULL, len = 0; - result = DONE; - while ((i = read (pdo[0], buffer, strlen (buffer))) > 0) { - if (cp) { - int j; - char *dp; - dp = mh_xrealloc (cp, (unsigned) (j = len + i)); - memcpy(dp + len, buffer, i); - cp = dp, len = j; - } - else { - cp = mh_xmalloc ((unsigned) i); - memcpy(cp, buffer, i); - len = i; - } - if (result == DONE) - for (bp = buffer + i - 1; bp >= buffer; bp--) - if (!isascii (*bp) || iscntrl (*bp)) { - result = OK; - break; - } - } - close (pdo[0]); - -/* no waiting for child... */ - - if (result == OK) { /* binary */ - if (write (1, cp, len) != len) - adios ("writing", "error"); - free (cp); - } - else /* empty */ - if ((c1->c_text = cp) == NULL) - result = OK; - break; - } - - return result; -} -#endif /* COMMENTED OUT */ - - -int -mhlsbr (int argc, char **argv, FILE *(*action)()) -{ - SIGNAL_HANDLER istat = NULL, pstat = NULL, qstat = NULL; - char *cp = NULL; - struct mcomp *c1; - - switch (setjmp (mhlenv)) { - case OK: - cp = invo_name; - sleepsw = 0; /* XXX */ - bellflg = clearflg = forwflg = forwall = exitstat = 0; - digest = NULL; - ontty = NOTTY; - mhl_action = action; - - /* - * If signal is at default action, then start ignoring - * it, else let it set to its current action. - */ - if ((istat = SIGNAL (SIGINT, SIG_IGN)) != SIG_DFL) - SIGNAL (SIGINT, istat); - if ((qstat = SIGNAL (SIGQUIT, SIG_IGN)) != SIG_DFL) - SIGNAL (SIGQUIT, qstat); - pstat = SIGNAL (SIGPIPE, pipeser); - mhl (argc, argv); /* FALL THROUGH! */ - - default: - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - SIGNAL (SIGPIPE, SIG_IGN);/* should probably change to block instead */ - if (ontty == PITTY) - m_pclose (); - SIGNAL (SIGPIPE, pstat); - invo_name = cp; - if (holder.c_text) { - free (holder.c_text); - holder.c_text = NULL; - } - free_queue (&msghd, &msgtl); - for (c1 = fmthd; c1; c1 = c1->c_next) - c1->c_flags &= ~HDROUTPUT; - return exitstat; - } -} - -#undef adios -#undef done - -static void -mhladios (char *what, char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); - mhldone (1); -} - - -static void -mhldone (int status) -{ - exitstat = status; - if (mhl_action) - longjmp (mhlenv, DONE); - else - done (exitstat); -} - - -static int m_pid = NOTOK; -static int sd = NOTOK; - -static void -m_popen (char *name) -{ - int pd[2]; - - if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK) - adios ("standard output", "unable to dup()"); - - if (pipe (pd) == NOTOK) - adios ("pipe", "unable to"); - - switch (m_pid = vfork ()) { - case NOTOK: - adios ("fork", "unable to"); - - case OK: - SIGNAL (SIGINT, SIG_DFL); - SIGNAL (SIGQUIT, SIG_DFL); - - close (pd[1]); - if (pd[0] != fileno (stdin)) { - dup2 (pd[0], fileno (stdin)); - close (pd[0]); - } - execlp (name, r1bindex (name, '/'), NULL); - fprintf (stderr, "unable to exec "); - perror (name); - _exit (-1); - - default: - close (pd[0]); - if (pd[1] != fileno (stdout)) { - dup2 (pd[1], fileno (stdout)); - close (pd[1]); - } - } -} - - -void -m_pclose (void) -{ - if (m_pid == NOTOK) - return; - - if (sd != NOTOK) { - fflush (stdout); - if (dup2 (sd, fileno (stdout)) == NOTOK) - adios ("standard output", "unable to dup2()"); - - clearerr (stdout); - close (sd); - sd = NOTOK; - } - else - fclose (stdout); - - pidwait (m_pid, OK); - m_pid = NOTOK; -} diff --git a/uip/mhmail.c b/uip/mhmail.c index e586860..7e170a8 100644 --- a/uip/mhmail.c +++ b/uip/mhmail.c @@ -1,211 +1,206 @@ - /* - * mhmail.c -- simple mail program - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhmail.c -- simple mail program +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include +#include + static struct swit switches[] = { -#define BODYSW 0 - { "body text", 0 }, -#define CCSW 1 - { "cc addrs ...", 0 }, -#define FROMSW 2 - { "from addr", 0 }, -#define SUBJSW 3 - { "subject text", 0 }, -#define VERSIONSW 4 - { "version", 0 }, -#define HELPSW 5 - { "help", 0 }, -#define RESNDSW 6 - { "resent", -6 }, -#define QUEUESW 7 - { "queued", -6 }, - { NULL, 0 } +#define BODYSW 0 + { "bodytext text", 0 }, +#define CCSW 1 + { "cc addrs ...", 0 }, +#define FROMSW 2 + { "from addr", 0 }, +#define SUBJSW 3 + { "subject text", 0 }, +#define VERSIONSW 4 + { "Version", 0 }, +#define HELPSW 5 + { "help", 0 }, + { NULL, 0 } }; static char tmpfil[BUFSIZ]; /* - * static prototypes - */ -static RETSIGTYPE intrser (int); +** static prototypes +*/ +static void intrser(int); int -main (int argc, char **argv) +main(int argc, char **argv) { - pid_t child_id; - int status, i, iscc = 0, nvec; - int queued = 0, resent = 0, somebody; - char *cp, *tolist = NULL, *cclist = NULL, *subject = NULL; - char *from = NULL, *body = NULL, **argp, **arguments; - char *vec[5], buf[BUFSIZ]; - FILE *out; - char *tfile = NULL; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - /* If no arguments, just incorporate new mail */ - if (argc == 1) { - execlp (incproc, r1bindex (incproc, '/'), NULL); - adios (incproc, "unable to exec"); - } - - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [addrs ... [switches]]", - invo_name); - print_help (buf, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FROMSW: - if (!(from = *argp++) || *from == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case BODYSW: - if (!(body = *argp++) || *body == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case CCSW: - iscc++; - continue; - - case SUBJSW: - if (!(subject = *argp++) || *subject == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case RESNDSW: - resent++; - continue; - - case QUEUESW: - queued++; - continue; - } + pid_t child_id; + int status, iscc = 0, nvec; + char *cp, *tolist = NULL, *cclist = NULL, *subject = NULL; + char *from = NULL, *body = NULL, **argp, **arguments; + char *vec[5], buf[BUFSIZ]; + FILE *out; + char *tfile = NULL; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* Without arguments, exit. */ + if (argc == 1) { + adios(NULL, "no interactive mail shell. Use inc/scan/show instead."); } - if (iscc) - cclist = cclist ? add (cp, add (", ", cclist)) : getcpy (cp); - else - tolist = tolist ? add (cp, add (", ", tolist)) : getcpy (cp); - } - - if (tolist == NULL) - adios (NULL, "usage: %s addrs ... [switches]", invo_name); - - tfile = m_mktemp2(NULL, invo_name, NULL, &out); - if (tfile == NULL) adios("mhmail", "unable to create temporary file"); - chmod(tfile, 0600); - strncpy (tmpfil, tfile, sizeof(tmpfil)); - - SIGNAL2 (SIGINT, intrser); - - fprintf (out, "%sTo: %s\n", resent ? "Resent-" : "", tolist); - if (cclist) - fprintf (out, "%scc: %s\n", resent ? "Resent-" : "", cclist); - if (subject) - fprintf (out, "%sSubject: %s\n", resent ? "Resent-" : "", subject); - if (from) - fprintf (out, "%sFrom: %s\n", resent ? "Resent-" : "", from); - if (!resent) - fputs ("\n", out); - - if (body) { - fprintf (out, "%s", body); - if (*body && *(body + strlen (body) - 1) != '\n') - fputs ("\n", out); - } else { - for (somebody = 0; - (i = fread (buf, sizeof(*buf), sizeof(buf), stdin)) > 0; - somebody++) - if (fwrite (buf, sizeof(*buf), i, out) != i) - adios (tmpfil, "error writing"); - if (!somebody) { - unlink (tmpfil); - done (1); + + context_read(); + + arguments = getarguments(invo_name, argc, argv, 0); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s addrs... [switches]", + invo_name); + print_help(buf, switches, 0); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FROMSW: + if (!(from = *argp++) || *from == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case BODYSW: + if (!(body = *argp++) || *body == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case CCSW: + iscc++; + continue; + + case SUBJSW: + if (!(subject = *argp++) || *subject == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + } + } + if (iscc) + cclist = cclist ? add(cp, add(", ", cclist)) : + getcpy(cp); + else + tolist = tolist ? add(cp, add(", ", tolist)) : + getcpy(cp); } - } - fclose (out); - - nvec = 0; - vec[nvec++] = r1bindex (postproc, '/'); - vec[nvec++] = tmpfil; - if (resent) - vec[nvec++] = "-dist"; - if (queued) - vec[nvec++] = "-queued"; - vec[nvec] = NULL; - - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - - if (child_id == NOTOK) { - /* report failure and then send it */ - adios (NULL, "unable to fork"); - } else if (child_id) { - /* parent process */ - if ((status = pidXwait(child_id, postproc))) { - fprintf (stderr, "Letter saved in dead.letter\n"); - execl ("/bin/mv", "mv", tmpfil, "dead.letter", NULL); - execl ("/usr/bin/mv", "mv", tmpfil, "dead.letter", NULL); - perror ("mv"); - _exit (-1); + + if (tolist == NULL) + adios(NULL, "usage: %s addrs ... [switches]", invo_name); + + tfile = m_mktemp2("/tmp/", invo_name, NULL, &out); + if (tfile == NULL) + adios("mhmail", "unable to create temporary file"); + chmod(tfile, 0600); + strncpy(tmpfil, tfile, sizeof(tmpfil)); + + SIGNAL2(SIGINT, intrser); + + fprintf(out, "To: %s\n", tolist); + if (cclist) + fprintf(out, "Cc: %s\n", cclist); + if (subject) + fprintf(out, "Subject: %s\n", subject); + if (from) + fprintf(out, "From: %s\n", from); + fputs("\n", out); + + if (body) { + fprintf(out, "%s", body); + if (*body && body[strlen(body) - 1] != '\n') + fputs("\n", out); + } else { + int empty = 1; + + while (fgets(buf, sizeof buf, stdin)) { + if (buf[0]=='.' && buf[1]=='\n') { + /* A period alone on a line means EOF. */ + break; + } + empty = 0; + if (fputs(buf, out) == EOF) { + adios(tmpfil, "error writing"); + } + } + if (empty) { + unlink(tmpfil); + adios(NULL, "not sending message with empty body"); + } } - unlink (tmpfil); - done (status ? 1 : 0); - } else { - /* child process */ - execvp (postproc, vec); - fprintf (stderr, "unable to exec "); - perror (postproc); - _exit (-1); - } - - return 0; /* dead code to satisfy the compiler */ + fclose(out); + + nvec = 0; + vec[nvec++] = "spost"; + vec[nvec++] = tmpfil; + vec[nvec] = NULL; + + if ((child_id = fork()) == NOTOK) { + /* report failure and then send it */ + adios(NULL, "unable to fork"); + + } else if (child_id == 0) { + /* child process */ + execvp(*vec, vec); + fprintf(stderr, "unable to exec "); + perror(*vec); + _exit(-1); + + } else { + /* parent process */ + if ((status = pidXwait(child_id, *vec))) { + /* spost failed, save draft as dead.letter */ + int in, out; + + in = open(tmpfil, O_RDONLY); + out = creat("dead.letter", 0600); + if (in == -1 || out == -1) { + fprintf(stderr, "Letter left at %s.\n", + tmpfil); + done(status ? 1 : 0); + } + cpydata(in, out, tmpfil, "dead.letter"); + close(in); + close(out); + fprintf(stderr, "Letter saved in dead.letter\n"); + } + unlink(tmpfil); + done(status ? 1 : 0); + } + + return 0; /* dead code to satisfy the compiler */ } -static RETSIGTYPE -intrser (int i) +static void +intrser(int i) { -#ifndef RELIABLE_SIGNALS - if (i) - SIGNAL (i, SIG_IGN); -#endif - - unlink (tmpfil); - done (i != 0 ? 1 : 0); + unlink(tmpfil); + done(i != 0 ? 1 : 0); } diff --git a/uip/mhmisc.c b/uip/mhmisc.c index 7a23139..0c8e644 100644 --- a/uip/mhmisc.c +++ b/uip/mhmisc.c @@ -1,11 +1,10 @@ - /* - * mhparse.c -- misc routines to process MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhparse.c -- misc routines to process MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -16,222 +15,227 @@ extern int debugsw; /* - * limit actions to specified parts or content types - */ +** limit actions to specified parts or content types +*/ int npart = 0; int ntype = 0; char *parts[NPARTS + 1]; char *types[NTYPES + 1]; -int endian = 0; /* little or big endian */ +int endian = 0; /* little or big endian */ int userrs = 0; static char *errs = NULL; /* - * prototypes - */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -int make_intermediates (char *); -void content_error (char *, CT, char *, ...); -void flush_errors (void); +** prototypes +*/ +int part_ok(CT, int); +int type_ok(CT, int); +void set_endian(void); +int make_intermediates(char *); +void content_error(char *, CT, char *, ...); +void flush_errors(void); int -part_ok (CT ct, int sP) +part_ok(CT ct, int sP) { - char **ap; - int len; - - if (npart == 0 || (ct->c_type == CT_MULTIPART && (sP || ct->c_subtype))) - return 1; - - for (ap = parts; *ap; ap++) { - len = strlen(*ap); - if (!strncmp (*ap, ct->c_partno, len) && - (!ct->c_partno[len] || ct->c_partno[len] == '.' )) - return 1; - } + char **ap; + int len; + + if (npart == 0 || (ct->c_type == CT_MULTIPART && + (sP || ct->c_subtype))) + return 1; + + for (ap = parts; *ap; ap++) { + len = strlen(*ap); + if (strncmp(*ap, ct->c_partno, len)==0 && + (!ct->c_partno[len] || + ct->c_partno[len] == '.' )) + return 1; + } - return 0; + return 0; } int -type_ok (CT ct, int sP) +type_ok(CT ct, int sP) { - char **ap; - char buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; + char **ap; + char buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; - if (ntype == 0 || (ct->c_type == CT_MULTIPART && (sP || ct->c_subtype))) - return 1; + if (ntype == 0 || (ct->c_type == CT_MULTIPART && + (sP || ct->c_subtype))) + return 1; - snprintf (buffer, sizeof(buffer), "%s/%s", ci->ci_type, ci->ci_subtype); - for (ap = types; *ap; ap++) - if (!mh_strcasecmp (*ap, ci->ci_type) || !mh_strcasecmp (*ap, buffer)) - return 1; + snprintf(buffer, sizeof(buffer), "%s/%s", ci->ci_type, ci->ci_subtype); + for (ap = types; *ap; ap++) + if (!mh_strcasecmp(*ap, ci->ci_type) || + !mh_strcasecmp(*ap, buffer)) + return 1; - return 0; + return 0; } void -set_endian (void) +set_endian(void) { - union { - long l; - char c[sizeof(long)]; - } un; - - un.l = 1; - endian = un.c[0] ? -1 : 1; - if (debugsw) - fprintf (stderr, "%s endian architecture\n", - endian > 0 ? "big" : "little"); + union { + long l; + char c[sizeof(long)]; + } un; + + un.l = 1; + endian = un.c[0] ? -1 : 1; + if (debugsw) + fprintf(stderr, "%s endian architecture\n", + endian > 0 ? "big" : "little"); } int -make_intermediates (char *file) +make_intermediates(char *file) { - char *cp; + char *cp; - for (cp = file + 1; (cp = strchr(cp, '/')); cp++) { - struct stat st; + for (cp = file + 1; (cp = strchr(cp, '/')); cp++) { + struct stat st; - *cp = '\0'; - if (stat (file, &st) == NOTOK) { - int answer; - char *ep; - if (errno != ENOENT) { - advise (file, "error on directory"); + *cp = '\0'; + if (stat(file, &st) == NOTOK) { + int answer; + char *ep; + if (errno != ENOENT) { + advise(file, "error on directory"); losing_directory: + *cp = '/'; + return NOTOK; + } + + ep = concat("Create directory \"", file, "\"? ", NULL); + answer = getanswer(ep); + free(ep); + + if (!answer) + goto losing_directory; + if (!makedir(file)) { + advise(NULL, "unable to create directory %s", + file); + goto losing_directory; + } + } + *cp = '/'; - return NOTOK; - } - - ep = concat ("Create directory \"", file, "\"? ", NULL); - answer = getanswer (ep); - free (ep); - - if (!answer) - goto losing_directory; - if (!makedir (file)) { - advise (NULL, "unable to create directory %s", file); - goto losing_directory; - } } - *cp = '/'; - } - - return OK; + return OK; } /* - * Construct error message for content - */ +** Construct error message for content +*/ void -content_error (char *what, CT ct, char *fmt, ...) +content_error(char *what, CT ct, char *fmt, ...) { - va_list arglist; - int i, len, buflen; - char *bp, buffer[BUFSIZ]; - CI ci; + va_list arglist; + int i, len, buflen; + char *bp, buffer[BUFSIZ]; + CI ci; + + bp = buffer; + buflen = sizeof(buffer); + + if (userrs && invo_name && *invo_name) { + snprintf(bp, buflen, "%s: ", invo_name); + len = strlen(bp); + bp += len; + buflen -= len; + } - bp = buffer; - buflen = sizeof(buffer); + va_start(arglist, fmt); - if (userrs && invo_name && *invo_name) { - snprintf (bp, buflen, "%s: ", invo_name); - len = strlen (bp); + vsnprintf(bp, buflen, fmt, arglist); + len = strlen(bp); bp += len; buflen -= len; - } - va_start (arglist, fmt); + ci = &ct->c_ctinfo; - vsnprintf (bp, buflen, fmt, arglist); - len = strlen (bp); - bp += len; - buflen -= len; + if (what) { + char *s; - ci = &ct->c_ctinfo; + if (*what) { + snprintf(bp, buflen, " %s: ", what); + len = strlen(bp); + bp += len; + buflen -= len; + } - if (what) { - char *s; + if ((s = strerror(errno))) + snprintf(bp, buflen, "%s", s); + else + snprintf(bp, buflen, "Error %d", errno); - if (*what) { - snprintf (bp, buflen, " %s: ", what); - len = strlen (bp); - bp += len; - buflen -= len; + len = strlen(bp); + bp += len; + buflen -= len; } - if ((s = strerror (errno))) - snprintf (bp, buflen, "%s", s); - else - snprintf (bp, buflen, "Error %d", errno); + i = strlen(invo_name) + 2; - len = strlen (bp); + /* Now add content type and subtype */ + snprintf(bp, buflen, "\n%*.*s(content %s/%s", i, i, "", + ci->ci_type, ci->ci_subtype); + len = strlen(bp); bp += len; buflen -= len; - } - - i = strlen (invo_name) + 2; - /* Now add content type and subtype */ - snprintf (bp, buflen, "\n%*.*s(content %s/%s", i, i, "", - ci->ci_type, ci->ci_subtype); - len = strlen (bp); - bp += len; - buflen -= len; + /* Now add the message/part number */ + if (ct->c_file) { + snprintf(bp, buflen, " in message %s", ct->c_file); + len = strlen(bp); + bp += len; + buflen -= len; + + if (ct->c_partno) { + snprintf(bp, buflen, ", part %s", ct->c_partno); + len = strlen(bp); + bp += len; + buflen -= len; + } + } - /* Now add the message/part number */ - if (ct->c_file) { - snprintf (bp, buflen, " in message %s", ct->c_file); - len = strlen (bp); + snprintf(bp, buflen, ")"); + len = strlen(bp); bp += len; buflen -= len; - if (ct->c_partno) { - snprintf (bp, buflen, ", part %s", ct->c_partno); - len = strlen (bp); - bp += len; - buflen -= len; + if (userrs) { + *bp++ = '\n'; + *bp = '\0'; + buflen--; + + errs = add(buffer, errs); + } else { + advise(NULL, "%s", buffer); } - } - - snprintf (bp, buflen, ")"); - len = strlen (bp); - bp += len; - buflen -= len; - - if (userrs) { - *bp++ = '\n'; - *bp = '\0'; - buflen--; - - errs = add (buffer, errs); - } else { - advise (NULL, "%s", buffer); - } } void -flush_errors (void) +flush_errors(void) { - if (errs) { - fflush (stdout); - fprintf (stderr, "%s", errs); - free (errs); - errs = NULL; - } + if (errs) { + fflush(stdout); + fprintf(stderr, "%s", errs); + free(errs); + errs = NULL; + } } diff --git a/uip/mhn.c b/uip/mhn.c deleted file mode 100644 index a7644a3..0000000 --- a/uip/mhn.c +++ /dev/null @@ -1,703 +0,0 @@ - -/* - * mhn.c -- display, list, cache, or store the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -static struct swit switches[] = { -#define AUTOSW 0 - { "auto", 0 }, -#define NAUTOSW 1 - { "noauto", 0 }, -#define CACHESW 2 - { "cache", 0 }, -#define NCACHESW 3 - { "nocache", 0 }, -#define CHECKSW 4 - { "check", 0 }, -#define NCHECKSW 5 - { "nocheck", 0 }, -#define HEADSW 6 - { "headers", 0 }, -#define NHEADSW 7 - { "noheaders", 0 }, -#define LISTSW 8 - { "list", 0 }, -#define NLISTSW 9 - { "nolist", 0 }, -#define PAUSESW 10 - { "pause", 0 }, -#define NPAUSESW 11 - { "nopause", 0 }, -#define SIZESW 12 - { "realsize", 0 }, -#define NSIZESW 13 - { "norealsize", 0 }, -#define SERIALSW 14 - { "serialonly", 0 }, -#define NSERIALSW 15 - { "noserialonly", 0 }, -#define SHOWSW 16 - { "show", 0 }, -#define NSHOWSW 17 - { "noshow", 0 }, -#define STORESW 18 - { "store", 0 }, -#define NSTORESW 19 - { "nostore", 0 }, -#define VERBSW 20 - { "verbose", 0 }, -#define NVERBSW 21 - { "noverbose", 0 }, -#define FILESW 22 /* interface from show */ - { "file file", 0 }, -#define FORMSW 23 - { "form formfile", 0 }, -#define PARTSW 24 - { "part number", 0 }, -#define TYPESW 25 - { "type content", 0 }, -#define RCACHESW 26 - { "rcache policy", 0 }, -#define WCACHESW 27 - { "wcache policy", 0 }, -#define VERSIONSW 28 - { "version", 0 }, -#define HELPSW 29 - { "help", 0 }, - -/* - * switches for debugging - */ -#define DEBUGSW 30 - { "debug", -5 }, - -/* - * switches for moreproc/mhlproc - */ -#define PROGSW 31 - { "moreproc program", -4 }, -#define NPROGSW 32 - { "nomoreproc", -3 }, -#define LENSW 33 - { "length lines", -4 }, -#define WIDTHSW 34 - { "width columns", -4 }, - -/* - * switches for mhbuild - */ -#define BUILDSW 35 - { "build", -5 }, -#define NBUILDSW 36 - { "nobuild", -7 }, -#define EBCDICSW 37 - { "ebcdicsafe", -10 }, -#define NEBCDICSW 38 - { "noebcdicsafe", -12 }, -#define RFC934SW 39 - { "rfc934mode", -10 }, -#define NRFC934SW 40 - { "norfc934mode", -12 }, - { NULL, 0 } -}; - - -/* mhparse.c */ -extern char *tmp; /* directory to place temp files */ - -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; - -/* mhshowsbr.c */ -extern int pausesw; -extern int serialsw; -extern char *progsw; -extern int nolist; -extern int nomore; /* flags for moreproc/header display */ -extern char *formsw; - -/* mhstoresbr.c */ -extern int autosw; -extern char *cwd; /* cache current working directory */ - -/* mhmisc.c */ -extern int npart; -extern int ntype; -extern char *parts[NPARTS + 1]; -extern char *types[NTYPES + 1]; -extern int userrs; - -int debugsw = 0; -int verbosw = 0; - -/* - * variables for mhbuild (mhn -build) - */ -static int buildsw = 0; -static int ebcdicsw = 0; -static int rfc934sw = 0; - -/* - * what action to take? - */ -static int cachesw = 0; -static int listsw = 0; -static int showsw = 0; -static int storesw = 0; - -#define quitser pipeser - -/* mhparse.c */ -CT parse_mime (char *); - -/* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -void flush_errors (void); - -/* mhshowsbr.c */ -void show_all_messages (CT *); - -/* mhlistsbr.c */ -void list_all_messages (CT *, int, int, int, int); - -/* mhstoresbr.c */ -void store_all_messages (CT *); - -/* mhcachesbr.c */ -void cache_all_messages (CT *); - -/* mhfree.c */ -void free_content (CT); -extern CT *cts; -void freects_done (int) NORETURN; - -/* - * static prototypes - */ -static RETSIGTYPE pipeser (int); - - -int -main (int argc, char **argv) -{ - int sizesw = 1, headsw = 1; - int msgnum, *icachesw; - char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp = NULL; - CT ct, *ctp; - FILE *fp; - - done=freects_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case AUTOSW: - autosw++; - continue; - case NAUTOSW: - autosw = 0; - continue; - - case CACHESW: - cachesw++; - continue; - case NCACHESW: - cachesw = 0; - continue; - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; -do_cache: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); - default: - break; - } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case HEADSW: - headsw = 1; - continue; - case NHEADSW: - headsw = 0; - continue; - - case LISTSW: - listsw = 1; - continue; - case NLISTSW: - listsw = 0; - continue; - - case PAUSESW: - pausesw = 1; - continue; - case NPAUSESW: - pausesw = 0; - continue; - - case SERIALSW: - serialsw = 1; - continue; - case NSERIALSW: - serialsw = 0; - continue; - - case SHOWSW: - showsw = 1; - continue; - case NSHOWSW: - showsw = 0; - continue; - - case SIZESW: - sizesw = 1; - continue; - case NSIZESW: - sizesw = 0; - continue; - - case STORESW: - storesw = 1; - continue; - case NSTORESW: - storesw = 0; - continue; - - case PARTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (npart >= NPARTS) - adios (NULL, "too many parts (starting with %s), %d max", - cp, NPARTS); - parts[npart++] = cp; - continue; - - case TYPESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (ntype >= NTYPES) - adios (NULL, "too many types (starting with %s), %d max", - cp, NTYPES); - types[ntype++] = cp; - continue; - - case FILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - file = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case FORMSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (formsw) - free (formsw); - formsw = getcpy (etcpath (cp)); - continue; - - /* - * Switches for moreproc/mhlproc - */ - case PROGSW: - if (!(progsw = *argp++) || *progsw == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NPROGSW: - nomore++; - continue; - - case LENSW: - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - /* - * Switches for mhbuild - */ - case BUILDSW: - buildsw = 1; - continue; - case NBUILDSW: - buildsw = 0; - continue; - case RFC934SW: - rfc934sw = 1; - continue; - case NRFC934SW: - rfc934sw = -1; - continue; - case EBCDICSW: - ebcdicsw = 1; - continue; - case NEBCDICSW: - ebcdicsw = -1; - continue; - - case VERBSW: - verbosw = 1; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* null terminate the list of acceptable parts/types */ - parts[npart] = NULL; - types[ntype] = NULL; - - set_endian (); - - if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1")) { - nolist = 1; - listsw = 0; - pausesw = 0; - } - - /* - * Check if we've specified an additional profile - */ - if ((cp = getenv ("MHN"))) { - if ((fp = fopen (cp, "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } else { - admonish ("", "unable to read $MHN profile (%s)", cp); - } - } - - /* - * Read the standard profile setup - */ - if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Cache the current directory before we do any chdirs()'s. - */ - cwd = getcpy (pwd()); - - /* - * Check for storage directory. If specified, - * then store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* - * Process a mhn composition file (mhn -build) - */ - if (buildsw) { - char *vec[MAXARGS]; - int vecp; - - if (showsw || storesw || cachesw) - adios (NULL, "cannot use -build with -show, -store, -cache"); - if (msgs.size < 1) - adios (NULL, "need to specify a %s composition file", invo_name); - if (msgs.size > 1) - adios (NULL, "only one %s composition file at a time", invo_name); - - vecp = 0; - vec[vecp++] = "mhbuild"; - - if (ebcdicsw == 1) - vec[vecp++] = "-ebcdicsafe"; - else if (ebcdicsw == -1) - vec[vecp++] = "-noebcdicsafe"; - - if (rfc934sw == 1) - vec[vecp++] = "-rfc934mode"; - else if (rfc934sw == -1) - vec[vecp++] = "-norfc934mode"; - - vec[vecp++] = msgs.msgs[0]; - vec[vecp] = NULL; - - execvp ("mhbuild", vec); - fprintf (stderr, "unable to exec "); - _exit (-1); - } - - /* - * Process a mhn composition file (old MH style) - */ - if (msgs.size == 1 && !folder && !npart && !cachesw - && !showsw && !storesw && !ntype && !file - && (cp = getenv ("mhdraft")) - && strcmp (cp, msgs.msgs[0]) == 0) { - - char *vec[MAXARGS]; - int vecp; - - vecp = 0; - vec[vecp++] = "mhbuild"; - - if (ebcdicsw == 1) - vec[vecp++] = "-ebcdicsafe"; - else if (ebcdicsw == -1) - vec[vecp++] = "-noebcdicsafe"; - - if (rfc934sw == 1) - vec[vecp++] = "-rfc934mode"; - else if (rfc934sw == -1) - vec[vecp++] = "-norfc934mode"; - - vec[vecp++] = cp; - vec[vecp] = NULL; - - execvp ("mhbuild", vec); - fprintf (stderr, "unable to exec "); - _exit (-1); - } - - if (file && msgs.size) - adios (NULL, "cannot specify msg and file at same time!"); - - /* - * check if message is coming from file - */ - if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - if ((ct = parse_mime (file))); - *ctp++ = ct; - } else { - /* - * message(s) are coming from a folder - */ - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - char *msgnam; - - msgnam = m_name (msgnum); - if ((ct = parse_mime (msgnam))) - *ctp++ = ct; - } - } - } - - if (!*cts) - done (1); - - /* - * You can't give more than one of these flags - * at a time. - */ - if (showsw + listsw + storesw + cachesw > 1) - adios (NULL, "can only use one of -show, -list, -store, -cache at same time"); - - /* If no action is specified, assume -show */ - if (!listsw && !showsw && !storesw && !cachesw) - showsw = 1; - - userrs = 1; - SIGNAL (SIGQUIT, quitser); - SIGNAL (SIGPIPE, pipeser); - - /* - * Get the associated umask for the relevant contents. - */ - for (ctp = cts; *ctp; ctp++) { - struct stat st; - - ct = *ctp; - if (type_ok (ct, 1) && !ct->c_umask) { - if (stat (ct->c_file, &st) != NOTOK) - ct->c_umask = ~(st.st_mode & 0777); - else - ct->c_umask = ~m_gmprot(); - } - } - - /* - * List the message content - */ - if (listsw) - list_all_messages (cts, headsw, sizesw, verbosw, debugsw); - - /* - * Store the message content - */ - if (storesw) - store_all_messages (cts); - - /* - * Cache the message content - */ - if (cachesw) - cache_all_messages (cts); - - /* - * Show the message content - */ - if (showsw) - show_all_messages (cts); - - /* Now free all the structures for the content */ - for (ctp = cts; *ctp; ctp++) - free_content (*ctp); - - free ((char *) cts); - cts = NULL; - - /* If reading from a folder, do some updating */ - if (mp) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - done (0); - return 1; -} - - -static RETSIGTYPE -pipeser (int i) -{ - if (i == SIGQUIT) { - unlink ("core"); - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - done (1); - /* NOTREACHED */ -} diff --git a/uip/mhoutsbr.c b/uip/mhoutsbr.c index 7e12c46..4d04b65 100644 --- a/uip/mhoutsbr.c +++ b/uip/mhoutsbr.c @@ -1,479 +1,341 @@ - /* - * mhoutsbr.c -- routines to output MIME messages - * -- given a Content structure - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhoutsbr.c -- routines to output MIME messages +** -- given a Content structure +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include -#include #include #include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - - -extern int ebcdicsw; - -static char ebcdicsafe[0x100] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; static char nib2b64[0x40+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* - * prototypes - */ -int output_message (CT, char *); -int output_message_fp (CT, FILE *, char *); -int writeBase64aux (FILE *, FILE *); +** prototypes +*/ +int output_message(CT, char *); +int output_message_fp(CT, FILE *, char *); /* - * static prototypes - */ -static int output_content (CT, FILE *); -static void output_headers (CT, FILE *); -static int writeExternalBody (CT, FILE *); -static int write8Bit (CT, FILE *); -static int writeQuoted (CT, FILE *); -static int writeBase64 (CT, FILE *); +** static prototypes +*/ +static int output_content(CT, FILE *); +static void output_headers(CT, FILE *); +static int write8Bit(CT, FILE *); +static int writeQuoted(CT, FILE *); +static int writeBase64(CT, FILE *); +static int writeBase64aux(FILE *, FILE *); /* - * Main routine to output a MIME message contained - * in a Content structure, to a file. Any necessary - * transfer encoding is added. - */ +** Main routine to output a MIME message contained +** in a Content structure, to a file. Any necessary +** transfer encoding is added. +*/ int -output_message_fp (CT ct, FILE *fp, char *file) +output_message_fp(CT ct, FILE *fp, char *file) { - if (output_content (ct, fp) == NOTOK) - return NOTOK; - - if (fflush (fp)) { - advise ((file?file:""), "error writing to"); - return NOTOK; - } - return OK; + if (output_content(ct, fp) == NOTOK) + return NOTOK; + + if (fflush(fp)) { + advise((file?file:""), "error writing to"); + return NOTOK; + } + return OK; } int -output_message (CT ct, char *file) +output_message(CT ct, char *file) { - FILE *fp; - int status; - - if ((fp = fopen (file, "w")) == NULL) { - advise (file, "unable to open for writing"); - return NOTOK; - } - status = output_message_fp(ct, fp, file); - fclose(fp); - return status; + FILE *fp; + int status; + + if ((fp = fopen(file, "w")) == NULL) { + advise(file, "unable to open for writing"); + return NOTOK; + } + status = output_message_fp(ct, fp, file); + fclose(fp); + return status; } /* - * Output a Content structure to a file. - */ +** Output a Content structure to a file. +*/ static int -output_content (CT ct, FILE *out) +output_content(CT ct, FILE *out) { - int result = 0; - CI ci = &ct->c_ctinfo; - - /* - * Output all header fields for this content - */ - output_headers (ct, out); - - /* - * If this is the internal content structure for a - * "message/external", then we are done with the - * headers (since it has no body). - */ - if (ct->c_ctexbody) - return OK; - - /* - * Now output the content bodies. - */ - switch (ct->c_type) { - case CT_MULTIPART: - { - struct multipart *m; - struct part *part; - - if (ct->c_rfc934) - putc ('\n', out); + int result = 0; + CI ci = &ct->c_ctinfo; + + /* + ** Output all header fields for this content + */ + output_headers(ct, out); + + /* + ** Now output the content bodies. + */ + switch (ct->c_type) { + case CT_MULTIPART: + { + struct multipart *m; + struct part *part; + + m = (struct multipart *) ct->c_ctparams; + for (part = m->mp_parts; part; part = part->mp_next) { + CT p = part->mp_part; + + fprintf(out, "\n--%s\n", ci->ci_values[0]); + if (output_content(p, out) == NOTOK) + return NOTOK; + } + fprintf(out, "\n--%s--\n", ci->ci_values[0]); + } + break; - m = (struct multipart *) ct->c_ctparams; - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; + case CT_MESSAGE: + putc('\n', out); + result = write8Bit(ct, out); + break; - fprintf (out, "\n--%s\n", ci->ci_values[0]); - if (output_content (p, out) == NOTOK) - return NOTOK; - } - fprintf (out, "\n--%s--\n", ci->ci_values[0]); - } - break; + /* + ** Handle discrete types (text/application/audio/image/video) + */ + default: + switch (ct->c_encoding) { + case CE_7BIT: + putc('\n', out); + result = write8Bit(ct, out); + break; - case CT_MESSAGE: - putc ('\n', out); - if (ct->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e; + case CE_8BIT: + putc('\n', out); + result = write8Bit(ct, out); + break; - e = (struct exbody *) ct->c_ctparams; - if (output_content (e->eb_content, out) == NOTOK) - return NOTOK; + case CE_QUOTED: + putc('\n', out); + result = writeQuoted(ct, out); + break; - /* output phantom body for access-type "mail-server" */ - if (e->eb_body) - writeExternalBody (ct, out); - } else { - result = write8Bit (ct, out); - } - break; + case CE_BASE64: + putc('\n', out); + result = writeBase64(ct, out); + break; - /* - * Handle discrete types (text/application/audio/image/video) - */ - default: - switch (ct->c_encoding) { - case CE_7BIT: - putc ('\n', out); - result = write8Bit (ct, out); - break; - - case CE_8BIT: - putc ('\n', out); - result = write8Bit (ct, out); - break; - - case CE_QUOTED: - putc ('\n', out); - result = writeQuoted (ct, out); - break; - - case CE_BASE64: - putc ('\n', out); - result = writeBase64 (ct, out); - break; - - case CE_BINARY: - advise (NULL, "can't handle binary transfer encoding in content"); - result = NOTOK; - break; + case CE_BINARY: + advise(NULL, "can't handle binary transfer encoding in content"); + result = NOTOK; + break; - default: - advise (NULL, "unknown transfer encoding in content"); - result = NOTOK; - break; + default: + advise(NULL, "unknown transfer encoding in content"); + result = NOTOK; + break; + } + break; } - break; - } - return result; + return result; } /* - * Output all the header fields for a content - */ +** Output all the header fields for a content +*/ static void -output_headers (CT ct, FILE *out) +output_headers(CT ct, FILE *out) { - HF hp; + HF hp; - hp = ct->c_first_hf; - while (hp) { - fprintf (out, "%s:%s", hp->name, hp->value); - hp = hp->next; - } + hp = ct->c_first_hf; + while (hp) { + fprintf(out, "%s:%s", hp->name, hp->value); + hp = hp->next; + } } /* - * Write the phantom body for access-type "mail-server". - */ +** Output a content without any transfer encoding +*/ static int -writeExternalBody (CT ct, FILE *out) +write8Bit(CT ct, FILE *out) { - char **ap, **ep, *cp; - struct exbody *e = (struct exbody *) ct->c_ctparams; - - putc ('\n', out); - for (cp = e->eb_body; *cp; cp++) { - CT ct2 = e->eb_content; - CI ci2 = &ct2->c_ctinfo; - - if (*cp == '\\') { - switch (*++cp) { - case 'I': - if (ct2->c_id) { - char *dp = trimcpy (ct2->c_id); - - fputs (dp, out); - free (dp); - } - continue; + int fd; + char c, *file, buffer[BUFSIZ]; + CE ce = ct->c_cefile; - case 'N': - for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++) - if (!mh_strcasecmp (*ap, "name")) { - fprintf (out, "%s", *ep); - break; - } - continue; - - case 'T': - fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype); - for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++) - fprintf (out, "; %s=\"%s\"", *ap, *ep); - continue; - - case 'n': - putc ('\n', out); - continue; - - case 't': - putc ('\t', out); - continue; - - case '\0': - cp--; - break; - - case '\\': - case '"': - break; + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; - default: - putc ('\\', out); - break; - } + c = '\n'; + while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) { + c = buffer[strlen(buffer) - 1]; + fputs(buffer, out); } - putc (*cp, out); - } - putc ('\n', out); + if (c != '\n') + putc('\n', out); - return OK; + (*ct->c_ceclosefnx) (ct); + return OK; } /* - * Output a content without any transfer encoding - */ +** Output a content using quoted-printable +*/ static int -write8Bit (CT ct, FILE *out) +writeQuoted(CT ct, FILE *out) { - int fd; - char c, *file, buffer[BUFSIZ]; - CE ce = ct->c_cefile; - - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; - - c = '\n'; - while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) { - c = buffer[strlen (buffer) - 1]; - fputs (buffer, out); - } - if (c != '\n') - putc ('\n', out); - - (*ct->c_ceclosefnx) (ct); - return OK; -} + int fd; + char *cp, *file; + char c, buffer[BUFSIZ]; + CE ce = ct->c_cefile; + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; -/* - * Output a content using quoted-printable - */ + while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) { + int n; -static int -writeQuoted (CT ct, FILE *out) -{ - int fd; - char *cp, *file; - char c, buffer[BUFSIZ]; - CE ce = ct->c_cefile; - - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; - - while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) { - int n; - - cp = buffer + strlen (buffer) - 1; - if ((c = *cp) == '\n') - *cp = '\0'; - - if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) { - fprintf (out, "=%02X", *cp++ & 0xff); - n = 3; - } else { - n = 0; - } - for (; *cp; cp++) { - if (n > CPERLIN - 3) { - fputs ("=\n", out); - n = 0; - } - - switch (*cp) { - case ' ': - case '\t': - putc (*cp, out); - n++; - break; + cp = buffer + strlen(buffer) - 1; + if ((c = *cp) == '\n') + *cp = '\0'; - default: - if (*cp < '!' || *cp > '~' - || (ebcdicsw && !ebcdicsafe[*cp & 0xff])) - goto three_print; - putc (*cp, out); - n++; - break; - - case '=': + if (strncmp(cp = buffer, "From ", sizeof("From ") - 1) == 0) { + fprintf(out, "=%02X", *cp++ & 0xff); + n = 3; + } else { + n = 0; + } + for (; *cp; cp++) { + if (n > CPERLIN - 3) { + fputs("=\n", out); + n = 0; + } + + switch (*cp) { + case ' ': + case '\t': + putc(*cp, out); + n++; + break; + + default: + if (*cp < '!' || *cp > '~') + goto three_print; + putc(*cp, out); + n++; + break; + + case '=': three_print: - fprintf (out, "=%02X", *cp & 0xff); - n += 3; - break; - } - } + fprintf(out, "=%02X", *cp & 0xff); + n += 3; + break; + } + } - if (c == '\n') { - if (cp > buffer && (*--cp == ' ' || *cp == '\t')) - fputs ("=\n", out); + if (c == '\n') { + if (cp > buffer && (*--cp == ' ' || *cp == '\t')) + fputs("=\n", out); - putc ('\n', out); - } else { - fputs ("=\n", out); + putc('\n', out); + } else { + fputs("=\n", out); + } } - } - (*ct->c_ceclosefnx) (ct); - return OK; + (*ct->c_ceclosefnx) (ct); + return OK; } /* - * Output a content using base64 - */ +** Output a content using base64 +*/ static int -writeBase64 (CT ct, FILE *out) +writeBase64(CT ct, FILE *out) { - int fd, result; - char *file; - CE ce = ct->c_cefile; + int fd, result; + char *file; + CE ce = ct->c_cefile; - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; - result = writeBase64aux (ce->ce_fp, out); - (*ct->c_ceclosefnx) (ct); - return result; + result = writeBase64aux(ce->ce_fp, out); + (*ct->c_ceclosefnx) (ct); + return result; } -int -writeBase64aux (FILE *in, FILE *out) +static int +writeBase64aux(FILE *in, FILE *out) { - int cc, n; - char inbuf[3]; - - n = BPERLIN; - while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) { - unsigned long bits; - char *bp; - char outbuf[4]; - - if (cc < sizeof(inbuf)) { - inbuf[2] = 0; - if (cc < sizeof(inbuf) - 1) - inbuf[1] = 0; - } - bits = (inbuf[0] & 0xff) << 16; - bits |= (inbuf[1] & 0xff) << 8; - bits |= inbuf[2] & 0xff; - - for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6) - *--bp = nib2b64[bits & 0x3f]; - if (cc < sizeof(inbuf)) { - outbuf[3] = '='; - if (cc < sizeof inbuf - 1) - outbuf[2] = '='; - } + unsigned int cc, n; + char inbuf[3]; + + n = BPERLIN; + while ((cc = fread(inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) { + unsigned long bits; + char *bp; + char outbuf[4]; + + if (cc < sizeof(inbuf)) { + inbuf[2] = 0; + if (cc < sizeof(inbuf) - 1) + inbuf[1] = 0; + } + bits = (inbuf[0] & 0xff) << 16; + bits |= (inbuf[1] & 0xff) << 8; + bits |= inbuf[2] & 0xff; + + for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6) + *--bp = nib2b64[bits & 0x3f]; + if (cc < sizeof(inbuf)) { + outbuf[3] = '='; + if (cc < sizeof inbuf - 1) + outbuf[2] = '='; + } - fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out); + fwrite(outbuf, sizeof(*outbuf), sizeof(outbuf), out); - if (cc < sizeof(inbuf)) { - putc ('\n', out); - return OK; - } + if (cc < sizeof(inbuf)) { + putc('\n', out); + return OK; + } - if (--n <= 0) { - n = BPERLIN; - putc ('\n', out); + if (--n <= 0) { + n = BPERLIN; + putc('\n', out); + } } - } - if (n != BPERLIN) - putc ('\n', out); + if (n != BPERLIN) + putc('\n', out); - return OK; + return OK; } diff --git a/uip/mhparam.c b/uip/mhparam.c index 8384544..4e1fc21 100644 --- a/uip/mhparam.c +++ b/uip/mhparam.c @@ -1,197 +1,178 @@ - /* - * mhparam.c -- print mh_profile values - * - * Originally contributed by - * Jeffrey C Honig - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhparam.c -- print mh_profile values +** +** Originally contributed by +** Jeffrey C Honig +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -extern char *mhlibdir; -extern char *mhetcdir; - -char *sbackup = BACKUP_PREFIX; -char *slink = LINK; - static struct swit switches[] = { -#define COMPSW 0 - { "components", 0 }, -#define NCOMPSW 1 - { "nocomponents", 0 }, -#define ALLSW 2 - { "all", 0 }, +#define COMPSW 0 + { "components", 0 }, +#define NCOMPSW 1 + { "nocomponents", 2 }, +#define ALLSW 2 + { "all", 0 }, #define VERSIONSW 3 - { "version", 0 }, -#define HELPSW 4 - { "help", 0 }, + { "Version", 0 }, +#define HELPSW 4 + { "help", 0 }, #define DEBUGSW 5 - { "debug", -5 }, - { NULL, 0 } + { "debug", -5 }, + { NULL, 0 } }; struct proc { - char *p_name; - char **p_field; + char *p_name; + char **p_field; }; static struct proc procs [] = { - { "context", &context }, - { "mh-sequences", &mh_seq }, - { "buildmimeproc", &buildmimeproc }, - { "faceproc", &faceproc }, - { "fileproc", &fileproc }, - { "foldprot", &foldprot }, - { "incproc", &incproc }, - { "installproc", &installproc }, - { "lproc", &lproc }, - { "mailproc", &mailproc }, - { "mhlproc", &mhlproc }, - { "moreproc", &moreproc }, - { "msgprot", &msgprot }, - { "mshproc", &mshproc }, - { "packproc", &packproc }, - { "postproc", &postproc }, - { "rmfproc", &rmfproc }, - { "rmmproc", &rmmproc }, - { "sendproc", &sendproc }, - { "showmimeproc", &showmimeproc }, - { "showproc", &showproc }, - { "version", &version_num }, - { "vmhproc", &vmhproc }, - { "whatnowproc", &whatnowproc }, - { "whomproc", &whomproc }, - { "etcdir", &mhetcdir }, - { "libdir", &mhlibdir }, - { "sbackup", &sbackup }, - { "link", &slink }, - { NULL, NULL }, + { "attachment-header", &attach_hdr }, + { "sign-header", &sign_hdr }, + { "enc-header", &enc_hdr }, + { "context", &context }, + { "mh-sequences", &mh_seq }, + { "editor", &defaulteditor }, + { "foldprot", &foldprot }, + { "listproc", &listproc }, + { "mimetypequeryproc", &mimetypequeryproc }, + { "msgprot", &msgprot }, + { "pager", &defaultpager }, + { "sendmail", &sendmail }, + { "version", &version_num }, + { "whatnowproc", &whatnowproc }, + { "etcdir", &mhetcdir }, + { "draft-folder", &draftfolder }, + { "trash-folder", &trashfolder }, + { NULL, NULL }, }; /* - * static prototypes - */ +** static prototypes +*/ static char *p_find(char *); int main(int argc, char **argv) { - int i, compp = 0, missed = 0; - int all = 0, debug = 0; - int components = -1; - char *cp, buf[BUFSIZ], **argp; - char **arguments, *comps[MAXARGS]; - - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [profile-components] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case COMPSW: - components = 1; - break; - case NCOMPSW: - components = 0; - break; - - case ALLSW: - all = 1; - break; - - case DEBUGSW: - debug = 1; - break; - } - } else { - comps[compp++] = cp; + int i, compp = 0, missed = 0; + int all = 0, debug = 0; + int components = -1; + char *cp, buf[BUFSIZ], **argp; + char **arguments, *comps[MAXARGS]; + + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [profile-components] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case COMPSW: + components = 1; + break; + case NCOMPSW: + components = 0; + break; + + case ALLSW: + all = 1; + break; + + case DEBUGSW: + debug = 1; + break; + } + } else { + comps[compp++] = cp; + } } - } - if (all) { - struct node *np; + if (all) { + struct node *np; - if (compp) - advise(NULL, "profile-components ignored with -all"); + if (compp) + advise(NULL, "profile-components ignored with -all"); - if (components >= 0) - advise(NULL, "-%scomponents ignored with -all", - components ? "" : "no"); + if (components >= 0) + advise(NULL, "-%scomponents ignored with -all", + components ? "" : "no"); - /* print all entries in context/profile list */ - for (np = m_defs; np; np = np->n_next) - printf("%s: %s\n", np->n_name, np->n_field); + /* print all entries in context/profile list */ + for (np = m_defs; np; np = np->n_next) + printf("%s: %s\n", np->n_name, np->n_field); - } else if (debug) { - struct proc *ps; - - /* - * Print the current value of everything in - * procs array. This will show their current - * value (as determined after context is read). - */ - for (ps = procs; ps->p_name; ps++) - printf ("%s: %s\n", ps->p_name, *ps->p_field ? *ps->p_field : ""); + } else if (debug) { + struct proc *ps; - } else { - if (components < 0) - components = compp > 1; + /* + ** Print the current value of everything in + ** procs array. This will show their current + ** value (as determined after context is read). + */ + for (ps = procs; ps->p_name; ps++) + printf("%s: %s\n", ps->p_name, + *ps->p_field ? *ps->p_field : ""); - for (i = 0; i < compp; i++) { - register char *value; - - value = context_find (comps[i]); - if (!value) - value = p_find (comps[i]); - if (value) { - if (components) - printf("%s: ", comps[i]); - - printf("%s\n", value); - } else - missed++; + } else { + if (components < 0) + components = compp > 1; + + for (i = 0; i < compp; i++) { + register char *value; + + value = context_find(comps[i]); + if (!value) + value = p_find(comps[i]); + if (value) { + if (components) + printf("%s: ", comps[i]); + + printf("%s\n", value); + } else + missed++; + } } - } - - done (missed); - return 1; + + done(missed); + return 1; } static char * p_find(char *str) { - struct proc *ps; + struct proc *ps; - for (ps = procs; ps->p_name; ps++) - if (!mh_strcasecmp (ps->p_name, str)) - return (*ps->p_field); + for (ps = procs; ps->p_name; ps++) + if (!mh_strcasecmp(ps->p_name, str)) + return (*ps->p_field); - return NULL; + return NULL; } diff --git a/uip/mhparse.c b/uip/mhparse.c index d40d78c..af460e6 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -1,2891 +1,2104 @@ - /* - * mhparse.c -- routines to parse the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhparse.c -- routines to parse the contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include #include -#include #include #include #include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - - extern int debugsw; -extern int endian; /* mhmisc.c */ - -extern pid_t xpid; /* mhshowsbr.c */ +extern int endian; /* mhmisc.c */ -/* cache policies */ -extern int rcachesw; /* mhcachesbr.c */ -extern int wcachesw; /* mhcachesbr.c */ - -int checksw = 0; /* check Content-MD5 field */ +extern pid_t xpid; /* mhshowsbr.c */ /* - * Directory to place temp files. This must - * be set before these routines are called. - */ +** Directory to place temp files. This must +** be set before these routines are called. +*/ char *tmp; /* - * Structures for TEXT messages - */ +** Structures for TEXT messages +*/ struct k2v SubText[] = { - { "plain", TEXT_PLAIN }, - { "richtext", TEXT_RICHTEXT }, /* defined in RFC-1341 */ - { "enriched", TEXT_ENRICHED }, /* defined in RFC-1896 */ - { NULL, TEXT_UNKNOWN } /* this one must be last! */ + { "plain", TEXT_PLAIN }, + { "richtext", TEXT_RICHTEXT }, /* defined in RFC-1341 */ + { "enriched", TEXT_ENRICHED }, /* defined in RFC-1896 */ + { NULL, TEXT_UNKNOWN } /* this one must be last! */ }; struct k2v Charset[] = { - { "us-ascii", CHARSET_USASCII }, - { "iso-8859-1", CHARSET_LATIN }, - { NULL, CHARSET_UNKNOWN } /* this one must be last! */ + { "us-ascii", CHARSET_USASCII }, + { "iso-8859-1", CHARSET_LATIN }, + { NULL, CHARSET_UNKNOWN } /* this one must be last! */ }; /* - * Structures for MULTIPART messages - */ +** Structures for MULTIPART messages +*/ struct k2v SubMultiPart[] = { - { "mixed", MULTI_MIXED }, - { "alternative", MULTI_ALTERNATE }, - { "digest", MULTI_DIGEST }, - { "parallel", MULTI_PARALLEL }, - { NULL, MULTI_UNKNOWN } /* this one must be last! */ + { "mixed", MULTI_MIXED }, + { "alternative", MULTI_ALTERNATE }, + { "digest", MULTI_DIGEST }, + { "parallel", MULTI_PARALLEL }, + { NULL, MULTI_UNKNOWN } /* this one must be last! */ }; /* - * Structures for MESSAGE messages - */ +** Structures for MESSAGE messages +*/ struct k2v SubMessage[] = { - { "rfc822", MESSAGE_RFC822 }, - { "partial", MESSAGE_PARTIAL }, - { "external-body", MESSAGE_EXTERNAL }, - { NULL, MESSAGE_UNKNOWN } /* this one must be last! */ + { "rfc822", MESSAGE_RFC822 }, + { "partial", MESSAGE_PARTIAL }, + { "external-body", MESSAGE_EXTERNAL }, + { NULL, MESSAGE_UNKNOWN } /* this one must be last! */ }; /* - * Structure for APPLICATION messages - */ +** Structure for APPLICATION messages +*/ struct k2v SubApplication[] = { - { "octet-stream", APPLICATION_OCTETS }, - { "postscript", APPLICATION_POSTSCRIPT }, - { NULL, APPLICATION_UNKNOWN } /* this one must be last! */ + { "octet-stream", APPLICATION_OCTETS }, + { "postscript", APPLICATION_POSTSCRIPT }, + { NULL, APPLICATION_UNKNOWN } /* this one must be last! */ }; -/* ftpsbr.c */ -int ftp_get (char *, char *, char *, char *, char *, char *, int, int); - -/* mhcachesbr.c */ -int find_cache (CT, int, int *, char *, char *, int); - /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -int make_intermediates (char *); -void content_error (char *, CT, char *, ...); +int part_ok(CT, int); +int type_ok(CT, int); +int make_intermediates(char *); +void content_error(char *, CT, char *, ...); /* mhfree.c */ -void free_content (CT); -void free_encoding (CT, int); +void free_content(CT); +void free_encoding(CT, int); /* - * static prototypes - */ -static CT get_content (FILE *, char *, int); -static int get_comment (CT, unsigned char **, int); - -static int InitGeneric (CT); -static int InitText (CT); -static int InitMultiPart (CT); -static void reverse_parts (CT); -static int InitMessage (CT); -static int InitApplication (CT); -static int init_encoding (CT, OpenCEFunc); -static unsigned long size_encoding (CT); -static int InitBase64 (CT); -static int openBase64 (CT, char **); -static int InitQuoted (CT); -static int openQuoted (CT, char **); -static int Init7Bit (CT); -static int openExternal (CT, CT, CE, char **, int *); -static int InitFile (CT); -static int openFile (CT, char **); -static int InitFTP (CT); -static int openFTP (CT, char **); -static int InitMail (CT); -static int openMail (CT, char **); -static int readDigest (CT, char *); +** static prototypes +*/ +static CT get_content(FILE *, char *, int); +static int get_comment(CT, unsigned char **, int); + +static int InitGeneric(CT); +static int InitText(CT); +static int InitMultiPart(CT); +static void reverse_parts(CT); +static int InitMessage(CT); +static int InitApplication(CT); +static int init_encoding(CT, OpenCEFunc); +static unsigned long size_encoding(CT); +static int InitBase64(CT); +static int openBase64(CT, char **); +static int InitQuoted(CT); +static int openQuoted(CT, char **); +static int Init7Bit(CT); struct str2init str2cts[] = { - { "application", CT_APPLICATION, InitApplication }, - { "audio", CT_AUDIO, InitGeneric }, - { "image", CT_IMAGE, InitGeneric }, - { "message", CT_MESSAGE, InitMessage }, - { "multipart", CT_MULTIPART, InitMultiPart }, - { "text", CT_TEXT, InitText }, - { "video", CT_VIDEO, InitGeneric }, - { NULL, CT_EXTENSION, NULL }, /* these two must be last! */ - { NULL, CT_UNKNOWN, NULL }, + { "application", CT_APPLICATION, InitApplication }, + { "audio", CT_AUDIO, InitGeneric }, + { "image", CT_IMAGE, InitGeneric }, + { "message", CT_MESSAGE, InitMessage }, + { "multipart", CT_MULTIPART, InitMultiPart }, + { "text", CT_TEXT, InitText }, + { "video", CT_VIDEO, InitGeneric }, + { NULL, CT_EXTENSION, NULL }, /* these two must be last! */ + { NULL, CT_UNKNOWN, NULL }, }; struct str2init str2ces[] = { - { "base64", CE_BASE64, InitBase64 }, - { "quoted-printable", CE_QUOTED, InitQuoted }, - { "8bit", CE_8BIT, Init7Bit }, - { "7bit", CE_7BIT, Init7Bit }, - { "binary", CE_BINARY, Init7Bit }, - { NULL, CE_EXTENSION, NULL }, /* these two must be last! */ - { NULL, CE_UNKNOWN, NULL }, -}; - -/* - * NOTE WELL: si_key MUST NOT have value of NOTOK - * - * si_key is 1 if access method is anonymous. - */ -struct str2init str2methods[] = { - { "afs", 1, InitFile }, - { "anon-ftp", 1, InitFTP }, - { "ftp", 0, InitFTP }, - { "local-file", 0, InitFile }, - { "mail-server", 0, InitMail }, - { NULL, 0, NULL } + { "base64", CE_BASE64, InitBase64 }, + { "quoted-printable", CE_QUOTED, InitQuoted }, + { "8bit", CE_8BIT, Init7Bit }, + { "7bit", CE_7BIT, Init7Bit }, + { "binary", CE_BINARY, Init7Bit }, + { NULL, CE_EXTENSION, NULL }, /* these two must be last! */ + { NULL, CE_UNKNOWN, NULL }, }; int -pidcheck (int status) +pidcheck(int status) { - if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT) - return status; + if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT) + return status; - fflush (stdout); - fflush (stderr); - done (1); - return 1; + fflush(stdout); + fflush(stderr); + done(1); + return 1; } /* - * Main entry point for parsing a MIME message or file. - * It returns the Content structure for the top level - * entity in the file. - */ - +** Main entry point for parsing a MIME message or file. +** It returns the Content structure for the top level +** entity in the file. +*/ CT -parse_mime (char *file) +parse_mime(char *file) { - int is_stdin; - char buffer[BUFSIZ]; - FILE *fp; - CT ct; - - /* - * Check if file is actually standard input - */ - if ((is_stdin = !(strcmp (file, "-")))) { - char *tfile = m_mktemp2(NULL, invo_name, NULL, &fp); - if (tfile == NULL) { - advise("mhparse", "unable to create temporary file"); - return NULL; - } - file = add (tfile, NULL); - chmod (file, 0600); - - while (fgets (buffer, sizeof(buffer), stdin)) - fputs (buffer, fp); - fflush (fp); - - if (ferror (stdin)) { - unlink (file); - advise ("stdin", "error reading"); - return NULL; - } - if (ferror (fp)) { - unlink (file); - advise (file, "error writing"); - return NULL; - } - fseek (fp, 0L, SEEK_SET); - } else if ((fp = fopen (file, "r")) == NULL) { - advise (file, "unable to read"); - return NULL; - } + int is_stdin; + char buffer[BUFSIZ]; + FILE *fp; + CT ct; - if (!(ct = get_content (fp, file, 1))) { - if (is_stdin) - unlink (file); - advise (NULL, "unable to decode %s", file); - return NULL; - } + /* + ** Check if file is actually standard input + */ + if ((is_stdin = (strcmp(file, "-")==0))) { + char *tfile = m_mktemp2(NULL, invo_name, NULL, &fp); + if (tfile == NULL) { + advise("mhparse", "unable to create temporary file"); + return NULL; + } + file = getcpy(tfile); + chmod(file, 0600); + + while (fgets(buffer, sizeof(buffer), stdin)) + fputs(buffer, fp); + fflush(fp); - if (is_stdin) - ct->c_unlink = 1; /* temp file to remove */ + if (ferror(stdin)) { + unlink(file); + advise("stdin", "error reading"); + return NULL; + } + if (ferror(fp)) { + unlink(file); + advise(file, "error writing"); + return NULL; + } + fseek(fp, 0L, SEEK_SET); + } else if ((fp = fopen(file, "r")) == NULL) { + advise(file, "unable to read"); + return NULL; + } - ct->c_fp = NULL; + if (!(ct = get_content(fp, file, 1))) { + if (is_stdin) + unlink(file); + advise(NULL, "unable to decode %s", file); + return NULL; + } - if (ct->c_end == 0L) { - fseek (fp, 0L, SEEK_END); - ct->c_end = ftell (fp); - } + if (is_stdin) + ct->c_unlink = 1; /* temp file to remove */ - if (ct->c_ctinitfnx && (*ct->c_ctinitfnx) (ct) == NOTOK) { - fclose (fp); - free_content (ct); - return NULL; - } + ct->c_fp = NULL; - fclose (fp); - return ct; + if (ct->c_end == 0L) { + fseek(fp, 0L, SEEK_END); + ct->c_end = ftell(fp); + } + + if (ct->c_ctinitfnx && (*ct->c_ctinitfnx) (ct) == NOTOK) { + fclose(fp); + free_content(ct); + return NULL; + } + + fclose(fp); + return ct; } /* - * Main routine for reading/parsing the headers - * of a message content. - * - * toplevel = 1 # we are at the top level of the message - * toplevel = 0 # we are inside message type or multipart type - * # other than multipart/digest - * toplevel = -1 # we are inside multipart/digest - * NB: on failure we will fclose(in)! - */ +** Main routine for reading/parsing the headers +** of a message content. +** +** toplevel = 1 # we are at the top level of the message +** toplevel = 0 # we are inside message type or multipart type +** # other than multipart/digest +** toplevel = -1 # we are inside multipart/digest +** NB: on failure we will fclose(in)! +*/ static CT -get_content (FILE *in, char *file, int toplevel) +get_content(FILE *in, char *file, int toplevel) { - int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; - char *np, *vp; - CT ct; - HF hp; - - /* allocate the content structure */ - if (!(ct = (CT) calloc (1, sizeof(*ct)))) - adios (NULL, "out of memory"); - - ct->c_fp = in; - ct->c_file = add (file, NULL); - ct->c_begin = ftell (ct->c_fp) + 1; - - /* - * Parse the header fields for this - * content into a linked list. - */ - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), in)) { - case FLD: - case FLDPLUS: - case FLDEOF: - compnum++; - - /* get copies of the buffers */ - np = add (name, NULL); - vp = add (buf, NULL); - - /* if necessary, get rest of field */ - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); - vp = add (buf, vp); /* add to previous value */ - } - - /* Now add the header data to the list */ - add_header (ct, np, vp); - - /* continue, if this isn't the last header field */ - if (state != FLDEOF) { - ct->c_begin = ftell (in) + 1; - continue; - } - /* else fall... */ + int compnum, state; + char buf[BUFSIZ], name[NAMESZ]; + char *np, *vp; + CT ct; + HF hp; - case BODY: - case BODYEOF: - ct->c_begin = ftell (in) - strlen (buf); - break; + /* allocate the content structure */ + if (!(ct = (CT) calloc(1, sizeof(*ct)))) + adios(NULL, "out of memory"); - case FILEEOF: - ct->c_begin = ftell (in); - break; + ct->c_fp = in; + ct->c_file = getcpy(file); + ct->c_begin = ftell(ct->c_fp) + 1; - case LENERR: - case FMTERR: - adios (NULL, "message format error in component #%d", compnum); + /* + ** Parse the header fields for this + ** content into a linked list. + */ + for (compnum = 1, state = FLD;;) { + switch (state = m_getfld(state, name, buf, sizeof(buf), in)) { + case FLD: + case FLDPLUS: + case FLDEOF: + compnum++; + + /* get copies of the buffers */ + np = getcpy(name); + vp = getcpy(buf); + + /* if necessary, get rest of field */ + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof(buf), in); + vp = add(buf, vp); /* add to previous value */ + } - default: - adios (NULL, "getfld() returned %d", state); - } - - /* break out of the loop */ - break; - } - - /* - * Read the content headers. We will parse the - * MIME related header fields into their various - * structures and set internal flags related to - * content type/subtype, etc. - */ - - hp = ct->c_first_hf; /* start at first header field */ - while (hp) { - /* Get MIME-Version field */ - if (!mh_strcasecmp (hp->name, VRSN_FIELD)) { - int ucmp; - char c; - unsigned char *cp, *dp; - - if (ct->c_vrsn) { - advise (NULL, "message %s has multiple %s: fields", - ct->c_file, VRSN_FIELD); - goto next_header; - } - ct->c_vrsn = add (hp->value, NULL); - - /* Now, cleanup this field */ - cp = ct->c_vrsn; - - while (isspace (*cp)) - cp++; - for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) - *dp++ = ' '; - for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) - break; - *++dp = '\0'; - if (debugsw) - fprintf (stderr, "%s: %s\n", VRSN_FIELD, cp); + /* Now add the header data to the list */ + add_header(ct, np, vp); - if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK) - goto out; + /* continue, if this isn't the last header field */ + if (state != FLDEOF) { + ct->c_begin = ftell(in) + 1; + continue; + } + /* else fall... */ - for (dp = cp; istoken (*dp); dp++) - continue; - c = *dp; - *dp = '\0'; - ucmp = !mh_strcasecmp (cp, VRSN_VALUE); - *dp = c; - if (!ucmp) { - admonish (NULL, "message %s has unknown value for %s: field (%s)", - ct->c_file, VRSN_FIELD, cp); - } - } - else if (!mh_strcasecmp (hp->name, TYPE_FIELD)) { - /* Get Content-Type field */ - struct str2init *s2i; - CI ci = &ct->c_ctinfo; - - /* Check if we've already seen a Content-Type header */ - if (ct->c_ctline) { - advise (NULL, "message %s has multiple %s: fields", - ct->c_file, TYPE_FIELD); - goto next_header; - } - - /* Parse the Content-Type field */ - if (get_ctinfo (hp->value, ct, 0) == NOTOK) - goto out; - - /* - * Set the Init function and the internal - * flag for this content type. - */ - for (s2i = str2cts; s2i->si_key; s2i++) - if (!mh_strcasecmp (ci->ci_type, s2i->si_key)) - break; - if (!s2i->si_key && !uprf (ci->ci_type, "X-")) - s2i++; - ct->c_type = s2i->si_val; - ct->c_ctinitfnx = s2i->si_init; - } - else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) { - /* Get Content-Transfer-Encoding field */ - char c; - unsigned char *cp, *dp; - struct str2init *s2i; - - /* - * Check if we've already seen the - * Content-Transfer-Encoding field - */ - if (ct->c_celine) { - advise (NULL, "message %s has multiple %s: fields", - ct->c_file, ENCODING_FIELD); - goto next_header; - } - - /* get copy of this field */ - ct->c_celine = cp = add (hp->value, NULL); - - while (isspace (*cp)) - cp++; - for (dp = cp; istoken (*dp); dp++) - continue; - c = *dp; - *dp = '\0'; - - /* - * Find the internal flag and Init function - * for this transfer encoding. - */ - for (s2i = str2ces; s2i->si_key; s2i++) - if (!mh_strcasecmp (cp, s2i->si_key)) - break; - if (!s2i->si_key && !uprf (cp, "X-")) - s2i++; - *dp = c; - ct->c_encoding = s2i->si_val; - - /* Call the Init function for this encoding */ - if (s2i->si_init && (*s2i->si_init) (ct) == NOTOK) - goto out; - } - else if (!mh_strcasecmp (hp->name, MD5_FIELD)) { - /* Get Content-MD5 field */ - unsigned char *cp, *dp; - char *ep; - - if (!checksw) - goto next_header; - - if (ct->c_digested) { - advise (NULL, "message %s has multiple %s: fields", - ct->c_file, MD5_FIELD); - goto next_header; - } - - ep = cp = add (hp->value, NULL); /* get a copy */ - - while (isspace (*cp)) - cp++; - for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) - *dp++ = ' '; - for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) - break; - *++dp = '\0'; - if (debugsw) - fprintf (stderr, "%s: %s\n", MD5_FIELD, cp); - - if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK) { - free (ep); - goto out; - } - - for (dp = cp; *dp && !isspace (*dp); dp++) - continue; - *dp = '\0'; + case BODY: + case BODYEOF: + ct->c_begin = ftell(in) - strlen(buf); + break; - readDigest (ct, cp); - free (ep); - ct->c_digested++; - } - else if (!mh_strcasecmp (hp->name, ID_FIELD)) { - /* Get Content-ID field */ - ct->c_id = add (hp->value, ct->c_id); - } - else if (!mh_strcasecmp (hp->name, DESCR_FIELD)) { - /* Get Content-Description field */ - ct->c_descr = add (hp->value, ct->c_descr); - } - else if (!mh_strcasecmp (hp->name, DISPO_FIELD)) { - /* Get Content-Disposition field */ - ct->c_dispo = add (hp->value, ct->c_dispo); + case FILEEOF: + ct->c_begin = ftell(in); + break; + + case LENERR: + case FMTERR: + adios(NULL, "message format error in component #%d", + compnum); + + default: + adios(NULL, "getfld() returned %d", state); + } + + /* break out of the loop */ + break; } + /* + ** Read the content headers. We will parse the + ** MIME related header fields into their various + ** structures and set internal flags related to + ** content type/subtype, etc. + */ + + hp = ct->c_first_hf; /* start at first header field */ + while (hp) { + /* Get MIME-Version field */ + if (!mh_strcasecmp(hp->name, VRSN_FIELD)) { + int ucmp; + char c; + unsigned char *cp, *dp; + + if (ct->c_vrsn) { + advise(NULL, "message %s has multiple %s: fields", ct->c_file, VRSN_FIELD); + goto next_header; + } + ct->c_vrsn = getcpy(hp->value); + + /* Now, cleanup this field */ + cp = ct->c_vrsn; + + while (isspace(*cp)) + cp++; + for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) + *dp++ = ' '; + for (dp = cp + strlen(cp) - 1; dp >= cp; dp--) + if (!isspace(*dp)) + break; + *++dp = '\0'; + if (debugsw) + fprintf(stderr, "%s: %s\n", VRSN_FIELD, cp); + + if (*cp == '(' && get_comment(ct, &cp, 0) == NOTOK) + goto out; + + for (dp = cp; istoken(*dp); dp++) + continue; + c = *dp; + *dp = '\0'; + ucmp = !mh_strcasecmp(cp, VRSN_VALUE); + *dp = c; + if (!ucmp) { + admonish(NULL, "message %s has unknown value for %s: field (%s)", ct->c_file, VRSN_FIELD, cp); + } + + } else if (!mh_strcasecmp(hp->name, TYPE_FIELD)) { + /* Get Content-Type field */ + struct str2init *s2i; + CI ci = &ct->c_ctinfo; + + /* Check if we've already seen a Content-Type header */ + if (ct->c_ctline) { + advise(NULL, "message %s has multiple %s: fields", ct->c_file, TYPE_FIELD); + goto next_header; + } + + /* Parse the Content-Type field */ + if (get_ctinfo(hp->value, ct, 0) == NOTOK) + goto out; + + /* + ** Set the Init function and the internal + ** flag for this content type. + */ + for (s2i = str2cts; s2i->si_key; s2i++) + if (!mh_strcasecmp(ci->ci_type, s2i->si_key)) + break; + if (!s2i->si_key && !uprf(ci->ci_type, "X-")) + s2i++; + ct->c_type = s2i->si_val; + ct->c_ctinitfnx = s2i->si_init; + + } else if (!mh_strcasecmp(hp->name, ENCODING_FIELD)) { + /* Get Content-Transfer-Encoding field */ + char c; + unsigned char *cp, *dp; + struct str2init *s2i; + + /* + ** Check if we've already seen the + ** Content-Transfer-Encoding field + */ + if (ct->c_celine) { + advise(NULL, "message %s has multiple %s: fields", ct->c_file, ENCODING_FIELD); + goto next_header; + } + + /* get copy of this field */ + ct->c_celine = cp = getcpy(hp->value); + + while (isspace(*cp)) + cp++; + for (dp = cp; istoken(*dp); dp++) + continue; + c = *dp; + *dp = '\0'; + + /* + ** Find the internal flag and Init function + ** for this transfer encoding. + */ + for (s2i = str2ces; s2i->si_key; s2i++) + if (!mh_strcasecmp(cp, s2i->si_key)) + break; + if (!s2i->si_key && !uprf(cp, "X-")) + s2i++; + *dp = c; + ct->c_encoding = s2i->si_val; + + /* Call the Init function for this encoding */ + if (s2i->si_init && (*s2i->si_init) (ct) == NOTOK) + goto out; + + } else if (!mh_strcasecmp(hp->name, ID_FIELD)) { + /* Get Content-ID field */ + ct->c_id = add(hp->value, ct->c_id); + + } else if (!mh_strcasecmp(hp->name, DESCR_FIELD)) { + /* Get Content-Description field */ + ct->c_descr = add(hp->value, ct->c_descr); + + } else if (!mh_strcasecmp(hp->name, DISPO_FIELD)) { + /* Get Content-Disposition field */ + ct->c_dispo = add(hp->value, ct->c_dispo); + } + next_header: - hp = hp->next; /* next header field */ - } - - /* - * Check if we saw a Content-Type field. - * If not, then assign a default value for - * it, and the Init function. - */ - if (!ct->c_ctline) { + hp = hp->next; /* next header field */ + } + /* - * If we are inside a multipart/digest message, - * so default type is message/rfc822 - */ - if (toplevel < 0) { - if (get_ctinfo ("message/rfc822", ct, 0) == NOTOK) - goto out; - ct->c_type = CT_MESSAGE; - ct->c_ctinitfnx = InitMessage; - } else { - /* - * Else default type is text/plain - */ - if (get_ctinfo ("text/plain", ct, 0) == NOTOK) - goto out; - ct->c_type = CT_TEXT; - ct->c_ctinitfnx = InitText; + ** Check if we saw a Content-Type field. + ** If not, then assign a default value for + ** it, and the Init function. + */ + if (!ct->c_ctline) { + /* + ** If we are inside a multipart/digest message, + ** so default type is message/rfc822 + */ + if (toplevel < 0) { + if (get_ctinfo("message/rfc822", ct, 0) == NOTOK) + goto out; + ct->c_type = CT_MESSAGE; + ct->c_ctinitfnx = InitMessage; + } else { + /* + ** Else default type is text/plain + */ + if (get_ctinfo("text/plain", ct, 0) == NOTOK) + goto out; + ct->c_type = CT_TEXT; + ct->c_ctinitfnx = InitText; + } } - } - /* Use default Transfer-Encoding, if necessary */ - if (!ct->c_celine) { - ct->c_encoding = CE_7BIT; - Init7Bit (ct); - } + /* Use default Transfer-Encoding, if necessary */ + if (!ct->c_celine) { + ct->c_encoding = CE_7BIT; + Init7Bit(ct); + } - return ct; + return ct; out: - free_content (ct); - return NULL; + free_content(ct); + return NULL; } /* - * small routine to add header field to list - */ +** small routine to add header field to list +*/ int -add_header (CT ct, char *name, char *value) +add_header(CT ct, char *name, char *value) { - HF hp; - - /* allocate header field structure */ - hp = mh_xmalloc (sizeof(*hp)); - - /* link data into header structure */ - hp->name = name; - hp->value = value; - hp->next = NULL; - - /* link header structure into the list */ - if (ct->c_first_hf == NULL) { - ct->c_first_hf = hp; /* this is the first */ - ct->c_last_hf = hp; - } else { - ct->c_last_hf->next = hp; /* add it to the end */ - ct->c_last_hf = hp; - } - - return 0; + HF hp; + + /* allocate header field structure */ + hp = mh_xmalloc(sizeof(*hp)); + + /* link data into header structure */ + hp->name = name; + hp->value = value; + hp->next = NULL; + + /* link header structure into the list */ + if (ct->c_first_hf == NULL) { + ct->c_first_hf = hp; /* this is the first */ + ct->c_last_hf = hp; + } else { + ct->c_last_hf->next = hp; /* add it to the end */ + ct->c_last_hf = hp; + } + + return 0; } -/* Make sure that buf contains at least one appearance of name, - followed by =. If not, insert both name and value, just after - first semicolon, if any. Note that name should not contain a - trailing =. And quotes will be added around the value. Typical - usage: make sure that a Content-Disposition header contains - filename="foo". If it doesn't and value does, use value from - that. */ +/* +** Make sure that buf contains at least one appearance of name, +** followed by =. If not, insert both name and value, just after +** first semicolon, if any. Note that name should not contain a +** trailing =. And quotes will be added around the value. Typical +** usage: make sure that a Content-Disposition header contains +** filename="foo". If it doesn't and value does, use value from +** that. +*/ static char * -incl_name_value (unsigned char *buf, char *name, char *value) { - char *newbuf = buf; - - /* Assume that name is non-null. */ - if (buf && value) { - char *name_plus_equal = concat (name, "=", NULL); - - if (! strstr (buf, name_plus_equal)) { - char *insertion; - unsigned char *cp; - char *prefix, *suffix; - - /* Trim trailing space, esp. newline. */ - for (cp = &buf[strlen (buf) - 1]; - cp >= buf && isspace (*cp); - --cp) { - *cp = '\0'; - } - - insertion = concat ("; ", name, "=", "\"", value, "\"", NULL); - - /* Insert at first semicolon, if any. If none, append to - end. */ - prefix = add (buf, NULL); - if ((cp = strchr (prefix, ';'))) { - suffix = concat (cp, NULL); - *cp = '\0'; - newbuf = concat (prefix, insertion, suffix, "\n", NULL); - free (suffix); - } else { - /* Append to end. */ - newbuf = concat (buf, insertion, "\n", NULL); - } - - free (prefix); - free (insertion); - free (buf); - } - - free (name_plus_equal); - } - - return newbuf; +incl_name_value(unsigned char *buf, char *name, char *value) { + char *newbuf = buf; + + /* Assume that name is non-null. */ + if (buf && value) { + char *name_plus_equal = concat(name, "=", NULL); + + if (!strstr(buf, name_plus_equal)) { + char *insertion; + unsigned char *cp; + char *prefix, *suffix; + + /* Trim trailing space, esp. newline. */ + for (cp = &buf[strlen(buf) - 1]; + cp >= buf && isspace(*cp); --cp) { + *cp = '\0'; + } + + insertion = concat("; ", name, "=", "\"", value, "\"", + NULL); + + /* + ** Insert at first semicolon, if any. + ** If none, append to end. + */ + prefix = getcpy(buf); + if ((cp = strchr(prefix, ';'))) { + suffix = concat(cp, NULL); + *cp = '\0'; + newbuf = concat(prefix, insertion, suffix, + "\n", NULL); + free(suffix); + } else { + /* Append to end. */ + newbuf = concat(buf, insertion, "\n", NULL); + } + + free(prefix); + free(insertion); + free(buf); + } + + free(name_plus_equal); + } + + return newbuf; } -/* Extract just name_suffix="foo", if any, from value. If there isn't - one, return the entire value. Note that, for example, a name_suffix - of name will match filename="foo", and return foo. */ +/* +** Extract just name_suffix="foo", if any, from value. If there isn't +** one, return the entire value. Note that, for example, a name_suffix +** of name will match filename="foo", and return foo. +*/ static char * -extract_name_value (char *name_suffix, char *value) { - char *extracted_name_value = value; - char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL); - char *name_suffix_equals = strstr (value, name_suffix_plus_quote); - char *cp; - - free (name_suffix_plus_quote); - if (name_suffix_equals) { - char *name_suffix_begin; - - /* Find first \". */ - for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */; - name_suffix_begin = ++cp; - /* Find second \". */ - for (; *cp != '"'; ++cp) /* empty */; - - extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1); - memcpy (extracted_name_value, - name_suffix_begin, - cp - name_suffix_begin); - extracted_name_value[cp - name_suffix_begin] = '\0'; - } - - return extracted_name_value; +extract_name_value(char *name_suffix, char *value) { + char *extracted_name_value = value; + char *name_suffix_plus_quote = concat(name_suffix, "=\"", NULL); + char *name_suffix_equals = strstr(value, name_suffix_plus_quote); + char *cp; + + free(name_suffix_plus_quote); + if (name_suffix_equals) { + char *name_suffix_begin; + + /* Find first \". */ + for (cp = name_suffix_equals; *cp != '"'; ++cp) + ; + name_suffix_begin = ++cp; + /* Find second \". */ + for (; *cp != '"'; ++cp) + ; + + extracted_name_value = mh_xmalloc(cp - name_suffix_begin + 1); + memcpy(extracted_name_value, name_suffix_begin, + cp - name_suffix_begin); + extracted_name_value[cp - name_suffix_begin] = '\0'; + } + + return extracted_name_value; } /* - * Parse Content-Type line and (if `magic' is non-zero) mhbuild composition - * directives. Fills in the information of the CTinfo structure. - */ +** Parse Content-Type line and (if `magic' is non-zero) mhbuild composition +** directives. Fills in the information of the CTinfo structure. +*/ int -get_ctinfo (unsigned char *cp, CT ct, int magic) +get_ctinfo(unsigned char *cp, CT ct, int magic) { - int i; - unsigned char *dp; - char **ap, **ep; - char c; - CI ci; + int i; + unsigned char *dp; + char **ap, **ep; + char c; + CI ci; - ci = &ct->c_ctinfo; - i = strlen (invo_name) + 2; + ci = &ct->c_ctinfo; + i = strlen(invo_name) + 2; - /* store copy of Content-Type line */ - cp = ct->c_ctline = add (cp, NULL); + /* store copy of Content-Type line */ + cp = ct->c_ctline = getcpy(cp); - while (isspace (*cp)) /* trim leading spaces */ - cp++; + while (isspace(*cp)) /* trim leading spaces */ + cp++; - /* change newlines to spaces */ - for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) - *dp++ = ' '; + /* change newlines to spaces */ + for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) + *dp++ = ' '; - /* trim trailing spaces */ - for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) - break; - *++dp = '\0'; + /* trim trailing spaces */ + for (dp = cp + strlen(cp) - 1; dp >= cp; dp--) + if (!isspace(*dp)) + break; + *++dp = '\0'; - if (debugsw) - fprintf (stderr, "%s: %s\n", TYPE_FIELD, cp); + if (debugsw) + fprintf(stderr, "%s: %s\n", TYPE_FIELD, cp); - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; - for (dp = cp; istoken (*dp); dp++) - continue; - c = *dp, *dp = '\0'; - ci->ci_type = add (cp, NULL); /* store content type */ - *dp = c, cp = dp; + for (dp = cp; istoken(*dp); dp++) + continue; + c = *dp, *dp = '\0'; + ci->ci_type = getcpy(cp); /* store content type */ + *dp = c, cp = dp; - if (!*ci->ci_type) { - advise (NULL, "invalid %s: field in message %s (empty type)", - TYPE_FIELD, ct->c_file); - return NOTOK; - } + if (!*ci->ci_type) { + advise(NULL, "invalid %s: field in message %s (empty type)", + TYPE_FIELD, ct->c_file); + return NOTOK; + } - /* down case the content type string */ - for (dp = ci->ci_type; *dp; dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + /* down case the content type string */ + for (dp = ci->ci_type; *dp; dp++) + if (isalpha(*dp) && isupper(*dp)) + *dp = tolower(*dp); - while (isspace (*cp)) - cp++; + while (isspace(*cp)) + cp++; - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; - if (*cp != '/') { - if (!magic) - ci->ci_subtype = add ("", NULL); - goto magic_skip; - } + if (*cp != '/') { + if (!magic) + ci->ci_subtype = getcpy(""); + goto magic_skip; + } - cp++; - while (isspace (*cp)) cp++; + while (isspace(*cp)) + cp++; - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; - for (dp = cp; istoken (*dp); dp++) - continue; - c = *dp, *dp = '\0'; - ci->ci_subtype = add (cp, NULL); /* store the content subtype */ - *dp = c, cp = dp; + for (dp = cp; istoken(*dp); dp++) + continue; + c = *dp, *dp = '\0'; + ci->ci_subtype = getcpy(cp); /* store the content subtype */ + *dp = c, cp = dp; - if (!*ci->ci_subtype) { - advise (NULL, - "invalid %s: field in message %s (empty subtype for \"%s\")", - TYPE_FIELD, ct->c_file, ci->ci_type); - return NOTOK; - } + if (!*ci->ci_subtype) { + advise(NULL, "invalid %s: field in message %s (empty subtype for \"%s\")", TYPE_FIELD, ct->c_file, ci->ci_type); + return NOTOK; + } - /* down case the content subtype string */ - for (dp = ci->ci_subtype; *dp; dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + /* down case the content subtype string */ + for (dp = ci->ci_subtype; *dp; dp++) + if (isalpha(*dp) && isupper(*dp)) + *dp = tolower(*dp); magic_skip: - while (isspace (*cp)) - cp++; + while (isspace(*cp)) + cp++; - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; - /* - * Parse attribute/value pairs given with Content-Type - */ - ep = (ap = ci->ci_attrs) + NPARMS; - while (*cp == ';') { - char *vp; - unsigned char *up; + /* + ** Parse attribute/value pairs given with Content-Type + */ + ep = (ap = ci->ci_attrs) + NPARMS; + while (*cp == ';') { + char *vp; + unsigned char *up; + + if (ap >= ep) { + advise(NULL, "too many parameters in message %s's %s: field (%d max)", ct->c_file, TYPE_FIELD, NPARMS); + return NOTOK; + } - if (ap >= ep) { - advise (NULL, - "too many parameters in message %s's %s: field (%d max)", - ct->c_file, TYPE_FIELD, NPARMS); - return NOTOK; - } + cp++; + while (isspace(*cp)) + cp++; - cp++; - while (isspace (*cp)) - cp++; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; + if (*cp == 0) { + advise (NULL, "extraneous trailing ';' in message %s's %s: parameter list", ct->c_file, TYPE_FIELD); + return OK; + } - if (*cp == 0) { - advise (NULL, - "extraneous trailing ';' in message %s's %s: parameter list", - ct->c_file, TYPE_FIELD); - return OK; - } + /* down case the attribute name */ + for (dp = cp; istoken(*dp); dp++) + if (isalpha(*dp) && isupper(*dp)) + *dp = tolower(*dp); + + for (up = dp; isspace(*dp);) + dp++; + if (dp == cp || *dp != '=') { + advise(NULL, "invalid parameter in message %s's %s: field\n%*.*sparameter %s (error detected at offset %d)", ct->c_file, TYPE_FIELD, i, i, "", cp, dp - cp); + return NOTOK; + } + + vp = (*ap = getcpy(cp)) + (up - cp); + *vp = '\0'; + for (dp++; isspace(*dp);) + dp++; + + /* now add the attribute value */ + ci->ci_values[ap - ci->ci_attrs] = vp = *ap + (dp - cp); + + if (*dp == '"') { + for (cp = ++dp, dp = vp;;) { + switch (c = *cp++) { + case '\0': +bad_quote: + advise(NULL, "invalid quoted-string in message %s's %s: field\n%*.*s(parameter %s)", ct->c_file, TYPE_FIELD, i, i, "", *ap); + return NOTOK; + + case '\\': + *dp++ = c; + if ((c = *cp++) == '\0') + goto bad_quote; + /* else fall... */ + + default: + *dp++ = c; + continue; + + case '"': + *dp = '\0'; + break; + } + break; + } + } else { + for (cp = dp, dp = vp; istoken(*cp); cp++, dp++) + continue; + *dp = '\0'; + } + if (!*vp) { + advise(NULL, "invalid parameter in message %s's %s: field\n%*.*s(parameter %s)", ct->c_file, TYPE_FIELD, i, i, "", *ap); + return NOTOK; + } + ap++; - /* down case the attribute name */ - for (dp = cp; istoken (*dp); dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + while (isspace(*cp)) + cp++; - for (up = dp; isspace (*dp);) - dp++; - if (dp == cp || *dp != '=') { - advise (NULL, - "invalid parameter in message %s's %s: field\n%*.*sparameter %s (error detected at offset %d)", - ct->c_file, TYPE_FIELD, i, i, "", cp, dp - cp); - return NOTOK; + if (*cp == '(' && get_comment(ct, &cp, 1) == NOTOK) + return NOTOK; } - vp = (*ap = add (cp, NULL)) + (up - cp); - *vp = '\0'; - for (dp++; isspace (*dp);) - dp++; + /* + ** Get any given in buffer + */ + if (magic && *cp == '<') { + if (ct->c_id) { + free(ct->c_id); + ct->c_id = NULL; + } + if (!(dp = strchr(ct->c_id = ++cp, '>'))) { + advise(NULL, "invalid ID in message %s", ct->c_file); + return NOTOK; + } + c = *dp; + *dp = '\0'; + if (*ct->c_id) + ct->c_id = concat("<", ct->c_id, ">\n", NULL); + else + ct->c_id = NULL; + *dp++ = c; + cp = dp; - /* now add the attribute value */ - ci->ci_values[ap - ci->ci_attrs] = vp = *ap + (dp - cp); + while (isspace(*cp)) + cp++; + } - if (*dp == '"') { - for (cp = ++dp, dp = vp;;) { - switch (c = *cp++) { - case '\0': -bad_quote: - advise (NULL, - "invalid quoted-string in message %s's %s: field\n%*.*s(parameter %s)", - ct->c_file, TYPE_FIELD, i, i, "", *ap); + /* + ** Get any [Content-Description] given in buffer. + */ + if (magic && *cp == '[') { + ct->c_descr = ++cp; + for (dp = cp + strlen(cp) - 1; dp >= cp; dp--) + if (*dp == ']') + break; + if (dp < cp) { + advise(NULL, "invalid description in message %s", + ct->c_file); + ct->c_descr = NULL; return NOTOK; + } - case '\\': - *dp++ = c; - if ((c = *cp++) == '\0') - goto bad_quote; - /* else fall... */ + c = *dp; + *dp = '\0'; + if (*ct->c_descr) + ct->c_descr = concat(ct->c_descr, "\n", NULL); + else + ct->c_descr = NULL; + *dp++ = c; + cp = dp; - default: - *dp++ = c; - continue; + while (isspace(*cp)) + cp++; + } - case '"': - *dp = '\0'; - break; + /* + ** Get any {Content-Disposition} given in buffer. + */ + if (magic && *cp == '{') { + ct->c_dispo = ++cp; + for (dp = cp + strlen(cp) - 1; dp >= cp; dp--) + if (*dp == '}') + break; + if (dp < cp) { + advise(NULL, "invalid disposition in message %s", + ct->c_file); + ct->c_dispo = NULL; + return NOTOK; } - break; - } - } else { - for (cp = dp, dp = vp; istoken (*cp); cp++, dp++) - continue; - *dp = '\0'; - } - if (!*vp) { - advise (NULL, - "invalid parameter in message %s's %s: field\n%*.*s(parameter %s)", - ct->c_file, TYPE_FIELD, i, i, "", *ap); - return NOTOK; - } - ap++; - - while (isspace (*cp)) - cp++; - - if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) - return NOTOK; - } - - /* - * Get any given in buffer - */ - if (magic && *cp == '<') { - if (ct->c_id) { - free (ct->c_id); - ct->c_id = NULL; - } - if (!(dp = strchr(ct->c_id = ++cp, '>'))) { - advise (NULL, "invalid ID in message %s", ct->c_file); - return NOTOK; - } - c = *dp; - *dp = '\0'; - if (*ct->c_id) - ct->c_id = concat ("<", ct->c_id, ">\n", NULL); - else - ct->c_id = NULL; - *dp++ = c; - cp = dp; - - while (isspace (*cp)) - cp++; - } - - /* - * Get any [Content-Description] given in buffer. - */ - if (magic && *cp == '[') { - ct->c_descr = ++cp; - for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (*dp == ']') - break; - if (dp < cp) { - advise (NULL, "invalid description in message %s", ct->c_file); - ct->c_descr = NULL; - return NOTOK; - } - - c = *dp; - *dp = '\0'; - if (*ct->c_descr) - ct->c_descr = concat (ct->c_descr, "\n", NULL); - else - ct->c_descr = NULL; - *dp++ = c; - cp = dp; - - while (isspace (*cp)) - cp++; - } - - /* - * Get any {Content-Disposition} given in buffer. - */ - if (magic && *cp == '{') { - ct->c_dispo = ++cp; - for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (*dp == '}') - break; - if (dp < cp) { - advise (NULL, "invalid disposition in message %s", ct->c_file); - ct->c_dispo = NULL; - return NOTOK; - } - - c = *dp; - *dp = '\0'; - if (*ct->c_dispo) - ct->c_dispo = concat (ct->c_dispo, "\n", NULL); - else - ct->c_dispo = NULL; - *dp++ = c; - cp = dp; - - while (isspace (*cp)) - cp++; - } - - /* - * Check if anything is left over - */ - if (*cp) { - if (magic) { - ci->ci_magic = add (cp, NULL); - - /* If there is a Content-Disposition header and it doesn't - have a *filename=, extract it from the magic contents. - The r1bindex call skips any leading directory - components. */ - if (ct->c_dispo) - ct->c_dispo = - incl_name_value (ct->c_dispo, - "filename", - r1bindex (extract_name_value ("name", - ci-> - ci_magic), - '/')); - } - else - advise (NULL, - "extraneous information in message %s's %s: field\n%*.*s(%s)", - ct->c_file, TYPE_FIELD, i, i, "", cp); - } - return OK; + c = *dp; + *dp = '\0'; + if (*ct->c_dispo) + ct->c_dispo = concat(ct->c_dispo, "\n", NULL); + else + ct->c_dispo = NULL; + *dp++ = c; + cp = dp; + + while (isspace(*cp)) + cp++; + } + + /* + ** Check if anything is left over + */ + if (*cp) { + if (magic) { + ci->ci_magic = getcpy(cp); + + /* + ** If there is a Content-Disposition header and + ** it doesn't have a *filename=, extract it from + ** the magic contents. The mhbasename call skips + ** any leading directory components. + */ + if (ct->c_dispo) + ct->c_dispo = incl_name_value(ct->c_dispo, "filename", mhbasename(extract_name_value("name", ci->ci_magic))); + } else + advise(NULL, "extraneous information in message %s's %s: field\n%*.*s(%s)", ct->c_file, TYPE_FIELD, i, i, "", cp); + } + + return OK; } static int -get_comment (CT ct, unsigned char **ap, int istype) +get_comment(CT ct, unsigned char **ap, int istype) { - int i; - char *bp; - unsigned char *cp; - char c, buffer[BUFSIZ], *dp; - CI ci; - - ci = &ct->c_ctinfo; - cp = *ap; - bp = buffer; - cp++; - - for (i = 0;;) { - switch (c = *cp++) { - case '\0': + int i; + char *bp; + unsigned char *cp; + char c, buffer[BUFSIZ], *dp; + CI ci; + + ci = &ct->c_ctinfo; + cp = *ap; + bp = buffer; + cp++; + + for (i = 0;;) { + switch (c = *cp++) { + case '\0': invalid: - advise (NULL, "invalid comment in message %s's %s: field", - ct->c_file, istype ? TYPE_FIELD : VRSN_FIELD); - return NOTOK; + advise(NULL, "invalid comment in message %s's %s: field", + ct->c_file, istype ? TYPE_FIELD : VRSN_FIELD); + return NOTOK; - case '\\': - *bp++ = c; - if ((c = *cp++) == '\0') - goto invalid; - *bp++ = c; - continue; + case '\\': + *bp++ = c; + if ((c = *cp++) == '\0') + goto invalid; + *bp++ = c; + continue; - case '(': - i++; - /* and fall... */ - default: - *bp++ = c; - continue; + case '(': + i++; + /* and fall... */ + default: + *bp++ = c; + continue; - case ')': - if (--i < 0) + case ')': + if (--i < 0) + break; + *bp++ = c; + continue; + } break; - *bp++ = c; - continue; } - break; - } - *bp = '\0'; + *bp = '\0'; - if (istype) { - if ((dp = ci->ci_comment)) { - ci->ci_comment = concat (dp, " ", buffer, NULL); - free (dp); - } else { - ci->ci_comment = add (buffer, NULL); + if (istype) { + if ((dp = ci->ci_comment)) { + ci->ci_comment = concat(dp, " ", buffer, NULL); + free(dp); + } else { + ci->ci_comment = getcpy(buffer); + } } - } - while (isspace (*cp)) - cp++; + while (isspace(*cp)) + cp++; - *ap = cp; - return OK; + *ap = cp; + return OK; } /* - * CONTENTS - * - * Handles content types audio, image, and video. - * There's not much to do right here. - */ +** CONTENTS +** +** Handles content types audio, image, and video. +** There's not much to do right here. +*/ static int -InitGeneric (CT ct) +InitGeneric(CT ct) { - return OK; /* not much to do here */ + return OK; /* not much to do here */ } /* - * TEXT - */ +** TEXT +*/ static int -InitText (CT ct) +InitText(CT ct) { - char buffer[BUFSIZ]; - char *chset = NULL; - char **ap, **ep, *cp; - struct k2v *kv; - struct text *t; - CI ci = &ct->c_ctinfo; - - /* check for missing subtype */ - if (!*ci->ci_subtype) - ci->ci_subtype = add ("plain", ci->ci_subtype); - - /* match subtype */ - for (kv = SubText; kv->kv_key; kv++) - if (!mh_strcasecmp (ci->ci_subtype, kv->kv_key)) - break; - ct->c_subtype = kv->kv_value; - - /* allocate text character set structure */ - if ((t = (struct text *) calloc (1, sizeof(*t))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) t; - - /* scan for charset parameter */ - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) - if (!mh_strcasecmp (*ap, "charset")) - break; - - /* check if content specified a character set */ - if (*ap) { - /* match character set or set to CHARSET_UNKNOWN */ - for (kv = Charset; kv->kv_key; kv++) { - if (!mh_strcasecmp (*ep, kv->kv_key)) { - chset = *ep; - break; - } - } - t->tx_charset = kv->kv_value; - } else { - t->tx_charset = CHARSET_UNSPECIFIED; - } - - /* - * If we can not handle character set natively, - * then check profile for string to modify the - * terminal or display method. - * - * termproc is for mhshow, though mhlist -debug prints it, too. - */ - if (chset != NULL && !check_charset (chset, strlen (chset))) { - snprintf (buffer, sizeof(buffer), "%s-charset-%s", invo_name, chset); - if ((cp = context_find (buffer))) - ct->c_termproc = getcpy (cp); - } - - return OK; + char **ap, **ep; + struct k2v *kv; + struct text *t; + CI ci = &ct->c_ctinfo; + + /* check for missing subtype */ + if (!*ci->ci_subtype) + ci->ci_subtype = add("plain", ci->ci_subtype); + + /* match subtype */ + for (kv = SubText; kv->kv_key; kv++) + if (!mh_strcasecmp(ci->ci_subtype, kv->kv_key)) + break; + ct->c_subtype = kv->kv_value; + + /* allocate text character set structure */ + if ((t = (struct text *) calloc(1, sizeof(*t))) == NULL) + adios(NULL, "out of memory"); + ct->c_ctparams = (void *) t; + + /* scan for charset parameter */ + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) + if (!mh_strcasecmp(*ap, "charset")) + break; + + /* check if content specified a character set */ + if (*ap) { + /* store its name */ + ct->c_charset = getcpy(norm_charmap(*ep)); + /* match character set or set to CHARSET_UNKNOWN */ + for (kv = Charset; kv->kv_key; kv++) { + if (!mh_strcasecmp(*ep, kv->kv_key)) { + break; + } + } + t->tx_charset = kv->kv_value; + } else { + t->tx_charset = CHARSET_UNSPECIFIED; + } + + return OK; } /* - * MULTIPART - */ +** MULTIPART +*/ static int -InitMultiPart (CT ct) +InitMultiPart(CT ct) { - int inout; - long last, pos; - unsigned char *cp, *dp; - char **ap, **ep; - char *bp, buffer[BUFSIZ]; - struct multipart *m; - struct k2v *kv; - struct part *part, **next; - CI ci = &ct->c_ctinfo; - CT p; - FILE *fp; - - /* - * The encoding for multipart messages must be either - * 7bit, 8bit, or binary (per RFC2045). - */ - if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT - && ct->c_encoding != CE_BINARY) { - admonish (NULL, - "\"%s/%s\" type in message %s must be encoded in 7bit, 8bit, or binary", - ci->ci_type, ci->ci_subtype, ct->c_file); - return NOTOK; - } - - /* match subtype */ - for (kv = SubMultiPart; kv->kv_key; kv++) - if (!mh_strcasecmp (ci->ci_subtype, kv->kv_key)) - break; - ct->c_subtype = kv->kv_value; - - /* - * Check for "boundary" parameter, which is - * required for multipart messages. - */ - bp = 0; - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (!mh_strcasecmp (*ap, "boundary")) { - bp = *ep; - break; - } - } - - /* complain if boundary parameter is missing */ - if (!*ap) { - advise (NULL, - "a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field", - ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); - return NOTOK; - } - - /* allocate primary structure for multipart info */ - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) m; - - /* check if boundary parameter contains only whitespace characters */ - for (cp = bp; isspace (*cp); cp++) - continue; - if (!*cp) { - advise (NULL, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field", - ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); - return NOTOK; - } + int inout; + long last, pos; + unsigned char *cp, *dp; + char **ap, **ep; + char *bp, buffer[BUFSIZ]; + struct multipart *m; + struct k2v *kv; + struct part *part, **next; + CI ci = &ct->c_ctinfo; + CT p; + FILE *fp; - /* remove trailing whitespace from boundary parameter */ - for (cp = bp, dp = cp + strlen (cp) - 1; dp > cp; dp--) - if (!isspace (*dp)) - break; - *++dp = '\0'; + /* + ** The encoding for multipart messages must be either + ** 7bit, 8bit, or binary (per RFC2045). + */ + if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT + && ct->c_encoding != CE_BINARY) { + admonish(NULL, "\"%s/%s\" type in message %s must be encoded in 7bit, 8bit, or binary", ci->ci_type, ci->ci_subtype, ct->c_file); + return NOTOK; + } - /* record boundary separators */ - m->mp_start = concat (bp, "\n", NULL); - m->mp_stop = concat (bp, "--\n", NULL); + /* match subtype */ + for (kv = SubMultiPart; kv->kv_key; kv++) + if (!mh_strcasecmp(ci->ci_subtype, kv->kv_key)) + break; + ct->c_subtype = kv->kv_value; - if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - advise (ct->c_file, "unable to open for reading"); - return NOTOK; - } - - fseek (fp = ct->c_fp, pos = ct->c_begin, SEEK_SET); - last = ct->c_end; - next = &m->mp_parts; - part = NULL; - inout = 1; - - while (fgets (buffer, sizeof(buffer) - 1, fp)) { - if (pos > last) - break; - - pos += strlen (buffer); - if (buffer[0] != '-' || buffer[1] != '-') - continue; - if (inout) { - if (strcmp (buffer + 2, m->mp_start)) - continue; -next_part: - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) - adios (NULL, "out of memory"); - *next = part; - next = &part->mp_next; + /* + ** Check for "boundary" parameter, which is + ** required for multipart messages. + */ + bp = 0; + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { + if (!mh_strcasecmp(*ap, "boundary")) { + bp = *ep; + break; + } + } - if (!(p = get_content (fp, ct->c_file, - ct->c_subtype == MULTI_DIGEST ? -1 : 0))) { - ct->c_fp = NULL; + /* complain if boundary parameter is missing */ + if (!*ap) { + advise (NULL, "a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field", ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); return NOTOK; - } - p->c_fp = NULL; - part->mp_part = p; - pos = p->c_begin; - fseek (fp, pos, SEEK_SET); - inout = 0; - } else { - if (strcmp (buffer + 2, m->mp_start) == 0) { - inout = 1; -end_part: - p = part->mp_part; - p->c_end = ftell(fp) - (strlen(buffer) + 1); - if (p->c_end < p->c_begin) - p->c_begin = p->c_end; - if (inout) - goto next_part; - goto last_part; - } else { - if (strcmp (buffer + 2, m->mp_stop) == 0) - goto end_part; - } - } - } - - advise (NULL, "bogus multipart content in message %s", ct->c_file); - if (!inout && part) { - p = part->mp_part; - p->c_end = ct->c_end; - - if (p->c_begin >= p->c_end) { - for (next = &m->mp_parts; *next != part; - next = &((*next)->mp_next)) - continue; - *next = NULL; - free_content (p); - free ((char *) part); } - } -last_part: - /* reverse the order of the parts for multipart/alternative */ - if (ct->c_subtype == MULTI_ALTERNATE) - reverse_parts (ct); - - /* - * label all subparts with part number, and - * then initialize the content of the subpart. - */ - { - int partnum; - char *pp; - char partnam[BUFSIZ]; - - if (ct->c_partno) { - snprintf (partnam, sizeof(partnam), "%s.", ct->c_partno); - pp = partnam + strlen (partnam); - } else { - pp = partnam; + /* allocate primary structure for multipart info */ + if ((m = (struct multipart *) calloc(1, sizeof(*m))) == NULL) + adios(NULL, "out of memory"); + ct->c_ctparams = (void *) m; + + /* check if boundary parameter contains only whitespace characters */ + for (cp = bp; isspace(*cp); cp++) + continue; + if (!*cp) { + advise(NULL, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field", ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); + return NOTOK; } - for (part = m->mp_parts, partnum = 1; part; - part = part->mp_next, partnum++) { - p = part->mp_part; + /* remove trailing whitespace from boundary parameter */ + for (cp = bp, dp = cp + strlen(cp) - 1; dp > cp; dp--) + if (!isspace(*dp)) + break; + *++dp = '\0'; - sprintf (pp, "%d", partnum); - p->c_partno = add (partnam, NULL); + /* record boundary separators */ + m->mp_start = concat(bp, "\n", NULL); + m->mp_stop = concat(bp, "--\n", NULL); - /* initialize the content of the subparts */ - if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) { - fclose (ct->c_fp); - ct->c_fp = NULL; + if (!ct->c_fp && (ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + advise(ct->c_file, "unable to open for reading"); return NOTOK; - } } - } - fclose (ct->c_fp); - ct->c_fp = NULL; - return OK; -} + fseek(fp = ct->c_fp, pos = ct->c_begin, SEEK_SET); + last = ct->c_end; + next = &m->mp_parts; + part = NULL; + inout = 1; + while (fgets(buffer, sizeof(buffer) - 1, fp)) { + if (pos > last) + break; -/* - * reverse the order of the parts of a multipart - */ + pos += strlen(buffer); + if (buffer[0] != '-' || buffer[1] != '-') + continue; + if (inout) { + if (strcmp(buffer + 2, m->mp_start)!=0) + continue; +next_part: + if ((part = (struct part *) calloc(1, sizeof(*part))) + == NULL) + adios(NULL, "out of memory"); + *next = part; + next = &part->mp_next; + + if (!(p = get_content(fp, ct->c_file, + ct->c_subtype == MULTI_DIGEST ? -1 : 0))) { + ct->c_fp = NULL; + return NOTOK; + } + p->c_fp = NULL; + part->mp_part = p; + pos = p->c_begin; + fseek(fp, pos, SEEK_SET); + inout = 0; + } else { + if (strcmp(buffer + 2, m->mp_start) == 0) { + inout = 1; +end_part: + p = part->mp_part; + p->c_end = ftell(fp) - (strlen(buffer) + 1); + if (p->c_end < p->c_begin) + p->c_begin = p->c_end; + if (inout) + goto next_part; + goto last_part; + } else { + if (strcmp(buffer + 2, m->mp_stop) == 0) + goto end_part; + } + } + } + + advise(NULL, "bogus multipart content in message %s", ct->c_file); + if (!inout && part) { + p = part->mp_part; + p->c_end = ct->c_end; + + if (p->c_begin >= p->c_end) { + for (next = &m->mp_parts; *next != part; + next = &((*next)->mp_next)) + continue; + *next = NULL; + free_content(p); + free((char *) part); + } + } + +last_part: + /* reverse the order of the parts for multipart/alternative */ + if (ct->c_subtype == MULTI_ALTERNATE) + reverse_parts(ct); + + /* + ** label all subparts with part number, and + ** then initialize the content of the subpart. + */ + { + int partnum; + char *pp; + char partnam[BUFSIZ]; + + if (ct->c_partno) { + snprintf(partnam, sizeof(partnam), "%s.", + ct->c_partno); + pp = partnam + strlen(partnam); + } else { + pp = partnam; + } + + for (part = m->mp_parts, partnum = 1; part; + part = part->mp_next, partnum++) { + p = part->mp_part; + + sprintf(pp, "%d", partnum); + p->c_partno = getcpy(partnam); + + /* initialize the content of the subparts */ + if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) { + fclose(ct->c_fp); + ct->c_fp = NULL; + return NOTOK; + } + } + } + + fclose(ct->c_fp); + ct->c_fp = NULL; + return OK; +} + + +/* +** reverse the order of the parts of a multipart +*/ static void -reverse_parts (CT ct) +reverse_parts(CT ct) { - int i; - struct multipart *m; - struct part **base, **bmp, **next, *part; - - m = (struct multipart *) ct->c_ctparams; - - /* if only one part, just return */ - if (!m->mp_parts || !m->mp_parts->mp_next) - return; - - /* count number of parts */ - i = 0; - for (part = m->mp_parts; part; part = part->mp_next) - i++; - - /* allocate array of pointers to the parts */ - if (!(base = (struct part **) calloc ((size_t) (i + 1), sizeof(*base)))) - adios (NULL, "out of memory"); - bmp = base; - - /* point at all the parts */ - for (part = m->mp_parts; part; part = part->mp_next) - *bmp++ = part; - *bmp = NULL; - - /* reverse the order of the parts */ - next = &m->mp_parts; - for (bmp--; bmp >= base; bmp--) { - part = *bmp; - *next = part; - next = &part->mp_next; - } - *next = NULL; - - /* free array of pointers */ - free ((char *) base); + int i; + struct multipart *m; + struct part **base, **bmp, **next, *part; + + m = (struct multipart *) ct->c_ctparams; + + /* if only one part, just return */ + if (!m->mp_parts || !m->mp_parts->mp_next) + return; + + /* count number of parts */ + i = 0; + for (part = m->mp_parts; part; part = part->mp_next) + i++; + + /* allocate array of pointers to the parts */ + if (!(base = (struct part **) calloc((size_t) (i + 1), sizeof(*base)))) + adios(NULL, "out of memory"); + bmp = base; + + /* point at all the parts */ + for (part = m->mp_parts; part; part = part->mp_next) + *bmp++ = part; + *bmp = NULL; + + /* reverse the order of the parts */ + next = &m->mp_parts; + for (bmp--; bmp >= base; bmp--) { + part = *bmp; + *next = part; + next = &part->mp_next; + } + *next = NULL; + + /* free array of pointers */ + free((char *) base); } /* - * MESSAGE - */ +** MESSAGE +*/ static int -InitMessage (CT ct) +InitMessage(CT ct) { - struct k2v *kv; - CI ci = &ct->c_ctinfo; + struct k2v *kv; + CI ci = &ct->c_ctinfo; - if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) { - admonish (NULL, - "\"%s/%s\" type in message %s should be encoded in 7bit or 8bit", - ci->ci_type, ci->ci_subtype, ct->c_file); - return NOTOK; - } + if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) { + admonish(NULL, "\"%s/%s\" type in message %s should be encoded in 7bit or 8bit", ci->ci_type, ci->ci_subtype, ct->c_file); + return NOTOK; + } - /* check for missing subtype */ - if (!*ci->ci_subtype) - ci->ci_subtype = add ("rfc822", ci->ci_subtype); + /* check for missing subtype */ + if (!*ci->ci_subtype) + ci->ci_subtype = add("rfc822", ci->ci_subtype); - /* match subtype */ - for (kv = SubMessage; kv->kv_key; kv++) - if (!mh_strcasecmp (ci->ci_subtype, kv->kv_key)) - break; - ct->c_subtype = kv->kv_value; + /* match subtype */ + for (kv = SubMessage; kv->kv_key; kv++) + if (!mh_strcasecmp(ci->ci_subtype, kv->kv_key)) + break; + ct->c_subtype = kv->kv_value; - switch (ct->c_subtype) { + switch (ct->c_subtype) { case MESSAGE_RFC822: - break; + break; case MESSAGE_PARTIAL: - { + { char **ap, **ep; struct partial *p; - if ((p = (struct partial *) calloc (1, sizeof(*p))) == NULL) - adios (NULL, "out of memory"); + if ((p = (struct partial *) calloc(1, sizeof(*p))) == NULL) + adios(NULL, "out of memory"); ct->c_ctparams = (void *) p; - /* scan for parameters "id", "number", and "total" */ + /* + ** scan for parameters "id", "number", + ** and "total" + */ for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (!mh_strcasecmp (*ap, "id")) { - p->pm_partid = add (*ep, NULL); - continue; - } - if (!mh_strcasecmp (*ap, "number")) { - if (sscanf (*ep, "%d", &p->pm_partno) != 1 - || p->pm_partno < 1) { + if (!mh_strcasecmp(*ap, "id")) { + p->pm_partid = getcpy(*ep); + continue; + } + if (!mh_strcasecmp(*ap, "number")) { + if (sscanf(*ep, "%d", &p->pm_partno) != 1 || p->pm_partno < 1) { invalid_param: - advise (NULL, - "invalid %s parameter for \"%s/%s\" type in message %s's %s field", - *ap, ci->ci_type, ci->ci_subtype, - ct->c_file, TYPE_FIELD); - return NOTOK; + advise(NULL, "invalid %s parameter for \"%s/%s\" type in message %s's %s field", *ap, ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); + return NOTOK; + } + continue; + } + if (!mh_strcasecmp(*ap, "total")) { + if (sscanf(*ep, "%d", &p->pm_maxno) != 1 || + p->pm_maxno < 1) + goto invalid_param; + continue; } - continue; - } - if (!mh_strcasecmp (*ap, "total")) { - if (sscanf (*ep, "%d", &p->pm_maxno) != 1 - || p->pm_maxno < 1) - goto invalid_param; - continue; - } } - if (!p->pm_partid - || !p->pm_partno - || (p->pm_maxno && p->pm_partno > p->pm_maxno)) { - advise (NULL, - "invalid parameters for \"%s/%s\" type in message %s's %s field", - ci->ci_type, ci->ci_subtype, - ct->c_file, TYPE_FIELD); - return NOTOK; + if (!p->pm_partid || !p->pm_partno + || (p->pm_maxno && p->pm_partno > p->pm_maxno)) { + advise(NULL, "invalid parameters for \"%s/%s\" type in message %s's %s field", ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); + return NOTOK; + } } - } - break; + break; case MESSAGE_EXTERNAL: - { - int exresult; - struct exbody *e; + { CT p; FILE *fp; - if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL) - adios (NULL, "out of memory"); - ct->c_ctparams = (void *) e; - - if (!ct->c_fp - && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - advise (ct->c_file, "unable to open for reading"); - return NOTOK; + if (!ct->c_fp && (ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + advise(ct->c_file, "unable to open for reading"); + return NOTOK; } - fseek (fp = ct->c_fp, ct->c_begin, SEEK_SET); + fseek(fp = ct->c_fp, ct->c_begin, SEEK_SET); - if (!(p = get_content (fp, ct->c_file, 0))) { - ct->c_fp = NULL; - return NOTOK; + if (!(p = get_content(fp, ct->c_file, 0))) { + ct->c_fp = NULL; + return NOTOK; } - e->eb_parent = ct; - e->eb_content = p; - p->c_ctexbody = e; - if ((exresult = params_external (ct, 0)) != NOTOK - && p->c_ceopenfnx == openMail) { - int cc, size; - char *bp; - - if ((size = ct->c_end - p->c_begin) <= 0) { - if (!e->eb_subject) - content_error (NULL, ct, - "empty body for access-type=mail-server"); - goto no_body; - } - - e->eb_body = bp = mh_xmalloc ((unsigned) size); - fseek (p->c_fp, p->c_begin, SEEK_SET); - while (size > 0) - switch (cc = fread (bp, sizeof(*bp), size, p->c_fp)) { - case NOTOK: - adios ("failed", "fread"); - - case OK: - adios (NULL, "unexpected EOF from fread"); - - default: - bp += cc, size -= cc; - break; - } - *bp = 0; - } -no_body: p->c_fp = NULL; p->c_end = p->c_begin; - fclose (ct->c_fp); + fclose(ct->c_fp); ct->c_fp = NULL; - if (exresult == NOTOK) - return NOTOK; - if (e->eb_flags == NOTOK) - return OK; - switch (p->c_type) { - case CT_MULTIPART: - break; + case CT_MULTIPART: + break; - case CT_MESSAGE: + case CT_MESSAGE: if (p->c_subtype != MESSAGE_RFC822) - break; + break; /* else fall... */ - default: - e->eb_partno = ct->c_partno; + default: if (p->c_ctinitfnx) - (*p->c_ctinitfnx) (p); + (*p->c_ctinitfnx) (p); break; } - } - break; + } + break; default: - break; - } - - return OK; -} - - -int -params_external (CT ct, int composing) -{ - char **ap, **ep; - struct exbody *e = (struct exbody *) ct->c_ctparams; - CI ci = &ct->c_ctinfo; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (!mh_strcasecmp (*ap, "access-type")) { - struct str2init *s2i; - CT p = e->eb_content; - - for (s2i = str2methods; s2i->si_key; s2i++) - if (!mh_strcasecmp (*ep, s2i->si_key)) - break; - if (!s2i->si_key) { - e->eb_access = *ep; - e->eb_flags = NOTOK; - p->c_encoding = CE_EXTERNAL; - continue; - } - e->eb_access = s2i->si_key; - e->eb_flags = s2i->si_val; - p->c_encoding = CE_EXTERNAL; - - /* Call the Init function for this external type */ - if ((*s2i->si_init)(p) == NOTOK) - return NOTOK; - continue; - } - if (!mh_strcasecmp (*ap, "name")) { - e->eb_name = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "permission")) { - e->eb_permission = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "site")) { - e->eb_site = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "directory")) { - e->eb_dir = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "mode")) { - e->eb_mode = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "size")) { - sscanf (*ep, "%lu", &e->eb_size); - continue; - } - if (!mh_strcasecmp (*ap, "server")) { - e->eb_server = *ep; - continue; - } - if (!mh_strcasecmp (*ap, "subject")) { - e->eb_subject = *ep; - continue; - } - if (composing && !mh_strcasecmp (*ap, "body")) { - e->eb_body = getcpy (*ep); - continue; + break; } - } - if (!e->eb_access) { - advise (NULL, - "invalid parameters for \"%s/%s\" type in message %s's %s field", - ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); - return NOTOK; - } - - return OK; + return OK; } /* - * APPLICATION - */ +** APPLICATION +*/ static int -InitApplication (CT ct) +InitApplication(CT ct) { - struct k2v *kv; - CI ci = &ct->c_ctinfo; + struct k2v *kv; + CI ci = &ct->c_ctinfo; - /* match subtype */ - for (kv = SubApplication; kv->kv_key; kv++) - if (!mh_strcasecmp (ci->ci_subtype, kv->kv_key)) - break; - ct->c_subtype = kv->kv_value; + /* match subtype */ + for (kv = SubApplication; kv->kv_key; kv++) + if (!mh_strcasecmp(ci->ci_subtype, kv->kv_key)) + break; + ct->c_subtype = kv->kv_value; - return OK; + return OK; } /* - * TRANSFER ENCODINGS - */ +** TRANSFER ENCODINGS +*/ static int -init_encoding (CT ct, OpenCEFunc openfnx) +init_encoding(CT ct, OpenCEFunc openfnx) { - CE ce; + CE ce; - if ((ce = (CE) calloc (1, sizeof(*ce))) == NULL) - adios (NULL, "out of memory"); + if ((ce = (CE) calloc(1, sizeof(*ce))) == NULL) + adios(NULL, "out of memory"); - ct->c_cefile = ce; - ct->c_ceopenfnx = openfnx; - ct->c_ceclosefnx = close_encoding; - ct->c_cesizefnx = size_encoding; + ct->c_cefile = ce; + ct->c_ceopenfnx = openfnx; + ct->c_ceclosefnx = close_encoding; + ct->c_cesizefnx = size_encoding; - return OK; + return OK; } void -close_encoding (CT ct) +close_encoding(CT ct) { - CE ce; + CE ce; - if (!(ce = ct->c_cefile)) - return; + if (!(ce = ct->c_cefile)) + return; - if (ce->ce_fp) { - fclose (ce->ce_fp); - ce->ce_fp = NULL; - } + if (ce->ce_fp) { + fclose(ce->ce_fp); + ce->ce_fp = NULL; + } } static unsigned long -size_encoding (CT ct) +size_encoding(CT ct) { - int fd; - unsigned long size; - char *file; - CE ce; - struct stat st; + int fd; + unsigned long size; + char *file; + CE ce; + struct stat st; - if (!(ce = ct->c_cefile)) - return (ct->c_end - ct->c_begin); + if (!(ce = ct->c_cefile)) + return (ct->c_end - ct->c_begin); - if (ce->ce_fp && fstat (fileno (ce->ce_fp), &st) != NOTOK) - return (long) st.st_size; + if (ce->ce_fp && fstat(fileno(ce->ce_fp), &st) != NOTOK) + return (long) st.st_size; - if (ce->ce_file) { - if (stat (ce->ce_file, &st) != NOTOK) - return (long) st.st_size; - else - return 0L; - } + if (ce->ce_file) { + if (stat(ce->ce_file, &st) != NOTOK) + return (long) st.st_size; + else + return 0L; + } - if (ct->c_encoding == CE_EXTERNAL) - return (ct->c_end - ct->c_begin); + if (ct->c_encoding == CE_EXTERNAL) + return (ct->c_end - ct->c_begin); - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return (ct->c_end - ct->c_begin); + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return (ct->c_end - ct->c_begin); - if (fstat (fd, &st) != NOTOK) - size = (long) st.st_size; - else - size = 0L; + if (fstat(fd, &st) != NOTOK) + size = (long) st.st_size; + else + size = 0L; - (*ct->c_ceclosefnx) (ct); - return size; + (*ct->c_ceclosefnx) (ct); + return size; } /* - * BASE64 - */ +** BASE64 +*/ static unsigned char b642nib[0x80] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff }; static int -InitBase64 (CT ct) +InitBase64(CT ct) { - return init_encoding (ct, openBase64); + return init_encoding(ct, openBase64); } static int -openBase64 (CT ct, char **file) +openBase64(CT ct, char **file) { - int bitno, cc, digested; - int fd, len, skip; - unsigned long bits; - unsigned char value, *b, *b1, *b2, *b3; - unsigned char *cp, *ep; - char buffer[BUFSIZ]; - /* sbeck -- handle suffixes */ - CI ci; - CE ce; - MD5_CTX mdContext; - - b = (unsigned char *) &bits; - b1 = &b[endian > 0 ? 1 : 2]; - b2 = &b[endian > 0 ? 2 : 1]; - b3 = &b[endian > 0 ? 3 : 0]; - - ce = ct->c_cefile; - if (ce->ce_fp) { - fseek (ce->ce_fp, 0L, SEEK_SET); - goto ready_to_go; - } - - if (ce->ce_file) { - if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading"); - return NOTOK; - } - goto ready_to_go; - } - - if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); - ce->ce_unlink = 1; - } else { - ce->ce_file = add (*file, NULL); - ce->ce_unlink = 0; - } - - /* sbeck@cise.ufl.edu -- handle suffixes */ - ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - // Temporary file already exists, so we rename to - // version with extension. - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } - } - - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } - - if ((len = ct->c_end - ct->c_begin) < 0) - adios (NULL, "internal error(1)"); + int bitno, cc; + int fd, len, skip, own_ct_fp = 0; + unsigned long bits; + unsigned char value, *b, *b1, *b2, *b3; + unsigned char *cp, *ep; + char buffer[BUFSIZ]; + /* sbeck -- handle suffixes */ + CI ci; + CE ce; + + b = (unsigned char *) &bits; + b1 = &b[endian > 0 ? 1 : 2]; + b2 = &b[endian > 0 ? 2 : 1]; + b3 = &b[endian > 0 ? 3 : 0]; + + ce = ct->c_cefile; + if (ce->ce_fp) { + fseek(ce->ce_fp, 0L, SEEK_SET); + goto ready_to_go; + } - if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - content_error (ct->c_file, ct, "unable to open for reading"); - return NOTOK; - } - - if ((digested = ct->c_digested)) - MD5Init (&mdContext); - - bitno = 18; - bits = 0L; - skip = 0; - - lseek (fd = fileno (ct->c_fp), (off_t) ct->c_begin, SEEK_SET); - while (len > 0) { - switch (cc = read (fd, buffer, sizeof(buffer) - 1)) { - case NOTOK: - content_error (ct->c_file, ct, "error reading from"); - goto clean_up; - - case OK: - content_error (NULL, ct, "premature eof"); - goto clean_up; + if (ce->ce_file) { + if ((ce->ce_fp = fopen(ce->ce_file, "r")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading"); + return NOTOK; + } + goto ready_to_go; + } - default: - if (cc > len) - cc = len; - len -= cc; + if (*file == NULL) { + ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL)); + ce->ce_unlink = 1; + } else { + ce->ce_file = getcpy(*file); + ce->ce_unlink = 0; + } - for (ep = (cp = buffer) + cc; cp < ep; cp++) { - switch (*cp) { - default: - if (isspace (*cp)) - break; - if (skip || (*cp & 0x80) - || (value = b642nib[*cp & 0x7f]) > 0x3f) { - if (debugsw) { - fprintf (stderr, "*cp=0x%x pos=%ld skip=%d\n", - *cp, - (long) (lseek (fd, (off_t) 0, SEEK_CUR) - (ep - cp)), - skip); + /* sbeck@cise.ufl.edu -- handle suffixes */ + ci = &ct->c_ctinfo; + snprintf(buffer, sizeof(buffer), "%s-suffix-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + cp = context_find(buffer); + if (cp == NULL || *cp == '\0') { + snprintf(buffer, sizeof(buffer), "%s-suffix-%s", invo_name, + ci->ci_type); + cp = context_find(buffer); + } + if (cp != NULL && *cp != '\0') { + if (ce->ce_unlink) { + /* + ** Temporary file already exists, so we rename to + ** version with extension. + */ + char *file_org = strdup(ce->ce_file); + ce->ce_file = add(cp, ce->ce_file); + if (rename(file_org, ce->ce_file)) { + adios(ce->ce_file, "unable to rename %s to ", + file_org); } - content_error (NULL, ct, - "invalid BASE64 encoding -- continuing"); - continue; - } + free(file_org); - bits |= value << bitno; -test_end: - if ((bitno -= 6) < 0) { - putc ((char) *b1, ce->ce_fp); - if (digested) - MD5Update (&mdContext, b1, 1); - if (skip < 2) { - putc ((char) *b2, ce->ce_fp); - if (digested) - MD5Update (&mdContext, b2, 1); - if (skip < 1) { - putc ((char) *b3, ce->ce_fp); - if (digested) - MD5Update (&mdContext, b3, 1); - } - } + } else { + ce->ce_file = add(cp, ce->ce_file); + } + } - if (ferror (ce->ce_fp)) { - content_error (ce->ce_file, ct, - "error writing to"); - goto clean_up; - } - bitno = 18, bits = 0L, skip = 0; - } - break; - - case '=': - if (++skip > 3) - goto self_delimiting; - goto test_end; + if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading/writing"); + return NOTOK; + } + + if ((len = ct->c_end - ct->c_begin) < 0) + adios(NULL, "internal error(1)"); + + if (!ct->c_fp) { + if ((ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + content_error(ct->c_file, ct, + "unable to open for reading"); + return NOTOK; } - } + own_ct_fp = 1; } - } - if (bitno != 18) { - if (debugsw) - fprintf (stderr, "premature ending (bitno %d)\n", bitno); + bitno = 18; + bits = 0L; + skip = 0; - content_error (NULL, ct, "invalid BASE64 encoding"); - goto clean_up; - } + lseek(fd = fileno(ct->c_fp), (off_t) ct->c_begin, SEEK_SET); + while (len > 0) { + switch (cc = read(fd, buffer, sizeof(buffer) - 1)) { + case NOTOK: + content_error(ct->c_file, ct, "error reading from"); + goto clean_up; -self_delimiting: - fseek (ct->c_fp, 0L, SEEK_SET); + case OK: + content_error(NULL, ct, "premature eof"); + goto clean_up; + + default: + if (cc > len) + cc = len; + len -= cc; + + for (ep = (cp = buffer) + cc; cp < ep; cp++) { + switch (*cp) { + default: + if (isspace(*cp)) + break; + if (skip || (*cp & 0x80) || (value = b642nib[*cp & 0x7f]) > 0x3f) { + if (debugsw) { + fprintf(stderr, "*cp=0x%x pos=%ld skip=%d\n", *cp, (long) (lseek(fd, (off_t) 0, SEEK_CUR) - (ep - cp)), skip); + } + content_error(NULL, ct, "invalid BASE64 encoding -- continuing"); + continue; + } + + bits |= value << bitno; +test_end: + if ((bitno -= 6) < 0) { + putc((char) *b1, ce->ce_fp); + if (skip < 2) { + putc((char) *b2, ce->ce_fp); + if (skip < 1) { + putc((char) *b3, ce->ce_fp); + } + } + + if (ferror(ce->ce_fp)) { + content_error(ce->ce_file, ct, + "error writing to"); + goto clean_up; + } + bitno = 18, bits = 0L, skip = 0; + } + break; + + case '=': + if (++skip > 3) + goto self_delimiting; + goto test_end; + } + } + } + } - if (fflush (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); - goto clean_up; - } + if (bitno != 18) { + if (debugsw) + fprintf(stderr, "premature ending (bitno %d)\n", + bitno); - if (digested) { - unsigned char digest[16]; + content_error(NULL, ct, "invalid BASE64 encoding"); + goto clean_up; + } - MD5Final (digest, &mdContext); - if (memcmp((char *) digest, (char *) ct->c_digest, - sizeof(digest) / sizeof(digest[0]))) - content_error (NULL, ct, - "content integrity suspect (digest mismatch) -- continuing"); - else - if (debugsw) - fprintf (stderr, "content integrity confirmed\n"); - } +self_delimiting: + fseek(ct->c_fp, 0L, SEEK_SET); - fseek (ce->ce_fp, 0L, SEEK_SET); + if (fflush(ce->ce_fp)) { + content_error(ce->ce_file, ct, "error writing to"); + goto clean_up; + } + + fseek(ce->ce_fp, 0L, SEEK_SET); ready_to_go: - *file = ce->ce_file; - return fileno (ce->ce_fp); + *file = ce->ce_file; + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + return fileno(ce->ce_fp); clean_up: - free_encoding (ct, 0); - return NOTOK; + free_encoding(ct, 0); + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + return NOTOK; } /* - * QUOTED PRINTABLE - */ +** QUOTED PRINTABLE +*/ static char hex2nib[0x80] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static int -InitQuoted (CT ct) +static int +InitQuoted(CT ct) { - return init_encoding (ct, openQuoted); + return init_encoding(ct, openQuoted); } static int -openQuoted (CT ct, char **file) +openQuoted(CT ct, char **file) { - int cc, digested, len, quoted; - unsigned char *cp, *ep; - char buffer[BUFSIZ]; - unsigned char mask; - CE ce; - /* sbeck -- handle suffixes */ - CI ci; - MD5_CTX mdContext; - - ce = ct->c_cefile; - if (ce->ce_fp) { - fseek (ce->ce_fp, 0L, SEEK_SET); - goto ready_to_go; - } - - if (ce->ce_file) { - if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading"); - return NOTOK; - } - goto ready_to_go; - } - - if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); - ce->ce_unlink = 1; - } else { - ce->ce_file = add (*file, NULL); - ce->ce_unlink = 0; - } - - /* sbeck@cise.ufl.edu -- handle suffixes */ - ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - // Temporary file already exists, so we rename to - // version with extension. - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } - } - - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } - - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } - - if ((len = ct->c_end - ct->c_begin) < 0) - adios (NULL, "internal error(2)"); - - if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - content_error (ct->c_file, ct, "unable to open for reading"); - return NOTOK; - } - - if ((digested = ct->c_digested)) - MD5Init (&mdContext); - - quoted = 0; -#ifdef lint - mask = 0; -#endif + int cc, len, quoted, own_ct_fp = 0; + unsigned char *cp, *ep; + char buffer[BUFSIZ]; + unsigned char mask = 0; + CE ce; + /* sbeck -- handle suffixes */ + CI ci; + + ce = ct->c_cefile; + if (ce->ce_fp) { + fseek(ce->ce_fp, 0L, SEEK_SET); + goto ready_to_go; + } - fseek (ct->c_fp, ct->c_begin, SEEK_SET); - while (len > 0) { - if (fgets (buffer, sizeof(buffer) - 1, ct->c_fp) == NULL) { - content_error (NULL, ct, "premature eof"); - goto clean_up; + if (ce->ce_file) { + if ((ce->ce_fp = fopen(ce->ce_file, "r")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading"); + return NOTOK; + } + goto ready_to_go; } - if ((cc = strlen (buffer)) > len) - cc = len; - len -= cc; + if (*file == NULL) { + ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL)); + ce->ce_unlink = 1; + } else { + ce->ce_file = getcpy(*file); + ce->ce_unlink = 0; + } - for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--) - if (!isspace (*ep)) - break; - *++ep = '\n', ep++; - - for (; cp < ep; cp++) { - if (quoted > 0) { - /* in an escape sequence */ - if (quoted == 1) { - /* at byte 1 of an escape sequence */ - mask = hex2nib[*cp & 0x7f]; - /* next is byte 2 */ - quoted = 2; - } else { - /* at byte 2 of an escape sequence */ - mask <<= 4; - mask |= hex2nib[*cp & 0x7f]; - putc (mask, ce->ce_fp); - if (digested) - MD5Update (&mdContext, &mask, 1); - if (ferror (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); - goto clean_up; - } - /* finished escape sequence; next may be literal or a new - * escape sequence */ - quoted = 0; - } - /* on to next byte */ - continue; - } - - /* not in an escape sequence */ - if (*cp == '=') { - /* starting an escape sequence, or invalid '='? */ - if (cp + 1 < ep && cp[1] == '\n') { - /* "=\n" soft line break, eat the \n */ - cp++; - continue; - } - if (cp + 1 >= ep || cp + 2 >= ep) { - /* We don't have 2 bytes left, so this is an invalid - * escape sequence; just show the raw bytes (below). */ - } else if (isxdigit (cp[1]) && isxdigit (cp[2])) { - /* Next 2 bytes are hex digits, making this a valid escape - * sequence; let's decode it (above). */ - quoted = 1; - continue; - } else { - /* One or both of the next 2 is out of range, making this - * an invalid escape sequence; just show the raw bytes - * (below). */ - } - } + /* sbeck@cise.ufl.edu -- handle suffixes */ + ci = &ct->c_ctinfo; + snprintf(buffer, sizeof(buffer), "%s-suffix-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + cp = context_find(buffer); + if (cp == NULL || *cp == '\0') { + snprintf(buffer, sizeof(buffer), "%s-suffix-%s", invo_name, + ci->ci_type); + cp = context_find(buffer); + } + if (cp != NULL && *cp != '\0') { + if (ce->ce_unlink) { + /* + ** Temporary file already exists, so we rename to + ** version with extension. + */ + char *file_org = strdup(ce->ce_file); + ce->ce_file = add(cp, ce->ce_file); + if (rename(file_org, ce->ce_file)) { + adios(ce->ce_file, "unable to rename %s to ", + file_org); + } + free(file_org); - /* Just show the raw byte. */ - putc (*cp, ce->ce_fp); - if (digested) { - if (*cp == '\n') { - MD5Update (&mdContext, (unsigned char *) "\r\n",2); } else { - MD5Update (&mdContext, (unsigned char *) cp, 1); + ce->ce_file = add(cp, ce->ce_file); } - } - if (ferror (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); - goto clean_up; - } - } - } - if (quoted) { - content_error (NULL, ct, - "invalid QUOTED-PRINTABLE encoding -- end-of-content while still quoting"); - goto clean_up; - } - - fseek (ct->c_fp, 0L, SEEK_SET); - - if (fflush (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); - goto clean_up; - } - - if (digested) { - unsigned char digest[16]; - - MD5Final (digest, &mdContext); - if (memcmp((char *) digest, (char *) ct->c_digest, - sizeof(digest) / sizeof(digest[0]))) - content_error (NULL, ct, - "content integrity suspect (digest mismatch) -- continuing"); - else - if (debugsw) - fprintf (stderr, "content integrity confirmed\n"); - } - - fseek (ce->ce_fp, 0L, SEEK_SET); - -ready_to_go: - *file = ce->ce_file; - return fileno (ce->ce_fp); - -clean_up: - free_encoding (ct, 0); - return NOTOK; -} - - -/* - * 7BIT - */ - -static int -Init7Bit (CT ct) -{ - if (init_encoding (ct, open7Bit) == NOTOK) - return NOTOK; + } - ct->c_cesizefnx = NULL; /* no need to decode for real size */ - return OK; -} + if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading/writing"); + return NOTOK; + } + if ((len = ct->c_end - ct->c_begin) < 0) + adios(NULL, "internal error(2)"); -int -open7Bit (CT ct, char **file) -{ - int cc, fd, len; - char buffer[BUFSIZ]; - /* sbeck -- handle suffixes */ - char *cp; - CI ci; - CE ce; - - ce = ct->c_cefile; - if (ce->ce_fp) { - fseek (ce->ce_fp, 0L, SEEK_SET); - goto ready_to_go; - } - - if (ce->ce_file) { - if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading"); - return NOTOK; - } - goto ready_to_go; - } - - if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); - ce->ce_unlink = 1; - } else { - ce->ce_file = add (*file, NULL); - ce->ce_unlink = 0; - } - - /* sbeck@cise.ufl.edu -- handle suffixes */ - ci = &ct->c_ctinfo; - snprintf (buffer, sizeof(buffer), "%s-suffix-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - cp = context_find (buffer); - if (cp == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-suffix-%s", invo_name, - ci->ci_type); - cp = context_find (buffer); - } - if (cp != NULL && *cp != '\0') { - if (ce->ce_unlink) { - // Temporary file already exists, so we rename to - // version with extension. - char *file_org = strdup(ce->ce_file); - ce->ce_file = add (cp, ce->ce_file); - if (rename(file_org, ce->ce_file)) { - adios (ce->ce_file, "unable to rename %s to ", file_org); - } - free(file_org); - - } else { - ce->ce_file = add (cp, ce->ce_file); - } - } - - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } + if (!ct->c_fp) { + if ((ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + content_error(ct->c_file, ct, + "unable to open for reading"); + return NOTOK; + } + own_ct_fp = 1; + } - if (ct->c_type == CT_MULTIPART) { - char **ap, **ep; - CI ci = &ct->c_ctinfo; + quoted = 0; - len = 0; - fprintf (ce->ce_fp, "%s: %s/%s", TYPE_FIELD, ci->ci_type, ci->ci_subtype); - len += strlen (TYPE_FIELD) + 2 + strlen (ci->ci_type) - + 1 + strlen (ci->ci_subtype); - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - putc (';', ce->ce_fp); - len++; - - snprintf (buffer, sizeof(buffer), "%s=\"%s\"", *ap, *ep); - - if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) { - fputs ("\n\t", ce->ce_fp); - len = 8; - } else { - putc (' ', ce->ce_fp); - len++; - } - fprintf (ce->ce_fp, "%s", buffer); - len += cc; - } - - if (ci->ci_comment) { - if (len + 1 + (cc = 2 + strlen (ci->ci_comment)) >= CPERLIN) { - fputs ("\n\t", ce->ce_fp); - len = 8; - } - else { - putc (' ', ce->ce_fp); - len++; - } - fprintf (ce->ce_fp, "(%s)", ci->ci_comment); - len += cc; - } - fprintf (ce->ce_fp, "\n"); - if (ct->c_id) - fprintf (ce->ce_fp, "%s:%s", ID_FIELD, ct->c_id); - if (ct->c_descr) - fprintf (ce->ce_fp, "%s:%s", DESCR_FIELD, ct->c_descr); - if (ct->c_dispo) - fprintf (ce->ce_fp, "%s:%s", DISPO_FIELD, ct->c_dispo); - fprintf (ce->ce_fp, "\n"); - } - - if ((len = ct->c_end - ct->c_begin) < 0) - adios (NULL, "internal error(3)"); - - if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - content_error (ct->c_file, ct, "unable to open for reading"); - return NOTOK; - } + fseek(ct->c_fp, ct->c_begin, SEEK_SET); + while (len > 0) { + if (fgets(buffer, sizeof(buffer) - 1, ct->c_fp) == NULL) { + content_error(NULL, ct, "premature eof"); + goto clean_up; + } - lseek (fd = fileno (ct->c_fp), (off_t) ct->c_begin, SEEK_SET); - while (len > 0) - switch (cc = read (fd, buffer, sizeof(buffer) - 1)) { - case NOTOK: - content_error (ct->c_file, ct, "error reading from"); - goto clean_up; + if ((cc = strlen(buffer)) > len) + cc = len; + len -= cc; - case OK: - content_error (NULL, ct, "premature eof"); - goto clean_up; + for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--) + if (!isspace(*ep)) + break; + *++ep = '\n', ep++; + + for (; cp < ep; cp++) { + if (quoted > 0) { + /* in an escape sequence */ + if (quoted == 1) { + /* at byte 1 of an escape sequence */ + mask = hex2nib[*cp & 0x7f]; + /* next is byte 2 */ + quoted = 2; + } else { + /* at byte 2 of an escape sequence */ + mask <<= 4; + mask |= hex2nib[*cp & 0x7f]; + putc(mask, ce->ce_fp); + if (ferror(ce->ce_fp)) { + content_error(ce->ce_file, ct, "error writing to"); + goto clean_up; + } + /* + ** finished escape sequence; next may + ** be literal or a new escape sequence + */ + quoted = 0; + } + /* on to next byte */ + continue; + } - default: - if (cc > len) - cc = len; - len -= cc; + /* not in an escape sequence */ + if (*cp == '=') { + /* + ** starting an escape sequence, + ** or invalid '='? + */ + if (cp + 1 < ep && cp[1] == '\n') { + /* "=\n" soft line break, eat the \n */ + cp++; + continue; + } + if (cp + 1 >= ep || cp + 2 >= ep) { + /* + ** We don't have 2 bytes left, + ** so this is an invalid escape + ** sequence; just show the raw bytes + ** (below). + */ + } else if (isxdigit(cp[1]) && isxdigit(cp[2])) { + /* + ** Next 2 bytes are hex digits, + ** making this a valid escape + ** sequence; let's decode it (above). + */ + quoted = 1; + continue; + } else { + /* + ** One or both of the next 2 is + ** out of range, making this an + ** invalid escape sequence; just + ** show the raw bytes (below). + */ + } + } - fwrite (buffer, sizeof(*buffer), cc, ce->ce_fp); - if (ferror (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); + /* Just show the raw byte. */ + putc(*cp, ce->ce_fp); + if (ferror(ce->ce_fp)) { + content_error(ce->ce_file, ct, + "error writing to"); + goto clean_up; + } + } + } + if (quoted) { + content_error(NULL, ct, "invalid QUOTED-PRINTABLE encoding -- end-of-content while still quoting"); goto clean_up; - } } - fseek (ct->c_fp, 0L, SEEK_SET); + fseek(ct->c_fp, 0L, SEEK_SET); - if (fflush (ce->ce_fp)) { - content_error (ce->ce_file, ct, "error writing to"); - goto clean_up; - } + if (fflush(ce->ce_fp)) { + content_error(ce->ce_file, ct, "error writing to"); + goto clean_up; + } - fseek (ce->ce_fp, 0L, SEEK_SET); + fseek(ce->ce_fp, 0L, SEEK_SET); ready_to_go: - *file = ce->ce_file; - return fileno (ce->ce_fp); + *file = ce->ce_file; + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + return fileno(ce->ce_fp); clean_up: - free_encoding (ct, 0); - return NOTOK; + free_encoding(ct, 0); + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + return NOTOK; } /* - * External - */ +** 7BIT +*/ static int -openExternal (CT ct, CT cb, CE ce, char **file, int *fd) +Init7Bit(CT ct) { - char cachefile[BUFSIZ]; - - if (ce->ce_fp) { - fseek (ce->ce_fp, 0L, SEEK_SET); - goto ready_already; - } - - if (ce->ce_file) { - if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading"); - return NOTOK; - } - goto ready_already; - } - - if (find_cache (ct, rcachesw, (int *) 0, cb->c_id, - cachefile, sizeof(cachefile)) != NOTOK) { - if ((ce->ce_fp = fopen (cachefile, "r"))) { - ce->ce_file = getcpy (cachefile); - ce->ce_unlink = 0; - goto ready_already; - } else { - admonish (cachefile, "unable to fopen for reading"); - } - } - - return OK; - -ready_already: - *file = ce->ce_file; - *fd = fileno (ce->ce_fp); - return DONE; -} - -/* - * File - */ + if (init_encoding(ct, open7Bit) == NOTOK) + return NOTOK; -static int -InitFile (CT ct) -{ - return init_encoding (ct, openFile); + ct->c_cesizefnx = NULL; /* no need to decode for real size */ + return OK; } -static int -openFile (CT ct, char **file) +int +open7Bit(CT ct, char **file) { - int fd, cachetype; - char cachefile[BUFSIZ]; - struct exbody *e = ct->c_ctexbody; - CE ce = ct->c_cefile; - - switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) { - case NOTOK: - return NOTOK; - - case OK: - break; - - case DONE: - return fd; - } - - if (!e->eb_name) { - content_error (NULL, ct, "missing name parameter"); - return NOTOK; - } - - ce->ce_file = getcpy (e->eb_name); - ce->ce_unlink = 0; - - if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading"); - return NOTOK; - } - - if ((!e->eb_permission || mh_strcasecmp (e->eb_permission, "read-write")) - && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id, - cachefile, sizeof(cachefile)) != NOTOK) { - int mask; - FILE *fp; + int cc, fd, len, own_ct_fp = 0; + char buffer[BUFSIZ]; + /* sbeck -- handle suffixes */ + char *cp; + CI ci; + CE ce; + + ce = ct->c_cefile; + if (ce->ce_fp) { + fseek(ce->ce_fp, 0L, SEEK_SET); + goto ready_to_go; + } - mask = umask (cachetype ? ~m_gmprot () : 0222); - if ((fp = fopen (cachefile, "w"))) { - int cc; - char buffer[BUFSIZ]; - FILE *gp = ce->ce_fp; - - fseek (gp, 0L, SEEK_SET); - - while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) - > 0) - fwrite (buffer, sizeof(*buffer), cc, fp); - fflush (fp); - - if (ferror (gp)) { - admonish (ce->ce_file, "error reading"); - unlink (cachefile); - } - else - if (ferror (fp)) { - admonish (cachefile, "error writing"); - unlink (cachefile); + if (ce->ce_file) { + if ((ce->ce_fp = fopen(ce->ce_file, "r")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading"); + return NOTOK; } - fclose (fp); + goto ready_to_go; } - umask (mask); - } - fseek (ce->ce_fp, 0L, SEEK_SET); - *file = ce->ce_file; - return fileno (ce->ce_fp); -} - -/* - * FTP - */ - -static int -InitFTP (CT ct) -{ - return init_encoding (ct, openFTP); -} - - -static int -openFTP (CT ct, char **file) -{ - int cachetype, caching, fd; - int len, buflen; - char *bp, *ftp, *user, *pass; - char buffer[BUFSIZ], cachefile[BUFSIZ]; - struct exbody *e; - CE ce; - static char *username = NULL; - static char *password = NULL; - - e = ct->c_ctexbody; - ce = ct->c_cefile; - - if ((ftp = context_find (nmhaccessftp)) && !*ftp) - ftp = NULL; - -#ifndef BUILTIN_FTP - if (!ftp) - return NOTOK; -#endif - - switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) { - case NOTOK: - return NOTOK; - - case OK: - break; - - case DONE: - return fd; - } - - if (!e->eb_name || !e->eb_site) { - content_error (NULL, ct, "missing %s parameter", - e->eb_name ? "site": "name"); - return NOTOK; - } - - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - - /* Get the buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - /* - * Construct the query message for user - */ - snprintf (bp, buflen, "Retrieve %s", e->eb_name); - len = strlen (bp); - bp += len; - buflen -= len; - - if (e->eb_partno) { - snprintf (bp, buflen, " (content %s)", e->eb_partno); - len = strlen (bp); - bp += len; - buflen -= len; - } - - snprintf (bp, buflen, "\n using %sFTP from site %s", - e->eb_flags ? "anonymous " : "", e->eb_site); - len = strlen (bp); - bp += len; - buflen -= len; - - if (e->eb_size > 0) { - snprintf (bp, buflen, " (%lu octets)", e->eb_size); - len = strlen (bp); - bp += len; - buflen -= len; - } - snprintf (bp, buflen, "? "); - - /* - * Now, check the answer - */ - if (!getanswer (buffer)) - return NOTOK; - - if (e->eb_flags) { - user = "anonymous"; - snprintf (buffer, sizeof(buffer), "%s@%s", getusername (), LocalName ()); - pass = buffer; - } else { - ruserpass (e->eb_site, &username, &password); - user = username; - pass = password; - } - - ce->ce_unlink = (*file == NULL); - caching = 0; - cachefile[0] = '\0'; - if ((!e->eb_permission || mh_strcasecmp (e->eb_permission, "read-write")) - && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id, - cachefile, sizeof(cachefile)) != NOTOK) { if (*file == NULL) { - ce->ce_unlink = 0; - caching = 1; + ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL)); + ce->ce_unlink = 1; + } else { + ce->ce_file = getcpy(*file); + ce->ce_unlink = 0; } - } - if (*file) - ce->ce_file = add (*file, NULL); - else if (caching) - ce->ce_file = add (cachefile, NULL); - else - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); + /* sbeck@cise.ufl.edu -- handle suffixes */ + ci = &ct->c_ctinfo; + snprintf(buffer, sizeof(buffer), "%s-suffix-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + cp = context_find(buffer); + if (cp == NULL || *cp == '\0') { + snprintf(buffer, sizeof(buffer), "%s-suffix-%s", invo_name, + ci->ci_type); + cp = context_find(buffer); + } + if (cp != NULL && *cp != '\0') { + if (ce->ce_unlink) { + /* + ** Temporary file already exists, so we rename to + ** version with extension. + */ + char *file_org = strdup(ce->ce_file); + ce->ce_file = add(cp, ce->ce_file); + if (rename(file_org, ce->ce_file)) { + adios(ce->ce_file, "unable to rename %s to ", + file_org); + } + free(file_org); - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } - -#ifdef BUILTIN_FTP - if (ftp) -#endif - { - int child_id, i, vecp; - char *vec[9]; - - vecp = 0; - vec[vecp++] = r1bindex (ftp, '/'); - vec[vecp++] = e->eb_site; - vec[vecp++] = user; - vec[vecp++] = pass; - vec[vecp++] = e->eb_dir; - vec[vecp++] = e->eb_name; - vec[vecp++] = ce->ce_file, - vec[vecp++] = e->eb_mode && !mh_strcasecmp (e->eb_mode, "ascii") - ? "ascii" : "binary"; - vec[vecp] = NULL; - - fflush (stdout); - - for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - adios ("fork", "unable to"); - /* NOTREACHED */ - - case OK: - close (fileno (ce->ce_fp)); - execvp (ftp, vec); - fprintf (stderr, "unable to exec "); - perror (ftp); - _exit (-1); - /* NOTREACHED */ - - default: - if (pidXwait (child_id, NULL)) { -#ifdef BUILTIN_FTP -losing_ftp: -#endif - username = password = NULL; - ce->ce_unlink = 1; - return NOTOK; + } else { + ce->ce_file = add(cp, ce->ce_file); } - break; } - } -#ifdef BUILTIN_FTP - else - if (ftp_get (e->eb_site, user, pass, e->eb_dir, e->eb_name, - ce->ce_file, - e->eb_mode && !mh_strcasecmp (e->eb_mode, "ascii"), 0) - == NOTOK) - goto losing_ftp; -#endif - - if (cachefile[0]) { - if (caching) - chmod (cachefile, cachetype ? m_gmprot () : 0444); - else { - int mask; - FILE *fp; - - mask = umask (cachetype ? ~m_gmprot () : 0222); - if ((fp = fopen (cachefile, "w"))) { - int cc; - FILE *gp = ce->ce_fp; - - fseek (gp, 0L, SEEK_SET); - - while ((cc= fread (buffer, sizeof(*buffer), sizeof(buffer), gp)) - > 0) - fwrite (buffer, sizeof(*buffer), cc, fp); - fflush (fp); - - if (ferror (gp)) { - admonish (ce->ce_file, "error reading"); - unlink (cachefile); - } - else - if (ferror (fp)) { - admonish (cachefile, "error writing"); - unlink (cachefile); - } - fclose (fp); - } - umask (mask); - } - } - - fseek (ce->ce_fp, 0L, SEEK_SET); - *file = ce->ce_file; - return fileno (ce->ce_fp); -} - - -/* - * Mail - */ - -static int -InitMail (CT ct) -{ - return init_encoding (ct, openMail); -} - -static int -openMail (CT ct, char **file) -{ - int child_id, fd, i, vecp; - int len, buflen; - char *bp, buffer[BUFSIZ], *vec[7]; - struct exbody *e = ct->c_ctexbody; - CE ce = ct->c_cefile; - - switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) { - case NOTOK: - return NOTOK; - - case OK: - break; + if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) { + content_error(ce->ce_file, ct, + "unable to fopen for reading/writing"); + return NOTOK; + } - case DONE: - return fd; - } + if (ct->c_type == CT_MULTIPART) { + char **ap, **ep; + CI ci = &ct->c_ctinfo; - if (!e->eb_server) { - content_error (NULL, ct, "missing server parameter"); - return NOTOK; - } - - if (xpid) { - if (xpid < 0) - xpid = -xpid; - pidcheck (pidwait (xpid, NOTOK)); - xpid = 0; - } - - /* Get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - /* Now, construct query message */ - snprintf (bp, buflen, "Retrieve content"); - len = strlen (bp); - bp += len; - buflen -= len; - - if (e->eb_partno) { - snprintf (bp, buflen, " %s", e->eb_partno); - len = strlen (bp); - bp += len; - buflen -= len; - } - - snprintf (bp, buflen, " by asking %s\n\n%s\n? ", - e->eb_server, - e->eb_subject ? e->eb_subject : e->eb_body); - - /* Now, check answer */ - if (!getanswer (buffer)) - return NOTOK; + len = 0; + fprintf(ce->ce_fp, "%s: %s/%s", TYPE_FIELD, ci->ci_type, + ci->ci_subtype); + len += strlen(TYPE_FIELD) + 2 + strlen(ci->ci_type) + 1 + + strlen(ci->ci_subtype); + for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { + putc(';', ce->ce_fp); + len++; + + snprintf(buffer, sizeof(buffer), "%s=\"%s\"", + *ap, *ep); + + if (len + 1 + (cc = strlen(buffer)) >= CPERLIN) { + fputs("\n\t", ce->ce_fp); + len = 8; + } else { + putc(' ', ce->ce_fp); + len++; + } + fprintf(ce->ce_fp, "%s", buffer); + len += cc; + } - vecp = 0; - vec[vecp++] = r1bindex (mailproc, '/'); - vec[vecp++] = e->eb_server; - vec[vecp++] = "-subject"; - vec[vecp++] = e->eb_subject ? e->eb_subject : "mail-server request"; - vec[vecp++] = "-body"; - vec[vecp++] = e->eb_body; - vec[vecp] = NULL; - - for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - advise ("fork", "unable to"); - return NOTOK; - - case OK: - execvp (mailproc, vec); - fprintf (stderr, "unable to exec "); - perror (mailproc); - _exit (-1); - /* NOTREACHED */ + if (ci->ci_comment) { + if (len + 1 + (cc = 2 + strlen(ci->ci_comment)) + >= CPERLIN) { + fputs("\n\t", ce->ce_fp); + len = 8; + } else { + putc(' ', ce->ce_fp); + len++; + } + fprintf(ce->ce_fp, "(%s)", ci->ci_comment); + len += cc; + } + fprintf(ce->ce_fp, "\n"); + if (ct->c_id) + fprintf(ce->ce_fp, "%s:%s", ID_FIELD, ct->c_id); + if (ct->c_descr) + fprintf(ce->ce_fp, "%s:%s", DESCR_FIELD, ct->c_descr); + if (ct->c_dispo) + fprintf(ce->ce_fp, "%s:%s", DISPO_FIELD, ct->c_dispo); + fprintf(ce->ce_fp, "\n"); + } - default: - if (pidXwait (child_id, NULL) == OK) - advise (NULL, "request sent"); - break; - } - - if (*file == NULL) { - ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL); - ce->ce_unlink = 1; - } else { - ce->ce_file = add (*file, NULL); - ce->ce_unlink = 0; - } - - if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { - content_error (ce->ce_file, ct, "unable to fopen for reading/writing"); - return NOTOK; - } + if ((len = ct->c_end - ct->c_begin) < 0) + adios(NULL, "internal error(3)"); - /* showproc is for mhshow and mhstore, though mhlist -debug - * prints it, too. */ - if (ct->c_showproc) - free (ct->c_showproc); - ct->c_showproc = add ("true", NULL); + if (!ct->c_fp) { + if ((ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + content_error(ct->c_file, ct, + "unable to open for reading"); + return NOTOK; + } + own_ct_fp = 1; + } - fseek (ce->ce_fp, 0L, SEEK_SET); - *file = ce->ce_file; - return fileno (ce->ce_fp); -} + lseek(fd = fileno(ct->c_fp), (off_t) ct->c_begin, SEEK_SET); + while (len > 0) + switch (cc = read(fd, buffer, sizeof(buffer) - 1)) { + case NOTOK: + content_error(ct->c_file, ct, "error reading from"); + goto clean_up; + case OK: + content_error(NULL, ct, "premature eof"); + goto clean_up; -static int -readDigest (CT ct, char *cp) -{ - int bitno, skip; - unsigned long bits; - char *bp = cp; - unsigned char *dp, value, *ep; - unsigned char *b, *b1, *b2, *b3; - - b = (unsigned char *) &bits, - b1 = &b[endian > 0 ? 1 : 2], - b2 = &b[endian > 0 ? 2 : 1], - b3 = &b[endian > 0 ? 3 : 0]; - bitno = 18; - bits = 0L; - skip = 0; - - for (ep = (dp = ct->c_digest) - + sizeof(ct->c_digest) / sizeof(ct->c_digest[0]); *cp; cp++) - switch (*cp) { - default: - if (skip - || (*cp & 0x80) - || (value = b642nib[*cp & 0x7f]) > 0x3f) { - if (debugsw) - fprintf (stderr, "invalid BASE64 encoding\n"); - return NOTOK; + default: + if (cc > len) + cc = len; + len -= cc; + + fwrite(buffer, sizeof(*buffer), cc, ce->ce_fp); + if (ferror(ce->ce_fp)) { + content_error(ce->ce_file, ct, + "error writing to"); + goto clean_up; + } } - bits |= value << bitno; -test_end: - if ((bitno -= 6) < 0) { - if (dp + (3 - skip) > ep) - goto invalid_digest; - *dp++ = *b1; - if (skip < 2) { - *dp++ = *b2; - if (skip < 1) - *dp++ = *b3; - } - bitno = 18; - bits = 0L; - skip = 0; - } - break; + fseek(ct->c_fp, 0L, SEEK_SET); - case '=': - if (++skip > 3) - goto self_delimiting; - goto test_end; + if (fflush(ce->ce_fp)) { + content_error(ce->ce_file, ct, "error writing to"); + goto clean_up; } - if (bitno != 18) { - if (debugsw) - fprintf (stderr, "premature ending (bitno %d)\n", bitno); - return NOTOK; - } -self_delimiting: - if (dp != ep) { -invalid_digest: - if (debugsw) { - while (*cp) - cp++; - fprintf (stderr, "invalid MD5 digest (got %d octets)\n", - (int)(cp - bp)); + fseek(ce->ce_fp, 0L, SEEK_SET); + +ready_to_go: + *file = ce->ce_file; + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; } + return fileno(ce->ce_fp); +clean_up: + free_encoding(ct, 0); + if (own_ct_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } return NOTOK; - } - - if (debugsw) { - fprintf (stderr, "MD5 digest="); - for (dp = ct->c_digest; dp < ep; dp++) - fprintf (stderr, "%02x", *dp & 0xff); - fprintf (stderr, "\n"); - } - - return OK; } diff --git a/uip/mhpath.c b/uip/mhpath.c index 23ca542..a8de5cb 100644 --- a/uip/mhpath.c +++ b/uip/mhpath.c @@ -1,126 +1,127 @@ - /* - * mhpath.c -- print full pathnames of nmh messages and folders - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhpath.c -- print full pathnames of nmh messages and folders +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include static struct swit switches[] = { #define VERSIONSW 0 - { "version", 0 }, -#define HELPSW 1 - { "help", 0 }, - { NULL, 0 } + { "Version", 0 }, +#define HELPSW 1 + { "help", 0 }, + { NULL, 0 } }; int main(int argc, char **argv) { - int i; - char *cp, *maildir, *folder = NULL; - char **argp; - char **arguments, buf[BUFSIZ]; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - } + int i; + char *cp, *maildir, *folder = NULL; + char **argp; + char **arguments, buf[BUFSIZ]; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + /* If no messages are given, print folder pathname */ + if (!msgs.size) { + printf("%s\n", maildir); + done(0); + } + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* + ** We need to make sure there is message status space + ** for all the message numbers from 1 to one beyond last since + ** mhpath can select empty slots. If we are adding + ** space at the end, we go ahead and add 10 slots. + */ + if (mp->hghmsg >= mp->hghoff) { + if (!(mp = folder_realloc(mp, 1, mp->hghmsg + 10))) + adios(NULL, "unable to allocate folder storage"); + } else if (mp->lowoff > 1) { + if (!(mp = folder_realloc(mp, 1, mp->hghoff))) + adios(NULL, "unable to allocate folder storage"); } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - /* If no messages are given, print folder pathname */ - if (!msgs.size) { - printf ("%s\n", maildir); - done (0); - } - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* - * We need to make sure there is message status space - * for all the message numbers from 1 to "new" since - * mhpath can select empty slots. If we are adding - * space at the end, we go ahead and add 10 slots. - */ - if (mp->hghmsg >= mp->hghoff) { - if (!(mp = folder_realloc (mp, 1, mp->hghmsg + 10))) - adios (NULL, "unable to allocate folder storage"); - } else if (mp->lowoff > 1) { - if (!(mp = folder_realloc (mp, 1, mp->hghoff))) - adios (NULL, "unable to allocate folder storage"); - } - - mp->msgflags |= ALLOW_NEW; /* allow the "new" sequence */ - - /* parse all the message ranges/sequences and set SELECTED */ - for (i = 0; i < msgs.size; i++) - if (!m_convert (mp, msgs.msgs[i])) - done (1); - - seq_setprev (mp); /* set the previous-sequence */ - - /* print the path of all selected messages */ - for (i = mp->lowsel; i <= mp->hghsel; i++) - if (is_selected (mp, i)) - printf ("%s/%s\n", mp->foldpath, m_name (i)); - - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; + /* + ** TODO: As folder_realloc() checks itself if the realloc + ** really is necesary, why don't we then: + ** if (!(mp = folder_realloc (mp, 1, mp->hghmsg+1))) + ** adios (NULL, "unable to allocate folder storage"); + ** ? This at least appears most clear to me. -- meillo + */ + + + mp->msgflags |= ALLOW_BEYOND; /* allow the beyond sequence */ + + /* parse all the message ranges/sequences and set SELECTED */ + for (i = 0; i < msgs.size; i++) + if (!m_convert(mp, msgs.msgs[i])) + done(1); + + seq_setprev(mp); /* set the previous-sequence */ + + /* print the path of all selected messages */ + for (i = mp->lowsel; i <= mp->hghsel; i++) + if (is_selected(mp, i)) + printf("%s/%s\n", mp->foldpath, m_name(i)); + + seq_save(mp); /* synchronize message sequences */ + context_save(); /* save the context file */ + folder_free(mp); /* free folder/message structure */ + done(0); + return 1; } diff --git a/uip/mhpgp.sh b/uip/mhpgp.sh new file mode 100755 index 0000000..c562c64 --- /dev/null +++ b/uip/mhpgp.sh @@ -0,0 +1,179 @@ +#!/bin/sh +# Based on mhpgp 1.1.0.7 2005/11/29 06:25:05 by Neil Rickert +# Adjusted to mmh by markus schnalke , 2012-07 + + +# mhpgp: +# -write: Save the decrypted message to the current folder + +usage="Usage: mhpgp [-write] msg" + +# prepend the default options from the profile +set -- `mhparam -nocomp ${0##*/}` "$@" + +while : ; do + case "$1" in + -w*) + wflag=1 + ;; + -V*) + echo "${0##*/} has no own version number, thus this instead:" + folder -Version + exit 0 + ;; + -h*|-*) + echo "$usage" >&2 + exit 1 + ;; + *) + break + ;; + esac + shift +done + +TEMP=/tmp/${0##*/}.$$ +umask 077 +mkdir $TEMP || exit 1 +trap "rm -rf $TEMP" 0 1 2 15 + + +### verify a mime message +mimeverify() { + bdry=`echo "$CH" | sed -n \ + -e 's/[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]=/;boundary=/' \ + -e 's/.*;boundary=/boundary=/' \ + -e 's/^boundary=\([^;]*\);.*/boundary=\1/' \ + -e 's/^boundary="\([^"]*\)".*/boundary=\1/' \ + -e 's/[ ][ ]*$//' \ + -e 's/^boundary=//p'` + + xbdry=`echo "$bdry" | sed -e 's"/"\\\\/"g' -e 's"\."\\\\."g'` + + sed -e '1,/^--'"$xbdry"'[ ]*$/d' $FILE > $TEMP/body + + sed -e '/^--'"$xbdry"'[ ]*$/,$d' \ + -e 's/[ ][ ]*$//' $TEMP/body | + sed -e '$d' -e 's/$/ /' > $TEMP/msg + if grep "[ ^M ]$" $TEMP/body >/dev/null 2>&1 ; then + echo 'Warning: trailing blanks removed from message body' >&2 + fi + + sed -e '1,/^--'"$xbdry"'[ ]*$/d' $TEMP/body | + sed -n -e '/BEGIN PGP /,/END PGP /p' > $TEMP/msg.asc + + gpg --verify $TEMP/msg.asc +} + +### decrypt MIME and non-MIME messages (type is in $1) +###; invoke the pager as needed +decrypt() { + sed -n -e ':a + /^-----BEGIN PGP MESSAGE/b x + d + :x + p + /^-----END PGP MESSAGE/b y + n + b x + :y + n + b y' $FILE | gpg --decrypt >$TEMP/msg + X=`tail -1c $TEMP/msg` + if [ "$X" != "" ] ; then + # ensure trailing newline + echo >> $TEMP/msg + fi + if [ "$1" = "plain" ] ; then + sedcmd="/^[Mm][Ii][Mm][Ee]-.*:/b r" + else + sedcmd='/^-*$/q' + fi + + sed -n ':a + /^-*$/q + '"$sedcmd"' + /^[Cc][Oo][Nn][Tt][Ee][Nn][Tt]-/b r + p + n + b a + :r + n + /^[ ]/b r + b a' "$FILE" > "$TEMP/outfile" + + if [ "$1" = "plain" ] ; then echo "" >> "$TEMP/outfile" ; fi + sed -e 's/ $//' $TEMP/msg >> "$TEMP/outfile" || exit 1 + + if [ "$wflag" = "1" ] ; then + refile -file "$TEMP/outfile" @ + else + show -file "$TEMP/outfile" + fi +} + + +### Mainline processing + +case "$#" in +0) + FILE=`mhpath c` || exit 1 ;; +*) + case "$*" in + /*) FILE=`echo "$@"` ;; + *) FILE=`mhpath "$@"` || exit 1 ;; + esac ;; +esac + +set X $FILE + +if [ $# != 2 ] ; then + echo "One message at a time, please!" >&2 + exit 1 +fi + +# get mime-version and content-type headers. +CH=`sed -n -e '\ + :a + /^-*$/q + /^[Mm][Ii][Mm][Ee]-[Vv][Ee][Rr][Ss][Ii][Oo][Nn]:/b x + /^[Cc][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]:/b x + d + :x + p + n + /^[ ]/b x + b a' $FILE` + +if echo "$CH" | grep -i mime-version >/dev/null 2>&1; then + : ## nothing, this is good +else + CH= +fi + +# Handle MIME variants +case "$CH" in +*application/pgp-signature*) + mimeverify + exit + ;; +*application/pgp-encrypted*) + decrypt mime + exit + ;; +esac + +# Handle plain variants +case "`grep '^-----BEGIN PGP' $FILE 2>/dev/null`" in +*"PGP SIGNED MESSAGE"*) + gpg --verify "$FILE" + exit + ;; +*"BEGIN PGP MESSAGE"*) + decrypt plain + exit + ;; +esac + +echo "I can't find a PGP message there" >&2 +exit 1 diff --git a/uip/mhshow.c b/uip/mhshow.c index 191eeff..0b49b7e 100644 --- a/uip/mhshow.c +++ b/uip/mhshow.c @@ -1,99 +1,49 @@ - /* - * mhshow.c -- display the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhshow.c -- display the contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include -#include #include #include #include -#include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - static struct swit switches[] = { -#define CHECKSW 0 - { "check", 0 }, -#define NCHECKSW 1 - { "nocheck", 0 }, -#define PAUSESW 2 - { "pause", 0 }, -#define NPAUSESW 3 - { "nopause", 0 }, -#define SERIALSW 4 - { "serialonly", 0 }, -#define NSERIALSW 5 - { "noserialonly", 0 }, -#define VERBSW 6 - { "verbose", 0 }, -#define NVERBSW 7 - { "noverbose", 0 }, -#define FILESW 8 /* interface from show */ - { "file file", 0 }, -#define FORMSW 9 - { "form formfile", 0 }, -#define PARTSW 10 - { "part number", 0 }, -#define TYPESW 11 - { "type content", 0 }, -#define RCACHESW 12 - { "rcache policy", 0 }, -#define WCACHESW 13 - { "wcache policy", 0 }, -#define VERSIONSW 14 - { "version", 0 }, -#define HELPSW 15 - { "help", 0 }, - -/* - * switches for moreproc/mhlproc - */ -#define PROGSW 16 - { "moreproc program", -4 }, -#define NPROGSW 17 - { "nomoreproc", -3 }, -#define LENSW 18 - { "length lines", -4 }, -#define WIDTHSW 19 - { "width columns", -4 }, - -/* - * switches for debugging - */ -#define DEBUGSW 20 - { "debug", -5 }, - { NULL, 0 } +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define FILESW 2 /* interface from show */ + { "file file", 0 }, +#define FORMSW 3 + { "form formfile", 0 }, +#define PARTSW 4 + { "part number", 0 }, +#define TYPESW 5 + { "type content", 0 }, +#define VERSIONSW 6 + { "Version", 0 }, +#define HELPSW 7 + { "help", 0 }, +#define DEBUGSW 8 + { "debug", -5 }, + { NULL, 0 } }; /* mhparse.c */ -extern char *tmp; /* directory to place temp files */ - -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; +extern char *tmp; /* directory to place temp files */ /* mhshowsbr.c */ -extern int pausesw; -extern int serialsw; -extern char *progsw; extern int nolist; -extern int nomore; /* flags for moreproc/header display */ extern char *formsw; /* mhmisc.c */ @@ -103,368 +53,400 @@ extern char *parts[NPARTS + 1]; extern char *types[NTYPES + 1]; extern int userrs; +static enum { SHOW, NEXT, PREV } mode = SHOW; + int debugsw = 0; int verbosw = 0; -#define quitser pipeser +#define quitser pipeser /* mhparse.c */ -CT parse_mime (char *); +CT parse_mime(char *); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void set_endian(void); +void flush_errors(void); /* mhshowsbr.c */ -void show_all_messages (CT *); +void show_all_messages(CT *); /* mhfree.c */ -void free_content (CT); +void free_content(CT); extern CT *cts; -void freects_done (int) NORETURN; +void freects_done(int) NORETURN; /* - * static prototypes - */ -static RETSIGTYPE pipeser (int); +** static prototypes +*/ +static void pipeser(int); +static void m_popen(char *); +static void m_pclose(void); int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgnum, *icachesw; - char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp = NULL; - CT ct, *ctp; - FILE *fp; - - done=freects_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; -do_cache: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); - default: - break; + int msgnum; + char *cp, *file = NULL, *folder = NULL; + char *maildir, buf[100], **argp; + char **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp = NULL; + CT ct, *ctp; + FILE *fp; + int ontty = 0; + + done=freects_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + if (mh_strcasecmp(invo_name, "next")==0) { + mode = NEXT; + } else if (mh_strcasecmp(invo_name, "prev")==0) { + mode = PREV; + } + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] %s[switches]", invo_name, mode==SHOW ? "[msgs] " : ""); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case PARTSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (npart >= NPARTS) + adios(NULL, "too many parts (starting with %s), %d max", cp, NPARTS); + parts[npart++] = cp; + continue; + + case TYPESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (ntype >= NTYPES) + adios(NULL, "too many types (starting with %s), %d max", cp, NTYPES); + types[ntype++] = cp; + continue; + + case FILESW: + if (mode != SHOW) { + adios(NULL, "Either call show as `%s' or use -file", invo_name); + } + + if (!(cp = *argp++) || (*cp == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + file = *cp == '-' ? cp : getcpy(expanddir(cp)); + continue; + + case FORMSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (formsw) + free(formsw); + formsw = getcpy(etcpath(cp)); + continue; + + case VERBSW: + verbosw = 1; + continue; + case NVERBSW: + verbosw = 0; + continue; + case DEBUGSW: + debugsw = 1; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else if (mode != SHOW) { + adios(NULL, "Either call show as `%s' or give message arguments", invo_name); + } else { + app_msgarg(&msgs, cp); } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case PAUSESW: - pausesw = 1; - continue; - case NPAUSESW: - pausesw = 0; - continue; - - case SERIALSW: - serialsw = 1; - continue; - case NSERIALSW: - serialsw = 0; - continue; - - case PARTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (npart >= NPARTS) - adios (NULL, "too many parts (starting with %s), %d max", - cp, NPARTS); - parts[npart++] = cp; - continue; - - case TYPESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (ntype >= NTYPES) - adios (NULL, "too many types (starting with %s), %d max", - cp, NTYPES); - types[ntype++] = cp; - continue; - - case FILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - file = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case FORMSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (formsw) - free (formsw); - formsw = getcpy (etcpath (cp)); - continue; - - /* - * Switches for moreproc/mhlproc - */ - case PROGSW: - if (!(progsw = *argp++) || *progsw == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NPROGSW: - nomore++; - continue; - - case LENSW: - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case VERBSW: - verbosw = 1; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* null terminate the list of acceptable parts/types */ - parts[npart] = NULL; - types[ntype] = NULL; - - set_endian (); - - if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1")) { - nolist = 1; - pausesw = 0; - } - - /* - * Check if we've specified an additional profile - */ - if ((cp = getenv ("MHSHOW"))) { - if ((fp = fopen (cp, "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } else { - admonish ("", "unable to read $MHSHOW profile (%s)", cp); + + /* null terminate the list of acceptable parts/types */ + parts[npart] = NULL; + types[ntype] = NULL; + + set_endian(); + + if ((cp = getenv("MM_NOASK")) && strcmp(cp, "1")==0) { + nolist = 1; + } + + /* + ** Check if we've specified an additional profile + */ + if ((cp = getenv("MHSHOW"))) { + if ((fp = fopen(cp, "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); + } else { + admonish("", "unable to read $MHSHOW profile (%s)", + cp); + } + } + + /* + ** Read the standard profile setup + */ + if ((fp = fopen(cp = etcpath("mhn.defaults"), "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); } - } - - /* - * Read the standard profile setup - */ - if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Check for storage directory. If specified, - * then store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (file && msgs.size) - adios (NULL, "cannot specify msg and file at same time!"); - - /* - * check if message is coming from file - */ - if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - if ((ct = parse_mime (file))); - *ctp++ = ct; - } else { + /* - * message(s) are coming from a folder - */ - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); + ** Check for storage directory. If specified, + ** then store temporary files there. Else we + ** store them in standard nmh directory. + */ + if ((cp = context_find(nmhstorage)) && *cp) + tmp = concat(cp, "/", invo_name, NULL); + else + tmp = getcpy(toabsdir(invo_name)); + + if (file && msgs.size) + adios(NULL, "cannot specify msg and file at same time!"); /* - * Set the SELECT_UNSEEN bit for all the SELECTED messages, - * since we will use that as a tag to know which messages - * to remove from the "unseen" sequence. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected(mp, msgnum)) - set_unseen (mp, msgnum); + ** check if message is coming from file + */ + if (file) { + if (!(cts = (CT *) calloc((size_t) 2, sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + if ((ct = parse_mime(file))) + *ctp++ = ct; + } else { + /* + ** message(s) are coming from a folder + */ + if (!msgs.size) { + switch (mode) { + case NEXT: + app_msgarg(&msgs, seq_next); + break; + case PREV: + app_msgarg(&msgs, seq_prev); + break; + default: + app_msgarg(&msgs, seq_cur); + break; + } + } + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + + /* + ** Set the SELECT_UNSEEN bit for all the SELECTED messages, + ** since we will use that as a tag to know which messages + ** to remove from the "unseen" sequence. + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) + if (is_selected(mp, msgnum)) + set_unseen(mp, msgnum); + + seq_setprev(mp); /* set the Previous-Sequence */ + seq_setunseen(mp, 0); /* unset unseen seqs for shown msgs */ + + if (!(cts = (CT *) calloc((size_t) (mp->numsel + 1), + sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + /* + ** Parse all the SELECTED messages. + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + char *msgnam; + + msgnam = m_name(msgnum); + if ((ct = parse_mime(msgnam))) + *ctp++ = ct; + } + } + } + + if (!*cts) + done(1); + + userrs = 1; + SIGNAL(SIGQUIT, quitser); + SIGNAL(SIGPIPE, pipeser); - seq_setprev (mp); /* set the Previous-Sequence */ - seq_setunseen (mp, 1); /* unset the Unseen-Sequence */ + /* + ** Get the associated umask for the relevant contents. + */ + for (ctp = cts; *ctp; ctp++) { + struct stat st; + + ct = *ctp; + if (type_ok(ct, 1) && !ct->c_umask) { + if (stat(ct->c_file, &st) != NOTOK) + ct->c_umask = ~(st.st_mode & 0777); + else + ct->c_umask = ~m_gmprot(); + } + } - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; + if ((ontty = isatty(fileno(stdout)))) { + m_popen(defaultpager); + } /* - * Parse all the SELECTED messages. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - char *msgnam; - - msgnam = m_name (msgnum); - if ((ct = parse_mime (msgnam))) - *ctp++ = ct; - } + ** Show the message content + */ + show_all_messages(cts); + + if (ontty) { + m_pclose(); } - } - - if (!*cts) - done (1); - - userrs = 1; - SIGNAL (SIGQUIT, quitser); - SIGNAL (SIGPIPE, pipeser); - - /* - * Get the associated umask for the relevant contents. - */ - for (ctp = cts; *ctp; ctp++) { - struct stat st; - - ct = *ctp; - if (type_ok (ct, 1) && !ct->c_umask) { - if (stat (ct->c_file, &st) != NOTOK) - ct->c_umask = ~(st.st_mode & 0777); - else - ct->c_umask = ~m_gmprot(); + + /* Now free all the structures for the content */ + for (ctp = cts; *ctp; ctp++) + free_content(*ctp); + + free((char *) cts); + cts = NULL; + + /* If reading from a folder, do some updating */ + if (mp) { + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->hghsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ } - } - - /* - * Show the message content - */ - show_all_messages (cts); - - /* Now free all the structures for the content */ - for (ctp = cts; *ctp; ctp++) - free_content (*ctp); - - free ((char *) cts); - cts = NULL; - - /* If reading from a folder, do some updating */ - if (mp) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - done (0); - return 1; + + done(0); + return 1; } -static RETSIGTYPE -pipeser (int i) +static void +pipeser(int i) +{ + if (i == SIGQUIT) { + unlink("core"); + fflush(stdout); + fprintf(stderr, "\n"); + fflush(stderr); + } + + done(1); + /* NOTREACHED */ +} + + +static int m_pid = NOTOK; +static int sd = NOTOK; + + +static void +m_popen(char *name) { - if (i == SIGQUIT) { - unlink ("core"); - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - done (1); - /* NOTREACHED */ + int pd[2]; + + if ((sd = dup(fileno(stdout))) == NOTOK) + adios("standard output", "unable to dup()"); + + if (pipe(pd) == NOTOK) + adios("pipe", "unable to"); + + switch (m_pid = fork()) { + case NOTOK: + adios("fork", "unable to"); + + case OK: + SIGNAL(SIGINT, SIG_DFL); + SIGNAL(SIGQUIT, SIG_DFL); + + close(pd[1]); + if (pd[0] != fileno(stdin)) { + dup2(pd[0], fileno(stdin)); + close(pd[0]); + } + execlp(name, mhbasename(name), NULL); + fprintf(stderr, "unable to exec "); + perror(name); + _exit(-1); + + default: + close(pd[0]); + if (pd[1] != fileno(stdout)) { + dup2(pd[1], fileno(stdout)); + close(pd[1]); + } + } +} + + +void +m_pclose(void) +{ + if (m_pid == NOTOK) + return; + + if (sd != NOTOK) { + fflush(stdout); + if (dup2(sd, fileno(stdout)) == NOTOK) + adios("standard output", "unable to dup2()"); + + clearerr(stdout); + close(sd); + sd = NOTOK; + } else + fclose(stdout); + + pidwait(m_pid, OK); + m_pid = NOTOK; } diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index a63b8ed..71c1699 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -1,1122 +1,927 @@ - /* - * mhshowsbr.c -- routines to display the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhshowsbr.c -- routines to display the contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include #include -#include #include #include #include #include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -/* - * Just use sigjmp/longjmp on older machines that - * don't have sigsetjmp/siglongjmp. - */ -#ifndef HAVE_SIGSETJMP -# define sigjmp_buf jmp_buf -# define sigsetjmp(env,mask) setjmp(env) -# define siglongjmp(env,val) longjmp(env,val) -#endif +#include extern int debugsw; -int pausesw = 1; -int serialsw = 0; int nolist = 0; - -char *progsw = NULL; - -/* flags for moreproc/header display */ -int nomore = 0; char *formsw = NULL; -pid_t xpid = 0; - -static sigjmp_buf intrenv; - - -/* termsbr.c */ -int SOprintf (char *, ...); /* mhparse.c */ -int pidcheck (int); +int pidcheck(int); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void content_error (char *, CT, char *, ...); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void content_error(char *, CT, char *, ...); +void flush_errors(void); /* mhlistsbr.c */ -int list_switch (CT, int, int, int, int); -int list_content (CT, int, int, int, int); +int list_switch(CT, int, int, int); +int list_content(CT, int, int, int); /* - * prototypes - */ -void show_all_messages (CT *); -int show_content_aux (CT, int, int, char *, char *); +** prototypes +*/ +void show_all_messages(CT *); +int show_content_aux(CT, int, char *, char *); /* - * static prototypes - */ -static void show_single_message (CT, char *); -static void DisplayMsgHeader (CT, char *); -static int show_switch (CT, int, int); -static int show_content (CT, int, int); -static int show_content_aux2 (CT, int, int, char *, char *, int, int, int, int, int); -static int show_text (CT, int, int); -static int show_multi (CT, int, int); -static int show_multi_internal (CT, int, int); -static int show_multi_aux (CT, int, int, char *); -static int show_message_rfc822 (CT, int, int); -static int show_partial (CT, int, int); -static int show_external (CT, int, int); -static RETSIGTYPE intrser (int); +** static prototypes +*/ +static void show_single_message(CT, char *); +static void DisplayMsgHeader(CT, char *); +static int show_switch(CT, int); +static int show_content(CT, int); +static int show_content_aux2(CT, int, char *, char *, int, int, int); +static int show_text(CT, int); +static int show_multi(CT, int); +static int show_multi_internal(CT, int); +static int show_multi_aux(CT, int, char *); +static int show_message_rfc822(CT, int); +static int show_partial(CT, int); +static int show_external(CT, int); /* - * Top level entry point to show/display a group of messages - */ +** Top level entry point to show/display a group of messages +*/ void -show_all_messages (CT *cts) +show_all_messages(CT *cts) { - CT ct, *ctp; - - /* - * If form is not specified, then get default form - * for showing headers of MIME messages. - */ - if (!formsw) - formsw = getcpy (etcpath ("mhl.headers")); - - /* - * If form is "mhl.null", suppress display of header. - */ - if (!strcmp (formsw, "mhl.null")) - formsw = NULL; - - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - - /* if top-level type is ok, then display message */ - if (type_ok (ct, 1)) - show_single_message (ct, formsw); - } + CT ct, *ctp; + + /* + ** If form is not specified, then get default form + ** for showing headers of MIME messages. + */ + if (!formsw) + formsw = getcpy(etcpath("mhl.headers")); + + /* + ** If form is "mhl.null", suppress display of header. + */ + if (strcmp(formsw, "mhl.null")==0) + formsw = NULL; + + for (ctp = cts; *ctp; ctp++) { + ct = *ctp; + + if (!type_ok(ct, 1)) { /* top-level type */ + continue; + } + if (cts[1]) { + if (ctp != cts) { + printf("\n\n"); + } + printf(">>> Message %s\n\n", ct->c_file); + } + show_single_message(ct, formsw); + } } /* - * Entry point to show/display a single message - */ +** Entry point to show/display a single message +*/ static void -show_single_message (CT ct, char *form) +show_single_message(CT ct, char *form) { - sigset_t set, oset; - -#ifdef HAVE_UNION_WAIT - union wait status; -#else - int status; -#endif - - /* Allow user executable bit so that temporary directories created by - * the viewer (e.g., lynx) are going to be accessible */ - umask (ct->c_umask & ~(0100)); - - /* - * If you have a format file, then display - * the message headers. - */ - if (form) - DisplayMsgHeader(ct, form); - else - xpid = 0; - - /* Show the body of the message */ - show_switch (ct, 1, 0); - - if (ct->c_fp) { - fclose (ct->c_fp); - ct->c_fp = NULL; - } - if (ct->c_ceclosefnx) - (*ct->c_ceclosefnx) (ct); - - /* block a few signals */ - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - - while (wait (&status) != NOTOK) { -#ifdef HAVE_UNION_WAIT - pidcheck (status.w_status); -#else - pidcheck (status); -#endif - continue; - } - - /* reset the signal mask */ - SIGPROCMASK (SIG_SETMASK, &oset, &set); - - xpid = 0; - flush_errors (); + /* + ** Allow user executable bit so that temporary directories created by + ** the viewer (e.g., lynx) are going to be accessible + */ + umask(ct->c_umask & ~(0100)); + + /* + ** If you have a format file, then display + ** the message headers. + */ + if (form) + DisplayMsgHeader(ct, form); + + /* Show the body of the message */ + show_switch(ct, 0); + + if (ct->c_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + if (ct->c_ceclosefnx) + (*ct->c_ceclosefnx) (ct); + + flush_errors(); } /* - * Use the mhlproc to show the header fields - */ - +** Use mhl to show the header fields +*/ static void -DisplayMsgHeader (CT ct, char *form) +DisplayMsgHeader(CT ct, char *form) { - pid_t child_id; - int i, vecp; - char *vec[8]; - - vecp = 0; - vec[vecp++] = r1bindex (mhlproc, '/'); - vec[vecp++] = "-form"; - vec[vecp++] = form; - vec[vecp++] = "-nobody"; - vec[vecp++] = ct->c_file; - - /* - * If we've specified -(no)moreproc, - * then just pass that along. - */ - if (nomore) { - vec[vecp++] = "-nomoreproc"; - } else if (progsw) { - vec[vecp++] = "-moreproc"; - vec[vecp++] = progsw; - } - vec[vecp] = NULL; - - fflush (stdout); - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case NOTOK: - adios ("fork", "unable to"); - /* NOTREACHED */ - - case OK: - execvp (mhlproc, vec); - fprintf (stderr, "unable to exec "); - perror (mhlproc); - _exit (-1); - /* NOTREACHED */ - - default: - xpid = -child_id; - break; - } + pid_t child_id; + int vecp; + char *vec[8]; + + vecp = 0; + vec[vecp++] = "mhl"; + vec[vecp++] = "-form"; + vec[vecp++] = form; + vec[vecp++] = "-nobody"; + vec[vecp++] = ct->c_file; + vec[vecp] = NULL; + + fflush(stdout); + + switch (child_id = fork()) { + case NOTOK: + adios("fork", "unable to"); + /* NOTREACHED */ + + case OK: + execvp("mhl", vec); + fprintf(stderr, "unable to exec "); + perror("mhl"); + _exit(-1); + /* NOTREACHED */ + + default: + pidcheck(pidwait(child_id, NOTOK)); + break; + } } /* - * Switching routine. Call the correct routine - * based on content type. - */ +** Switching routine. Call the correct routine +** based on content type. +*/ static int -show_switch (CT ct, int serial, int alternate) +show_switch(CT ct, int alternate) { - switch (ct->c_type) { + switch (ct->c_type) { case CT_MULTIPART: - return show_multi (ct, serial, alternate); - break; + return show_multi(ct, alternate); + break; case CT_MESSAGE: - switch (ct->c_subtype) { - case MESSAGE_PARTIAL: - return show_partial (ct, serial, alternate); - break; - - case MESSAGE_EXTERNAL: - return show_external (ct, serial, alternate); - break; - - case MESSAGE_RFC822: - default: - return show_message_rfc822 (ct, serial, alternate); - break; - } - break; + switch (ct->c_subtype) { + case MESSAGE_PARTIAL: + return show_partial(ct, alternate); + break; + + case MESSAGE_EXTERNAL: + return show_external(ct, alternate); + break; + + case MESSAGE_RFC822: + default: + return show_message_rfc822(ct, alternate); + break; + } + break; case CT_TEXT: - return show_text (ct, serial, alternate); - break; + return show_text(ct, alternate); + break; case CT_AUDIO: case CT_IMAGE: case CT_VIDEO: case CT_APPLICATION: - return show_content (ct, serial, alternate); - break; + return show_content(ct, alternate); + break; default: - adios (NULL, "unknown content type %d", ct->c_type); - break; - } + adios(NULL, "unknown content type %d", ct->c_type); + break; + } - return 0; /* NOT REACHED */ + return 0; /* NOT REACHED */ } /* - * Generic method for displaying content - */ +** Generic method for displaying content +*/ static int -show_content (CT ct, int serial, int alternate) +show_content(CT ct, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s", + ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); - if ((cp = ct->c_showproc)) - return show_content_aux (ct, serial, alternate, cp, NULL); + if ((cp = ct->c_showproc)) + return show_content_aux(ct, alternate, cp, NULL); - /* complain if we are not a part of a multipart/alternative */ - if (!alternate) - content_error (NULL, ct, "don't know how to display content"); + /* complain if we are not a part of a multipart/alternative */ + if (!alternate) + return show_content_aux(ct, alternate, "%l", NULL); - return NOTOK; + return NOTOK; } /* - * Parse the display string for displaying generic content - */ - +** Parse the display string for displaying generic content +*/ int -show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked) +show_content_aux(CT ct, int alternate, char *cp, char *cracked) { - int fd, len, buflen, quoted; - int xstdin, xlist, xpause, xtty; - char *bp, *pp, *file, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - if (!ct->c_ceopenfnx) { - if (!alternate) - content_error (NULL, ct, "don't know how to decode content"); - - return NOTOK; - } + int fd, len, buflen, quoted; + int xstdin, xlist; + char *bp, *pp, *file, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; - if (ct->c_showproc && !strcmp (ct->c_showproc, "true")) - return (alternate ? DONE : OK); - - xlist = 0; - xpause = 0; - xstdin = 0; - xtty = 0; - - if (cracked) { - strncpy (buffer, cp, sizeof(buffer)); - goto got_command; - } - - /* get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer) - 1; - bp[0] = bp[buflen] = '\0'; - quoted = 0; - - /* Now parse display string */ - for ( ; *cp && buflen > 0; cp++) { - if (*cp == '%') { - pp = bp; - - switch (*++cp) { - case 'a': - /* insert parameters from Content-Type field */ - { - char **ap, **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; - } - } - break; - - case 'd': - /* insert content description */ - if (ct->c_descr) { - char *s; - - s = trimcpy (ct->c_descr); - strncpy (bp, s, buflen); - free (s); - } - break; - - case 'e': - /* exclusive execution */ - xtty = 1; - break; + if (!ct->c_ceopenfnx) { + if (!alternate) + content_error(NULL, ct, + "don't know how to decode content"); - case 'F': - /* %e, %f, and stdin is terminal not content */ - xstdin = 1; - xtty = 1; - /* and fall... */ - - case 'f': - /* insert filename containing content */ - snprintf (bp, buflen, "'%s'", file); - /* since we've quoted the file argument, set things up - * to look past it, to avoid problems with the quoting - * logic below. (I know, I should figure out what's - * broken with the quoting logic, but..) - */ - len = strlen(bp); - buflen -= len; - bp += len; - pp = bp; - break; + return NOTOK; + } - case 'p': - /* %l, and pause prior to displaying content */ - xpause = pausesw; - /* and fall... */ + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; + if (ct->c_showproc && strcmp(ct->c_showproc, "true")==0) + return (alternate ? DONE : OK); - case 'l': - /* display listing prior to displaying content */ - xlist = !nolist; - break; + xlist = 0; + xstdin = 0; - case 's': - /* insert subtype of content */ - strncpy (bp, ci->ci_subtype, buflen); - break; + if (cracked) { + strncpy(buffer, cp, sizeof(buffer)); + goto got_command; + } - case '%': - /* insert character % */ - goto raw; - - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - - /* Did we actually insert something? */ - if (bp != pp) { - /* Insert single quote if not inside quotes already */ - if (!quoted && buflen) { - len = strlen (pp); - memmove (pp + 1, pp, len); - *pp++ = '\''; - buflen--; - bp++; - } - /* Escape existing quotes */ - while ((pp = strchr (pp, '\'')) && buflen > 3) { - len = strlen (pp++); - memmove (pp + 3, pp, len); - *pp++ = '\\'; - *pp++ = '\''; - *pp++ = '\''; - buflen -= 3; - bp += 3; - } - /* If pp is still set, that means we ran out of space. */ - if (pp) - buflen = 0; - if (!quoted && buflen) { - *bp++ = '\''; - *bp = '\0'; - buflen--; - } - } - } else { + /* get buffer ready to go */ + bp = buffer; + buflen = sizeof(buffer) - 1; + bp[0] = bp[buflen] = '\0'; + quoted = 0; + + /* Now parse display string */ + for ( ; *cp && buflen > 0; cp++) { + if (*cp == '%') { + pp = bp; + + switch (*++cp) { + case 'a': + /* insert parameters from Content-Type field */ + { + char **ap, **ep; + char *s = ""; + + for (ap = ci->ci_attrs, ep = ci->ci_values; + *ap; ap++, ep++) { + snprintf(bp, buflen, "%s%s=\"%s\"", + s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'c': + /* insert charset */ + strncpy(bp, ct->c_charset ? ct->c_charset : + "US-ASCII", buflen); + break; + + case 'd': + /* insert content description */ + if (ct->c_descr) { + char *s; + + s = trimcpy(ct->c_descr); + strncpy(bp, s, buflen); + free(s); + } + break; + + case 'F': + /* %f, and stdin is terminal not content */ + xstdin = 1; + /* and fall... */ + + case 'f': + /* insert filename containing content */ + snprintf(bp, buflen, "'%s'", file); + /* + ** since we've quoted the file argument, + ** set things up to look past it, to avoid + ** problems with the quoting logic below. + ** (I know, I should figure out what's + ** broken with the quoting logic, but..) + */ + len = strlen(bp); + buflen -= len; + bp += len; + pp = bp; + break; + + case 'l': + /* + ** display listing prior to displaying content + */ + xlist = !nolist; + break; + + case 's': + /* insert subtype of content */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + len = strlen(bp); + bp += len; + buflen -= len; + + /* Did we actually insert something? */ + if (bp != pp) { + /* + ** Insert single quote if not inside quotes + ** already + */ + if (!quoted && buflen) { + len = strlen(pp); + memmove(pp + 1, pp, len); + *pp++ = '\''; + buflen--; + bp++; + } + /* Escape existing quotes */ + while ((pp = strchr(pp, '\'')) && buflen > 3) { + len = strlen(pp++); + memmove(pp + 3, pp, len); + *pp++ = '\\'; + *pp++ = '\''; + *pp++ = '\''; + buflen -= 3; + bp += 3; + } + /* + ** If pp is still set, that means we ran + ** out of space. + */ + if (pp) + buflen = 0; + if (!quoted && buflen) { + *bp++ = '\''; + *bp = '\0'; + buflen--; + } + } + } else { raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; + *bp++ = *cp; + *bp = '\0'; + buflen--; - if (*cp == '\'') - quoted = !quoted; + if (*cp == '\'') + quoted = !quoted; + } } - } - - if (buflen <= 0 || (ct->c_termproc && buflen <= strlen(ct->c_termproc))) { - /* content_error would provide a more useful error message - * here, except that if we got overrun, it probably would - * too. - */ - fprintf(stderr, "Buffer overflow constructing show command!\n"); - return NOTOK; - } - - /* use charset string to modify display method */ - if (ct->c_termproc) { - char term[BUFSIZ]; - - strncpy (term, buffer, sizeof(term)); - snprintf (buffer, sizeof(buffer), ct->c_termproc, term); - } got_command: - return show_content_aux2 (ct, serial, alternate, cracked, buffer, - fd, xlist, xpause, xstdin, xtty); + return show_content_aux2(ct, alternate, cracked, buffer, + fd, xlist, xstdin); } /* - * Routine to actually display the content - */ - +** Routine to actually display the content +*/ static int -show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer, - int fd, int xlist, int xpause, int xstdin, int xtty) +show_content_aux2(CT ct, int alternate, char *cracked, + char *buffer, int fd, int xlist, int xstdin) { - pid_t child_id; - int i; - char *vec[4], exec[BUFSIZ + sizeof "exec "]; - - if (debugsw || cracked) { - fflush (stdout); - - fprintf (stderr, "%s msg %s", cracked ? "storing" : "show", - ct->c_file); - if (ct->c_partno) - fprintf (stderr, " part %s", ct->c_partno); - if (cracked) - fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer); - else - fprintf (stderr, " using command %s\n", buffer); - } - - if (xpid < 0 || (xtty && xpid)) { - if (xpid < 0) - xpid = -xpid; - pidcheck(pidwait (xpid, NOTOK)); - xpid = 0; - } - - if (xlist) { - char prompt[BUFSIZ]; - - if (ct->c_type == CT_MULTIPART) - list_content (ct, -1, 1, 0, 0); - else - list_switch (ct, -1, 1, 0, 0); - - if (xpause && SOprintf ("Press to show content...")) - printf ("Press to show content..."); - - if (xpause) { - int intr; - SIGNAL_HANDLER istat; - - istat = SIGNAL (SIGINT, intrser); - if ((intr = sigsetjmp (intrenv, 1)) == OK) { - fflush (stdout); - prompt[0] = 0; - read (fileno (stdout), prompt, sizeof(prompt)); - } - SIGNAL (SIGINT, istat); - if (intr != OK || prompt[0] == 'n') { - (*ct->c_ceclosefnx) (ct); - return (alternate ? DONE : NOTOK); - } - if (prompt[0] == 'q') done(OK); + pid_t child_id; + + if (debugsw || cracked) { + fflush(stdout); + + fprintf(stderr, "%s msg %s", cracked ? "storing" : "show", + ct->c_file); + if (ct->c_partno) + fprintf(stderr, " part %s", ct->c_partno); + if (cracked) + fprintf(stderr, " using command (cd %s; %s)\n", + cracked, buffer); + else + fprintf(stderr, " using command %s\n", buffer); } - } - - snprintf (exec, sizeof(exec), "exec %s", buffer); - vec[0] = "/bin/sh"; - vec[1] = "-c"; - vec[2] = exec; - vec[3] = NULL; + if (xlist) { + if (ct->c_type == CT_MULTIPART) + list_content(ct, -1, 0, 0); + else + list_switch(ct, -1, 0, 0); + } - fflush (stdout); + fflush(stdout); - for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { + switch (child_id = fork()) { case NOTOK: - advise ("fork", "unable to"); - (*ct->c_ceclosefnx) (ct); - return NOTOK; + advise("fork", "unable to"); + (*ct->c_ceclosefnx) (ct); + return NOTOK; case OK: - if (cracked) - chdir (cracked); - if (!xstdin) - dup2 (fd, 0); - close (fd); - execvp ("/bin/sh", vec); - fprintf (stderr, "unable to exec "); - perror ("/bin/sh"); - _exit (-1); - /* NOTREACHED */ + if (cracked) + chdir(cracked); + if (!xstdin) + dup2(fd, 0); + close(fd); + execlp("/bin/sh", "/bin/sh", "-c", buffer, NULL); + fprintf(stderr, "unable to exec "); + perror("/bin/sh"); + _exit(-1); + /* NOTREACHED */ default: - if (!serial) { - ct->c_pid = child_id; - if (xtty) - xpid = child_id; - } else { - pidcheck (pidXwait (child_id, NULL)); - } - - if (fd != NOTOK) - (*ct->c_ceclosefnx) (ct); - return (alternate ? DONE : OK); - } + pidcheck(pidXwait(child_id, NULL)); + + if (fd != NOTOK) + (*ct->c_ceclosefnx) (ct); + return (alternate ? DONE : OK); + } } /* - * show content of type "text" - */ +** show content of type "text" +*/ static int -show_text (CT ct, int serial, int alternate) +show_text(CT ct, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* - * Use default method if content is text/plain, or if - * if it is not a text part of a multipart/alternative - */ - if (!alternate || ct->c_subtype == TEXT_PLAIN) { - snprintf (buffer, sizeof(buffer), "%%p%s '%%F'", progsw ? progsw : - moreproc && *moreproc ? moreproc : "more"); - cp = (ct->c_showproc = add (buffer, NULL)); - return show_content_aux (ct, serial, alternate, cp, NULL); - } - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s", + ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); + + /* + ** Use default method if content is text/plain, or if + ** if it is not a text part of a multipart/alternative + */ + if (!alternate || ct->c_subtype == TEXT_PLAIN) { + if (ct->c_charset && !is_native_charset(ct->c_charset)) { + snprintf(buffer, sizeof(buffer), "%%liconv -f '%s'", + ct->c_charset); + } else { + snprintf(buffer, sizeof(buffer), "%%lcat"); + } + ct->c_showproc = getcpy(buffer); + return show_content_aux(ct, alternate, ct->c_showproc, NULL); + } + + return NOTOK; } /* - * show message body of type "multipart" - */ +** show message body of type "multipart" +*/ static int -show_multi (CT ct, int serial, int alternate) +show_multi(CT ct, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_multi_aux (ct, serial, alternate, cp); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_multi_aux (ct, serial, alternate, cp); - - if ((cp = ct->c_showproc)) - return show_multi_aux (ct, serial, alternate, cp); - - /* - * Use default method to display this multipart content - * if it is not a (nested) part of a multipart/alternative, - * or if it is one of the known subtypes of multipart. - */ - if (!alternate || ct->c_subtype != MULTI_UNKNOWN) - return show_multi_internal (ct, serial, alternate); - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s", + ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_multi_aux(ct, alternate, cp); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_multi_aux(ct, alternate, cp); + + if ((cp = ct->c_showproc)) + return show_multi_aux(ct, alternate, cp); + + /* + ** Use default method to display this multipart content + ** if it is not a (nested) part of a multipart/alternative, + ** or if it is one of the known subtypes of multipart. + */ + if (!alternate || ct->c_subtype != MULTI_UNKNOWN) + return show_multi_internal(ct, alternate); + + return NOTOK; } /* - * show message body of subtypes of multipart that - * we understand directly (mixed, alternate, etc...) - */ +** show message body of subtypes of multipart that +** we understand directly (mixed, alternate, etc...) +*/ static int -show_multi_internal (CT ct, int serial, int alternate) +show_multi_internal(CT ct, int alternate) { - int alternating, nowalternate, nowserial, result; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - CT p; - sigset_t set, oset; - - alternating = 0; - nowalternate = alternate; - - if (ct->c_subtype == MULTI_PARALLEL) { - nowserial = serialsw; - } else if (ct->c_subtype == MULTI_ALTERNATE) { - nowalternate = 1; - alternating = 1; - nowserial = serial; - } else { - /* - * multipart/mixed - * mutlipart/digest - * unknown subtypes of multipart (treat as mixed per rfc2046) - */ - nowserial = serial; - } - - /* block a few signals */ - if (!nowserial) { - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - } + int alternating, nowalternate, result; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + CT p; -/* - * alternate -> we are a part inside an multipart/alternative - * alternating -> we are a multipart/alternative - */ - - result = alternate ? NOTOK : OK; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; - - if (part_ok (p, 0) && type_ok (p, 0)) { - int inneresult; - - inneresult = show_switch (p, nowserial, nowalternate); - switch (inneresult) { - case NOTOK: - if (alternate && !alternating) { - result = NOTOK; - goto out; - } - continue; - - case OK: - case DONE: - if (alternating) { - result = DONE; - break; - } - if (alternate) { - alternate = nowalternate = 0; - if (result == NOTOK) - result = inneresult; - } - continue; - } - break; + alternating = 0; + nowalternate = alternate; + + if (ct->c_subtype == MULTI_ALTERNATE) { + nowalternate = 1; + alternating = 1; } - } - if (alternating && !part) { - if (!alternate) - content_error (NULL, ct, "don't know how to display any of the contents"); - result = NOTOK; - goto out; - } - - if (serial && !nowserial) { - pid_t pid; - int kids; -#ifdef HAVE_UNION_WAIT - union wait status; -#else - int status; -#endif - - kids = 0; - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; + /* + ** Other possible multipart types are: + ** - multipart/parallel + ** - multipart/mixed + ** - multipart/digest + ** - unknown subtypes of multipart (treat as mixed per rfc2046) + */ - if (p->c_pid > OK) { - if (kill (p->c_pid, 0) == NOTOK) - p->c_pid = 0; - else - kids++; - } - } + /* + ** alternate -> we are a part inside an multipart/alternative + ** alternating -> we are a multipart/alternative + */ - while (kids > 0 && (pid = wait (&status)) != NOTOK) { -#ifdef HAVE_UNION_WAIT - pidcheck (status.w_status); -#else - pidcheck (status); -#endif + result = alternate ? NOTOK : OK; - for (part = m->mp_parts; part; part = part->mp_next) { + for (part = m->mp_parts; part; part = part->mp_next) { p = part->mp_part; - if (xpid == pid) - xpid = 0; - if (p->c_pid == pid) { - p->c_pid = 0; - kids--; - break; + if (part_ok(p, 1) && type_ok(p, 1)) { + int inneresult; + + inneresult = show_switch(p, nowalternate); + switch (inneresult) { + case NOTOK: + if (alternate && !alternating) { + result = NOTOK; + goto out; + } + continue; + + case OK: + case DONE: + if (alternating) { + result = DONE; + break; + } + if (alternate) { + alternate = nowalternate = 0; + if (result == NOTOK) + result = inneresult; + } + continue; + } + break; } - } } - } + if (alternating && !part) { + if (!alternate) + content_error(NULL, ct, "don't know how to display any of the contents"); + result = NOTOK; + goto out; + } out: - if (!nowserial) { - /* reset the signal mask */ - SIGPROCMASK (SIG_SETMASK, &oset, &set); - } - - return result; + return result; } /* - * Parse display string for multipart content - * and use external program to display it. - */ +** Parse display string for multipart content +** and use external program to display it. +*/ static int -show_multi_aux (CT ct, int serial, int alternate, char *cp) +show_multi_aux(CT ct, int alternate, char *cp) { - int len, buflen, quoted; - int xlist, xpause, xtty; - char *bp, *pp, *file, buffer[BUFSIZ]; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - CI ci = &ct->c_ctinfo; - CT p; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; - - if (!p->c_ceopenfnx) { - if (!alternate) - content_error (NULL, p, "don't know how to decode content"); - return NOTOK; - } - - if (p->c_storage == NULL) { - file = NULL; - if ((*p->c_ceopenfnx) (p, &file) == NOTOK) - return NOTOK; + int len, buflen, quoted; + int xlist; + char *bp, *pp, *file, buffer[BUFSIZ]; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + CI ci = &ct->c_ctinfo; + CT p; - /* I'm not sure if this is necessary? */ - p->c_storage = add (file, NULL); + for (part = m->mp_parts; part; part = part->mp_next) { + p = part->mp_part; - if (p->c_showproc && !strcmp (p->c_showproc, "true")) - return (alternate ? DONE : OK); - (*p->c_ceclosefnx) (p); - } - } - - xlist = 0; - xpause = 0; - xtty = 0; - - /* get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer) - 1; - bp[0] = bp[buflen] = '\0'; - quoted = 0; - - /* Now parse display string */ - for ( ; *cp && buflen > 0; cp++) { - if (*cp == '%') { - pp = bp; - switch (*++cp) { - case 'a': - /* insert parameters from Content-Type field */ - { - char **ap, **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; + if (!p->c_ceopenfnx) { + if (!alternate) + content_error(NULL, p, "don't know how to decode content"); + return NOTOK; } - } - break; - case 'd': - /* insert content description */ - if (ct->c_descr) { - char *s; - - s = trimcpy (ct->c_descr); - strncpy (bp, s, buflen); - free (s); - } - break; + if (p->c_storage == NULL) { + file = NULL; + if ((*p->c_ceopenfnx) (p, &file) == NOTOK) + return NOTOK; - case 'e': - /* exclusive execution */ - xtty = 1; - break; + /* I'm not sure if this is necessary? */ + p->c_storage = getcpy(file); - case 'F': - /* %e and %f */ - xtty = 1; - /* and fall... */ - - case 'f': - /* insert filename(s) containing content */ - { - char *s = ""; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; - - snprintf (bp, buflen, "%s'%s'", s, p->c_storage); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; + if (p->c_showproc && strcmp(p->c_showproc, "true")==0) + return (alternate ? DONE : OK); + (*p->c_ceclosefnx) (p); } - /* set our starting pointer back to bp, to avoid - * requoting the filenames we just added - */ - pp = bp; - } - break; - - case 'p': - /* %l, and pause prior to displaying content */ - xpause = pausesw; - /* and fall... */ - - case 'l': - /* display listing prior to displaying content */ - xlist = !nolist; - break; + } - case 's': - /* insert subtype of content */ - strncpy (bp, ci->ci_subtype, buflen); - break; + xlist = 0; + + /* get buffer ready to go */ + bp = buffer; + buflen = sizeof(buffer) - 1; + bp[0] = bp[buflen] = '\0'; + quoted = 0; + + /* Now parse display string */ + for ( ; *cp && buflen > 0; cp++) { + if (*cp == '%') { + pp = bp; + switch (*++cp) { + case 'a': + /* insert parameters from Content-Type field */ + { + char **ap, **ep; + char *s = ""; + + for (ap = ci->ci_attrs, ep = ci->ci_values; + *ap; ap++, ep++) { + snprintf(bp, buflen, "%s%s=\"%s\"", + s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'c': + /* insert charset */ + strncpy(bp, ct->c_charset ? ct->c_charset : + "US-ASCII", buflen); + break; + + case 'd': + /* insert content description */ + if (ct->c_descr) { + char *s; + + s = trimcpy(ct->c_descr); + strncpy(bp, s, buflen); + free(s); + } + break; + + case 'F': + case 'f': + /* insert filename(s) containing content */ + { + char *s = ""; + + for (part = m->mp_parts; part; + part = part->mp_next) { + p = part->mp_part; + + snprintf(bp, buflen, "%s'%s'", + s, p->c_storage); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + /* + ** set our starting pointer back to bp, + ** to avoid requoting the filenames we + ** just added + */ + pp = bp; + } + break; - case '%': - /* insert character % */ - goto raw; - - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - - /* Did we actually insert something? */ - if (bp != pp) { - /* Insert single quote if not inside quotes already */ - if (!quoted && buflen) { - len = strlen (pp); - memmove (pp + 1, pp, len); - *pp++ = '\''; - buflen--; - bp++; - } - /* Escape existing quotes */ - while ((pp = strchr (pp, '\'')) && buflen > 3) { - len = strlen (pp++); - memmove (pp + 3, pp, len); - *pp++ = '\\'; - *pp++ = '\''; - *pp++ = '\''; - buflen -= 3; - bp += 3; - } - /* If pp is still set, that means we ran out of space. */ - if (pp) - buflen = 0; - if (!quoted && buflen) { - *bp++ = '\''; - *bp = '\0'; - buflen--; - } - } - } else { + case 'l': + /* + ** display listing prior to displaying content + */ + xlist = !nolist; + break; + + case 's': + /* insert subtype of content */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + len = strlen(bp); + bp += len; + buflen -= len; + + /* Did we actually insert something? */ + if (bp != pp) { + /* + ** Insert single quote if not inside quotes + ** already + */ + if (!quoted && buflen) { + len = strlen(pp); + memmove(pp + 1, pp, len); + *pp++ = '\''; + buflen--; + bp++; + } + /* Escape existing quotes */ + while ((pp = strchr(pp, '\'')) && buflen > 3) { + len = strlen(pp++); + memmove(pp + 3, pp, len); + *pp++ = '\\'; + *pp++ = '\''; + *pp++ = '\''; + buflen -= 3; + bp += 3; + } + /* + ** If pp is still set, that means we ran + ** out of space. + */ + if (pp) + buflen = 0; + if (!quoted && buflen) { + *bp++ = '\''; + *bp = '\0'; + buflen--; + } + } + } else { raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; + *bp++ = *cp; + *bp = '\0'; + buflen--; - if (*cp == '\'') - quoted = !quoted; + if (*cp == '\'') + quoted = !quoted; + } } - } - - if (buflen <= 0 || (ct->c_termproc && buflen <= strlen(ct->c_termproc))) { - /* content_error would provide a more useful error message - * here, except that if we got overrun, it probably would - * too. - */ - fprintf(stderr, "Buffer overflow constructing show command!\n"); - return NOTOK; - } - - /* use charset string to modify display method */ - if (ct->c_termproc) { - char term[BUFSIZ]; - strncpy (term, buffer, sizeof(term)); - snprintf (buffer, sizeof(buffer), ct->c_termproc, term); - } - - return show_content_aux2 (ct, serial, alternate, NULL, buffer, - NOTOK, xlist, xpause, 0, xtty); + return show_content_aux2(ct, alternate, NULL, buffer, + NOTOK, xlist, 0); } /* - * show content of type "message/rfc822" - */ +** show content of type "message/rfc822" +*/ static int -show_message_rfc822 (CT ct, int serial, int alternate) +show_message_rfc822(CT ct, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - if ((cp = ct->c_showproc)) - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* default method for message/rfc822 */ - if (ct->c_subtype == MESSAGE_RFC822) { - cp = (ct->c_showproc = add ("%pshow -file '%F'", NULL)); - return show_content_aux (ct, serial, alternate, cp, NULL); - } - - /* complain if we are not a part of a multipart/alternative */ - if (!alternate) - content_error (NULL, ct, "don't know how to display content"); - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s", + ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, alternate, cp, NULL); + + if ((cp = ct->c_showproc)) + return show_content_aux(ct, alternate, cp, NULL); + + /* default method for message/rfc822 */ + if (ct->c_subtype == MESSAGE_RFC822) { + cp = (ct->c_showproc = getcpy("%lshow -file %F")); + return show_content_aux(ct, alternate, cp, NULL); + } + + /* complain if we are not a part of a multipart/alternative */ + if (!alternate) + return show_content_aux(ct, alternate, "%l", NULL); + + return NOTOK; } /* - * Show content of type "message/partial". - */ +** Show content of type "message/partial". +*/ static int -show_partial (CT ct, int serial, int alternate) +show_partial(CT ct, int alternate) { - content_error (NULL, ct, - "in order to display this message, you must reassemble it"); - return NOTOK; + show_content_aux(ct, alternate, "%l", NULL); + puts("in order to display this message, you must reassemble it"); + return NOTOK; } /* - * Show content of type "message/external". - * - * THE ERROR CHECKING IN THIS ONE IS NOT DONE YET. - */ - +** Show how to retrieve content of type "message/external". +*/ static int -show_external (CT ct, int serial, int alternate) +show_external(CT ct, int alternate) { - struct exbody *e = (struct exbody *) ct->c_ctparams; - CT p = e->eb_content; - - if (!type_ok (p, 0)) + char **ap, **ep; + char *msg; + FILE *fp; + char buf[BUFSIZ]; + + msg = add("You need to fetch the contents yourself:\n", NULL); + ap = ct->c_ctinfo.ci_attrs; + ep = ct->c_ctinfo.ci_values; + for (; *ap; ap++, ep++) { + msg = add(concat("\t", *ap, ": ", *ep, NULL), msg); + } + if (!(fp = fopen(ct->c_file, "r"))) { + adios(ct->c_file, "unable to open"); + } + fseek(fp, ct->c_begin, SEEK_SET); + while (!feof(fp) && ftell(fp) < ct->c_end) { + if (!fgets(buf, sizeof buf, fp)) { + adios(ct->c_file, "unable to read"); + } + *strchr(buf, '\n') = '\0'; + if (!*buf) { + continue; /* skip empty lines */ + } + msg = add(concat("\t", buf, "\n", NULL), msg); + } + fclose(fp); + show_content_aux(ct, alternate, "%l", NULL); + fputs(msg, stdout); return OK; - - return show_switch (p, serial, alternate); - -#if 0 - content_error (NULL, p, "don't know how to display content"); - return NOTOK; -#endif -} - - -static RETSIGTYPE -intrser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGINT, intrser); -#endif - - putchar ('\n'); - siglongjmp (intrenv, DONE); } diff --git a/uip/mhsign.sh b/uip/mhsign.sh new file mode 100755 index 0000000..e6f54b3 --- /dev/null +++ b/uip/mhsign.sh @@ -0,0 +1,312 @@ +#!/bin/sh +# Based on mhsign 1.1.0.9 2007/05/30 14:48:40 by Neil Rickert +# Adjusted to mmh by markus schnalke , 2012-07 + + +# mhsign: +# -encrypt: Encrypt to recipients of message. This implies signing. +# -mime: Use MIME pgp standard. For signature, trailing blanks +# will be removed and any "From " line will be indented for +# best compatibility. Enforced for multipart messages. + +usage="Usage: mhsign [-encrypt] [-mime] file" + +# defaults +usemime=n +function=sign + + +# find out the signing key +userid="$MMHPGPKEY" +if [ "x$userid" = "x" ] ; then + userid="`mhparam pgpkey`" +fi +userid="`gpg --list-secret-keys --with-colons 2>/dev/null | + sed -n '/^sec/{p;q;}' | cut -d: -f5`" +if [ "x$userid" = x ] ; then + echo "No secret key found" >&2 + exit 1 +fi + +# find out the file of recipient key exceptions (for encrypt only) +keyfile="${MMH:-$HOME/.mmh}/pgpkeys" +if [ ! -r "$keyfile" ] ; then + keyfile="${GNUPGHOME:-$HOME/.gnupg}/pgpkeys" + if [ ! -r "$keyfile" ] ; then + keyfile=/dev/null + fi +fi + +# prepend the default options from the profile +set -- `mhparam -nocomp ${0##*/}` "$@" + +while : ; do + case "$1" in + -e*) + function=encrypt + ;; + -m*) + usemime=y + ;; + -V*) + echo "mhsign has no own version number, thus this instead:" + folder -Version + exit 0 + ;; + -h*|-*) + echo "$usage" >&2 + exit 1 + ;; + *) + break + esac + shift +done + +if [ $# -ne 1 ] ; then + echo "$usage" >&2 + exit 1 +fi + +TEMP=/tmp/${0##*/}.$$ +umask 077 +mkdir $TEMP || exit 1 +trap "rm -rf $TEMP" 0 1 2 15 + +### lookupkeyfile address -- lookup one address in our database +lookupkeyfile() { + key=`grep -i "^[^#].*[ ]$1\$" "$keyfile" 2>/dev/null` + if [ $? != 0 ] ; then + return 1 + fi + echo "$key" | sed 's/[ ].*//;q' + return 0 +} + +### lookupkeyring address -- lookup one address in keyring +lookupkeyring() { + key=`gpg --list-keys --with-colons "<$1>" 2>/dev/null` + if [ $? != 0 ] ; then + return 1 + fi + echo "$key" | sed -n '/^pub/{p;q;}' | cut -d: -f5 + return 0 +} + +### lookupkeys file -- set $KL to list of recipient keys +lookupkeys() { + KL= + status=0 + if whom -ali -notocc -bcc "$1" >/dev/null ; then + echo "Encryption is not supported for BCCs" >&2 + return 1 + fi + + for i in `whom -ali -tocc -nobcc "$1"` ; do + case "$i" in + '|'*) echo "Ignoring pipe address" >&2 + continue ;; + *@*) ;; + *) i="$i@`hostname -f`" ;; + esac + if k=`lookupkeyfile "$i"` ; then + KL="$KL $k" + elif k=`lookupkeyring "$i"` ; then + KL="$KL $k" + else + echo "Could not find key for <$i>" >&2 + status=1 + fi + done + return $status +} + +### getheader headername msgfile +getheader() { + HDR=`sed -n -e '/^-*$/q' -e 's/^\([^ :]*\):.*/\1/p' $2 | + grep -i '^'"$1"'$' | head -1` + if [ "$HDR" = "" ] ; then return 1 ; fi + sed -n -e ':a + /^-*$/q + /^'"$HDR"':/b x + d + b a + :x + p + n + /^[ ]/b x + b a' $2 + return 0 +} + +### headbody msgfile # separate msgfile into $TEMP/head $TEMP/body +headbody() { + sed -n '1,/^\-*$/p' "$1" > $TEMP/head + sed '1,/^-*$/d' "$1" > $TEMP/body +} + +### fixheaders -- remove Content headers, add newheaders +fixheaders() { + sed -n ':a + /^-*$/q + /^[Cc][Oo][Nn][Tt][Ee][Nn][Tt]-/b r + p + n + b a + :r + n + /^[ ]/b r + b a' $TEMP/head + cat $TEMP/newheaders + grep "^-" $TEMP/head || echo "" +} + +### newboundary -- output a suitable boundary marker +newboundary() { + b=$$_`date|sed 's/[ : ]/_/g'` + for i in 0 x '=' _ + , Z 9 4 ; do + if grep "^--$b" $TEMP/body >/dev/null 2>&1 ; then + ## oops, bad boundary -- try again + b=`echo $i$b | tr \ +'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456780=+,_' \ +'3Ba+c98bdACmzXpqR,tTuMDSs_hLkwZ0ef7PQrW=2x5l6E14ZKivIVgOjoJnGNUyHF'` + else + echo "$b" + return 0 + fi + done + echo "Failed to generate unique mime boundary" >&2 + exit 1 +} + +### detachsign -- sign $TEMP/body, output in $TEMP/body.asc +detachsign() { + gpg -u "$userid" --armor --textmode --detach-sign \ + <$TEMP/body >$TEMP/body.asc +} + +### sign --- inline signature for $TEMP/body, output in $TEMP/body.asc +sign() { + gpg -u "$userid" --armor --textmode --clearsign \ + <$TEMP/body >$TEMP/body.asc +} + +### encrypt recipients -- encrypt $TEMP/body to recipients +encrypt() { + R= + for i in $KL ; do + R="$R -r $i" + done + gpg --no-encrypt-to -u "$userid" --armor --textmode \ + --always-trust --output $TEMP/body.asc \ + -r "$userid" $R --sign --encrypt $TEMP/body +} + +### Mainline processing + +FILE="$1" ## we assume a disk file +if [ ! -r "$FILE" ] ; then + echo "cannot read $FILE" >&2 + exit 1 +fi + +case "$function" in +encrypt) + lookupkeys "$FILE" || exit 1 +esac + +cp "$FILE" "$FILE.orig" +outfile="$FILE" +headbody "$FILE" + +CT="" +if grep -i "^mime-version:" $TEMP/head >/dev/null 2>&1 ; then + >$TEMP/newheaders + if CT=`getheader content-type $TEMP/head` ; then + echo "$CT" >$TEMP/newbody + if grep -i multipart $TEMP/newbody >/dev/null 2>&1 ; then + usemime=y # Force MIME if already multi-part + fi + getheader content-transfer-encoding $TEMP/head \ + >>$TEMP/newbody || : + else + CT="" + fi +else + echo "Mime-Version: 1.0" >$TEMP/newheaders +fi + +if [ "$usemime" = n ] ; then + ### non-MIME ### + case "$function" in + sign) + sign || exit 1 ;; + encrypt) + encrypt || exit 1 ;; + esac + cat $TEMP/head $TEMP/body.asc >$outfile || exit 1 + exit 0 +fi + +### MIME ### + +BDRY="`newboundary`" + +if [ "$CT" = "" ] ; then + echo "Content-Type: text/plain; charset=us-ascii" >$TEMP/newbody +fi +echo >>$TEMP/newbody + +case $function in +sign) + sed 's/^From / &/; s/[ ]*$//' $TEMP/body >>$TEMP/newbody + if grep "^From " $TEMP/body >/dev/null 2>&1 ; then + echo 'Warning: "From " lines in message body have been indented' >&2 + fi + if grep "[ ]$" $TEMP/body >/dev/null 2>&1 ; then + echo 'Warning: trailing blanks removed from message body' >&2 + fi + echo 'Content-Type: multipart/signed; protocol="application/pgp-signature";' >>$TEMP/newheaders + echo " micalg=pgp-sha1"'; boundary="'"$BDRY"'"' >>$TEMP/newheaders + + sed -e 's/$/ /' "$TEMP/newbody" >"$TEMP/body" + detachsign || exit 1 + ( + echo "--$BDRY" + cat $TEMP/newbody + echo + echo "--$BDRY" + echo "Content-Type: application/pgp-signature" + echo + cat $TEMP/body.asc + echo + echo "--$BDRY--" + echo + ) >$TEMP/body + ;; + +encrypt) + cat $TEMP/body >>$TEMP/newbody + echo 'Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";' >>$TEMP/newheaders + echo " boundary=\"$BDRY\"" >> $TEMP/newheaders + + mv $TEMP/newbody $TEMP/body || exit 1 + encrypt || exit 1 + ( + echo "--$BDRY" + echo "Content-Type: application/pgp-encrypted" + echo + echo "Version: 1" + echo + echo "--$BDRY" + echo "Content-Type: application/octet-stream" + echo + cat $TEMP/body.asc + echo + echo "--$BDRY--" + echo + ) >"$TEMP/body" + ;; +esac + +fixheaders | cat - $TEMP/body >"$outfile" diff --git a/uip/mhstore.c b/uip/mhstore.c index 7b44a96..ae812ad 100644 --- a/uip/mhstore.c +++ b/uip/mhstore.c @@ -1,78 +1,45 @@ - /* - * mhstore.c -- store the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhstore.c -- store the contents of MIME messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include +#include #include -#include #include #include #include -#include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - static struct swit switches[] = { -#define AUTOSW 0 - { "auto", 0 }, -#define NAUTOSW 1 - { "noauto", 0 }, -#define CHECKSW 2 - { "check", 0 }, -#define NCHECKSW 3 - { "nocheck", 0 }, -#define VERBSW 4 - { "verbose", 0 }, -#define NVERBSW 5 - { "noverbose", 0 }, -#define FILESW 6 /* interface from show */ - { "file file", 0 }, -#define PARTSW 7 - { "part number", 0 }, -#define TYPESW 8 - { "type content", 0 }, -#define RCACHESW 9 - { "rcache policy", 0 }, -#define WCACHESW 10 - { "wcache policy", 0 }, -#define VERSIONSW 11 - { "version", 0 }, -#define HELPSW 12 - { "help", 0 }, - -/* - * switches for debugging - */ -#define DEBUGSW 13 - { "debug", -5 }, - { NULL, 0 } +#define AUTOSW 0 + { "auto", 0 }, +#define NAUTOSW 1 + { "noauto", 2 }, +#define FILESW 2 /* interface from show */ + { "file file", 0 }, +#define PARTSW 3 + { "part number", 0 }, +#define TYPESW 4 + { "type content", 0 }, +#define VERSIONSW 5 + { "Version", 0 }, +#define HELPSW 6 + { "help", 0 }, +#define DEBUGSW 7 + { "debug", -5 }, + { NULL, 0 } }; /* mhparse.c */ -extern char *tmp; /* directory to place temp files */ - -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; - -/* mhstoresbr.c */ -extern int autosw; -extern char *cwd; /* cache current working directory */ +extern char *tmp; /* directory to place temp files */ /* mhmisc.c */ extern int npart; @@ -82,321 +49,1212 @@ extern char *types[NTYPES + 1]; extern int userrs; int debugsw = 0; -int verbosw = 0; -#define quitser pipeser +#define quitser pipeser /* mhparse.c */ -CT parse_mime (char *); +CT parse_mime(char *); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -void flush_errors (void); - -/* mhstoresbr.c */ -void store_all_messages (CT *); +int part_ok(CT, int); +int type_ok(CT, int); +void set_endian(void); +void flush_errors(void); /* mhfree.c */ -void free_content (CT); -extern CT *cts; -void freects_done (int) NORETURN; +void free_content(CT); +extern CT *cts; /* The list of top-level contents to display */ +void freects_done(int) NORETURN; /* - * static prototypes - */ -static RETSIGTYPE pipeser (int); +** static prototypes +*/ +static void pipeser(int); + +int autosw = 1; + +/* +** Cache of current directory. This must be +** set before these routines are called. +*/ +char *cwd; + +/* +** The directory in which to store the contents. +*/ +static char *dir; + +/* +** Type for a compare function for qsort. This keeps +** the compiler happy. +*/ +typedef int (*qsort_comp) (const void *, const void *); + + +/* mhmisc.c */ +int part_ok(CT, int); +int type_ok(CT, int); +int make_intermediates(char *); +void flush_errors(void); + +/* mhshowsbr.c */ +int show_content_aux(CT, int, char *, char *); + +/* +** static prototypes +*/ +static void store_single_message(CT); +static int store_switch(CT); +static int store_generic(CT); +static int store_multi(CT); +static int store_partial(CT); +static int store_external(CT); +static int ct_compar(CT *, CT *); +static int store_content(CT, CT); +static int output_content_file(CT, int); +static int output_content_folder(char *, char *); +static int parse_format_string(CT, char *, char *, int, char *); +static int copy_some_headers(FILE *, CT); +static void store_all_messages(CT *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgnum, *icachesw; - char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp = NULL; - CT ct, *ctp; - FILE *fp; - - done=freects_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case AUTOSW: - autosw++; - continue; - case NAUTOSW: - autosw = 0; - continue; - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; -do_cache: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); + int msgnum; + char *cp, *file = NULL, *folder = NULL; + char *maildir, buf[100], **argp; + char **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp = NULL; + CT ct, *ctp; + FILE *fp; + + done=freects_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case AUTOSW: + autosw++; + continue; + case NAUTOSW: + autosw = 0; + continue; + + case PARTSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (npart >= NPARTS) + adios(NULL, "too many parts (starting with %s), %d max", cp, NPARTS); + parts[npart++] = cp; + continue; + + case TYPESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + if (ntype >= NTYPES) + adios(NULL, "too many types (starting with %s), %d max", cp, NTYPES); + types[ntype++] = cp; + continue; + + case FILESW: + if (!(cp = *argp++) || (*cp == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + file = *cp == '-' ? cp : getcpy(expanddir(cp)); + continue; + + case DEBUGSW: + debugsw = 1; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + + /* null terminate the list of acceptable parts/types */ + parts[npart] = NULL; + types[ntype] = NULL; + + set_endian(); + + /* + ** Check if we've specified an additional profile + */ + if ((cp = getenv("MHSTORE"))) { + if ((fp = fopen(cp, "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); + } else { + admonish("", "unable to read $MHSTORE profile (%s)", + cp); + } + } + + /* + ** Read the standard profile setup + */ + if ((fp = fopen(cp = etcpath("mhn.defaults"), "r"))) { + readconfig((struct node **) 0, fp, cp, 0); + fclose(fp); + } + + /* + ** Cache the current directory before we do any chdirs()'s. + */ + cwd = getcpy(pwd()); + + /* + ** Check for storage directory. If specified, + ** then store temporary files there. Else we + ** store them in standard nmh directory. + */ + if ((cp = context_find(nmhstorage)) && *cp) + tmp = concat(cp, "/", invo_name, NULL); + else + tmp = getcpy(toabsdir(invo_name)); + + if (file && msgs.size) + adios(NULL, "cannot specify msg and file at same time!"); + + /* + ** check if message is coming from file + */ + if (file) { + if (!(cts = (CT *) calloc((size_t) 2, sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + if ((ct = parse_mime(file))) + *ctp++ = ct; + } else { + /* + ** message(s) are coming from a folder + */ + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + if (!(cts = (CT *) calloc((size_t) (mp->numsel + 1), + sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + char *msgnam; + + msgnam = m_name(msgnum); + if ((ct = parse_mime(msgnam))) + *ctp++ = ct; + } + } + } + + if (!*cts) + done(1); + + userrs = 1; + SIGNAL(SIGQUIT, quitser); + SIGNAL(SIGPIPE, pipeser); + + /* + ** Get the associated umask for the relevant contents. + */ + for (ctp = cts; *ctp; ctp++) { + struct stat st; + + ct = *ctp; + if (type_ok(ct, 1) && !ct->c_umask) { + if (stat(ct->c_file, &st) != NOTOK) + ct->c_umask = ~(st.st_mode & 0777); + else + ct->c_umask = ~m_gmprot(); + } + } + + /* + ** Store the message content + */ + store_all_messages(cts); + + /* Now free all the structures for the content */ + for (ctp = cts; *ctp; ctp++) + free_content(*ctp); + + free((char *) cts); + cts = NULL; + + /* If reading from a folder, do some updating */ + if (mp) { + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->hghsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ + } + + done(0); + return 1; +} + + +static void +pipeser(int i) +{ + if (i == SIGQUIT) { + unlink("core"); + fflush(stdout); + fprintf(stderr, "\n"); + fflush(stderr); + } + + done(1); + /* NOTREACHED */ +} + + +/* +** Main entry point to store content from a collection of messages. +*/ +static void +store_all_messages(CT *cts) +{ + CT ct, *ctp; + char *cp; + + /* + ** Check for the directory in which to + ** store any contents. + */ + if ((cp = context_find(nmhstorage)) && *cp) + dir = getcpy(cp); + else + dir = getcpy(cwd); + + for (ctp = cts; *ctp; ctp++) { + ct = *ctp; + store_single_message(ct); + } + + flush_errors(); +} + + +/* +** Entry point to store the content +** in a (single) message +*/ + +static void +store_single_message(CT ct) +{ + if (type_ok(ct, 1)) { + umask(ct->c_umask); + store_switch(ct); + if (ct->c_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + if (ct->c_ceclosefnx) + (*ct->c_ceclosefnx) (ct); + } +} + + +/* +** Switching routine to store different content types +*/ + +static int +store_switch(CT ct) +{ + switch (ct->c_type) { + case CT_MULTIPART: + return store_multi(ct); + break; + + case CT_MESSAGE: + switch (ct->c_subtype) { + case MESSAGE_PARTIAL: + return store_partial(ct); + break; + + case MESSAGE_EXTERNAL: + return store_external(ct); + + case MESSAGE_RFC822: default: - break; + return store_generic(ct); + break; + } + break; + + case CT_APPLICATION: + case CT_TEXT: + case CT_AUDIO: + case CT_IMAGE: + case CT_VIDEO: + return store_generic(ct); + break; + + default: + adios(NULL, "unknown content type %d", ct->c_type); + break; + } + + return OK; /* NOT REACHED */ +} + + +/* +** Generic routine to store a MIME content. +** (application, audio, video, image, text, message/rfc922) +*/ +static int +store_generic(CT ct) +{ + char **ap, **vp, *cp; + CI ci = &ct->c_ctinfo; + + /* + ** Check if the content specifies a filename in its MIME parameters. + ** Don't bother with this for type "message" + ** (only the "message" subtype "rfc822" will use store_generic). + */ + if (autosw && ct->c_type != CT_MESSAGE) { + /* + ** Check the attribute/value pairs, for the attribute "name". + ** If found, take the basename, do a few sanity checks and + ** copy the value into c_storeproc. + */ + for (ap = ci->ci_attrs, vp = ci->ci_values; *ap; ap++,vp++) { + if (mh_strcasecmp(*ap, "name")!=0) { + continue; + } + cp = mhbasename(*vp); + if (*cp && *cp!='.' && *cp!='|' && *cp!='!' && + !strchr(cp, '%')) { + /* filename looks good: use it */ + ct->c_storeproc = getcpy(cp); + } + break; + } + } + + return store_content(ct, NULL); +} + + +/* +** Store the content of a multipart message +*/ + +static int +store_multi(CT ct) +{ + int result; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + + result = NOTOK; + for (part = m->mp_parts; part; part = part->mp_next) { + CT p = part->mp_part; + + if (part_ok(p, 1) && type_ok(p, 1)) { + result = store_switch(p); + if (result == OK && ct->c_subtype == MULTI_ALTERNATE) + break; + } + } + + return result; +} + + +/* +** Reassemble and store the contents of a collection +** of messages of type "message/partial". +*/ + +static int +store_partial(CT ct) +{ + int cur, hi, i; + CT p, *ctp, *ctq; + CT *base; + struct partial *pm, *qm; + + qm = (struct partial *) ct->c_ctparams; + if (qm->pm_stored) + return OK; + + hi = i = 0; + for (ctp = cts; *ctp; ctp++) { + p = *ctp; + if (p->c_type == CT_MESSAGE && p->c_subtype == ct->c_subtype) { + pm = (struct partial *) p->c_ctparams; + if (!pm->pm_stored && + strcmp(qm->pm_partid, pm->pm_partid) + == 0) { + pm->pm_marked = pm->pm_partno; + if (pm->pm_maxno) + hi = pm->pm_maxno; + pm->pm_stored = 1; + i++; + } else + pm->pm_marked = 0; + } + } + + if (hi == 0) { + advise(NULL, "missing (at least) last part of multipart message"); + return NOTOK; + } + + if ((base = (CT *) calloc((size_t) (i + 1), sizeof(*base))) == NULL) + adios(NULL, "out of memory"); + + ctq = base; + for (ctp = cts; *ctp; ctp++) { + p = *ctp; + if (p->c_type == CT_MESSAGE && p->c_subtype == ct->c_subtype) { + pm = (struct partial *) p->c_ctparams; + if (pm->pm_marked) + *ctq++ = p; } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case PARTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (npart >= NPARTS) - adios (NULL, "too many parts (starting with %s), %d max", - cp, NPARTS); - parts[npart++] = cp; - continue; - - case TYPESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (ntype >= NTYPES) - adios (NULL, "too many types (starting with %s), %d max", - cp, NTYPES); - types[ntype++] = cp; - continue; - - case FILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - file = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case VERBSW: - verbosw = 1; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } } + *ctq = NULL; + + if (i > 1) + qsort((char *) base, i, sizeof(*base), (qsort_comp) ct_compar); + + cur = 1; + for (ctq = base; *ctq; ctq++) { + p = *ctq; + pm = (struct partial *) p->c_ctparams; + if (pm->pm_marked != cur) { + if (pm->pm_marked == cur - 1) { + admonish(NULL, "duplicate part %d of %d part multipart message", pm->pm_marked, hi); + continue; + } + +missing_part: + advise (NULL, "missing %spart %d of %d part multipart message", cur != hi ? "(at least) " : "", cur, hi); + goto losing; + } else + cur++; + } + if (hi != --cur) { + cur = hi; + goto missing_part; + } + + /* + ** Now cycle through the sorted list of messages of type + ** "message/partial" and save/append them to a file. + */ + + ctq = base; + ct = *ctq++; + if (store_content(ct, NULL) == NOTOK) { +losing: + free((char *) base); + return NOTOK; + } + + for (; *ctq; ctq++) { + p = *ctq; + if (store_content(p, ct) == NOTOK) + goto losing; + } + + free((char *) base); + return OK; +} + + +/* +** Show how to retrieve content of type "message/external". +*/ +static int +store_external(CT ct) +{ + char **ap, **ep; + char *msg; + FILE *fp; + char buf[BUFSIZ]; + + msg = add("You need to fetch the contents yourself:", NULL); + ap = ct->c_ctinfo.ci_attrs; + ep = ct->c_ctinfo.ci_values; + for (; *ap; ap++, ep++) { + msg = add(concat("\n\t", *ap, ": ", *ep, NULL), msg); + } + if (!(fp = fopen(ct->c_file, "r"))) { + adios(ct->c_file, "unable to open"); + } + fseek(fp, ct->c_begin, SEEK_SET); + while (!feof(fp) && ftell(fp) < ct->c_end) { + if (!fgets(buf, sizeof buf, fp)) { + adios(ct->c_file, "unable to read"); + } + *strchr(buf, '\n') = '\0'; + msg = add(concat("\n\t", buf, NULL), msg); + } + fclose(fp); + advise(NULL, msg); + return OK; +} + + +/* +** Compare the numbering from two different +** message/partials (needed for sorting). +*/ + +static int +ct_compar(CT *a, CT *b) +{ + struct partial *am = (struct partial *) ((*a)->c_ctparams); + struct partial *bm = (struct partial *) ((*b)->c_ctparams); + + return (am->pm_marked - bm->pm_marked); +} + + +/* +** Store contents of a message or message part to +** a folder, a file, the standard output, or pass +** the contents to a command. +** +** If the current content to be saved is a followup part +** to a collection of messages of type "message/partial", +** then field "p" is a pointer to the Content structure +** to the first message/partial in the group. +*/ + +static int +store_content(CT ct, CT p) +{ + int appending = 0, msgnum = 0; + int is_partial = 0, first_partial = 0; + int last_partial = 0; + char *cp, buffer[BUFSIZ]; + + /* + ** Do special processing for messages of + ** type "message/partial". + ** + ** We first check if this content is of type + ** "message/partial". If it is, then we need to check + ** whether it is the first and/or last in the group. + ** + ** Then if "p" is a valid pointer, it points to the Content + ** structure of the first partial in the group. So we copy + ** the file name and/or folder name from that message. In + ** this case, we also note that we will be appending. + */ + if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { + struct partial *pm = (struct partial *) ct->c_ctparams; + + /* Yep, it's a message/partial */ + is_partial = 1; + + /* But is it the first and/or last in the collection? */ + if (pm->pm_partno == 1) + first_partial = 1; + if (pm->pm_maxno && pm->pm_partno == pm->pm_maxno) + last_partial = 1; + + /* + ** If "p" is a valid pointer, then it points to the + ** Content structure for the first message in the group. + ** So we just copy the filename or foldername information + ** from the previous iteration of this function. + */ + if (p) { + appending = 1; + ct->c_storage = getcpy(p->c_storage); + + /* record the folder name */ + if (p->c_folder) { + ct->c_folder = getcpy(p->c_folder); + } + goto got_filename; + } + } + + /* + ** Get storage formatting string. + ** + ** 1) If we have storeproc defined, then use that + ** 2) Else check for a mhstore-store-/ entry + ** 3) Else check for a mhstore-store- entry + ** 4) Else if content is "message", use "+" (current folder) + ** 5) Else use string "%m%P.%s". + */ + if (!(cp = ct->c_storeproc) || !*cp) { + CI ci = &ct->c_ctinfo; + + snprintf(buffer, sizeof(buffer), "%s-store-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) == NULL || *cp == '\0') { + snprintf(buffer, sizeof(buffer), "%s-store-%s", + invo_name, ci->ci_type); + if ((cp = context_find(buffer)) == NULL || + *cp == '\0') { + cp = ct->c_type == CT_MESSAGE ? + "+" : "%m%P.%s"; + } + } + } + + /* + ** Check the beginning of storage formatting string + ** to see if we are saving content to a folder. + */ if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* null terminate the list of acceptable parts/types */ - parts[npart] = NULL; - types[ntype] = NULL; - - set_endian (); - - /* - * Check if we've specified an additional profile - */ - if ((cp = getenv ("MHSTORE"))) { - if ((fp = fopen (cp, "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); + char *tmpfilenam, *folder; + + /* Store content in temporary file for now */ + tmpfilenam = m_mktemp(invo_name, NULL, NULL); + ct->c_storage = getcpy(tmpfilenam); + + /* Get the folder name */ + if (cp[1]) + folder = getcpy(expandfol(cp)); + else + folder = getcurfol(); + + /* Check if folder exists */ + create_folder(toabsdir(folder), 0, exit); + + /* Record the folder name */ + ct->c_folder = getcpy(folder); + + if (cp[1]) + free(folder); + + goto got_filename; + } + + /* + ** Parse and expand the storage formatting string + ** in `cp' into `buffer'. + */ + parse_format_string(ct, cp, buffer, sizeof(buffer), dir); + + /* + ** If formatting begins with '|' or '!', then pass + ** content to standard input of a command and return. + */ + if (buffer[0] == '|' || buffer[0] == '!') + return show_content_aux(ct, 0, buffer + 1, dir); + + /* record the filename */ + ct->c_storage = getcpy(buffer); + +got_filename: + /* flush the output stream */ + fflush(stdout); + + /* Now save or append the content to a file */ + if (output_content_file(ct, appending) == NOTOK) + return NOTOK; + + /* + ** If necessary, link the file into a folder and remove + ** the temporary file. If this message is a partial, + ** then only do this if it is the last one in the group. + */ + if (ct->c_folder && (!is_partial || last_partial)) { + msgnum = output_content_folder(ct->c_folder, ct->c_storage); + unlink(ct->c_storage); + if (msgnum == NOTOK) + return NOTOK; + } + + /* + ** Now print out the name/number of the message + ** that we are storing. + */ + if (is_partial) { + if (first_partial) + fprintf(stderr, "reassembling partials "); + if (last_partial) + fprintf(stderr, "%s", ct->c_file); + else + fprintf(stderr, "%s,", ct->c_file); + } else { + fprintf(stderr, "storing message %s", ct->c_file); + if (ct->c_partno) + fprintf(stderr, " part %s", ct->c_partno); + } + + /* + ** Unless we are in the "middle" of group of message/partials, + ** we now print the name of the file, folder, and/or message + ** to which we are storing the content. + */ + if (!is_partial || last_partial) { + if (ct->c_folder) { + fprintf(stderr, " to folder %s as message %d\n", + ct->c_folder, msgnum); + } else if (strcmp(ct->c_storage, "-")==0) { + fprintf(stderr, " to stdout\n"); + } else { + int cwdlen; + + cwdlen = strlen(cwd); + fprintf(stderr, " as file %s\n", + strncmp(ct->c_storage, cwd, + cwdlen)!=0 || + ct->c_storage[cwdlen] != '/' ? + ct->c_storage : + ct->c_storage + cwdlen + 1); + } + } + + return OK; +} + + +/* +** Output content to a file +*/ + +static int +output_content_file(CT ct, int appending) +{ + int filterstate; + char *file, buffer[BUFSIZ]; + long pos, last; + FILE *fp; + + /* + ** If the pathname contains directories, make sure + ** all of them exist. + */ + if (strchr(ct->c_storage, '/') && make_intermediates(ct->c_storage) + == NOTOK) + return NOTOK; + + if (ct->c_encoding != CE_7BIT) { + int cc, fd; + + if (!ct->c_ceopenfnx) { + advise(NULL, "don't know how to decode part %s of message %s", ct->c_partno, ct->c_file); + return NOTOK; + } + + file = appending || strcmp(ct->c_storage, "-")==0 ? + NULL : ct->c_storage; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; + if (strcmp(file, ct->c_storage)==0) { + (*ct->c_ceclosefnx) (ct); + return OK; + } + + /* + ** Send to standard output + */ + if (strcmp(ct->c_storage, "-")==0) { + int gd; + + if ((gd = dup(fileno(stdout))) == NOTOK) { + advise("stdout", "unable to dup"); +losing: + (*ct->c_ceclosefnx) (ct); + return NOTOK; + } + if ((fp = fdopen(gd, appending ? "a" : "w")) == NULL) { + advise("stdout", "unable to fdopen (%d, \"%s\") from", gd, appending ? "a" : "w"); + close(gd); + goto losing; + } + } else { + /* + ** Open output file + */ + if ((fp = fopen(ct->c_storage, appending ? "a" : "w")) + == NULL) { + advise(ct->c_storage, "unable to fopen for %s", + appending ? + "appending" : "writing"); + goto losing; + } + } + + /* + ** Filter the header fields of the initial enclosing + ** message/partial into the file. + */ + if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { + struct partial *pm = (struct partial *) ct->c_ctparams; + + if (pm->pm_partno == 1) + copy_some_headers(fp, ct); + } + + for (;;) { + switch (cc = read(fd, buffer, sizeof(buffer))) { + case NOTOK: + advise(file, "error reading content from"); + break; + + case OK: + break; + + default: + fwrite(buffer, sizeof(*buffer), cc, fp); + continue; + } + break; + } + + (*ct->c_ceclosefnx) (ct); + + if (cc != NOTOK && fflush(fp)) + advise(ct->c_storage, "error writing to"); + + fclose(fp); + + return (cc != NOTOK ? OK : NOTOK); + } + + if (!ct->c_fp && (ct->c_fp = fopen(ct->c_file, "r")) == NULL) { + advise(ct->c_file, "unable to open for reading"); + return NOTOK; + } + + pos = ct->c_begin; + last = ct->c_end; + fseek(ct->c_fp, pos, SEEK_SET); + + if (strcmp(ct->c_storage, "-")==0) { + int gd; + + if ((gd = dup(fileno(stdout))) == NOTOK) { + advise("stdout", "unable to dup"); + return NOTOK; + } + if ((fp = fdopen(gd, appending ? "a" : "w")) == NULL) { + advise("stdout", "unable to fdopen (%d, \"%s\") from", + gd, appending ? "a" : "w"); + close(gd); + return NOTOK; + } + } else { + if ((fp = fopen(ct->c_storage, appending ? "a" : "w")) + == NULL) { + advise(ct->c_storage, "unable to fopen for %s", + appending ? "appending" : "writing"); + return NOTOK; + } + } + + /* + ** Copy a few of the header fields of the initial + ** enclosing message/partial into the file. + */ + filterstate = 0; + if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { + struct partial *pm = (struct partial *) ct->c_ctparams; + + if (pm->pm_partno == 1) { + copy_some_headers(fp, ct); + filterstate = 1; + } + } + + while (fgets(buffer, sizeof(buffer) - 1, ct->c_fp)) { + if ((pos += strlen(buffer)) > last) { + int diff; + + diff = strlen(buffer) - (pos - last); + if (diff >= 0) + buffer[diff] = '\0'; + } + /* + ** If this is the first content of a group of + ** message/partial contents, then we only copy a few + ** of the header fields of the enclosed message. + */ + if (filterstate) { + switch (buffer[0]) { + case ' ': + case '\t': + if (filterstate < 0) + buffer[0] = 0; + break; + + case '\n': + filterstate = 0; + break; + + default: + if (!uprf(buffer, XXX_FIELD_PRF) && !uprf(buffer, VRSN_FIELD) && !uprf(buffer, "Subject:") && !uprf(buffer, "Message-ID:")) { + filterstate = -1; + buffer[0] = 0; + break; + } + filterstate = 1; + break; + } + } + fputs(buffer, fp); + if (pos >= last) + break; + } + + if (fflush(fp)) + advise(ct->c_storage, "error writing to"); + + fclose(fp); + fclose(ct->c_fp); + ct->c_fp = NULL; + return OK; +} + + +/* +** Add a file to a folder. +** +** Return the new message number of the file +** when added to the folder. Return -1, if +** there is an error. +*/ + +static int +output_content_folder(char *folder, char *filename) +{ + int msgnum; + struct msgs *mp; + + /* Read the folder. */ + if ((mp = folder_read(folder))) { + /* Link file into folder */ + msgnum = folder_addmsg(&mp, filename, 0, 0, 0, 0, NULL); } else { - admonish ("", "unable to read $MHSTORE profile (%s)", cp); - } - } - - /* - * Read the standard profile setup - */ - if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); - fclose (fp); - } - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Cache the current directory before we do any chdirs()'s. - */ - cwd = getcpy (pwd()); - - /* - * Check for storage directory. If specified, - * then store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (file && msgs.size) - adios (NULL, "cannot specify msg and file at same time!"); - - /* - * check if message is coming from file - */ - if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - if ((ct = parse_mime (file))); - *ctp++ = ct; - } else { + advise(NULL, "unable to read folder %s", folder); + return NOTOK; + } + + /* free folder structure */ + folder_free(mp); + + /* + ** Return msgnum. We are relying on the fact that + ** msgnum will be -1, if folder_addmsg() had an error. + */ + return msgnum; +} + + +/* +** Parse and expand the storage formatting string +** pointed to by "cp" into "buffer". +*/ + +static int +parse_format_string(CT ct, char *cp, char *buffer, int buflen, char *dir) +{ + int len; + char *bp; + CI ci = &ct->c_ctinfo; + + /* + ** If storage string is "-", just copy it, and + ** return (send content to standard output). + */ + if (cp[0] == '-' && cp[1] == '\0') { + strncpy(buffer, cp, buflen); + return 0; + } + + bp = buffer; + bp[0] = '\0'; + /* - * message(s) are coming from a folder - */ - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - char *msgnam; - - msgnam = m_name (msgnum); - if ((ct = parse_mime (msgnam))) - *ctp++ = ct; - } - } - } - - if (!*cts) - done (1); - - userrs = 1; - SIGNAL (SIGQUIT, quitser); - SIGNAL (SIGPIPE, pipeser); - - /* - * Get the associated umask for the relevant contents. - */ - for (ctp = cts; *ctp; ctp++) { - struct stat st; - - ct = *ctp; - if (type_ok (ct, 1) && !ct->c_umask) { - if (stat (ct->c_file, &st) != NOTOK) - ct->c_umask = ~(st.st_mode & 0777); - else - ct->c_umask = ~m_gmprot(); - } - } - - /* - * Store the message content - */ - store_all_messages (cts); - - /* Now free all the structures for the content */ - for (ctp = cts; *ctp; ctp++) - free_content (*ctp); - - free ((char *) cts); - cts = NULL; - - /* If reading from a folder, do some updating */ - if (mp) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - done (0); - return 1; + ** If formatting string is a pathname that doesn't + ** begin with '/', then preface the path with the + ** appropriate directory. + */ + if (*cp != '/' && *cp != '|' && *cp != '!') { + snprintf(bp, buflen, "%s/", dir[1] ? dir : ""); + len = strlen(bp); + bp += len; + buflen -= len; + } + + for (; *cp; cp++) { + + /* We are processing a storage escape */ + if (*cp == '%') { + switch (*++cp) { + case 'a': + /* + ** Insert parameters from Content-Type. + ** This is only valid for '|' commands. + */ + if (buffer[0] != '|' && buffer[0] != '!') { + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } else { + char **ap, **ep; + char *s = ""; + + for (ap=ci->ci_attrs, ep=ci->ci_values; + *ap; ap++, ep++) { + snprintf(bp, buflen, + "%s%s=\"%s\"", + s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'm': + /* insert message number */ + snprintf(bp, buflen, "%s", + mhbasename(ct->c_file)); + break; + + case 'P': + /* insert part number with leading dot */ + if (ct->c_partno) + snprintf(bp, buflen, ".%s", + ct->c_partno); + break; + + case 'p': + /* insert part number withouth leading dot */ + if (ct->c_partno) + strncpy(bp, ct->c_partno, buflen); + break; + + case 't': + /* insert content type */ + strncpy(bp, ci->ci_type, buflen); + break; + + case 's': + /* insert content subtype */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert the character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + + /* Advance bp and decrement buflen */ + len = strlen(bp); + bp += len; + buflen -= len; + + } else { +raw: + *bp++ = *cp; + *bp = '\0'; + buflen--; + } + } + + return 0; } -static RETSIGTYPE -pipeser (int i) +/* +** Copy some of the header fields of the initial message/partial +** message into the header of the reassembled message. +*/ + +static int +copy_some_headers(FILE *out, CT ct) { - if (i == SIGQUIT) { - unlink ("core"); - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - done (1); - /* NOTREACHED */ + HF hp; + + hp = ct->c_first_hf; /* start at first header field */ + + while (hp) { + /* + ** A few of the header fields of the enclosing + ** messages are not copied. + */ + if (!uprf(hp->name, XXX_FIELD_PRF) && + mh_strcasecmp(hp->name, VRSN_FIELD) && + mh_strcasecmp(hp->name, "Subject") && + mh_strcasecmp(hp->name, "Message-ID")) + fprintf(out, "%s:%s", hp->name, hp->value); + hp = hp->next; /* next header field */ + } + + return OK; } diff --git a/uip/mhstoresbr.c b/uip/mhstoresbr.c deleted file mode 100644 index a1b5e2a..0000000 --- a/uip/mhstoresbr.c +++ /dev/null @@ -1,1082 +0,0 @@ - -/* - * mhstoresbr.c -- routines to save/store the contents of MIME messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * The list of top-level contents to display - */ -extern CT *cts; - -int autosw = 0; - -/* - * Cache of current directory. This must be - * set before these routines are called. - */ -char *cwd; - -/* - * The directory in which to store the contents. - */ -static char *dir; - -/* - * Type for a compare function for qsort. This keeps - * the compiler happy. - */ -typedef int (*qsort_comp) (const void *, const void *); - - -/* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -int make_intermediates (char *); -void flush_errors (void); - -/* mhshowsbr.c */ -int show_content_aux (CT, int, int, char *, char *); - -/* - * prototypes - */ -void store_all_messages (CT *); - -/* - * static prototypes - */ -static void store_single_message (CT); -static int store_switch (CT); -static int store_generic (CT); -static int store_application (CT); -static int store_multi (CT); -static int store_partial (CT); -static int store_external (CT); -static int ct_compar (CT *, CT *); -static int store_content (CT, CT); -static int output_content_file (CT, int); -static int output_content_folder (char *, char *); -static int parse_format_string (CT, char *, char *, int, char *); -static void get_storeproc (CT); -static int copy_some_headers (FILE *, CT); - - -/* - * Main entry point to store content - * from a collection of messages. - */ - -void -store_all_messages (CT *cts) -{ - CT ct, *ctp; - char *cp; - - /* - * Check for the directory in which to - * store any contents. - */ - if (autosw) - dir = getcpy (cwd); - else if ((cp = context_find (nmhstorage)) && *cp) - dir = getcpy (cp); - else - dir = getcpy (cwd); - - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - store_single_message (ct); - } - - flush_errors (); -} - - -/* - * Entry point to store the content - * in a (single) message - */ - -static void -store_single_message (CT ct) -{ - if (type_ok (ct, 1)) { - umask (ct->c_umask); - store_switch (ct); - if (ct->c_fp) { - fclose (ct->c_fp); - ct->c_fp = NULL; - } - if (ct->c_ceclosefnx) - (*ct->c_ceclosefnx) (ct); - } -} - - -/* - * Switching routine to store different content types - */ - -static int -store_switch (CT ct) -{ - switch (ct->c_type) { - case CT_MULTIPART: - return store_multi (ct); - break; - - case CT_MESSAGE: - switch (ct->c_subtype) { - case MESSAGE_PARTIAL: - return store_partial (ct); - break; - - case MESSAGE_EXTERNAL: - return store_external (ct); - - case MESSAGE_RFC822: - default: - return store_generic (ct); - break; - } - break; - - case CT_APPLICATION: - return store_application (ct); - break; - - case CT_TEXT: - case CT_AUDIO: - case CT_IMAGE: - case CT_VIDEO: - return store_generic (ct); - break; - - default: - adios (NULL, "unknown content type %d", ct->c_type); - break; - } - - return OK; /* NOT REACHED */ -} - - -/* - * Generic routine to store a MIME content. - * (audio, video, image, text, message/rfc922) - */ - -static int -store_generic (CT ct) -{ - /* - * Check if the content specifies a filename. - * Don't bother with this for type "message" - * (only "message/rfc822" will use store_generic). - */ - if (autosw && ct->c_type != CT_MESSAGE) - get_storeproc (ct); - - return store_content (ct, NULL); -} - - -/* - * Store content of type "application" - */ - -static int -store_application (CT ct) -{ - char **ap, **ep; - CI ci = &ct->c_ctinfo; - - /* Check if the content specifies a filename */ - if (autosw) - get_storeproc (ct); - - /* - * If storeproc is not defined, and the content is type - * "application/octet-stream", we also check for various - * attribute/value pairs which specify if this a tar file. - */ - if (!ct->c_storeproc && ct->c_subtype == APPLICATION_OCTETS) { - int tarP = 0, zP = 0, gzP = 0; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - /* check for "type=tar" attribute */ - if (!mh_strcasecmp (*ap, "type")) { - if (mh_strcasecmp (*ep, "tar")) - break; - - tarP = 1; - continue; - } - - /* check for "conversions=compress" attribute */ - if ((!mh_strcasecmp (*ap, "conversions") || !mh_strcasecmp (*ap, "x-conversions")) - && (!mh_strcasecmp (*ep, "compress") || !mh_strcasecmp (*ep, "x-compress"))) { - zP = 1; - continue; - } - /* check for "conversions=gzip" attribute */ - if ((!mh_strcasecmp (*ap, "conversions") || !mh_strcasecmp (*ap, "x-conversions")) - && (!mh_strcasecmp (*ep, "gzip") || !mh_strcasecmp (*ep, "x-gzip"))) { - gzP = 1; - continue; - } - } - - if (tarP) { - ct->c_showproc = add (zP ? "%euncompress | tar tvf -" - : (gzP ? "%egzip -dc | tar tvf -" - : "%etar tvf -"), NULL); - if (!ct->c_storeproc) { - if (autosw) { - ct->c_storeproc = add (zP ? "| uncompress | tar xvpf -" - : (gzP ? "| gzip -dc | tar xvpf -" - : "| tar xvpf -"), NULL); - ct->c_umask = 0022; - } else { - ct->c_storeproc= add (zP ? "%m%P.tar.Z" - : (gzP ? "%m%P.tar.gz" - : "%m%P.tar"), NULL); - } - } - } - } - - return store_content (ct, NULL); -} - - -/* - * Store the content of a multipart message - */ - -static int -store_multi (CT ct) -{ - int result; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - - result = NOTOK; - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if (part_ok (p, 1) && type_ok (p, 1)) { - result = store_switch (p); - if (result == OK && ct->c_subtype == MULTI_ALTERNATE) - break; - } - } - - return result; -} - - -/* - * Reassemble and store the contents of a collection - * of messages of type "message/partial". - */ - -static int -store_partial (CT ct) -{ - int cur, hi, i; - CT p, *ctp, *ctq; - CT *base; - struct partial *pm, *qm; - - qm = (struct partial *) ct->c_ctparams; - if (qm->pm_stored) - return OK; - - hi = i = 0; - for (ctp = cts; *ctp; ctp++) { - p = *ctp; - if (p->c_type == CT_MESSAGE && p->c_subtype == ct->c_subtype) { - pm = (struct partial *) p->c_ctparams; - if (!pm->pm_stored - && strcmp (qm->pm_partid, pm->pm_partid) == 0) { - pm->pm_marked = pm->pm_partno; - if (pm->pm_maxno) - hi = pm->pm_maxno; - pm->pm_stored = 1; - i++; - } - else - pm->pm_marked = 0; - } - } - - if (hi == 0) { - advise (NULL, "missing (at least) last part of multipart message"); - return NOTOK; - } - - if ((base = (CT *) calloc ((size_t) (i + 1), sizeof(*base))) == NULL) - adios (NULL, "out of memory"); - - ctq = base; - for (ctp = cts; *ctp; ctp++) { - p = *ctp; - if (p->c_type == CT_MESSAGE && p->c_subtype == ct->c_subtype) { - pm = (struct partial *) p->c_ctparams; - if (pm->pm_marked) - *ctq++ = p; - } - } - *ctq = NULL; - - if (i > 1) - qsort ((char *) base, i, sizeof(*base), (qsort_comp) ct_compar); - - cur = 1; - for (ctq = base; *ctq; ctq++) { - p = *ctq; - pm = (struct partial *) p->c_ctparams; - if (pm->pm_marked != cur) { - if (pm->pm_marked == cur - 1) { - admonish (NULL, - "duplicate part %d of %d part multipart message", - pm->pm_marked, hi); - continue; - } - -missing_part: - advise (NULL, - "missing %spart %d of %d part multipart message", - cur != hi ? "(at least) " : "", cur, hi); - goto losing; - } - else - cur++; - } - if (hi != --cur) { - cur = hi; - goto missing_part; - } - - /* - * Now cycle through the sorted list of messages of type - * "message/partial" and save/append them to a file. - */ - - ctq = base; - ct = *ctq++; - if (store_content (ct, NULL) == NOTOK) { -losing: - free ((char *) base); - return NOTOK; - } - - for (; *ctq; ctq++) { - p = *ctq; - if (store_content (p, ct) == NOTOK) - goto losing; - } - - free ((char *) base); - return OK; -} - - -/* - * Store content from a message of type "message/external". - */ - -static int -store_external (CT ct) -{ - int result = NOTOK; - struct exbody *e = (struct exbody *) ct->c_ctparams; - CT p = e->eb_content; - - if (!type_ok (p, 1)) - return OK; - - /* - * Check if the parameters for the external body - * specified a filename. - */ - if (autosw) { - char *cp; - - if ((cp = e->eb_name) - && *cp != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { - if (!ct->c_storeproc) - ct->c_storeproc = add (cp, NULL); - if (!p->c_storeproc) - p->c_storeproc = add (cp, NULL); - } - } - - /* - * Since we will let the Content structure for the - * external body substitute for the current content, - * we temporarily change its partno (number inside - * multipart), so everything looks right. - */ - p->c_partno = ct->c_partno; - - /* we probably need to check if content is really there */ - result = store_switch (p); - - p->c_partno = NULL; - return result; -} - - -/* - * Compare the numbering from two different - * message/partials (needed for sorting). - */ - -static int -ct_compar (CT *a, CT *b) -{ - struct partial *am = (struct partial *) ((*a)->c_ctparams); - struct partial *bm = (struct partial *) ((*b)->c_ctparams); - - return (am->pm_marked - bm->pm_marked); -} - - -/* - * Store contents of a message or message part to - * a folder, a file, the standard output, or pass - * the contents to a command. - * - * If the current content to be saved is a followup part - * to a collection of messages of type "message/partial", - * then field "p" is a pointer to the Content structure - * to the first message/partial in the group. - */ - -static int -store_content (CT ct, CT p) -{ - int appending = 0, msgnum = 0; - int is_partial = 0, first_partial = 0; - int last_partial = 0; - char *cp, buffer[BUFSIZ]; - - /* - * Do special processing for messages of - * type "message/partial". - * - * We first check if this content is of type - * "message/partial". If it is, then we need to check - * whether it is the first and/or last in the group. - * - * Then if "p" is a valid pointer, it points to the Content - * structure of the first partial in the group. So we copy - * the file name and/or folder name from that message. In - * this case, we also note that we will be appending. - */ - if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { - struct partial *pm = (struct partial *) ct->c_ctparams; - - /* Yep, it's a message/partial */ - is_partial = 1; - - /* But is it the first and/or last in the collection? */ - if (pm->pm_partno == 1) - first_partial = 1; - if (pm->pm_maxno && pm->pm_partno == pm->pm_maxno) - last_partial = 1; - - /* - * If "p" is a valid pointer, then it points to the - * Content structure for the first message in the group. - * So we just copy the filename or foldername information - * from the previous iteration of this function. - */ - if (p) { - appending = 1; - ct->c_storage = add (p->c_storage, NULL); - - /* record the folder name */ - if (p->c_folder) { - ct->c_folder = add (p->c_folder, NULL); - } - goto got_filename; - } - } - - /* - * Get storage formatting string. - * - * 1) If we have storeproc defined, then use that - * 2) Else check for a mhn-store-/ entry - * 3) Else check for a mhn-store- entry - * 4) Else if content is "message", use "+" (current folder) - * 5) Else use string "%m%P.%s". - */ - if ((cp = ct->c_storeproc) == NULL || *cp == '\0') { - CI ci = &ct->c_ctinfo; - - snprintf (buffer, sizeof(buffer), "%s-store-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - snprintf (buffer, sizeof(buffer), "%s-store-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) == NULL || *cp == '\0') { - cp = ct->c_type == CT_MESSAGE ? "+" : "%m%P.%s"; - } - } - } - - /* - * Check the beginning of storage formatting string - * to see if we are saving content to a folder. - */ - if (*cp == '+' || *cp == '@') { - char *tmpfilenam, *folder; - - /* Store content in temporary file for now */ - tmpfilenam = m_mktemp(invo_name, NULL, NULL); - ct->c_storage = add (tmpfilenam, NULL); - - /* Get the folder name */ - if (cp[1]) - folder = pluspath (cp); - else - folder = getfolder (1); - - /* Check if folder exists */ - create_folder(m_mailpath(folder), 0, exit); - - /* Record the folder name */ - ct->c_folder = add (folder, NULL); - - if (cp[1]) - free (folder); - - goto got_filename; - } - - /* - * Parse and expand the storage formatting string - * in `cp' into `buffer'. - */ - parse_format_string (ct, cp, buffer, sizeof(buffer), dir); - - /* - * If formatting begins with '|' or '!', then pass - * content to standard input of a command and return. - */ - if (buffer[0] == '|' || buffer[0] == '!') - return show_content_aux (ct, 1, 0, buffer + 1, dir); - - /* record the filename */ - ct->c_storage = add (buffer, NULL); - -got_filename: - /* flush the output stream */ - fflush (stdout); - - /* Now save or append the content to a file */ - if (output_content_file (ct, appending) == NOTOK) - return NOTOK; - - /* - * If necessary, link the file into a folder and remove - * the temporary file. If this message is a partial, - * then only do this if it is the last one in the group. - */ - if (ct->c_folder && (!is_partial || last_partial)) { - msgnum = output_content_folder (ct->c_folder, ct->c_storage); - unlink (ct->c_storage); - if (msgnum == NOTOK) - return NOTOK; - } - - /* - * Now print out the name/number of the message - * that we are storing. - */ - if (is_partial) { - if (first_partial) - fprintf (stderr, "reassembling partials "); - if (last_partial) - fprintf (stderr, "%s", ct->c_file); - else - fprintf (stderr, "%s,", ct->c_file); - } else { - fprintf (stderr, "storing message %s", ct->c_file); - if (ct->c_partno) - fprintf (stderr, " part %s", ct->c_partno); - } - - /* - * Unless we are in the "middle" of group of message/partials, - * we now print the name of the file, folder, and/or message - * to which we are storing the content. - */ - if (!is_partial || last_partial) { - if (ct->c_folder) { - fprintf (stderr, " to folder %s as message %d\n", ct->c_folder, msgnum); - } else if (!strcmp(ct->c_storage, "-")) { - fprintf (stderr, " to stdout\n"); - } else { - int cwdlen; - - cwdlen = strlen (cwd); - fprintf (stderr, " as file %s\n", - strncmp (ct->c_storage, cwd, cwdlen) - || ct->c_storage[cwdlen] != '/' - ? ct->c_storage : ct->c_storage + cwdlen + 1); - } - } - - return OK; -} - - -/* - * Output content to a file - */ - -static int -output_content_file (CT ct, int appending) -{ - int filterstate; - char *file, buffer[BUFSIZ]; - long pos, last; - FILE *fp; - - /* - * If the pathname is absolute, make sure - * all the relevant directories exist. - */ - if (strchr(ct->c_storage, '/') - && make_intermediates (ct->c_storage) == NOTOK) - return NOTOK; - - if (ct->c_encoding != CE_7BIT) { - int cc, fd; - - if (!ct->c_ceopenfnx) { - advise (NULL, "don't know how to decode part %s of message %s", - ct->c_partno, ct->c_file); - return NOTOK; - } - - file = appending || !strcmp (ct->c_storage, "-") ? NULL - : ct->c_storage; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; - if (!strcmp (file, ct->c_storage)) { - (*ct->c_ceclosefnx) (ct); - return OK; - } - - /* - * Send to standard output - */ - if (!strcmp (ct->c_storage, "-")) { - int gd; - - if ((gd = dup (fileno (stdout))) == NOTOK) { - advise ("stdout", "unable to dup"); -losing: - (*ct->c_ceclosefnx) (ct); - return NOTOK; - } - if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) { - advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd, - appending ? "a" : "w"); - close (gd); - goto losing; - } - } else { - /* - * Open output file - */ - if ((fp = fopen (ct->c_storage, appending ? "a" : "w")) == NULL) { - advise (ct->c_storage, "unable to fopen for %s", - appending ? "appending" : "writing"); - goto losing; - } - } - - /* - * Filter the header fields of the initial enclosing - * message/partial into the file. - */ - if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { - struct partial *pm = (struct partial *) ct->c_ctparams; - - if (pm->pm_partno == 1) - copy_some_headers (fp, ct); - } - - for (;;) { - switch (cc = read (fd, buffer, sizeof(buffer))) { - case NOTOK: - advise (file, "error reading content from"); - break; - - case OK: - break; - - default: - fwrite (buffer, sizeof(*buffer), cc, fp); - continue; - } - break; - } - - (*ct->c_ceclosefnx) (ct); - - if (cc != NOTOK && fflush (fp)) - advise (ct->c_storage, "error writing to"); - - fclose (fp); - - return (cc != NOTOK ? OK : NOTOK); - } - - if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { - advise (ct->c_file, "unable to open for reading"); - return NOTOK; - } - - pos = ct->c_begin; - last = ct->c_end; - fseek (ct->c_fp, pos, SEEK_SET); - - if (!strcmp (ct->c_storage, "-")) { - int gd; - - if ((gd = dup (fileno (stdout))) == NOTOK) { - advise ("stdout", "unable to dup"); - return NOTOK; - } - if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) { - advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd, - appending ? "a" : "w"); - close (gd); - return NOTOK; - } - } else { - if ((fp = fopen (ct->c_storage, appending ? "a" : "w")) == NULL) { - advise (ct->c_storage, "unable to fopen for %s", - appending ? "appending" : "writing"); - return NOTOK; - } - } - - /* - * Copy a few of the header fields of the initial - * enclosing message/partial into the file. - */ - filterstate = 0; - if (ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_PARTIAL) { - struct partial *pm = (struct partial *) ct->c_ctparams; - - if (pm->pm_partno == 1) { - copy_some_headers (fp, ct); - filterstate = 1; - } - } - - while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) { - if ((pos += strlen (buffer)) > last) { - int diff; - - diff = strlen (buffer) - (pos - last); - if (diff >= 0) - buffer[diff] = '\0'; - } - /* - * If this is the first content of a group of - * message/partial contents, then we only copy a few - * of the header fields of the enclosed message. - */ - if (filterstate) { - switch (buffer[0]) { - case ' ': - case '\t': - if (filterstate < 0) - buffer[0] = 0; - break; - - case '\n': - filterstate = 0; - break; - - default: - if (!uprf (buffer, XXX_FIELD_PRF) - && !uprf (buffer, VRSN_FIELD) - && !uprf (buffer, "Subject:") - && !uprf (buffer, "Encrypted:") - && !uprf (buffer, "Message-ID:")) { - filterstate = -1; - buffer[0] = 0; - break; - } - filterstate = 1; - break; - } - } - fputs (buffer, fp); - if (pos >= last) - break; - } - - if (fflush (fp)) - advise (ct->c_storage, "error writing to"); - - fclose (fp); - fclose (ct->c_fp); - ct->c_fp = NULL; - return OK; -} - - -/* - * Add a file to a folder. - * - * Return the new message number of the file - * when added to the folder. Return -1, if - * there is an error. - */ - -static int -output_content_folder (char *folder, char *filename) -{ - int msgnum; - struct msgs *mp; - - /* Read the folder. */ - if ((mp = folder_read (folder))) { - /* Link file into folder */ - msgnum = folder_addmsg (&mp, filename, 0, 0, 0, 0, (char *)0); - } else { - advise (NULL, "unable to read folder %s", folder); - return NOTOK; - } - - /* free folder structure */ - folder_free (mp); - - /* - * Return msgnum. We are relying on the fact that - * msgnum will be -1, if folder_addmsg() had an error. - */ - return msgnum; -} - - -/* - * Parse and expand the storage formatting string - * pointed to by "cp" into "buffer". - */ - -static int -parse_format_string (CT ct, char *cp, char *buffer, int buflen, char *dir) -{ - int len; - char *bp; - CI ci = &ct->c_ctinfo; - - /* - * If storage string is "-", just copy it, and - * return (send content to standard output). - */ - if (cp[0] == '-' && cp[1] == '\0') { - strncpy (buffer, cp, buflen); - return 0; - } - - bp = buffer; - bp[0] = '\0'; - - /* - * If formatting string is a pathname that doesn't - * begin with '/', then preface the path with the - * appropriate directory. - */ - if (*cp != '/' && *cp != '|' && *cp != '!') { - snprintf (bp, buflen, "%s/", dir[1] ? dir : ""); - len = strlen (bp); - bp += len; - buflen -= len; - } - - for (; *cp; cp++) { - - /* We are processing a storage escape */ - if (*cp == '%') { - switch (*++cp) { - case 'a': - /* - * Insert parameters from Content-Type. - * This is only valid for '|' commands. - */ - if (buffer[0] != '|' && buffer[0] != '!') { - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } else { - char **ap, **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; - *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; - } - } - break; - - case 'm': - /* insert message number */ - snprintf (bp, buflen, "%s", r1bindex (ct->c_file, '/')); - break; - - case 'P': - /* insert part number with leading dot */ - if (ct->c_partno) - snprintf (bp, buflen, ".%s", ct->c_partno); - break; - - case 'p': - /* insert part number withouth leading dot */ - if (ct->c_partno) - strncpy (bp, ct->c_partno, buflen); - break; - - case 't': - /* insert content type */ - strncpy (bp, ci->ci_type, buflen); - break; - - case 's': - /* insert content subtype */ - strncpy (bp, ci->ci_subtype, buflen); - break; - - case '%': - /* insert the character % */ - goto raw; - - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - - /* Advance bp and decrement buflen */ - len = strlen (bp); - bp += len; - buflen -= len; - - } else { -raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; - } - } - - return 0; -} - - -/* - * Check if the content specifies a filename - * in its MIME parameters. - */ - -static void -get_storeproc (CT ct) -{ - char **ap, **ep, *cp; - CI ci = &ct->c_ctinfo; - - /* - * If the storeproc has already been defined, - * we just return (for instance, if this content - * is part of a "message/external". - */ - if (ct->c_storeproc) - return; - - /* - * Check the attribute/value pairs, for the attribute "name". - * If found, do a few sanity checks and copy the value into - * the storeproc. - */ - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - if (!mh_strcasecmp (*ap, "name") - && *(cp = *ep) != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { - ct->c_storeproc = add (cp, NULL); - return; - } - } -} - - -/* - * Copy some of the header fields of the initial message/partial - * message into the header of the reassembled message. - */ - -static int -copy_some_headers (FILE *out, CT ct) -{ - HF hp; - - hp = ct->c_first_hf; /* start at first header field */ - - while (hp) { - /* - * A few of the header fields of the enclosing - * messages are not copied. - */ - if (!uprf (hp->name, XXX_FIELD_PRF) - && mh_strcasecmp (hp->name, VRSN_FIELD) - && mh_strcasecmp (hp->name, "Subject") - && mh_strcasecmp (hp->name, "Encrypted") - && mh_strcasecmp (hp->name, "Message-ID")) - fprintf (out, "%s:%s", hp->name, hp->value); - hp = hp->next; /* next header field */ - } - - return OK; -} diff --git a/uip/mhtest.c b/uip/mhtest.c index 5c10b8b..1c1684f 100644 --- a/uip/mhtest.c +++ b/uip/mhtest.c @@ -1,74 +1,46 @@ - /* - * mhtest.c -- test harness for MIME routines - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** mhtest.c -- test harness for MIME routines +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include -#include #include #include -#include #include #include #include -#include #include -#ifdef HAVE_SYS_WAIT_H -# include -#endif - static struct swit switches[] = { -#define CHECKSW 0 - { "check", 0 }, -#define NCHECKSW 1 - { "nocheck", 0 }, -#define VERBSW 2 - { "verbose", 0 }, -#define NVERBSW 3 - { "noverbose", 0 }, -#define FILESW 4 - { "file file", 0 }, -#define OUTFILESW 5 - { "outfile file", 0 }, -#define PARTSW 6 - { "part number", 0 }, -#define TYPESW 7 - { "type content", 0 }, -#define RCACHESW 8 - { "rcache policy", 0 }, -#define WCACHESW 9 - { "wcache policy", 0 }, -#define VERSIONSW 10 - { "version", 0 }, -#define HELPSW 11 - { "help", 0 }, - -/* - * switches for debugging - */ -#define DEBUGSW 12 - { "debug", -5 }, - { NULL, 0 } +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define FILESW 2 + { "file file", 0 }, +#define OUTFILESW 3 + { "outfile file", 0 }, +#define PARTSW 4 + { "part number", 0 }, +#define TYPESW 5 + { "type content", 0 }, +#define VERSIONSW 6 + { "Version", 0 }, +#define HELPSW 7 + { "help", 0 }, +#define DEBUGSW 8 + { "debug", -5 }, + { NULL, 0 } }; -int ebcdicsw = 0; /* hack for linking purposes */ - /* mhparse.c */ -extern char *tmp; /* directory to place temp files */ - -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; +extern char *tmp; /* directory to place temp files */ /* mhmisc.c */ extern int npart; @@ -78,319 +50,280 @@ extern char *types[NTYPES + 1]; extern int userrs; /* - * This is currently needed to keep mhparse happy. - * This needs to be changed. - */ +** This is currently needed to keep mhparse happy. +** This needs to be changed. +*/ pid_t xpid = 0; int debugsw = 0; int verbosw = 0; -#define quitser pipeser +#define quitser pipeser /* mhparse.c */ -CT parse_mime (char *); +CT parse_mime(char *); /* mhoutsbr.c */ -int output_message (CT, char *); +int output_message(CT, char *); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void set_endian (void); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void set_endian(void); +void flush_errors(void); /* mhfree.c */ -void free_content (CT); +void free_content(CT); extern CT *cts; -void freects_done (int) NORETURN; +void freects_done(int) NORETURN; /* - * static prototypes - */ -static int write_content (CT *, char *); -static RETSIGTYPE pipeser (int); +** static prototypes +*/ +static int write_content(CT *, char *); +static void pipeser(int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgnum, *icachesw; - char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], *outfile = NULL; - char **argp, **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp = NULL; - CT ct, *ctp; - - done=freects_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case RCACHESW: - icachesw = &rcachesw; - goto do_cache; - case WCACHESW: - icachesw = &wcachesw; -do_cache: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { - case AMBIGSW: - ambigsw (cp, caches); - done (1); - case UNKWNSW: - adios (NULL, "%s unknown", cp); - default: - break; + int msgnum; + char *cp, *file = NULL, *folder = NULL; + char *maildir, buf[100], *outfile = NULL; + char **argp, **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp = NULL; + CT ct, *ctp; + + done=freects_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case PARTSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", argp[-2]); + if (npart >= NPARTS) + adios(NULL, "too many parts (starting with %s), %d max", cp, NPARTS); + parts[npart++] = cp; + continue; + + case TYPESW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", argp[-2]); + if (ntype >= NTYPES) + adios(NULL, "too many types (starting with %s), %d max", + cp, NTYPES); + types[ntype++] = cp; + continue; + + case FILESW: + if (!(cp = *argp++) || (*cp == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + file = *cp == '-' ? cp : getcpy(expanddir(cp)); + continue; + + case OUTFILESW: + if (!(cp = *argp++) || (*cp == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + outfile = *cp == '-' ? cp : getcpy(expanddir(cp)); + continue; + + case VERBSW: + verbosw = 1; + continue; + case NVERBSW: + verbosw = 0; + continue; + case DEBUGSW: + debugsw = 1; + continue; + } } - continue; - - case CHECKSW: - checksw++; - continue; - case NCHECKSW: - checksw = 0; - continue; - - case PARTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (npart >= NPARTS) - adios (NULL, "too many parts (starting with %s), %d max", - cp, NPARTS); - parts[npart++] = cp; - continue; - - case TYPESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (ntype >= NTYPES) - adios (NULL, "too many types (starting with %s), %d max", - cp, NTYPES); - types[ntype++] = cp; - continue; - - case FILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - file = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case OUTFILESW: - if (!(cp = *argp++) || (*cp == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - outfile = *cp == '-' ? cp : path (cp, TFILE); - continue; - - case VERBSW: - verbosw = 1; - continue; - case NVERBSW: - verbosw = 0; - continue; - case DEBUGSW: - debugsw = 1; - continue; - } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - /* null terminate the list of acceptable parts/types */ - parts[npart] = NULL; - types[ntype] = NULL; - - set_endian (); - - if (outfile == NULL) - adios (NULL, "must specify output file"); - - /* Check for public cache location */ - if ((cache_public = context_find (nmhcache)) && *cache_public != '/') - cache_public = NULL; - - /* Check for private cache location */ - if (!(cache_private = context_find (nmhprivcache))) - cache_private = ".cache"; - cache_private = getcpy (m_maildir (cache_private)); - - /* - * Check for storage directory. If specified, - * then store temporary files there. Else we - * store them in standard nmh directory. - */ - if ((cp = context_find (nmhstorage)) && *cp) - tmp = concat (cp, "/", invo_name, NULL); - else - tmp = add (m_maildir (invo_name), NULL); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (file && msgs.size) - adios (NULL, "cannot specify msg and file at same time!"); - - /* - * check if message is coming from file - */ - if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - if ((ct = parse_mime (file))); - *ctp++ = ct; - } else { + + /* null terminate the list of acceptable parts/types */ + parts[npart] = NULL; + types[ntype] = NULL; + + set_endian(); + + if (outfile == NULL) + adios(NULL, "must specify output file"); + /* - * message(s) are coming from a folder - */ - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) - adios (NULL, "out of memory"); - ctp = cts; - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - char *msgnam; - - msgnam = m_name (msgnum); - if ((ct = parse_mime (msgnam))) - *ctp++ = ct; - } + ** Check for storage directory. If specified, + ** then store temporary files there. Else we + ** store them in standard nmh directory. + */ + if ((cp = context_find(nmhstorage)) && *cp) + tmp = concat(cp, "/", invo_name, NULL); + else + tmp = getcpy(toabsdir(invo_name)); + + if (file && msgs.size) + adios(NULL, "cannot specify msg and file at same time!"); + + /* + ** check if message is coming from file + */ + if (file) { + if (!(cts = (CT *) calloc((size_t) 2, sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + if ((ct = parse_mime(file))) + *ctp++ = ct; + } else { + /* + ** message(s) are coming from a folder + */ + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + if (!(cts = (CT *) calloc((size_t) (mp->numsel + 1), + sizeof(*cts)))) + adios(NULL, "out of memory"); + ctp = cts; + + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + char *msgnam; + + msgnam = m_name(msgnum); + if ((ct = parse_mime(msgnam))) + *ctp++ = ct; + } + } } - } - - if (!*cts) - done (1); - - userrs = 1; - SIGNAL (SIGQUIT, quitser); - SIGNAL (SIGPIPE, pipeser); - - /* - * Get the associated umask for the relevant contents. - */ - for (ctp = cts; *ctp; ctp++) { - struct stat st; - - ct = *ctp; - if (type_ok (ct, 1) && !ct->c_umask) { - if (stat (ct->c_file, &st) != NOTOK) - ct->c_umask = ~(st.st_mode & 0777); - else - ct->c_umask = ~m_gmprot(); + + if (!*cts) + done(1); + + userrs = 1; + SIGNAL(SIGQUIT, quitser); + SIGNAL(SIGPIPE, pipeser); + + /* + ** Get the associated umask for the relevant contents. + */ + for (ctp = cts; *ctp; ctp++) { + struct stat st; + + ct = *ctp; + if (type_ok(ct, 1) && !ct->c_umask) { + if (stat(ct->c_file, &st) != NOTOK) + ct->c_umask = ~(st.st_mode & 0777); + else + ct->c_umask = ~m_gmprot(); + } } - } - - /* - * Write the content to a file - */ - write_content (cts, outfile); - - /* Now free all the structures for the content */ - for (ctp = cts; *ctp; ctp++) - free_content (*ctp); - - free ((char *) cts); - cts = NULL; - - /* If reading from a folder, do some updating */ - if (mp) { - context_replace (pfolder, folder);/* update current folder */ - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - done (0); - return 1; + + /* + ** Write the content to a file + */ + write_content(cts, outfile); + + /* Now free all the structures for the content */ + for (ctp = cts; *ctp; ctp++) + free_content(*ctp); + + free((char *) cts); + cts = NULL; + + /* If reading from a folder, do some updating */ + if (mp) { + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->hghsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ + } + + done(0); + return 1; } static int -write_content (CT *cts, char *outfile) +write_content(CT *cts, char *outfile) { - CT ct, *ctp; + CT ct, *ctp; - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - output_message (ct, outfile); - } + for (ctp = cts; *ctp; ctp++) { + ct = *ctp; + output_message(ct, outfile); + } - flush_errors (); - return OK; + flush_errors(); + return OK; } -static RETSIGTYPE -pipeser (int i) +static void +pipeser(int i) { - if (i == SIGQUIT) { - unlink ("core"); - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - done (1); - /* NOTREACHED */ + if (i == SIGQUIT) { + unlink("core"); + fflush(stdout); + fprintf(stderr, "\n"); + fflush(stderr); + } + + done(1); + /* NOTREACHED */ } diff --git a/uip/mmh.sh b/uip/mmh.sh new file mode 100755 index 0000000..10fc070 --- /dev/null +++ b/uip/mmh.sh @@ -0,0 +1,141 @@ +#!/bin/sh +# 2011 markus schnalke +# +# replacement for install-mh(1) +# set up mmh for the user +# +# Uses: folder(1) +# +# Todo: use chmod or set umask for created files? +# Todo: install signal handlers and tell how to abort + + +# the following constants must match the values in config/config.c +mmhdir=.mmh +profile=profile +mailstore=Mail + + +# +# process args +# +while [ $# -ge 1 ] ; do + case $1 in + -c*) + # check if mmh is set up + # Note: The mail storage dir gets silently created if + # everything else is properly set up. + # (folder will always create the folder if input is no tty!) + echo | folder >/dev/null 2>&1 + exit $? + ;; + -V*) + echo "mmh has no own version number, thus this instead:" + folder -Version + exit 0 + ;; + -h*|*) + echo "Usage: $0 -- set up mmh for you" >&2 + echo " $0 -c -- check if mmh is set up for you" >&2 + exit 1 + esac + shift +done + + +cat <"$profile" + echo 3. + folder + echo + echo "Enjoy ..." + exit 0 +} + + +# +# mmh dir +# +mmhdir="${MMH:=$mmhdir}" +cd # relative to HOME +echo 1. +if [ -d "$mmhdir" ] ; then + echo "--> Using existing mmh directory $mmhdir" +else + mkdir "$mmhdir" && echo "--> Created mmh directory $mmhdir" +fi +cd "$mmhdir" +mmhpath="`pwd`" + + +# +# profile +# +profile="${MMHP:=$profile}" # relative to $mmhpath +if [ -f "$profile" ] ; then + echo 2. + echo "You already have an mmh profile." + printf "Do you want to edit the file now? [Y/n] " + read answ + case "$answ" in + ''|Y*|y*) + cd "$mmhpath" + ${VISUAL:-${EDITOR:-vi}} "$profile" + echo + echo "Enjoy ..." + exit 0 + ;; + *) + echo "Exiting." + exit 1 + ;; + esac +fi + + +# +# mail store +# +echo 2. +echo "Mmh needs a mail storage." +cd # relative to HOME +if [ -d "$mailstore" ] ; then + echo "The suggested directory `pwd`/$mailstore already exists." + printf "Do you want to use it for mmh? [Y/n] " + read answ + case "$answ" in + ''|Y*|y*) + cd "$mailstore" + echo "--> Using existing directory $mailstore" + finish + exit + ;; + esac +fi +printf "Where do you want it to be located? [`pwd`/Mail] " +read answ +if [ -z "$answ" ] ; then + answ="`pwd`/Mail" +fi +mkdir "$answ" && echo "--> Created $answ" +cd "$answ" +mailstore="`pwd`" +finish diff --git a/uip/mmhwrap.sh b/uip/mmhwrap.sh new file mode 100644 index 0000000..dfd308a --- /dev/null +++ b/uip/mmhwrap.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# Wrapper for mmh commands +# +# For parallel installations of nmh and mmh. +# Removes the need to add /usr/local/mmh/bin to $PATH. +# +# Copy only this script into a $PATH directory. + +PATH="%bindir%:$PATH" +exec "$@" diff --git a/uip/msgchk.c b/uip/msgchk.c deleted file mode 100644 index 9b56649..0000000 --- a/uip/msgchk.c +++ /dev/null @@ -1,402 +0,0 @@ - -/* - * msgchk.c -- check for mail - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include - -#ifdef POP -# include -#endif - -#ifndef POP -# define POPminc(a) (a) -#else -# define POPminc(a) 0 -#endif - -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else -# define SASLminc(a) 0 -#endif - -static struct swit switches[] = { -#define DATESW 0 - { "date", 0 }, -#define NDATESW 1 - { "nodate", 0 }, -#define NOTESW 2 - { "notify type", 0 }, -#define NNOTESW 3 - { "nonotify type", 0 }, -#define HOSTSW 4 - { "host hostname", POPminc (-4) }, -#define USERSW 5 - { "user username", POPminc (-4) }, -#define PORTSW 6 - { "port name/number", POPminc(-4) }, -#define VERSIONSW 7 - { "version", 0 }, -#define HELPSW 8 - { "help", 0 }, -#define SNOOPSW 9 - { "snoop", -5 }, -#define SASLSW 10 - { "sasl", SASLminc(-4) }, -#define SASLMECHSW 11 - { "saslmech", SASLminc(-5) }, -#define PROXYSW 12 - { "proxy command", POPminc(-5) }, - { NULL, 0 } -}; - -/* - * Maximum numbers of users we can check (plus - * one for the NULL vector at the end). - */ -#define MAXVEC 51 - -#define NT_NONE 0x0 -#define NT_MAIL 0x1 -#define NT_NMAI 0x2 -#define NT_ALL (NT_MAIL | NT_NMAI) - -#define NONEOK 0x0 -#define UUCPOLD 0x1 -#define UUCPNEW 0x2 -#define UUCPOK (UUCPOLD | UUCPNEW) -#define MMDFOLD 0x4 -#define MMDFNEW 0x8 -#define MMDFOK (MMDFOLD | MMDFNEW) - - -/* - * static prototypes - */ -static int donote (char *, int); -static int checkmail (char *, char *, int, int, int); - -#ifdef POP -static int remotemail (char *, char *, char *, char *, int, int, int, int, - char *); -#endif - - -int -main (int argc, char **argv) -{ - int datesw = 1, notifysw = NT_ALL; - int status = 0, sasl = 0; - int snoop = 0, vecp = 0; - uid_t uid; - char *cp, *host = NULL, *port = NULL, *user, *proxy = NULL; - char buf[BUFSIZ], *saslmech = NULL; - char **argp, **arguments, *vec[MAXVEC]; - struct passwd *pw; - -#ifdef HESIOD - struct hes_postoffice *po; - char *tmphost; -#endif - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - uid = getuid (); - user = getusername(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - -#ifdef POP - if ((cp = getenv ("MHPOPDEBUG")) && *cp) - snoop++; -#endif - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [users ...]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DATESW: - datesw++; - continue; - case NDATESW: - datesw = 0; - continue; - - case NOTESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - notifysw |= donote (cp, 1); - continue; - case NNOTESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - notifysw &= ~donote (cp, 0); - continue; - - case HOSTSW: - if (!(host = *argp++) || *host == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PORTSW: - if (!(port = *argp++) || *port == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case USERSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (vecp >= MAXVEC-1) - adios (NULL, "you can only check %d users at a time", MAXVEC-1); - else - vec[vecp++] = cp; - continue; - - case SNOOPSW: - snoop++; - continue; - - case SASLSW: - sasl++; - continue; - - case SASLMECHSW: - if (!(saslmech = *argp++) || *saslmech == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PROXYSW: - if (!(proxy = *argp++) || *proxy == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - } - } - if (vecp >= MAXVEC-1) - adios (NULL, "you can only check %d users at a time", MAXVEC-1); - else - vec[vecp++] = cp; - } - -#ifdef POP - /* - * If -host is not specified by user - */ - if (!host || !*host) { - /* - * If "pophost" is specified in mts.conf, - * use it as default value. - */ - if (pophost && *pophost) - host = pophost; - } - if (!host || !*host) - host = NULL; -#endif /* POP */ - - if (vecp != 0) - vec[vecp] = NULL; - -#ifdef POP - if (host) { - if (vecp == 0) { - status = remotemail (host, port, user, proxy, notifysw, 1, - snoop, sasl, saslmech); - } else { - for (vecp = 0; vec[vecp]; vecp++) - status += remotemail (host, port, vec[vecp], proxy, notifysw, 0, - snoop, sasl, saslmech); - } - } else { -#endif /* POP */ - - if (vecp == 0) { - char *home; - - /* Not sure this check makes sense... */ - if (!geteuid() || NULL == (home = getenv("HOME"))) { - pw = getpwnam (user); - if (pw == NULL) - adios (NULL, "unable to get information about user"); - home = pw->pw_dir; - } - status = checkmail (user, home, datesw, notifysw, 1); - } else { - for (vecp = 0; vec[vecp]; vecp++) { - if ((pw = getpwnam (vec[vecp]))) - status += checkmail (pw->pw_name, pw->pw_dir, datesw, notifysw, 0); - else - advise (NULL, "no such user as %s", vec[vecp]); - } - } -#ifdef POP - } /* host == NULL */ -#endif - - done (status); - return 1; -} - - -static struct swit ntswitches[] = { -#define NALLSW 0 - { "all", 0 }, -#define NMAISW 1 - { "mail", 0 }, -#define NNMAISW 2 - { "nomail", 0 }, - { NULL, 0 } -}; - - -static int -donote (char *cp, int ntflag) -{ - switch (smatch (cp, ntswitches)) { - case AMBIGSW: - ambigsw (cp, ntswitches); - done (1); - case UNKWNSW: - adios (NULL, "-%snotify %s unknown", ntflag ? "" : "no", cp); - - case NALLSW: - return NT_ALL; - case NMAISW: - return NT_MAIL; - case NNMAISW: - return NT_NMAI; - } - - return 0; /* Before 1999-07-15, garbage was returned if control got here. */ -} - - -static int -checkmail (char *user, char *home, int datesw, int notifysw, int personal) -{ - int mf, status; - char buffer[BUFSIZ]; - struct stat st; - - snprintf (buffer, sizeof(buffer), "%s/%s", mmdfldir[0] ? mmdfldir : home, mmdflfil[0] ? mmdflfil : user); - if (datesw) { - st.st_size = 0; - st.st_atime = st.st_mtime = 0; - } - mf = (stat (buffer, &st) == NOTOK || st.st_size == 0) ? NONEOK - : st.st_atime <= st.st_mtime ? MMDFNEW : MMDFOLD; - - if ((mf & UUCPOK) || (mf & MMDFOK)) { - if (notifysw & NT_MAIL) { - printf (personal ? "You have " : "%s has ", user); - if (mf & UUCPOK) - printf ("%s old-style bell", mf & UUCPOLD ? "old" : "new"); - if ((mf & UUCPOK) && (mf & MMDFOK)) - printf (" and "); - if (mf & MMDFOK) - printf ("%s%s", mf & MMDFOLD ? "old" : "new", - mf & UUCPOK ? " Internet" : ""); - printf (" mail waiting"); - } else { - notifysw = 0; - } - status = 0; - } - else { - if (notifysw & NT_NMAI) - printf (personal ? "You don't %s%s" : "%s doesn't %s", - personal ? "" : user, "have any mail waiting"); - else - notifysw = 0; - - status = 1; - } - - if (notifysw) - if (datesw && st.st_atime) - printf ("; last read on %s", dtime (&st.st_atime, 1)); - if (notifysw) - printf ("\n"); - - return status; -} - - -#ifdef POP -extern char response[]; - -static int -remotemail (char *host, char *port, char *user, char *proxy, int notifysw, - int personal, int snoop, int sasl, char *saslmech) -{ - int nmsgs, nbytes, status; - char *pass = NULL; - - if (user == NULL) - user = getusername (); - if (sasl) - pass = getusername (); - else - ruserpass (host, &user, &pass); - - /* open the POP connection */ - if (pop_init (host, port, user, pass, proxy, snoop, sasl, saslmech) == NOTOK - || pop_stat (&nmsgs, &nbytes) == NOTOK /* check for messages */ - || pop_quit () == NOTOK) { /* quit POP connection */ - advise (NULL, "%s", response); - return 1; - } - - if (nmsgs) { - if (notifysw & NT_MAIL) { - printf (personal ? "You have " : "%s has ", user); - printf ("%d message%s (%d bytes)", - nmsgs, nmsgs != 1 ? "s" : "", nbytes); - } - else - notifysw = 0; - - status = 0; - } else { - if (notifysw & NT_NMAI) - printf (personal ? "You don't %s%s" : "%s doesn't %s", - personal ? "" : user, "have any mail waiting"); - else - notifysw = 0; - status = 1; - } - if (notifysw) - printf (" on %s\n", host); - - return status; -} -#endif /* POP */ diff --git a/uip/msh.c b/uip/msh.c deleted file mode 100644 index c2d4e1a..0000000 --- a/uip/msh.c +++ /dev/null @@ -1,2395 +0,0 @@ - -/* - * msh.c -- The nmh shell - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* - * TODO: - * Keep more status information in maildrop map - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include - -#define QUOTE '\\' /* sigh */ - -static struct swit switches[] = { -#define IDSW 0 - { "idstart number", -7 }, /* interface from bbc */ -#define FDSW 1 - { "idstop number", -6 }, /* .. */ -#define QDSW 2 - { "idquit number", -6 }, /* .. */ -#define NMSW 3 - { "idname BBoard", -6 }, /* .. */ -#define PRMPTSW 4 - { "prompt string", 0 }, -#define SCANSW 5 - { "scan", 0 }, -#define NSCANSW 6 - { "noscan", 0 }, -#define READSW 7 - { "vmhread fd", -7 }, -#define WRITESW 8 - { "vmhwrite fd", -8 }, -#define PREADSW 9 - { "popread fd", -7 }, -#define PWRITSW 10 - { "popwrite fd", -8 }, -#define TCURSW 11 - { "topcur", 0 }, -#define NTCURSW 12 - { "notopcur", 0 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - { NULL, 0 } -}; - -static int mbx_style = MMDF_FORMAT; - -/* - * FOLDER - */ -char*fmsh = NULL; /* folder instead of file */ -int modified; /* command modified folder */ -struct msgs *mp; /* used a lot */ -static int nMsgs = 0; -struct Msg *Msgs = NULL; /* Msgs[0] not used */ -static FILE *fp; /* input file */ -static FILE *yp = NULL; /* temporary file */ -static int mode; /* mode of file */ -static int numfds = 0; /* number of files cached */ -static int maxfds = 0; /* number of files cached to be cached */ -static time_t mtime = (time_t) 0; /* mtime of file */ - -/* - * VMH - */ -#define ALARM ((unsigned int) 10) -#define ttyN(c) ttyNaux ((c), NULL) - -static int vmh = 0; - -static int vmhpid = OK; -static int vmhfd0; -static int vmhfd1; -static int vmhfd2; - -static int vmhtty = NOTOK; - -#define SCAN 1 -#define STATUS 2 -#define DISPLAY 3 -#define NWIN DISPLAY - -static int topcur = 0; - -static int numwins = 0; -static int windows[NWIN + 1]; - -static jmp_buf peerenv; - -/* - * PARENT - */ -static int pfd = NOTOK; /* fd parent is reading from */ -static int ppid = 0; /* pid of parent */ - -/* - * COMMAND - */ -int interactive; /* running from a /dev/tty */ -int redirected; /* re-directing output */ -FILE *sp = NULL; /* original stdout */ - -char *cmd_name; /* command being run */ -char myfilter[BUFSIZ]; /* path to mhl.forward */ - -static char *myprompt = "(%s) ";/* prompting string */ - -/* - * BBOARDS - */ -static int gap; /* gap in BBoard-ID:s */ -static char *myname = NULL; /* BBoard name */ -char *BBoard_ID = "BBoard-ID"; /* BBoard-ID constant */ - -/* - * SIGNALS - */ -SIGNAL_HANDLER istat; /* original SIGINT */ -static SIGNAL_HANDLER pstat; /* current SIGPIPE */ -SIGNAL_HANDLER qstat; /* original SIGQUIT */ - -#ifdef SIGTSTP -SIGNAL_HANDLER tstat; /* original SIGTSTP */ -#endif - -int interrupted; /* SIGINT detected */ -int broken_pipe; /* SIGPIPE detected */ -int told_to_quit; /* SIGQUIT detected */ - -#ifdef BSD42 -int should_intr; /* signal handler should interrupt call */ -jmp_buf sigenv; /* the environment pointer */ -#endif - -/* - * prototypes - */ -int SOprintf (char *, ...); /* from termsbr.c */ -int sc_width (void); /* from termsbr.c */ -void fsetup (char *); -void setup (char *); -FILE *msh_ready (int, int); -void readids (int); -int readid (int); -void display_info (int); -int expand (char *); -void m_reset (void); -void seq_setcur (struct msgs *, int); -void padios (char *, char *, ...); -void padvise (char *, char *, ...); - - -/* - * static prototypes - */ -static void msh (int); -static int read_map (char *, long); -static int read_file (long, int); - -static void m_gMsgs (int); -FILE *msh_ready (int, int); -static int check_folder (int); -static void scanrange (int, int); -static void scanstring (char *); -static void write_ids (void); -static void quit (void); -static int getargs (char *, struct swit *, struct Cmd *); -static int getcmds (struct swit *, struct Cmd *, int); -static int parse (char *, struct Cmd *); -static int init_io (struct Cmd *, int); -static int initaux_io (struct Cmd *); -static void fin_io (struct Cmd *, int); -static void finaux_io (struct Cmd *); -static void m_init (void); -static RETSIGTYPE intrser (int); -static RETSIGTYPE pipeser (int); -static RETSIGTYPE quitser (int); -static RETSIGTYPE alrmser (int); -static int pINI (void); -static int pQRY (char *, int); -static int pQRY1 (int); -static int pQRY2 (void); -static int pCMD (char *, struct swit *, struct Cmd *); -static int pFIN (void); -static int peerwait (void); -static int ttyNaux (struct Cmd *, char *); -static int ttyR (struct Cmd *); -static int winN (struct Cmd *, int, int); -static int winR (struct Cmd *); -static int winX (int); - - -int -main (int argc, char **argv) -{ - int id = 0, scansw = 0, vmh1 = 0, vmh2 = 0; - char *cp, *file = NULL, *folder = NULL; - char **argp, **arguments, buf[BUFSIZ]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc,argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case IDSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((id = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case FDSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((pfd = atoi (cp)) <= 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case QDSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((ppid = atoi (cp)) <= 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case NMSW: - if (!(myname = *argp++) || *myname == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case SCANSW: - scansw++; - continue; - case NSCANSW: - scansw = 0; - continue; - - case PRMPTSW: - if (!(myprompt = *argp++) || *myprompt == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case READSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((vmh1 = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case WRITESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((vmh2 = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - - case PREADSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case PWRITSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case TCURSW: - topcur++; - continue; - case NTCURSW: - topcur = 0; - continue; - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } - else - if (file) - adios (NULL, "only one file at a time!"); - else - file = cp; - } - - if (!file && !folder) - file = "./msgbox"; - if (file && folder) - adios (NULL, "use a file or a folder, not both"); - strncpy (myfilter, etcpath (mhlforward), sizeof(myfilter)); -#ifdef FIOCLEX - if (pfd > 1) - ioctl (pfd, FIOCLEX, NULL); -#endif /* FIOCLEX */ - -#ifdef BSD42 - should_intr = 0; -#endif /* BSD42 */ - istat = SIGNAL2 (SIGINT, intrser); - qstat = SIGNAL2 (SIGQUIT, quitser); - - sc_width (); /* MAGIC... */ - - if ((vmh = vmh1 && vmh2)) { - rcinit (vmh1, vmh2); - pINI (); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); -#ifdef SIGTSTP - tstat = SIGNAL (SIGTSTP, SIG_IGN); -#endif /* SIGTSTP */ - } - - if (folder) - fsetup (folder); - else - setup (file); - readids (id); - display_info (id > 0 ? scansw : 0); - - msh (id > 0 ? scansw : 0); - - m_reset (); - - done (0); - return 1; -} - - -static struct swit mshcmds[] = { -#define ADVCMD 0 - { "advance", -7 }, -#define ALICMD 1 - { "ali", 0 }, -#define EXPLCMD 2 - { "burst", 0 }, -#define COMPCMD 3 - { "comp", 0 }, -#define DISTCMD 4 - { "dist", 0 }, -#define EXITCMD 5 - { "exit", 0 }, -#define FOLDCMD 6 - { "folder", 0 }, -#define FORWCMD 7 - { "forw", 0 }, -#define HELPCMD 8 - { "help", 0 }, -#define INCMD 9 - { "inc", 0 }, -#define MARKCMD 10 - { "mark", 0 }, -#define MAILCMD 11 - { "mhmail", 0 }, -#define MHNCMD 12 - { "mhn", 0 }, -#define MSGKCMD 13 - { "msgchk", 0 }, -#define NEXTCMD 14 - { "next", 0 }, -#define PACKCMD 15 - { "packf", 0 }, -#define PICKCMD 16 - { "pick", 0 }, -#define PREVCMD 17 - { "prev", 0 }, -#define QUITCMD 18 - { "quit", 0 }, -#define FILECMD 19 - { "refile", 0 }, -#define REPLCMD 20 - { "repl", 0 }, -#define RMMCMD 21 - { "rmm", 0 }, -#define SCANCMD 22 - { "scan", 0 }, -#define SENDCMD 23 - { "send", 0 }, -#define SHOWCMD 24 - { "show", 0 }, -#define SORTCMD 25 - { "sortm", 0 }, -#define WHATCMD 26 - { "whatnow", 0 }, -#define WHOMCMD 27 - { "whom", 0 }, - { NULL, 0 } -}; - - -static void -msh (int scansw) -{ - int i; - register char *cp, **ap; - char prompt[BUFSIZ], *vec[MAXARGS]; - struct Cmd typein; - register struct Cmd *cmdp; - static int once_only = ADVCMD; - - snprintf (prompt, sizeof(prompt), myprompt, invo_name); - cmdp = &typein; - - for (;;) { - if (yp) { - fclose (yp); - yp = NULL; - } - if (vmh) { - if ((i = getcmds (mshcmds, cmdp, scansw)) == EOF) { - rcdone (); - return; - } - } else { - check_folder (scansw); - if ((i = getargs (prompt, mshcmds, cmdp)) == EOF) { - putchar ('\n'); - return; - } - } - cmd_name = mshcmds[i].sw; - - switch (i) { - case QUITCMD: - quit (); - return; - - case ADVCMD: - if (once_only == ADVCMD) - once_only = i = SHOWCMD; - else - i = mp->curmsg != mp->hghmsg ? NEXTCMD : EXITCMD; - cmd_name = mshcmds[i].sw; - /* and fall... */ - - case EXITCMD: - case EXPLCMD: - case FOLDCMD: - case FORWCMD: /* sigh */ - case MARKCMD: - case NEXTCMD: - case PACKCMD: - case PICKCMD: - case PREVCMD: - case RMMCMD: - case SHOWCMD: - case SCANCMD: - case SORTCMD: - if ((cp = context_find (cmd_name))) { - cp = getcpy (cp); - ap = brkstring (cp, " ", "\n"); - ap = copyip (ap, vec, MAXARGS); - } else { - ap = vec; - } - break; - - default: - cp = NULL; - ap = vec; - break; - } - copyip (cmdp->args + 1, ap, MAXARGS); - - m_init (); - - if (!vmh && init_io (cmdp, vmh) == NOTOK) { - if (cp != NULL) - free (cp); - continue; - } - modified = 0; - redirected = vmh || cmdp->direction != STDIO; - - switch (i) { - case ALICMD: - case COMPCMD: - case INCMD: - case MAILCMD: - case MSGKCMD: - case SENDCMD: - case WHATCMD: - case WHOMCMD: - if (!vmh || ttyN (cmdp) != NOTOK) - forkcmd (vec, cmd_name); - break; - - case DISTCMD: - if (!vmh || ttyN (cmdp) != NOTOK) - distcmd (vec); - break; - - case EXPLCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - explcmd (vec); - break; - - case FILECMD: - if (!vmh - || (filehak (vec) == OK ? ttyN (cmdp) - : winN (cmdp, DISPLAY, 1)) != NOTOK) - filecmd (vec); - break; - - case FOLDCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - foldcmd (vec); - break; - - case FORWCMD: - if (!vmh || ttyN (cmdp) != NOTOK) - forwcmd (vec); - break; - - case HELPCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - helpcmd (vec); - break; - - case EXITCMD: - case MARKCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - markcmd (vec); - break; - - case MHNCMD: - if (!vmh || ttyN (cmdp) != NOTOK) - mhncmd (vec); - break; - - case NEXTCMD: - case PREVCMD: - case SHOWCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - showcmd (vec); - break; - - case PACKCMD: - if (!vmh - || (packhak (vec) == OK ? ttyN (cmdp) - : winN (cmdp, DISPLAY, 1)) != NOTOK) - packcmd (vec); - break; - - case PICKCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - pickcmd (vec); - break; - - case REPLCMD: - if (!vmh || ttyN (cmdp) != NOTOK) - replcmd (vec); - break; - - case RMMCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - rmmcmd (vec); - break; - - case SCANCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - scancmd (vec); - break; - - case SORTCMD: - if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK) - sortcmd (vec); - break; - - default: - padios (NULL, "no dispatch for %s", cmd_name); - } - - if (vmh) { - if (vmhtty != NOTOK) - ttyR (cmdp); - if (vmhpid > OK) - winR (cmdp); - } - else - fin_io (cmdp, vmh); - if (cp != NULL) - free (cp); - if (i == EXITCMD) { - quit (); - return; - } - } -} - - -void -fsetup (char *folder) -{ - register int msgnum; - char *maildir; - struct stat st; - - maildir = m_maildir (folder); - if (chdir (maildir) == NOTOK) - padios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - padios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - padios (NULL, "no messages in %s", folder); - - mode = m_gmprot (); - mtime = stat (mp->foldpath, &st) != NOTOK ? st.st_mtime : 0; - - m_gMsgs (mp->hghmsg); - - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { - Msgs[msgnum].m_bboard_id = 0; - Msgs[msgnum].m_top = NOTOK; - Msgs[msgnum].m_start = Msgs[msgnum].m_stop = 0L; - Msgs[msgnum].m_scanl = NULL; - } - - m_init (); - - fmsh = getcpy (folder); - - maxfds = OPEN_MAX / 2; - - if ((maxfds -= 2) < 1) - maxfds = 1; -} - - -void -setup (char *file) -{ - int i, msgp; - struct stat st; - if ((fp = fopen (file, "r")) == NULL) - padios (file, "unable to read"); -#ifdef FIOCLEX - ioctl (fileno (fp), FIOCLEX, NULL); -#endif /* FIOCLEX */ - if (fstat (fileno (fp), &st) != NOTOK) { - mode = (int) (st.st_mode & 0777), mtime = st.st_mtime; - msgp = read_map (file, (long) st.st_size); - } - else { - mode = m_gmprot (), mtime = 0; - msgp = 0; - } - - if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1) - padios (NULL, "no messages in %s", myname ? myname : file); - - if (!(mp = (struct msgs *) calloc ((size_t) 1, sizeof(*mp)))) - padios (NULL, "unable to allocate folder storage"); - - if (!(mp->msgstats = calloc ((size_t) msgp + 3, sizeof(*(mp->msgstats))))) - padios (NULL, "unable to allocate message status storage"); - - mp->hghmsg = msgp; - mp->nummsg = msgp; - mp->lowmsg = 1; - mp->curmsg = 0; - mp->foldpath = getcpy (myname ? myname : file); - clear_folder_flags (mp); - - stat (file, &st); - if (st.st_uid != getuid () || access (file, W_OK) == NOTOK) - set_readonly (mp); - - mp->lowoff = 1; - mp->hghoff = mp->hghmsg + 1; - - for (i = mp->lowmsg; i <= mp->hghmsg; i++) { - clear_msg_flags (mp, i); - set_exists (mp, i); - } - m_init (); - - mp->msgattrs[0] = getcpy ("unseen"); - mp->msgattrs[1] = NULL; - - m_unknown (fp); /* the MAGIC invocation */ - if (fmsh) { - free (fmsh); - fmsh = NULL; - } -} - - -static int -read_map (char *file, long size) -{ - register int i, msgp; - register struct drop *dp, *mp; - struct drop *rp; - - if ((i = map_read (file, size, &rp, 1)) == 0) - return 0; - - m_gMsgs (i); - - msgp = 1; - for (dp = rp + 1; i-- > 0; msgp++, dp++) { - mp = &Msgs[msgp].m_drop; - mp->d_id = dp->d_id; - mp->d_size = dp->d_size; - mp->d_start = dp->d_start; - mp->d_stop = dp->d_stop; - Msgs[msgp].m_scanl = NULL; - } - free ((char *) rp); - - return (msgp - 1); -} - - -static int -read_file (long pos, int msgp) -{ - register int i; - register struct drop *dp, *mp; - struct drop *rp; - - if ((i = mbx_read (fp, pos, &rp, 1)) <= 0) - return (msgp - 1); - - m_gMsgs ((msgp - 1) + i); - - for (dp = rp; i-- > 0; msgp++, dp++) { - mp = &Msgs[msgp].m_drop; - mp->d_id = 0; - mp->d_size = dp->d_size; - mp->d_start = dp->d_start; - mp->d_stop = dp->d_stop; - Msgs[msgp].m_scanl = NULL; - } - free ((char *) rp); - - return (msgp - 1); -} - - -static void -m_gMsgs (int n) -{ - int nmsgs; - - if (Msgs == NULL) { - nMsgs = n + MAXFOLDER / 2; - Msgs = (struct Msg *) calloc ((size_t) (nMsgs + 2), sizeof *Msgs); - if (Msgs == NULL) - padios (NULL, "unable to allocate Msgs structure"); - return; - } - - if (nMsgs >= n) - return; - - nmsgs = nMsgs + n + MAXFOLDER / 2; - Msgs = (struct Msg *) mh_xrealloc ((char *) Msgs, (size_t) (nmsgs + 2) * sizeof *Msgs); - memset((char *) (Msgs + nMsgs + 2), 0, (size_t) ((nmsgs - nMsgs) * sizeof *Msgs)); - - nMsgs = nmsgs; -} - - -FILE * -msh_ready (int msgnum, int full) -{ - register int msgp; - int fd; - char *cp; - - if (yp) { - fclose (yp); - yp = NULL; - } - - if (fmsh) { - if ((fd = Msgs[msgnum].m_top) == NOTOK) { - if (numfds >= maxfds) - for (msgp = mp->lowmsg; msgp <= mp->hghmsg; msgp++) - if (Msgs[msgp].m_top != NOTOK) { - close (Msgs[msgp].m_top); - Msgs[msgp].m_top = NOTOK; - numfds--; - break; - } - - if ((fd = open (cp = m_name (msgnum), O_RDONLY)) == NOTOK) - padios (cp, "unable to open message"); - Msgs[msgnum].m_top = fd; - numfds++; - } - - if ((fd = dup (fd)) == NOTOK) - padios ("cached message", "unable to dup"); - if ((yp = fdopen (fd, "r")) == NULL) - padios (NULL, "unable to fdopen cached message"); - fseek (yp, 0L, SEEK_SET); - return yp; - } - - m_eomsbr ((int (*)()) 0); /* XXX */ - fseek (fp, Msgs[msgnum].m_start, SEEK_SET); - return fp; -} - - -static int -check_folder (int scansw) -{ - int seqnum, i, low, hgh, msgp; - struct stat st; - - if (fmsh) { - if (stat (mp->foldpath, &st) == NOTOK) - padios (mp->foldpath, "unable to stat"); - if (mtime == st.st_mtime) - return 0; - mtime = st.st_mtime; - - low = mp->hghmsg + 1; - folder_free (mp); /* free folder/message structure */ - - if (!(mp = folder_read (fmsh))) - padios (NULL, "unable to re-read folder %s", fmsh); - - hgh = mp->hghmsg; - - for (msgp = mp->lowmsg; msgp <= mp->hghmsg; msgp++) { - if (Msgs[msgp].m_top != NOTOK) { - close (Msgs[msgp].m_top); - Msgs[msgp].m_top = NOTOK; - numfds--; - } - if (Msgs[msgp].m_scanl) { - free (Msgs[msgp].m_scanl); - Msgs[msgp].m_scanl = NULL; - } - } - - m_init (); - - if (modified || low > hgh) - return 1; - goto check_vmh; - } - if (fstat (fileno (fp), &st) == NOTOK) - padios (mp->foldpath, "unable to fstat"); - if (mtime == st.st_mtime) - return 0; - mode = (int) (st.st_mode & 0777); - mtime = st.st_mtime; - - if ((msgp = read_file (Msgs[mp->hghmsg].m_stop, mp->hghmsg + 1)) < 1) - padios (NULL, "no messages in %s", mp->foldpath); /* XXX */ - if (msgp >= MAXFOLDER) - padios (NULL, "more than %d messages in %s", MAXFOLDER, - mp->foldpath); - if (msgp <= mp->hghmsg) - return 0; /* XXX */ - - if (!(mp = folder_realloc (mp, mp->lowoff, msgp))) - padios (NULL, "unable to allocate folder storage"); - - low = mp->hghmsg + 1, hgh = msgp; - seqnum = scansw ? seq_getnum (mp, "unseen") : -1; - for (i = mp->hghmsg + 1; i <= msgp; i++) { - set_exists(mp, i); - if (seqnum != -1) - add_sequence(mp, seqnum, i); - mp->nummsg++; - } - mp->hghmsg = msgp; - m_init (); - -check_vmh: ; - if (vmh) - return 1; - - advise (NULL, "new messages have arrived!\007"); - if (scansw) - scanrange (low, hgh); - - return 1; -} - - -static void -scanrange (int low, int hgh) -{ - char buffer[BUFSIZ]; - - snprintf (buffer, sizeof(buffer), "%d-%d", low, hgh); - scanstring (buffer); -} - - -static void -scanstring (char *arg) -{ - char *cp, **ap, *vec[MAXARGS]; - - /* - * This should be replace with a call to getarguments() - */ - if ((cp = context_find (cmd_name = "scan"))) { - cp = getcpy (cp); - ap = brkstring (cp, " ", "\n"); - ap = copyip (ap, vec, MAXARGS); - } else { - ap = vec; - } - *ap++ = arg; - *ap = NULL; - m_init (); - scancmd (vec); - if (cp != NULL) - free (cp); -} - - -void -readids (int id) -{ - register int cur, seqnum, i=0, msgnum; - - if (mp->curmsg == 0) - seq_setcur (mp, mp->lowmsg); - if (id <= 0 || (seqnum = seq_getnum (mp, "unseen")) == -1) - return; - - for (msgnum = mp->hghmsg; msgnum >= mp->lowmsg; msgnum--) - add_sequence(mp, seqnum, msgnum); - - if (id != 1) { - cur = mp->curmsg; - - for (msgnum = mp->hghmsg; msgnum >= mp->lowmsg; msgnum--) - if (does_exist(mp, msgnum)) /* FIX */ - if ((i = readid (msgnum)) > 0 && i < id) { - cur = msgnum + 1; - clear_sequence(mp, seqnum, msgnum); - break; - } - for (i = mp->lowmsg; i < msgnum; i++) - clear_sequence(mp, seqnum, i); - - if (cur > mp->hghmsg) - cur = mp->hghmsg; - - seq_setcur (mp, cur); - } - - if ((gap = 1 < id && id < (i = readid (mp->lowmsg)) ? id : 0) && !vmh) - advise (NULL, "gap in ID:s, last seen %d, lowest present %d\n", - id - 1, i); -} - - -int -readid (int msgnum) -{ - int i, state; - char *bp, buf[BUFSIZ], name[NAMESZ]; - register FILE *zp; - - if (Msgs[msgnum].m_bboard_id) - return Msgs[msgnum].m_bboard_id; - - zp = msh_ready (msgnum, 0); - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof(buf), zp)) { - case FLD: - case FLDEOF: - case FLDPLUS: - if (!mh_strcasecmp (name, BBoard_ID)) { - bp = getcpy (buf); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), zp); - bp = add (buf, bp); - } - i = atoi (bp); - free (bp); - if (i > 0) - return (Msgs[msgnum].m_bboard_id = i); - else - continue; - } - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), zp); - if (state != FLDEOF) - continue; - - default: - return 0; - } -} - - -void -display_info (int scansw) -{ - int seqnum, sd; - - interactive = isatty (fileno (stdout)); - if (sp == NULL) { - if ((sd = dup (fileno (stdout))) == NOTOK) - padios ("standard output", "unable to dup"); -#ifndef BSD42 /* XXX */ -#ifdef FIOCLEX - ioctl (sd, FIOCLEX, NULL); -#endif /* FIOCLEX */ -#endif /* not BSD42 */ - if ((sp = fdopen (sd, "w")) == NULL) - padios ("standard output", "unable to fdopen"); - } - - m_putenv ("mhfolder", mp->foldpath); - if (vmh) - return; - - if (myname) { - printf ("Reading "); - if (SOprintf ("%s", myname)) - printf ("%s", myname); - printf (", currently at message %d of %d\n", - mp->curmsg, mp->hghmsg); - } - else { - printf ("Reading "); - if (fmsh) - printf ("+%s", fmsh); - else - printf ("%s", mp->foldpath); - printf (", currently at message %d of %d\n", - mp->curmsg, mp->hghmsg); - } - - if (((seqnum = seq_getnum (mp, "unseen")) != -1) - && scansw - && in_sequence(mp, seqnum, mp->hghmsg)) - scanstring ("unseen"); -} - - -static void -write_ids (void) -{ - int i = 0, seqnum, msgnum; - char buffer[80]; - - if (pfd <= 1) - return; - - if ((seqnum = seq_getnum (mp, "unseen")) != -1) - for (msgnum = mp->hghmsg; msgnum >= mp->lowmsg; msgnum--) - if (!in_sequence(mp, seqnum, msgnum)) { - if (Msgs[msgnum].m_bboard_id == 0) - readid (msgnum); - if ((i = Msgs[msgnum].m_bboard_id) > 0) - break; - } - - snprintf (buffer, sizeof(buffer), "%d %d\n", i, Msgs[mp->hghmsg].m_bboard_id); - write (pfd, buffer, sizeof(buffer)); - close (pfd); - pfd = NOTOK; -} - - -static void -quit (void) -{ - int i, md, msgnum; - char *cp, tmpfil[BUFSIZ]; - char map1[BUFSIZ], map2[BUFSIZ]; - struct stat st; - FILE *dp; - - if (!(mp->msgflags & MODIFIED) || is_readonly(mp) || fmsh) { - if (vmh) - rc2peer (RC_FIN, 0, NULL); - return; - } - - if (vmh) - ttyNaux (NULLCMD, "FAST"); - cp = NULL; - if ((dp = lkfopen (mp->foldpath, "r")) == NULL) { - advise (mp->foldpath, "unable to lock"); - if (vmh) { - ttyR (NULLCMD); - pFIN (); - } - return; - } - if (fstat (fileno (dp), &st) == NOTOK) { - advise (mp->foldpath, "unable to stat"); - goto release; - } - if (mtime != st.st_mtime) { - advise (NULL, "new messages have arrived, no update"); - goto release; - } - mode = (int) (st.st_mode & 0777); - - if (mp->nummsg == 0) { - cp = concat ("Zero file \"", mp->foldpath, "\"? ", NULL); - if (getanswer (cp)) { - if ((i = creat (mp->foldpath, mode)) != NOTOK) - close (i); - else - advise (mp->foldpath, "error zero'ing"); - unlink (map_name (mp->foldpath));/* XXX */ - } - goto release; - } - - cp = concat ("Update file \"", mp->foldpath, "\"? ", NULL); - if (!getanswer (cp)) - goto release; - strncpy (tmpfil, m_backup (mp->foldpath), sizeof(tmpfil)); - if ((md = mbx_open (tmpfil, mbx_style, st.st_uid, st.st_gid, mode)) == NOTOK) { - advise (tmpfil, "unable to open"); - goto release; - } - - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) - if (does_exist(mp, msgnum) && pack (tmpfil, md, msgnum) == NOTOK) { - mbx_close (tmpfil, md); - unlink (tmpfil); - unlink (map_name (tmpfil)); - goto release; - } - mbx_close (tmpfil, md); - - if (rename (tmpfil, mp->foldpath) == NOTOK) - admonish (mp->foldpath, "unable to rename %s to", tmpfil); - else { - strncpy (map1, map_name (tmpfil), sizeof(map1)); - strncpy (map2, map_name (mp->foldpath), sizeof(map2)); - - if (rename (map1, map2) == NOTOK) { - admonish (map2, "unable to rename %s to", map1); - unlink (map1); - unlink (map2); - } - } - -release: ; - if (cp) - free (cp); - lkfclose (dp, mp->foldpath); - if (vmh) { - ttyR (NULLCMD); - pFIN (); - } -} - - -static int -getargs (char *prompt, struct swit *sw, struct Cmd *cmdp) -{ - int i; - char *cp; - static char buffer[BUFSIZ]; - - told_to_quit = 0; - for (;;) { - interrupted = 0; -#ifdef BSD42 - switch (setjmp (sigenv)) { - case OK: - should_intr = 1; - break; - - default: - should_intr = 0; - if (interrupted && !told_to_quit) { - putchar ('\n'); - continue; - } - if (ppid > 0) -#ifdef SIGEMT - kill (ppid, SIGEMT); -#else - kill (ppid, SIGTERM); -#endif - return EOF; - } -#endif /* BSD42 */ - if (interactive) { - printf ("%s", prompt); - fflush (stdout); - } - for (cp = buffer; (i = getchar ()) != '\n';) { -#ifndef BSD42 - if (interrupted && !told_to_quit) { - buffer[0] = '\0'; - putchar ('\n'); - break; - } - if (told_to_quit || i == EOF) { - if (ppid > 0) -#ifdef SIGEMT - kill (ppid, SIGEMT); -#else - kill (ppid, SIGTERM); -#endif - return EOF; - } -#else /* BSD42 */ - if (i == EOF) - longjmp (sigenv, DONE); -#endif /* BSD42 */ - if (cp < &buffer[sizeof buffer - 2]) - *cp++ = i; - } - *cp = 0; - - if (buffer[0] == 0) - continue; - if (buffer[0] == '?') { - printf ("commands:\n"); - print_sw (ALL, sw, "", stdout); - printf ("type CTRL-D or use ``quit'' to leave %s\n", - invo_name); - continue; - } - - if (parse (buffer, cmdp) == NOTOK) - continue; - - switch (i = smatch (cmdp->args[0], sw)) { - case AMBIGSW: - ambigsw (cmdp->args[0], sw); - continue; - case UNKWNSW: - printf ("say what: ``%s'' -- type ? (or help) for help\n", - cmdp->args[0]); - continue; - default: -#ifdef BSD42 - should_intr = 0; -#endif /* BSD42 */ - return i; - } - } -} - - -static int -getcmds (struct swit *sw, struct Cmd *cmdp, int scansw) -{ - int i; - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - for (;;) - switch (peer2rc (rc)) { - case RC_QRY: - pQRY (rc->rc_data, scansw); - break; - - case RC_CMD: - if ((i = pCMD (rc->rc_data, sw, cmdp)) != NOTOK) - return i; - break; - - case RC_FIN: - if (ppid > 0) -#ifdef SIGEMT - kill (ppid, SIGEMT); -#else - kill (ppid, SIGTERM); -#endif - return EOF; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pLOOP protocol screw-up"); - done (1); - } -} - - -static int -parse (char *buffer, struct Cmd *cmdp) -{ - int argp = 0; - unsigned char c, *cp; - char *pp; - - cmdp->line[0] = 0; - pp = cmdp->args[argp++] = cmdp->line; - cmdp->redirect = NULL; - cmdp->direction = STDIO; - cmdp->stream = NULL; - - for (cp = buffer; (c = *cp); cp++) { - if (!isspace (c)) - break; - } - if (c == '\0') { - if (vmh) - fmt2peer (RC_EOF, "null command"); - return NOTOK; - } - - while ((c = *cp++)) { - if (isspace (c)) { - while (isspace (c)) - c = *cp++; - if (c == 0) - break; - *pp++ = 0; - cmdp->args[argp++] = pp; - *pp = 0; - } - - switch (c) { - case '"': - for (;;) { - switch (c = *cp++) { - case 0: - padvise (NULL, "unmatched \""); - return NOTOK; - case '"': - break; - case QUOTE: - if ((c = *cp++) == 0) - goto no_quoting; - default: - *pp++ = c; - continue; - } - break; - } - continue; - - case QUOTE: - if ((c = *cp++) == 0) { - no_quoting: ; - padvise (NULL, "the newline character can not be quoted"); - return NOTOK; - } - - default: ; - *pp++ = c; - continue; - - case '>': - case '|': - if (pp == cmdp->line) { - padvise (NULL, "invalid null command"); - return NOTOK; - } - if (*cmdp->args[argp - 1] == 0) - argp--; - cmdp->direction = c == '>' ? CRTIO : PIPIO; - if (cmdp->direction == CRTIO && (c = *cp) == '>') { - cmdp->direction = APPIO; - cp++; - } - cmdp->redirect = pp + 1;/* sigh */ - for (; (c = *cp); cp++) - if (!isspace (c)) - break; - if (c == 0) { - padvise (NULL, cmdp->direction != PIPIO - ? "missing name for redirect" - : "invalid null command"); - return NOTOK; - } - strcpy (cmdp->redirect, cp); - if (cmdp->direction != PIPIO) { - for (; *cp; cp++) - if (isspace (*cp)) { - padvise (NULL, "bad name for redirect"); - return NOTOK; - } - if (expand (cmdp->redirect) == NOTOK) - return NOTOK; - } - break; - } - break; - } - - *pp++ = 0; - cmdp->args[argp] = NULL; - - return OK; -} - - -int -expand (char *redirect) -{ - char *cp, *pp; - char path[BUFSIZ]; - struct passwd *pw; - - if (*redirect != '~') - return OK; - - if ((cp = strchr(pp = redirect + 1, '/'))) - *cp++ = 0; - if (*pp == 0) - pp = mypath; - else - if ((pw = getpwnam (pp))) - pp = pw->pw_dir; - else { - padvise (NULL, "unknown user: %s", pp); - return NOTOK; - } - - snprintf (path, sizeof(path), "%s/%s", pp, cp ? cp : ""); - strcpy (redirect, path); - return OK; -} - - -static int -init_io (struct Cmd *cmdp, int vio) -{ - int io, result; - - io = vmh; - - vmh = vio; - result = initaux_io (cmdp); - vmh = io; - - return result; -} - - -static int -initaux_io (struct Cmd *cmdp) -{ - char *mode; - - switch (cmdp->direction) { - case STDIO: - return OK; - - case CRTIO: - case APPIO: - mode = cmdp->direction == CRTIO ? "write" : "append"; - if ((cmdp->stream = fopen (cmdp->redirect, mode)) == NULL) { - padvise (cmdp->redirect, "unable to %s ", mode); - cmdp->direction = STDIO; - return NOTOK; - } - break; - - case PIPIO: - if ((cmdp->stream = popen (cmdp->redirect, "w")) == NULL) { - padvise (cmdp->redirect, "unable to pipe"); - cmdp->direction = STDIO; - return NOTOK; - } - SIGNAL (SIGPIPE, pipeser); - broken_pipe = 0; - break; - - default: - padios (NULL, "unknown redirection for command"); - } - - fflush (stdout); - if (dup2 (fileno (cmdp->stream), fileno (stdout)) == NOTOK) - padios ("standard output", "unable to dup2"); - clearerr (stdout); - - return OK; -} - - -static void -fin_io (struct Cmd *cmdp, int vio) -{ - int io; - - io = vmh; - vmh = vio; - finaux_io (cmdp); - vmh = io; -} - - -static void -finaux_io (struct Cmd *cmdp) -{ - switch (cmdp->direction) { - case STDIO: - return; - - case CRTIO: - case APPIO: - fflush (stdout); - close (fileno (stdout)); - if (ferror (stdout)) - padvise (NULL, "problems writing %s", cmdp->redirect); - fclose (cmdp->stream); - break; - - case PIPIO: - fflush (stdout); - close (fileno (stdout)); - pclose (cmdp->stream); - SIGNAL (SIGPIPE, SIG_DFL); - break; - - default: - padios (NULL, "unknown redirection for command"); - } - - if (dup2 (fileno (sp), fileno (stdout)) == NOTOK) - padios ("standard output", "unable to dup2"); - clearerr (stdout); - - cmdp->direction = STDIO; -} - - -static void -m_init (void) -{ - int msgnum; - - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) - unset_selected (mp, msgnum); - mp->lowsel = mp->hghsel = mp->numsel = 0; -} - - -void -m_reset (void) -{ - write_ids (); - folder_free (mp); /* free folder/message structure */ - myname = NULL; -} - - -void -seq_setcur (struct msgs *mp, int msgnum) -{ - if (mp->curmsg == msgnum) - return; - - if (mp->curmsg && Msgs[mp->curmsg].m_scanl) { - free (Msgs[mp->curmsg].m_scanl); - Msgs[mp->curmsg].m_scanl = NULL; - } - if (Msgs[msgnum].m_scanl) { - free (Msgs[msgnum].m_scanl); - Msgs[msgnum].m_scanl = NULL; - } - - mp->curmsg = msgnum; -} - - - -static RETSIGTYPE -intrser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGINT, intrser); -#endif - - discard (stdout); - interrupted++; - -#ifdef BSD42 - if (should_intr) - longjmp (sigenv, NOTOK); -#endif -} - - -static RETSIGTYPE -pipeser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGPIPE, pipeser); -#endif - - if (broken_pipe++ == 0) - fprintf (stderr, "broken pipe\n"); - told_to_quit++; - interrupted++; - -#ifdef BSD42 - if (should_intr) - longjmp (sigenv, NOTOK); -#endif -} - - -static RETSIGTYPE -quitser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGQUIT, quitser); -#endif - - told_to_quit++; - interrupted++; - -#ifdef BSD42 - if (should_intr) - longjmp (sigenv, NOTOK); -#endif -} - - -static RETSIGTYPE -alrmser (int i) -{ - longjmp (peerenv, DONE); -} - - -static int -pINI (void) -{ - int i, vrsn; - unsigned char *bp; - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - switch (peer2rc (rc)) { - case RC_INI: - bp = rc->rc_data; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &vrsn) != 1) { - bad_init: ; - fmt2peer (RC_ERR, "bad init \"%s\"", rc->rc_data); - done (1); - } - if (vrsn != RC_VRSN) { - fmt2peer (RC_ERR, "version %d unsupported", vrsn); - done (1); - } - - while (*bp && !isspace (*bp)) - bp++; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &numwins) != 1 || numwins <= 0) - goto bad_init; - if (numwins > NWIN) - numwins = NWIN; - - for (i = 1; i <= numwins; i++) { - while (*bp && !isspace (*bp)) - bp++; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &windows[i]) != 1 || windows[i] <= 0) - goto bad_init; - } - rc2peer (RC_ACK, 0, NULL); - return OK; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pINI protocol screw-up"); - done (1); /* NOTREACHED */ - } - - return 1; /* dead code to satisfy the compiler */ -} - - -static int -pQRY (char *str, int scansw) -{ - if (pQRY1 (scansw) == NOTOK || pQRY2 () == NOTOK) - return NOTOK; - - rc2peer (RC_EOF, 0, NULL); - return OK; -} - - -static int -pQRY1 (int scansw) -{ - int oldhgh; - static int lastlow = 0, - lastcur = 0, - lasthgh = 0, - lastnum = 0; - - oldhgh = mp->hghmsg; - if (check_folder (scansw) && oldhgh < mp->hghmsg) { - switch (winX (STATUS)) { - case NOTOK: - return NOTOK; - - case OK: - printf ("new messages have arrived!"); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - lastlow = lastcur = lasthgh = lastnum = 0; - break; - } - - switch (winX (DISPLAY)) { - case NOTOK: - return NOTOK; - - case OK: - scanrange (oldhgh + 1, mp->hghmsg); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - break; - } - return OK; - } - - if (gap) - switch (winX (STATUS)) { - case NOTOK: - return NOTOK; - - case OK: - printf ("%s: gap in ID:s, last seen %d, lowest present %d\n", - myname ? myname : fmsh ? fmsh : mp->foldpath, gap - 1, - readid (mp->lowmsg)); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - gap = 0; - return OK; - } - - if (mp->lowmsg != lastlow - || mp->curmsg != lastcur - || mp->hghmsg != lasthgh - || mp->nummsg != lastnum) - switch (winX (STATUS)) { - case NOTOK: - return NOTOK; - - case OK: - foldcmd (NULL); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - lastlow = mp->lowmsg; - lastcur = mp->curmsg; - lasthgh = mp->hghmsg; - lastnum = mp->nummsg; - return OK; - } - - return OK; -} - - -static int -pQRY2 (void) -{ - int i, j, k, msgnum, n; - static int cur = 0, - num = 0, - lo = 0, - hi = 0; - - if (mp->nummsg == 0 && mp->nummsg != num) - switch (winX (SCAN)) { - case NOTOK: - return NOTOK; - - case OK: - printf ("empty!"); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - num = mp->nummsg; - return OK; - } - num = mp->nummsg; - - i = 0; - j = (k = windows[SCAN]) / 2; - for (msgnum = mp->curmsg; msgnum <= mp->hghmsg; msgnum++) - if (does_exist (mp, msgnum)) - i++; - if (i-- > 0) { - if (topcur) - k = i >= k ? 1 : k - i; - else - k -= i > j ? j : i; - } - - i = j = 0; - n = 1; - for (msgnum = mp->curmsg; msgnum >= mp->lowmsg; msgnum--) - if (does_exist (mp, msgnum)) { - i = msgnum; - if (j == 0) - j = msgnum; - if (n++ >= k) - break; - } - for (msgnum = mp->curmsg + 1; msgnum <= mp->hghmsg; msgnum++) - if (does_exist (mp, msgnum)) { - if (i == 0) - i = msgnum; - j = msgnum; - if (n++ >= windows[SCAN]) - break; - } - if (!topcur - && lo > 0 - && hi > 0 - && does_exist (mp, lo) - && does_exist (mp, hi) - && (lo < mp->curmsg - || (lo == mp->curmsg && lo == mp->lowmsg)) - && (mp->curmsg < hi - || (hi == mp->curmsg && hi == mp->hghmsg)) - && hi - lo == j - i) - i = lo, j = hi; - - if (mp->curmsg != cur || modified) - switch (winN (NULLCMD, SCAN, 0)) { - case NOTOK: - return NOTOK; - - case OK: - return OK; - - default: - scanrange (lo = i, hi = j); - cur = mp->curmsg; - winR (NULLCMD); - return OK; - } - - return OK; -} - - -static int -pCMD (char *str, struct swit *sw, struct Cmd *cmdp) -{ - int i; - - if (*str == '?') - switch (winX (DISPLAY)) { - case NOTOK: - return NOTOK; - - case OK: - printf ("commands:\n"); - print_sw (ALL, sw, "", stdout); - printf ("type ``quit'' to leave %s\n", invo_name); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - rc2peer (RC_EOF, 0, NULL); - return NOTOK; - } - - if (parse (str, cmdp) == NOTOK) - return NOTOK; - - switch (i = smatch (cmdp->args[0], sw)) { - case AMBIGSW: - switch (winX (DISPLAY)) { - case NOTOK: - return NOTOK; - - case OK: - ambigsw (cmdp->args[0], sw); - fflush (stdout); - fflush (stderr); - _exit (0); /* NOTREACHED */ - - default: - rc2peer (RC_EOF, 0, NULL); - return NOTOK; - } - - case UNKWNSW: - fmt2peer (RC_ERR, - "say what: ``%s'' -- type ? (or help) for help", - cmdp->args[0]); - return NOTOK; - - default: - return i; - } -} - - -static int -pFIN (void) -{ - int status; - - switch (setjmp (peerenv)) { - case OK: - SIGNAL (SIGALRM, alrmser); - alarm (ALARM); - - status = peerwait (); - - alarm (0); - return status; - - default: - return NOTOK; - } -} - - -static int -peerwait (void) -{ - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - switch (peer2rc (rc)) { - case RC_QRY: - case RC_CMD: - rc2peer (RC_FIN, 0, NULL); - return OK; - - case RC_XXX: - advise (NULL, "%s", rc->rc_data); - return NOTOK; - - default: - fmt2peer (RC_FIN, "pLOOP protocol screw-up"); - return NOTOK; - } -} - - -static int -ttyNaux (struct Cmd *cmdp, char *s) -{ - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - if (cmdp && init_io (cmdp, vmh) == NOTOK) - return NOTOK; - - /* XXX: fseek() too tricky for our own good */ - if (!fmsh) - fseek (fp, 0L, SEEK_SET); - - vmhtty = NOTOK; - switch (rc2rc (RC_TTY, s ? strlen (s) : 0, s, rc)) { - case RC_ACK: - vmhtty = OK; /* fall */ - case RC_ERR: - break; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data);/* NOTREACHED */ - - default: - fmt2peer (RC_ERR, "pTTY protocol screw-up"); - done (1); /* NOTREACHED */ - } - -#ifdef SIGTSTP - SIGNAL (SIGTSTP, tstat); -#endif - return vmhtty; -} - - -static int -ttyR (struct Cmd *cmdp) -{ - struct record rcs, *rc; - - rc = &rcs; - -#ifdef SIGTSTP - SIGNAL (SIGTSTP, SIG_IGN); -#endif - - if (vmhtty != OK) - return NOTOK; - - initrc (rc); - - if (cmdp) - fin_io (cmdp, 0); - - vmhtty = NOTOK; - switch (rc2rc (RC_EOF, 0, NULL, rc)) { - case RC_ACK: - rc2peer (RC_EOF, 0, NULL); - return OK; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data);/* NOTREACHED */ - - default: - fmt2peer (RC_ERR, "pTTY protocol screw-up"); - done (1); /* NOTREACHED */ - } - - return 1; /* dead code to satisfy compiler */ -} - - -static int -winN (struct Cmd *cmdp, int n, int eof) -{ - int i, pd[2]; - char buffer[BUFSIZ]; - struct record rcs, *rc; - - rc = &rcs; - if (vmhpid == NOTOK) - return OK; - - initrc (rc); - - /* XXX: fseek() too tricky for our own good */ - if (!fmsh) - fseek (fp, 0L, SEEK_SET); - - vmhpid = OK; - - snprintf (buffer, sizeof(buffer), "%d", n); - switch (str2rc (RC_WIN, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - return NOTOK; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - - if (pipe (pd) == NOTOK) { - err2peer (RC_ERR, "pipe", "unable to"); - return NOTOK; - } - - switch (vmhpid = fork()) { - case NOTOK: - err2peer (RC_ERR, "fork", "unable to"); - close (pd[0]); - close (pd[1]); - return NOTOK; - - case OK: - close (pd[1]); - SIGNAL (SIGPIPE, SIG_IGN); - while ((i = read (pd[0], buffer, sizeof buffer)) > 0) - switch (rc2rc (RC_DATA, i, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - _exit (1); - - case RC_XXX: - advise (NULL, "%s", rc->rc_data); - _exit (2); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - _exit (2); - } - if (i == OK) - switch (rc2rc (RC_EOF, 0, NULL, rc)) { - case RC_ACK: - if (eof) - rc2peer (RC_EOF, 0, NULL); - i = 0; - break; - - case RC_XXX: - advise (NULL, "%s", rc->rc_data); - i = 2; - break; - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - i = 2; - break; - } - if (i == NOTOK) - err2peer (RC_ERR, "pipe", "error reading from"); - close (pd[0]); - _exit (i != NOTOK ? i : 1); - - default: - if ((vmhfd0 = dup (fileno (stdin))) == NOTOK) - padios ("standard input", "unable to dup"); - if ((vmhfd1 = dup (fileno (stdout))) == NOTOK) - padios ("standard output", "unable to dup"); - if ((vmhfd2 = dup (fileno (stderr))) == NOTOK) - padios ("diagnostic output", "unable to dup"); - - close (0); - if ((i = open ("/dev/null", O_RDONLY)) != NOTOK && i != fileno (stdin)) { - dup2 (i, fileno (stdin)); - close (i); - } - - fflush (stdout); - if (dup2 (pd[1], fileno (stdout)) == NOTOK) - padios ("standard output", "unable to dup2"); - clearerr (stdout); - - fflush (stderr); - if (dup2 (pd[1], fileno (stderr)) == NOTOK) - padios ("diagnostic output", "unable to dup2"); - clearerr (stderr); - - if (cmdp && init_io (cmdp, 0) == NOTOK) - return NOTOK; - pstat = SIGNAL (SIGPIPE, pipeser); - broken_pipe = 1; - - close (pd[0]); - close (pd[1]); - - return vmhpid; - } -} - - -static int -winR (struct Cmd *cmdp) -{ - int status; - - if (vmhpid <= OK) - return NOTOK; - - if (cmdp) - fin_io (cmdp, 0); - - if (dup2 (vmhfd0, fileno (stdin)) == NOTOK) - padios ("standard input", "unable to dup2"); - clearerr (stdin); - close (vmhfd0); - - fflush (stdout); - if (dup2 (vmhfd1, fileno (stdout)) == NOTOK) - padios ("standard output", "unable to dup2"); - clearerr (stdout); - close (vmhfd1); - - fflush (stderr); - if (dup2 (vmhfd2, fileno (stderr)) == NOTOK) - padios ("diagnostic output", "unable to dup2"); - clearerr (stderr); - close (vmhfd2); - - SIGNAL (SIGPIPE, pstat); - - if ((status = pidwait (vmhpid, OK)) == 2) - done (1); - - vmhpid = OK; - return (status == 0 ? OK : NOTOK); -} - - -static int -winX (int n) -{ - int i, pid, pd[2]; - char buffer[BUFSIZ]; - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - /* XXX: fseek() too tricky for our own good */ - if (!fmsh) - fseek (fp, 0L, SEEK_SET); - - snprintf (buffer, sizeof(buffer), "%d", n); - switch (str2rc (RC_WIN, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - return NOTOK; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - - if (pipe (pd) == NOTOK) { - err2peer (RC_ERR, "pipe", "unable to"); - return NOTOK; - } - - switch (pid = fork ()) { - case NOTOK: - err2peer (RC_ERR, "fork", "unable to"); - close (pd[0]); - close (pd[1]); - return NOTOK; - - case OK: - close (fileno (stdin)); - if ((i = open ("/dev/null", O_RDONLY)) != NOTOK && i != fileno (stdin)) { - dup2 (i, fileno (stdin)); - close (i); - } - dup2 (pd[1], fileno (stdout)); - dup2 (pd[1], fileno (stderr)); - close (pd[0]); - close (pd[1]); - vmhpid = NOTOK; - return OK; - - default: - close (pd[1]); - while ((i = read (pd[0], buffer, sizeof buffer)) > 0) - switch (rc2rc (RC_DATA, i, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - close (pd[0]); - pidwait (pid, OK); - return NOTOK; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - if (i == OK) - switch (rc2rc (RC_EOF, 0, NULL, rc)) { - case RC_ACK: - break; - - case RC_XXX: - padios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - if (i == NOTOK) - err2peer (RC_ERR, "pipe", "error reading from"); - - close (pd[0]); - pidwait (pid, OK); - return (i != NOTOK ? pid : NOTOK); - } -} - - -void -padios (char *what, char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (vmh) { - verr2peer (RC_FIN, what, fmt, ap); - rcdone (); - } else { - advertise (what, NULL, fmt, ap); - } - va_end(ap); - - done (1); -} - - -void -padvise (char *what, char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (vmh) { - verr2peer (RC_ERR, what, fmt, ap); - } else { - advertise (what, NULL, fmt, ap); - } - va_end(ap); -} diff --git a/uip/mshcmds.c b/uip/mshcmds.c deleted file mode 100644 index 3bd4db3..0000000 --- a/uip/mshcmds.c +++ /dev/null @@ -1,3004 +0,0 @@ - -/* - * mshcmds.c -- command handlers in msh - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static char delim3[] = "-------"; /* from burst.c */ - -static int mhlnum; -static FILE *mhlfp; - -/* - * Type for a compare function for qsort. This keeps - * the compiler happy. - */ -typedef int (*qsort_comp) (const void *, const void *); - -/* - * prototypes - */ -void clear_screen (void); /* from termsbr.c */ -int SOprintf (char *, ...); /* from termsbr.c */ -int sc_width (void); /* from termsbr.c */ - -/* - * static prototypes - */ -static int burst (struct Msg *, int, int, int, int); -static void forw (char *, char *, int, char **); -static void rmm (void); -static void show (int); -static int eom_action (int); -static FILE *mhl_action (char *); -static int ask (int); -static int is_nontext (int); -static int get_fields (char *, char *, int, struct Msg *); -static int msgsort (struct Msg *, struct Msg *); -static int subsort (struct Msg *, struct Msg *); -static char *sosmash (char *, char *); -static int process (int, char *, int, char **); -static void copy_message (int, FILE *); -static void copy_digest (int, FILE *); - -/* from mhlsbr.c */ -int mhlsbr (int, char **, FILE *(*)()); - -void -forkcmd (char **args, char *pgm) -{ - int child_id; - char *vec[MAXARGS]; - - vec[0] = r1bindex (pgm, '/'); - copyip (args, vec + 1, MAXARGS - 1); - - if (fmsh) { - context_del (pfolder); - context_replace (pfolder, fmsh);/* update current folder */ - seq_save (mp); - context_save (); /* save the context file */ - } - fflush (stdout); - switch (child_id = fork ()) { - case NOTOK: - advise ("fork", "unable to"); - return; - - case OK: - closefds (3); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - - execvp (pgm, vec); - fprintf (stderr, "unable to exec "); - perror (cmd_name); - _exit (1); - - default: - pidXwait (child_id, NULL); - break; - } - if (fmsh) { /* assume the worst case */ - mp->msgflags |= MODIFIED; - modified++; - } -} - - -static struct swit distswit[] = { -#define DIANSW 0 - { "annotate", 0 }, -#define DINANSW 1 - { "noannotate", 0 }, -#define DIDFSW 2 - { "draftfolder +folder", 0 }, -#define DIDMSW 3 - { "draftmessage msg", 0 }, -#define DINDFSW 4 - { "nodraftfolder", 0 }, -#define DIEDTSW 5 - { "editor editor", 0 }, -#define DINEDSW 6 - { "noedit", 0 }, -#define DIFRMSW 7 - { "form formfile", 0 }, -#define DIINSW 8 - { "inplace", 0 }, -#define DININSW 9 - { "noinplace", 0 }, -#define DIWHTSW 10 - { "whatnowproc program", 0 }, -#define DINWTSW 11 - { "nowhatnowproc", 0 }, -#define DIHELP 12 - { "help", 0 }, - { NULL, 0 } -}; - - -void -distcmd (char **args) -{ - int vecp = 1; - char *cp, *msg = NULL; - char buf[BUFSIZ], *vec[MAXARGS]; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, distswit)) { - case AMBIGSW: - ambigsw (cp, distswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case DIHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, distswit, 1); - return; - - case DIANSW: /* not implemented */ - case DINANSW: - case DIINSW: - case DININSW: - continue; - - case DINDFSW: - case DINEDSW: - case DINWTSW: - vec[vecp++] = --cp; - continue; - - case DIEDTSW: - case DIFRMSW: - case DIDFSW: - case DIDMSW: - case DIWHTSW: - vec[vecp++] = --cp; - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - if (msg) { - advise (NULL, "only one message at a time!"); - return; - } - else - msg = cp; - } - - vec[0] = cmd_name; - vec[vecp++] = "-file"; - vec[vecp] = NULL; - if (!msg) - msg = "cur"; - if (!m_convert (mp, msg)) - return; - seq_setprev (mp); - - if (mp->numsel > 1) { - advise (NULL, "only one message at a time!"); - return; - } - process (mp->hghsel, cmd_name, vecp, vec); - seq_setcur (mp, mp->hghsel); -} - - -static struct swit explswit[] = { -#define EXINSW 0 - { "inplace", 0 }, -#define EXNINSW 1 - { "noinplace", 0 }, -#define EXQISW 2 - { "quiet", 0 }, -#define EXNQISW 3 - { "noquiet", 0 }, -#define EXVBSW 4 - { "verbose", 0 }, -#define EXNVBSW 5 - { "noverbose", 0 }, -#define EXHELP 6 - { "help", 0 }, - { NULL, 0 } -}; - - -void -explcmd (char **args) -{ - int inplace = 0, quietsw = 0, verbosw = 0; - int msgp = 0, hi, msgnum; - char *cp, buf[BUFSIZ], *msgs[MAXARGS]; - struct Msg *smsgs; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, explswit)) { - case AMBIGSW: - ambigsw (cp, explswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case EXHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, explswit, 1); - return; - - case EXINSW: - inplace++; - continue; - case EXNINSW: - inplace = 0; - continue; - case EXQISW: - quietsw++; - continue; - case EXNQISW: - quietsw = 0; - continue; - case EXVBSW: - verbosw++; - continue; - case EXNVBSW: - verbosw = 0; - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - if (!msgp) - msgs[msgp++] = "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - smsgs = (struct Msg *) - calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs); - if (smsgs == NULL) - adios (NULL, "unable to allocate folder storage"); - - hi = mp->hghmsg + 1; - interrupted = 0; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) - if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK) - break; - - free ((char *) smsgs); - - if (inplace) - seq_setcur (mp, mp->lowsel); - else - if (hi <= mp->hghmsg) - seq_setcur (mp, hi); - - mp->msgflags |= MODIFIED; - modified++; -} - - -static int -burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw) -{ - int i, j, ld3, wasdlm, msgp; - long pos; - char c, buffer[BUFSIZ]; - register FILE *zp; - - ld3 = strlen (delim3); - - if (Msgs[msgnum].m_scanl) { - free (Msgs[msgnum].m_scanl); - Msgs[msgnum].m_scanl = NULL; - } - - pos = ftell (zp = msh_ready (msgnum, 1)); - for (msgp = 0; msgp <= MAXFOLDER;) { - while (fgets (buffer, sizeof buffer, zp) != NULL - && buffer[0] == '\n' - && pos < Msgs[msgnum].m_stop) - pos += (long) strlen (buffer); - if (feof (zp) || pos >= Msgs[msgnum].m_stop) - break; - fseek (zp, pos, SEEK_SET); - smsgs[msgp].m_start = pos; - - for (c = 0; - pos < Msgs[msgnum].m_stop - && fgets (buffer, sizeof buffer, zp) != NULL; - c = buffer[0]) - if (strncmp (buffer, delim3, ld3) == 0 - && (msgp == 1 || c == '\n') - && peekc (zp) == '\n') - break; - else - pos += (long) strlen (buffer); - - wasdlm = strncmp (buffer, delim3, ld3) == 0; - if (smsgs[msgp].m_start != pos) - smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos; - if (feof (zp) || pos >= Msgs[msgnum].m_stop) { - if (wasdlm) - smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1); - break; - } - pos += (long) strlen (buffer); - } - - switch (msgp--) { /* toss "End of XXX Digest" */ - case 0: - adios (NULL, "burst() botch -- you lose big"); - - case 1: - if (!quietsw) - printf ("message %d not in digest format\n", msgnum); - return OK; - - default: - if (verbosw) - printf ("%d message%s exploded from digest %d\n", - msgp, msgp != 1 ? "s" : "", msgnum); - break; - } - - if ((i = msgp + mp->hghmsg) > MAXFOLDER) { - advise (NULL, "more than %d messages", MAXFOLDER); - return NOTOK; - } - if (!(mp = folder_realloc (mp, mp->lowoff, i))) - adios (NULL, "unable to allocate folder storage"); - - j = mp->hghmsg; - mp->hghmsg += msgp; - mp->nummsg += msgp; - if (mp->hghsel > msgnum) - mp->hghsel += msgp; - - if (inplace) - for (i = mp->hghmsg; j > msgnum; i--, j--) { - if (verbosw) - printf ("message %d becomes message %d\n", j, i); - - Msgs[i].m_bboard_id = Msgs[j].m_bboard_id; - Msgs[i].m_top = Msgs[j].m_top; - Msgs[i].m_start = Msgs[j].m_start; - Msgs[i].m_stop = Msgs[j].m_stop; - Msgs[i].m_scanl = NULL; - if (Msgs[j].m_scanl) { - free (Msgs[j].m_scanl); - Msgs[j].m_scanl = NULL; - } - copy_msg_flags (mp, i, j); - } - - if (Msgs[msgnum].m_bboard_id == 0) - readid (msgnum); - - unset_selected (mp, msgnum); - i = inplace ? msgnum + msgp : mp->hghmsg; - for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) { - if (verbosw && i != msgnum) - printf ("message %d of digest %d becomes message %d\n", - j, msgnum, i); - - Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id; - Msgs[i].m_top = Msgs[j].m_top; - Msgs[i].m_start = smsgs[j].m_start; - Msgs[i].m_stop = smsgs[j].m_stop; - Msgs[i].m_scanl = NULL; - copy_msg_flags (mp, i, msgnum); - } - - return OK; -} - - -static struct swit fileswit[] = { -#define FIDRFT 0 - { "draft", 0 }, -#define FILINK 1 - { "link", 0 }, -#define FINLINK 2 - { "nolink", 0 }, -#define FIPRES 3 - { "preserve", 0 }, -#define FINPRES 4 - { "nopreserve", 0 }, -#define FISRC 5 - { "src +folder", 0 }, -#define FIFILE 6 - { "file file", 0 }, -#define FIPROC 7 - { "rmmproc program", 0 }, -#define FINPRC 8 - { "normmproc", 0 }, -#define FIHELP 9 - { "help", 0 }, - { NULL, 0 } -}; - - -void -filecmd (char **args) -{ - int linksw = 0, msgp = 0; - int vecp = 1, i, msgnum; - char *cp, buf[BUFSIZ]; - char *msgs[MAXARGS], *vec[MAXARGS]; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (i = smatch (++cp, fileswit)) { - case AMBIGSW: - ambigsw (cp, fileswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case FIHELP: - snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name); - print_help (buf, fileswit, 1); - return; - - case FILINK: - linksw++; - continue; - case FINLINK: - linksw = 0; - continue; - - case FIPRES: - case FINPRES: - continue; - - case FISRC: - case FIDRFT: - case FIFILE: - case FIPROC: - case FINPRC: - advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw); - return; - } - if (*cp == '+' || *cp == '@') - vec[vecp++] = cp; - else - msgs[msgp++] = cp; - } - - vec[0] = cmd_name; - vec[vecp++] = "-file"; - vec[vecp] = NULL; - if (!msgp) - msgs[msgp++] = "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - interrupted = 0; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) - if (process (msgnum, fileproc, vecp, vec)) { - unset_selected (mp, msgnum); - mp->numsel--; - } - - if (mp->numsel != mp->nummsg || linksw) - seq_setcur (mp, mp->hghsel); - if (!linksw) - rmm (); -} - - -int -filehak (char **args) -{ - int result, vecp = 0; - char *cp, *cwd, *vec[MAXARGS]; - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, fileswit)) { - case AMBIGSW: - case UNKWNSW: - case FIHELP: - return NOTOK; - - case FILINK: - case FINLINK: - case FIPRES: - case FINPRES: - continue; - - case FISRC: - case FIDRFT: - case FIFILE: - return NOTOK; - } - if (*cp == '+' || *cp == '@') - vec[vecp++] = cp; - } - vec[vecp] = NULL; - - result = NOTOK; - cwd = NULL; - for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) { - if (cwd == NULL) - cwd = getcpy (pwd ()); - chdir (m_maildir ("")); - cp = pluspath (cp); - if (access (m_maildir (cp), F_OK) == NOTOK) - result = OK; - free (cp); - } - if (cwd) - chdir (cwd); - - return result; -} - - -static struct swit foldswit[] = { -#define FLALSW 0 - { "all", 0 }, -#define FLFASW 1 - { "fast", 0 }, -#define FLNFASW 2 - { "nofast", 0 }, -#define FLHDSW 3 - { "header", 0 }, -#define FLNHDSW 4 - { "noheader", 0 }, -#define FLPKSW 5 - { "pack", 0 }, -#define FLNPKSW 6 - { "nopack", 0 }, -#define FLRCSW 7 - { "recurse", 0 }, -#define FLNRCSW 8 - { "norecurse", 0 }, -#define FLTLSW 9 - { "total", 0 }, -#define FLNTLSW 10 - { "nototal", 0 }, -#define FLPRSW 11 - { "print", 0 }, -#define FLPUSW 12 - { "push", 0 }, -#define FLPOSW 13 - { "pop", 0 }, -#define FLLISW 14 - { "list", 0 }, -#define FLHELP 15 - { "help", 0 }, - { NULL, 0 } -}; - - -void -foldcmd (char **args) -{ - int fastsw = 0, headersw = 0, packsw = 0; - int hole, msgnum; - char *cp, *folder = NULL, *msg = NULL; - char buf[BUFSIZ], **vec = args; - - if (args == NULL) - goto fast; - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, foldswit)) { - case AMBIGSW: - ambigsw (cp, foldswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case FLHELP: - snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name); - print_help (buf, foldswit, 1); - return; - - case FLALSW: /* not implemented */ - case FLRCSW: - case FLNRCSW: - case FLTLSW: - case FLNTLSW: - case FLPRSW: - case FLPUSW: - case FLPOSW: - case FLLISW: - continue; - - case FLFASW: - fastsw++; - continue; - case FLNFASW: - fastsw = 0; - continue; - case FLHDSW: - headersw++; - continue; - case FLNHDSW: - headersw = 0; - continue; - case FLPKSW: - packsw++; - continue; - case FLNPKSW: - packsw = 0; - continue; - } - if (*cp == '+' || *cp == '@') { - if (folder) { - advise (NULL, "only one folder at a time!\n"); - return; - } - else - folder = fmsh ? pluspath (cp) - : cp + 1; - } - else - if (msg) { - advise (NULL, "only one message at a time!\n"); - return; - } - else - msg = cp; - } - - if (folder) { - if (*folder == 0) { - advise (NULL, "null folder names are not permitted"); - return; - } - if (fmsh) { - if (access (m_maildir (folder), R_OK) == NOTOK) { - advise (folder, "unable to read"); - return; - } - } - else { - strncpy (buf, folder, sizeof(buf)); - if (expand (buf) == NOTOK) - return; - folder = buf; - if (access (folder, R_OK) == NOTOK) { - advise (folder, "unable to read"); - return; - } - } - m_reset (); - - if (fmsh) - fsetup (folder); - else - setup (folder); - readids (0); - display_info (0); - } - - if (msg) { - if (!m_convert (mp, msg)) - return; - seq_setprev (mp); - - if (mp->numsel > 1) { - advise (NULL, "only one message at a time!"); - return; - } - seq_setcur (mp, mp->hghsel); - } - - if (packsw) { - if (fmsh) { - forkcmd (vec, cmd_name); - return; - } - - if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg))) - adios (NULL, "unable to allocate folder storage"); - - for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) - if (does_exist (mp, msgnum)) { - if (msgnum != hole) { - Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id; - Msgs[hole].m_top = Msgs[msgnum].m_top; - Msgs[hole].m_start = Msgs[msgnum].m_start; - Msgs[hole].m_stop = Msgs[msgnum].m_stop; - Msgs[hole].m_scanl = NULL; - if (Msgs[msgnum].m_scanl) { - free (Msgs[msgnum].m_scanl); - Msgs[msgnum].m_scanl = NULL; - } - copy_msg_flags (mp, hole, msgnum); - if (mp->curmsg == msgnum) - seq_setcur (mp, hole); - } - hole++; - } - if (mp->nummsg > 0) { - mp->lowmsg = 1; - mp->hghmsg = hole - 1; - } - mp->msgflags |= MODIFIED; - modified++; - } - -fast: ; - if (fastsw) - printf ("%s\n", fmsh ? fmsh : mp->foldpath); - else { - if (headersw) - printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n", - DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "", - DMAXFOLDER - 2, ""); - printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath); - - /* check for empty folder */ - if (mp->nummsg == 0) { - printf ("has no messages%*s", - mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, ""); - } else { - printf ("has %*d message%s (%*d-%*d)", - DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "", - DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg); - if (mp->curmsg >= mp->lowmsg - && mp->curmsg <= mp->hghmsg) - printf ("; cur=%*d", DMAXFOLDER, mp->curmsg); - } - printf (".\n"); - } -} - - -static struct swit forwswit[] = { -#define FOANSW 0 - { "annotate", 0 }, -#define FONANSW 1 - { "noannotate", 0 }, -#define FODFSW 2 - { "draftfolder +folder", 0 }, -#define FODMSW 3 - { "draftmessage msg", 0 }, -#define FONDFSW 4 - { "nodraftfolder", 0 }, -#define FOEDTSW 5 - { "editor editor", 0 }, -#define FONEDSW 6 - { "noedit", 0 }, -#define FOFTRSW 7 - { "filter filterfile", 0 }, -#define FOFRMSW 8 - { "form formfile", 0 }, -#define FOFTSW 9 - { "format", 5 }, -#define FONFTSW 10 - { "noformat", 7 }, -#define FOINSW 11 - { "inplace", 0 }, -#define FONINSW 12 - { "noinplace", 0 }, -#define FOMISW 13 - { "mime", 0 }, -#define FONMISW 14 - { "nomime", 0 }, -#define FOWHTSW 15 - { "whatnowproc program", 0 }, -#define FONWTSW 16 - { "nowhatnow", 0 }, -#define FOHELP 17 - { "help", 0 }, - { NULL, 0 } -}; - - -void -forwcmd (char **args) -{ - int msgp = 0, vecp = 1, msgnum; - char *cp, *filter = NULL, buf[BUFSIZ]; - char *msgs[MAXARGS], *vec[MAXARGS]; - char *tfile = NULL; - char tmpfil[BUFSIZ]; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, forwswit)) { - case AMBIGSW: - ambigsw (cp, forwswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case FOHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, forwswit, 1); - return; - - case FOANSW: /* not implemented */ - case FONANSW: - case FOINSW: - case FONINSW: - case FOMISW: - case FONMISW: - continue; - - case FONDFSW: - case FONEDSW: - case FONWTSW: - vec[vecp++] = --cp; - continue; - - case FOEDTSW: - case FOFRMSW: - case FODFSW: - case FODMSW: - case FOWHTSW: - vec[vecp++] = --cp; - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - case FOFTRSW: - if (!(filter = *args++) || *filter == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - continue; - case FOFTSW: - if (access (filter = myfilter, R_OK) == NOTOK) { - advise (filter, "unable to read default filter file"); - return; - } - continue; - case FONFTSW: - filter = NULL; - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - /* foil search of .mh_profile */ - snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name); - - tfile = m_mktemp(buf, NULL, NULL); - if (tfile == NULL) adios("forwcmd", "unable to create temporary file"); - strncpy (tmpfil, tfile, sizeof(tmpfil)); - vec[0] = tmpfil; - - vec[vecp++] = "-file"; - vec[vecp] = NULL; - if (!msgp) - msgs[msgp++] = "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - if (filter) { - strncpy (buf, filter, sizeof(buf)); - if (expand (buf) == NOTOK) - return; - if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) { - advise (filter, "unable to read"); - free (filter); - return; - } - } - forw (cmd_name, filter, vecp, vec); - seq_setcur (mp, mp->hghsel); - if (filter) - free (filter); -} - - -static void -forw (char *proc, char *filter, int vecp, char **vec) -{ - int i, child_id, msgnum, msgcnt; - char tmpfil[BUFSIZ], *args[MAXARGS]; - FILE *out; - char *tfile = NULL; - - tfile = m_mktemp2(NULL, invo_name, NULL, NULL); - if (tfile == NULL) adios("forw", "unable to create temporary file"); - strncpy (tmpfil, tfile, sizeof(tmpfil)); - - interrupted = 0; - if (filter) - switch (child_id = fork ()) { - case NOTOK: - advise ("fork", "unable to"); - return; - - case OK: /* "trust me" */ - if (freopen (tmpfil, "w", stdout) == NULL) { - fprintf (stderr, "unable to create "); - perror (tmpfil); - _exit (1); - } - args[0] = r1bindex (mhlproc, '/'); - i = 1; - args[i++] = "-forwall"; - args[i++] = "-form"; - args[i++] = filter; - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) - args[i++] = getcpy (m_name (msgnum)); - args[i] = NULL; - mhlsbr (i, args, mhl_action); - m_eomsbr ((int (*) ()) 0); - fclose (stdout); - _exit (0); - - default: - if (pidXwait (child_id, NULL)) - interrupted++; - break; - } - else { - if ((out = fopen (tmpfil, "w")) == NULL) { - advise (tmpfil, "unable to create temporary file"); - return; - } - - msgcnt = 1; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) { - fprintf (out, "\n\n-------"); - if (msgnum == mp->lowsel) - fprintf (out, " Forwarded Message%s", - mp->numsel > 1 ? "s" : ""); - else - fprintf (out, " Message %d", msgcnt); - fprintf (out, "\n\n"); - copy_digest (msgnum, out); - msgcnt++; - } - - fprintf (out, "\n\n------- End of Forwarded Message%s\n", - mp->numsel > 1 ? "s" : ""); - fclose (out); - } - - fflush (stdout); - if (!interrupted) - switch (child_id = fork ()) { - case NOTOK: - advise ("fork", "unable to"); - break; - - case OK: - closefds (3); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - - vec[vecp++] = tmpfil; - vec[vecp] = NULL; - - execvp (proc, vec); - fprintf (stderr, "unable to exec "); - perror (proc); - _exit (1); - - default: - pidXwait (child_id, NULL); - break; - } - - unlink (tmpfil); -} - - -static char *hlpmsg[] = { - "The %s program emulates many of the commands found in the nmh", - "system. Instead of operating on nmh folders, commands to %s concern", - "a single file.", - "", - "To see the list of commands available, just type a ``?'' followed by", - "the RETURN key. To find out what switches each command takes, type", - "the name of the command followed by ``-help''. To leave %s, use the", - "``quit'' command.", - "", - "Although a lot of nmh commands are found in %s, not all are fully", - "implemented. %s will always recognize all legal switches for a", - "given command though, and will let you know when you ask for an", - "option that it is unable to perform.", - "", - "Running %s is fun, but using nmh from your shell is far superior.", - "After you have familiarized yourself with the nmh style by using %s,", - "you should try using nmh from the shell. You can still use %s for", - "message files that aren't in nmh format, such as BBoard files.", - NULL -}; - - -void -helpcmd (char **args) -{ - int i; - - for (i = 0; hlpmsg[i]; i++) { - printf (hlpmsg[i], invo_name); - putchar ('\n'); - } -} - - -static struct swit markswit[] = { -#define MADDSW 0 - { "add", 0 }, -#define MDELSW 1 - { "delete", 0 }, -#define MLSTSW 2 - { "list", 0 }, -#define MSEQSW 3 - { "sequence name", 0 }, -#define MPUBSW 4 - { "public", 0 }, -#define MNPUBSW 5 - { "nopublic", 0 }, -#define MZERSW 6 - { "zero", 0 }, -#define MNZERSW 7 - { "nozero", 0 }, -#define MHELP 8 - { "help", 0 }, -#define MDBUGSW 9 - { "debug", -5 }, - { NULL, 0 } -}; - - -void -markcmd (char **args) -{ - int addsw = 0, deletesw = 0, debugsw = 0; - int listsw = 0, zerosw = 0, seqp = 0; - int msgp = 0, msgnum; - char *cp, buf[BUFSIZ]; - char *seqs[NUMATTRS + 1], *msgs[MAXARGS]; - - while ((cp = *args++)) { - if (*cp == '-') { - switch (smatch (++cp, markswit)) { - case AMBIGSW: - ambigsw (cp, markswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case MHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, markswit, 1); - return; - - case MADDSW: - addsw++; - deletesw = listsw = 0; - continue; - case MDELSW: - deletesw++; - addsw = listsw = 0; - continue; - case MLSTSW: - listsw++; - addsw = deletesw = 0; - continue; - - case MSEQSW: - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - if (seqp < NUMATTRS) - seqs[seqp++] = cp; - else { - advise (NULL, "only %d sequences allowed!", NUMATTRS); - return; - } - continue; - - case MPUBSW: /* not implemented */ - case MNPUBSW: - continue; - - case MDBUGSW: - debugsw++; - continue; - - case MZERSW: - zerosw++; - continue; - case MNZERSW: - zerosw = 0; - continue; - } - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } else { - msgs[msgp++] = cp; - } - } - - if (!addsw && !deletesw && !listsw) { - if (seqp) - addsw++; - else - if (debugsw) - listsw++; - else { - seqs[seqp++] = "unseen"; - deletesw++; - zerosw = 0; - if (!msgp) - msgs[msgp++] = "all"; - } - } - - if (!msgp) - msgs[msgp++] = listsw ? "all" :"cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - - if (debugsw) { - printf ("invo_name=%s mypath=%s defpath=%s\n", - invo_name, mypath, defpath); - printf ("ctxpath=%s context flags=%s\n", - ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS)); - printf ("foldpath=%s flags=%s\n", - mp->foldpath, - snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS)); - printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n", - mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg); - printf ("lowsel=%d hghsel=%d numsel=%d\n", - mp->lowsel, mp->hghsel, mp->numsel); - printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff); - } - - if (seqp == 0 && (addsw || deletesw)) { - advise (NULL, "-%s requires at least one -sequence argument", - addsw ? "add" : "delete"); - return; - } - seqs[seqp] = NULL; - - if (addsw) { - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_addsel (mp, seqs[seqp], 0, zerosw)) - return; - } - - if (deletesw) { - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_delsel (mp, seqs[seqp], 0, zerosw)) - return; - } - - /* Listing messages in sequences */ - if (listsw) { - if (seqp) { - /* list the given sequences */ - for (seqp = 0; seqs[seqp]; seqp++) - seq_print (mp, seqs[seqp]); - } else { - /* else list them all */ - seq_printall (mp); - } - - interrupted = 0; - if (debugsw) - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) { - printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n", - DMAXFOLDER, - msgnum, - Msgs[msgnum].m_bboard_id, - Msgs[msgnum].m_top, - (long) Msgs[msgnum].m_start, - (long) Msgs[msgnum].m_stop, - snprintb (buf, sizeof(buf), - (unsigned) mp->msgstats[msgnum - mp->lowoff], - seq_bits (mp))); - if (Msgs[msgnum].m_scanl) - printf ("%s", Msgs[msgnum].m_scanl); - } - } -} - - -static struct swit mhnswit[] = { -#define MHNAUTOSW 0 - { "auto", 0 }, -#define MHNNAUTOSW 1 - { "noauto", 0 }, -#define MHNDEBUGSW 2 - { "debug", -5 }, -#define MHNEBCDICSW 3 - { "ebcdicsafe", 0 }, -#define MHNNEBCDICSW 4 - { "noebcdicsafe", 0 }, -#define MHNFORMSW 5 - { "form formfile", 4 }, -#define MHNHEADSW 6 - { "headers", 0 }, -#define MHNNHEADSW 7 - { "noheaders", 0 }, -#define MHNLISTSW 8 - { "list", 0 }, -#define MHNNLISTSW 9 - { "nolist", 0 }, -#define MHNPARTSW 10 - { "part number", 0 }, -#define MHNSIZESW 11 - { "realsize", 0 }, -#define MHNNSIZESW 12 - { "norealsize", 0 }, -#define MHNRFC934SW 13 - { "rfc934mode", 0 }, -#define MHNNRFC934SW 14 - { "norfc934mode", 0 }, -#define MHNSERIALSW 15 - { "serialonly", 0 }, -#define MHNNSERIALSW 16 - { "noserialonly", 0 }, -#define MHNSHOWSW 17 - { "show", 0 }, -#define MHNNSHOWSW 18 - { "noshow", 0 }, -#define MHNSTORESW 19 - { "store", 0 }, -#define MHNNSTORESW 20 - { "nostore", 0 }, -#define MHNTYPESW 21 - { "type content", 0 }, -#define MHNVERBSW 22 - { "verbose", 0 }, -#define MHNNVERBSW 23 - { "noverbose", 0 }, -#define MHNHELPSW 24 - { "help", 0 }, -#define MHNPROGSW 25 - { "moreproc program", -4 }, -#define MHNNPROGSW 26 - { "nomoreproc", -3 }, -#define MHNLENSW 27 - { "length lines", -4 }, -#define MHNWIDSW 28 - { "width columns", -4 }, - { NULL, 0 } -}; - - -void -mhncmd (char **args) -{ - int msgp = 0, vecp = 1; - int msgnum; - char *cp, buf[BUFSIZ]; - char *msgs[MAXARGS], *vec[MAXARGS]; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - while ((cp = *args++)) { - if (*cp == '-') { - switch (smatch (++cp, mhnswit)) { - case AMBIGSW: - ambigsw (cp, mhnswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case MHNHELPSW: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, mhnswit, 1); - return; - - case MHNAUTOSW: - case MHNNAUTOSW: - case MHNDEBUGSW: - case MHNEBCDICSW: - case MHNNEBCDICSW: - case MHNHEADSW: - case MHNNHEADSW: - case MHNLISTSW: - case MHNNLISTSW: - case MHNSIZESW: - case MHNNSIZESW: - case MHNRFC934SW: - case MHNNRFC934SW: - case MHNSERIALSW: - case MHNNSERIALSW: - case MHNSHOWSW: - case MHNNSHOWSW: - case MHNSTORESW: - case MHNNSTORESW: - case MHNVERBSW: - case MHNNVERBSW: - case MHNNPROGSW: - vec[vecp++] = --cp; - continue; - - case MHNFORMSW: - case MHNPARTSW: - case MHNTYPESW: - case MHNPROGSW: - case MHNLENSW: - case MHNWIDSW: - vec[vecp++] = --cp; - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - } - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } else { - msgs[msgp++] = cp; - } - } - - vec[0] = cmd_name; - vec[vecp++] = "-file"; - vec[vecp] = NULL; - if (!msgp) - msgs[msgp++] = "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - interrupted = 0; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) - if (process (msgnum, cmd_name, vecp, vec)) { - unset_selected (mp, msgnum); - mp->numsel--; - } - - seq_setcur (mp, mp->hghsel); -} - - -static struct swit packswit[] = { -#define PAFISW 0 - { "file name", 0 }, -#define PAHELP 1 - { "help", 0 }, - { NULL, 0 } -}; - -static int mbx_style = MMDF_FORMAT; - -void -packcmd (char **args) -{ - int msgp = 0, md, msgnum; - char *cp, *file = NULL; - char buf[BUFSIZ], *msgs[MAXARGS]; - struct stat st; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, packswit)) { - case AMBIGSW: - ambigsw (cp, packswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case PAHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, packswit, 1); - return; - - case PAFISW: - if (!(file = *args++) || *file == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - if (!file) - file = "./msgbox"; - file = path (file, TFILE); - if (stat (file, &st) == NOTOK) { - if (errno != ENOENT) { - advise (file, "error on file"); - goto done_pack; - } - md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL)); - free (cp); - if (!md) - goto done_pack; - } - - if (!msgp) - msgs[msgp++] = "all"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - goto done_pack; - seq_setprev (mp); - - if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) { - advise (file, "unable to open"); - goto done_pack; - } - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) - if (pack (file, md, msgnum) == NOTOK) - break; - mbx_close (file, md); - - if (mp->hghsel != mp->curmsg) - seq_setcur (mp, mp->lowsel); - -done_pack: ; - free (file); -} - - -int -pack (char *mailbox, int md, int msgnum) -{ - register FILE *zp; - - if (Msgs[msgnum].m_bboard_id == 0) - readid (msgnum); - - zp = msh_ready (msgnum, 1); - return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id, - 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1); -} - - -int -packhak (char **args) -{ - int result; - char *cp, *file = NULL; - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, packswit)) { - case AMBIGSW: - case UNKWNSW: - case PAHELP: - return NOTOK; - - case PAFISW: - if (!(file = *args++) || *file == '-') - return NOTOK; - continue; - } - if (*cp == '+' || *cp == '@') - return NOTOK; - } - - file = path (file ? file : "./msgbox", TFILE); - result = access (file, F_OK) == NOTOK ? OK : NOTOK; - free (file); - - return result; -} - - -static struct swit pickswit[] = { -#define PIANSW 0 - { "and", 0 }, -#define PIORSW 1 - { "or", 0 }, -#define PINTSW 2 - { "not", 0 }, -#define PILBSW 3 - { "lbrace", 0 }, -#define PIRBSW 4 - { "rbrace", 0 }, -#define PICCSW 5 - { "cc pattern", 0 }, -#define PIDASW 6 - { "date pattern", 0 }, -#define PIFRSW 7 - { "from pattern", 0 }, -#define PISESW 8 - { "search pattern", 0 }, -#define PISUSW 9 - { "subject pattern", 0 }, -#define PITOSW 10 - { "to pattern", 0 }, -#define PIOTSW 11 - { "-othercomponent pattern", 15 }, -#define PIAFSW 12 - { "after date", 0 }, -#define PIBFSW 13 - { "before date", 0 }, -#define PIDFSW 14 - { "datefield field", 5 }, -#define PISQSW 15 - { "sequence name", 0 }, -#define PIPUSW 16 - { "public", 0 }, -#define PINPUSW 17 - { "nopublic", 0 }, -#define PIZRSW 18 - { "zero", 0 }, -#define PINZRSW 19 - { "nozero", 0 }, -#define PILISW 20 - { "list", 0 }, -#define PINLISW 21 - { "nolist", 0 }, -#define PIHELP 22 - { "help", 0 }, - { NULL, 0 } -}; - - -void -pickcmd (char **args) -{ - int zerosw = 1, msgp = 0, seqp = 0; - int vecp = 0, hi, lo, msgnum; - char *cp, buf[BUFSIZ], *msgs[MAXARGS]; - char *seqs[NUMATTRS], *vec[MAXARGS]; - register FILE *zp; - - while ((cp = *args++)) { - if (*cp == '-') { - if (*++cp == '-') { - vec[vecp++] = --cp; - goto pattern; - } - switch (smatch (cp, pickswit)) { - case AMBIGSW: - ambigsw (cp, pickswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case PIHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, pickswit, 1); - return; - - case PICCSW: - case PIDASW: - case PIFRSW: - case PISUSW: - case PITOSW: - case PIDFSW: - case PIAFSW: - case PIBFSW: - case PISESW: - vec[vecp++] = --cp; -pattern: ; - if (!(cp = *args++)) {/* allow -xyz arguments */ - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - case PIOTSW: - advise (NULL, "internal error!"); - return; - case PIANSW: - case PIORSW: - case PINTSW: - case PILBSW: - case PIRBSW: - vec[vecp++] = --cp; - continue; - - case PISQSW: - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - if (seqp < NUMATTRS) - seqs[seqp++] = cp; - else { - advise (NULL, "only %d sequences allowed!", NUMATTRS); - return; - } - continue; - case PIZRSW: - zerosw++; - continue; - case PINZRSW: - zerosw = 0; - continue; - - case PIPUSW: /* not implemented */ - case PINPUSW: - case PILISW: - case PINLISW: - continue; - } - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - vec[vecp] = NULL; - - if (!msgp) - msgs[msgp++] = "all"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - interrupted = 0; - if (!pcompile (vec, NULL)) - return; - - lo = mp->lowsel; - hi = mp->hghsel; - - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) { - zp = msh_ready (msgnum, 1); - if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start, - fmsh ? 0L : Msgs[msgnum].m_stop)) { - if (msgnum < lo) - lo = msgnum; - if (msgnum > hi) - hi = msgnum; - } - else { - unset_selected (mp, msgnum); - mp->numsel--; - } - } - - if (interrupted) - return; - - mp->lowsel = lo; - mp->hghsel = hi; - - if (mp->numsel <= 0) { - advise (NULL, "no messages match specification"); - return; - } - - seqs[seqp] = NULL; - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_addsel (mp, seqs[seqp], 0, zerosw)) - return; - - printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s"); -} - - -static struct swit replswit[] = { -#define REANSW 0 - { "annotate", 0 }, -#define RENANSW 1 - { "noannotate", 0 }, -#define RECCSW 2 - { "cc type", 0 }, -#define RENCCSW 3 - { "nocc type", 0 }, -#define REDFSW 4 - { "draftfolder +folder", 0 }, -#define REDMSW 5 - { "draftmessage msg", 0 }, -#define RENDFSW 6 - { "nodraftfolder", 0 }, -#define REEDTSW 7 - { "editor editor", 0 }, -#define RENEDSW 8 - { "noedit", 0 }, -#define REFCCSW 9 - { "fcc +folder", 0 }, -#define REFLTSW 10 - { "filter filterfile", 0 }, -#define REFRMSW 11 - { "form formfile", 0 }, -#define REINSW 12 - { "inplace", 0 }, -#define RENINSW 13 - { "noinplace", 0 }, -#define REQUSW 14 - { "query", 0 }, -#define RENQUSW 15 - { "noquery", 0 }, -#define REWHTSW 16 - { "whatnowproc program", 0 }, -#define RENWTSW 17 - { "nowhatnow", 0 }, -#define REWIDSW 19 - { "width columns", 0 }, -#define REHELP 20 - { "help", 0 }, - { NULL, 0 } -}; - - -void -replcmd (char **args) -{ - int vecp = 1; - char *cp, *msg = NULL; - char buf[BUFSIZ], *vec[MAXARGS]; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, replswit)) { - case AMBIGSW: - ambigsw (cp, replswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case REHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, replswit, 1); - return; - - case REANSW: /* not implemented */ - case RENANSW: - case REINSW: - case RENINSW: - continue; - - case REQUSW: - case RENQUSW: - case RENDFSW: - case RENEDSW: - case RENWTSW: - vec[vecp++] = --cp; - continue; - - case RECCSW: - case RENCCSW: - case REEDTSW: - case REFCCSW: - case REFLTSW: - case REFRMSW: - case REWIDSW: - case REDFSW: - case REDMSW: - case REWHTSW: - vec[vecp++] = --cp; - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - if (msg) { - advise (NULL, "only one message at a time!"); - return; - } - else - msg = cp; - } - - vec[0] = cmd_name; - vec[vecp++] = "-file"; - vec[vecp] = NULL; - if (!msg) - msg = "cur"; - if (!m_convert (mp, msg)) - return; - seq_setprev (mp); - - if (mp->numsel > 1) { - advise (NULL, "only one message at a time!"); - return; - } - process (mp->hghsel, cmd_name, vecp, vec); - seq_setcur (mp, mp->hghsel); -} - - -static struct swit rmmswit[] = { -#define RMHELP 0 - { "help", 0 }, - { NULL, 0 } -}; - - -void -rmmcmd (char **args) -{ - int msgp = 0, msgnum; - char *cp, buf[BUFSIZ], *msgs[MAXARGS]; - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, rmmswit)) { - case AMBIGSW: - ambigsw (cp, rmmswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case RMHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, rmmswit, 1); - return; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - if (!msgp) - msgs[msgp++] = "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - rmm (); -} - - -static void -rmm (void) -{ - register int msgnum, vecp; - register char *cp; - char buffer[BUFSIZ], *vec[MAXARGS]; - - if (fmsh) { - if (rmmproc) { - if (mp->numsel > MAXARGS - 1) { - advise (NULL, "more than %d messages for %s exec", - MAXARGS - 1, rmmproc); - return; - } - vecp = 0; - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) - vec[vecp++] = getcpy (m_name (msgnum)); - vec[vecp] = NULL; - forkcmd (vec, rmmproc); - for (vecp = 0; vec[vecp]; vecp++) - free (vec[vecp]); - } - else - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) { - strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer)); - if (rename (cp, buffer) == NOTOK) - admonish (buffer, "unable to rename %s to", cp); - } - } - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) { - set_deleted (mp, msgnum); - unset_exists (mp, msgnum); - } - - if ((mp->nummsg -= mp->numsel) <= 0) { - if (fmsh) - admonish (NULL, "no messages remaining in +%s", fmsh); - else - admonish (NULL, "no messages remaining in %s", mp->foldpath); - mp->lowmsg = mp->hghmsg = mp->nummsg = 0; - } - if (mp->lowsel == mp->lowmsg) { - for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++) - if (does_exist (mp, msgnum)) - break; - mp->lowmsg = msgnum; - } - if (mp->hghsel == mp->hghmsg) { - for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--) - if (does_exist (mp, msgnum)) - break; - mp->hghmsg = msgnum; - } - - mp->msgflags |= MODIFIED; - modified++; -} - - -static struct swit scanswit[] = { -#define SCCLR 0 - { "clear", 0 }, -#define SCNCLR 1 - { "noclear", 0 }, -#define SCFORM 2 - { "form formatfile", 0 }, -#define SCFMT 3 - { "format string", 5 }, -#define SCHEAD 4 - { "header", 0 }, -#define SCNHEAD 5 - { "noheader", 0 }, -#define SCWID 6 - { "width columns", 0 }, -#define SCHELP 7 - { "help", 0 }, - { NULL, 0 } -}; - - -void -scancmd (char **args) -{ -#define equiv(a,b) (a ? b && !strcmp (a, b) : !b) - - int clearsw = 0, headersw = 0, width = 0, msgp = 0; - int msgnum, optim, state; - char *cp, *form = NULL, *format = NULL; - char buf[BUFSIZ], *nfs, *msgs[MAXARGS]; - register FILE *zp; - static int s_optim = 0; - static char *s_form = NULL, *s_format = NULL; - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, scanswit)) { - case AMBIGSW: - ambigsw (cp, scanswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case SCHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, scanswit, 1); - return; - - case SCCLR: - clearsw++; - continue; - case SCNCLR: - clearsw = 0; - continue; - case SCHEAD: - headersw++; - continue; - case SCNHEAD: - headersw = 0; - continue; - case SCFORM: - if (!(form = *args++) || *form == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - format = NULL; - continue; - case SCFMT: - if (!(format = *args++) || *format == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - form = NULL; - continue; - case SCWID: - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - width = atoi (cp); - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - if (!msgp) - msgs[msgp++] = "all"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - /* Get new format string */ - nfs = new_fs (form, format, FORMAT); - - /* force scansbr to (re)compile format */ - if (scanl) { - free (scanl); - scanl = NULL; - } - - if (s_optim == 0) { - s_optim = optim = 1; - s_form = form ? getcpy (form) : NULL; - s_format = format ? getcpy (format) : NULL; - - } - else - optim = equiv (s_form, form) && equiv (s_format, format); - - interrupted = 0; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) { - if (optim && Msgs[msgnum].m_scanl) - printf ("%s", Msgs[msgnum].m_scanl); - else { - - zp = msh_ready (msgnum, 0); - switch (state = scan (zp, msgnum, 0, nfs, width, - msgnum == mp->curmsg, - is_unseen (mp, msgnum), - headersw ? (fmsh ? fmsh : mp->foldpath) : NULL, - fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start), - 1)) { - case SCNMSG: - case SCNENC: - case SCNERR: - if (optim) - Msgs[msgnum].m_scanl = getcpy (scanl); - break; - - default: - advise (NULL, "scan() botch (%d)", state); - return; - - case SCNEOF: - printf ("%*d empty\n", DMAXFOLDER, msgnum); - break; - } - } - headersw = 0; - } - - if (clearsw) - clear_screen (); -} - - -static struct swit showswit[] = { -#define SHDRAFT 0 - { "draft", 5 }, -#define SHFORM 1 - { "form formfile", 4 }, -#define SHPROG 2 - { "moreproc program", 4 }, -#define SHNPROG 3 - { "nomoreproc", 3 }, -#define SHLEN 4 - { "length lines", 4 }, -#define SHWID 5 - { "width columns", 4 }, -#define SHSHOW 6 - { "showproc program", 4 }, -#define SHNSHOW 7 - { "noshowproc", 3 }, -#define SHHEAD 8 - { "header", 4 }, -#define SHNHEAD 9 - { "noheader", 3 }, -#define SHHELP 10 - { "help", 0 }, - { NULL, 0 } -}; - - -void -showcmd (char **args) -{ - int headersw = 1, nshow = 0, msgp = 0, vecp = 1; - int mhl = 0, seqnum = -1, mode = 0, i, msgnum; - char *cp, *proc = showproc, buf[BUFSIZ]; - char *msgs[MAXARGS], *vec[MAXARGS]; - - if (!mh_strcasecmp (cmd_name, "next")) - mode = 1; - else - if (!mh_strcasecmp (cmd_name, "prev")) - mode = -1; - while ((cp = *args++)) { - if (*cp == '-') - switch (i = smatch (++cp, showswit)) { - case AMBIGSW: - ambigsw (cp, showswit); - return; - case UNKWNSW: - case SHNPROG: - vec[vecp++] = --cp; - continue; - case SHHELP: - snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]", - cmd_name, mode ? NULL : "[msgs] "); - print_help (buf, showswit, 1); - return; - - case SHFORM: - case SHPROG: - case SHLEN: - case SHWID: - vec[vecp++] = --cp; - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - vec[vecp++] = cp; - continue; - case SHHEAD: - headersw++; - continue; - case SHNHEAD: - headersw = 0; - continue; - case SHSHOW: - if (!(proc = *args++) || *proc == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - nshow = 0; - continue; - case SHNSHOW: - nshow++; - continue; - - case SHDRAFT: - advise (NULL, "sorry, -%s not allowed!", showswit[i].sw); - return; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - if (mode) { - fprintf (stderr, - "usage: %s [switches] [switches for showproc]\n", - cmd_name); - return; - } - else - msgs[msgp++] = cp; - } - vec[vecp] = NULL; - - if (!msgp) - msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - if (!nshow && !getenv ("NOMHNPROC")) - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum) && is_nontext (msgnum)) { - proc = showmimeproc; - vec[vecp++] = "-file"; - vec[vecp] = NULL; - goto finish; - } - - if (nshow) - proc = catproc; - else - if (strcmp (showproc, "mhl") == 0) { - proc = mhlproc; - mhl++; - } - -finish: ; - seqnum = seq_getnum (mp, "unseen"); - vec[0] = r1bindex (proc, '/'); - if (mhl) { - msgp = vecp; - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum)) { - vec[vecp++] = getcpy (m_name (msgnum)); - if (seqnum != -1) - seq_delmsg (mp, "unseen", msgnum); - } - vec[vecp] = NULL; - if (mp->numsel == 1 && headersw) - show (mp->lowsel); - mhlsbr (vecp, vec, mhl_action); - m_eomsbr ((int (*)()) 0); - while (msgp < vecp) - free (vec[msgp++]); - } else { - interrupted = 0; - for (msgnum = mp->lowsel; - msgnum <= mp->hghsel && !interrupted; - msgnum++) - if (is_selected (mp, msgnum)) { - switch (ask (msgnum)) { - case NOTOK: /* QUIT */ - break; - - case OK: /* INTR */ - continue; - - default: - if (mp->numsel == 1 && headersw) - show (msgnum); - if (nshow) - copy_message (msgnum, stdout); - else - process (msgnum, proc, vecp, vec); - - if (seqnum != -1) - seq_delmsg (mp, "unseen", msgnum); - continue; - } - break; - } - } - - seq_setcur (mp, mp->hghsel); -} - - -static void -show (int msgnum) -{ - if (Msgs[msgnum].m_bboard_id == 0) - readid (msgnum); - - printf ("(Message %d", msgnum); - if (Msgs[msgnum].m_bboard_id > 0) - printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id); - printf (")\n"); -} - - - -static int -eom_action (int c) -{ - return (ftell (mhlfp) >= Msgs[mhlnum].m_stop); -} - - -static FILE * -mhl_action (char *name) -{ - int msgnum; - - if ((msgnum = m_atoi (name)) < mp->lowmsg - || msgnum > mp->hghmsg - || !does_exist (mp, msgnum)) - return NULL; - mhlnum = msgnum; - - mhlfp = msh_ready (msgnum, 1); - if (!fmsh) - m_eomsbr (eom_action); - - return mhlfp; -} - - - -static int -ask (int msgnum) -{ - char buf[BUFSIZ]; - - if (mp->numsel == 1 || !interactive || redirected) - return DONE; - - if (SOprintf ("Press to list \"%d\"...", msgnum)) { - if (mp->lowsel != msgnum) - printf ("\n\n\n"); - printf ("Press to list \"%d\"...", msgnum); - } - fflush (stdout); - buf[0] = 0; - -#ifndef BSD42 - read (fileno (stdout), buf, sizeof buf); -#else /* BSD42 */ - switch (setjmp (sigenv)) { - case OK: - should_intr = 1; - read (fileno (stdout), buf, sizeof buf);/* fall... */ - - default: - should_intr = 0; - break; - } -#endif /* BSD42 */ - - if (strchr(buf, '\n') == NULL) - putchar ('\n'); - - if (told_to_quit) { - told_to_quit = interrupted = 0; - return NOTOK; - } - if (interrupted) { - interrupted = 0; - return OK; - } - - return DONE; -} - - -#include - -static int -is_nontext (int msgnum) -{ - int result, state; - unsigned char *bp, *dp; - char *cp; - char buf[BUFSIZ], name[NAMESZ]; - FILE *fp; - - if (Msgs[msgnum].m_flags & MHNCHK) - return (Msgs[msgnum].m_flags & MHNYES); - Msgs[msgnum].m_flags |= MHNCHK; - - fp = msh_ready (msgnum, 1); - - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof buf, fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - /* - * Check Content-Type field - */ - if (!mh_strcasecmp (name, TYPE_FIELD)) { - int passno; - char c; - - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); - cp = add (buf, cp); - } - bp = cp; - passno = 1; - -again: - for (; isspace (*bp); bp++) - continue; - if (*bp == '(') { - int i; - - for (bp++, i = 0;;) { - switch (*bp++) { - case '\0': -invalid: - result = 0; - goto out; - case '\\': - if (*bp++ == '\0') - goto invalid; - continue; - case '(': - i++; - /* and fall... */ - default: - continue; - case ')': - if (--i < 0) - break; - continue; - } - break; - } - } - if (passno == 2) { - if (*bp != '/') - goto invalid; - bp++; - passno = 3; - goto again; - } - for (dp = bp; istoken (*dp); dp++) - continue; - c = *dp; - *dp = '\0'; - if (!*bp) - goto invalid; - if (passno > 1) { - if ((result = (mh_strcasecmp (bp, "plain") != 0))) - goto out; - *dp = c; - for (dp++; isspace (*dp); dp++) - continue; - if (*dp) { - if ((result = !uprf (dp, "charset"))) - goto out; - dp += sizeof "charset" - 1; - while (isspace (*dp)) - dp++; - if (*dp++ != '=') - goto invalid; - while (isspace (*dp)) - dp++; - if (*dp == '"') { - if ((bp = strchr(++dp, '"'))) - *bp = '\0'; - } else { - for (bp = dp; *bp; bp++) - if (isspace (*bp)) { - *bp = '\0'; - break; - } - } - } else { - /* Default character set */ - dp = "US-ASCII"; - } - /* Check the character set */ - result = !check_charset (dp, strlen (dp)); - } else { - if (!(result = (mh_strcasecmp (bp, "text") != 0))) { - *dp = c; - bp = dp; - passno = 2; - goto again; - } - } -out: - free (cp); - if (result) { - Msgs[msgnum].m_flags |= MHNYES; - return result; - } - break; - } - - /* - * Check Content-Transfer-Encoding field - */ - if (!mh_strcasecmp (name, ENCODING_FIELD)) { - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); - cp = add (buf, cp); - } - for (bp = cp; isspace (*bp); bp++) - continue; - for (dp = bp; istoken (*dp); dp++) - continue; - *dp = '\0'; - result = (mh_strcasecmp (bp, "7bit") - && mh_strcasecmp (bp, "8bit") - && mh_strcasecmp (bp, "binary")); - - free (cp); - if (result) { - Msgs[msgnum].m_flags |= MHNYES; - return result; - } - break; - } - - /* - * Just skip the rest of this header - * field and go to next one. - */ - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); - break; - - /* - * We've passed the message header, - * so message is just text. - */ - default: - return 0; - } -} - - -static struct swit sortswit[] = { -#define SODATE 0 - { "datefield field", 0 }, -#define SOSUBJ 1 - { "textfield field", 0 }, -#define SONSUBJ 2 - { "notextfield", 0 }, -#define SOLIMT 3 - { "limit days", 0 }, -#define SONLIMT 4 - { "nolimit", 0 }, -#define SOVERB 5 - { "verbose", 0 }, -#define SONVERB 6 - { "noverbose", 0 }, -#define SOHELP 7 - { "help", 0 }, - { NULL, 0 } -}; - - -void -sortcmd (char **args) -{ - int msgp = 0, msgnum; - char *cp, *datesw = NULL, *subjsw = NULL; - char buf[BUFSIZ], *msgs[MAXARGS]; - struct tws tb; - - if (fmsh) { - forkcmd (args, cmd_name); - return; - } - - while ((cp = *args++)) { - if (*cp == '-') - switch (smatch (++cp, sortswit)) { - case AMBIGSW: - ambigsw (cp, sortswit); - return; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - return; - case SOHELP: - snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name); - print_help (buf, sortswit, 1); - return; - - case SODATE: - if (datesw) { - advise (NULL, "only one date field at a time!"); - return; - } - if (!(datesw = *args++) || *datesw == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - continue; - - case SOSUBJ: - if (subjsw) { - advise (NULL, "only one text field at a time!"); - return; - } - if (!(subjsw = *args++) || *subjsw == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - continue; - case SONSUBJ: - subjsw = (char *)0; - continue; - - case SOLIMT: /* too hard */ - if (!(cp = *args++) || *cp == '-') { - advise (NULL, "missing argument to %s", args[-2]); - return; - } - case SONLIMT: - case SOVERB: /* not implemented */ - case SONVERB: - continue; - } - if (*cp == '+' || *cp == '@') { - advise (NULL, "sorry, no folders allowed!"); - return; - } - else - msgs[msgp++] = cp; - } - - if (!msgp) - msgs[msgp++] = "all"; - if (!datesw) - datesw = "Date"; - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - return; - seq_setprev (mp); - - twscopy (&tb, dlocaltimenow ()); - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (Msgs[msgnum].m_scanl) { - free (Msgs[msgnum].m_scanl); - Msgs[msgnum].m_scanl = NULL; - } - if (is_selected (mp, msgnum)) { - if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum])) - twscopy (&Msgs[msgnum].m_tb, - msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb); - } - else /* m_scaln is already NULL */ - twscopy (&Msgs[msgnum].m_tb, &tb); - Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff]; - if (mp->curmsg == msgnum) - Msgs[msgnum].m_stats |= CUR; - } - - qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1, - sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort)); - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (subjsw && Msgs[msgnum].m_scanl) { - free (Msgs[msgnum].m_scanl); /* from subjsort */ - Msgs[msgnum].m_scanl = NULL; - } - mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR; - if (Msgs[msgnum].m_stats & CUR) - seq_setcur (mp, msgnum); - } - - mp->msgflags |= MODIFIED; - modified++; -} - - -/* - * get_fields - parse message, and get date and subject if needed. - * We'll use the msgp->m_tb tws struct for the date, and overload - * the msgp->m_scanl field with our subject string. - */ -static int -get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp) -{ - int state, gotdate = 0; - char *bp, buf[BUFSIZ], name[NAMESZ]; - struct tws *tw = (struct tws *) 0; - register FILE *zp; - - zp = msh_ready (msgnum, 0); - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof buf, zp)) { - case FLD: - case FLDEOF: - case FLDPLUS: - if (!mh_strcasecmp (name, datesw)) { - bp = getcpy (buf); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, zp); - bp = add (buf, bp); - } - if ((tw = dparsetime (bp)) == NULL) - admonish (NULL, - "unable to parse %s field in message %d", - datesw, msgnum); - else - twscopy (&(msgp->m_tb), tw); - free (bp); - if (!subjsw) /* not using this, or already done */ - break; /* all done! */ - gotdate++; - } - else if (subjsw && !mh_strcasecmp(name, subjsw)) { - bp = getcpy (buf); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, zp); - bp = add (buf, bp); - } - msgp->m_scanl = sosmash(subjsw, bp); - if (gotdate) - break; /* date done so we're done */ - else - subjsw = (char *)0;/* subject done, need date */ - } else { - while (state == FLDPLUS) /* flush this one */ - state = m_getfld (state, name, buf, sizeof buf, zp); - } - continue; - - case BODY: - case BODYEOF: - case FILEEOF: - break; - - case LENERR: - case FMTERR: - admonish (NULL, "format error in message %d", msgnum); - if (msgp->m_scanl) { /* this might need free'd */ - free (msgp->m_scanl); /* probably can't use subj anyway */ - msgp->m_scanl = NULL; - } - return NOTOK; - - default: - adios (NULL, "internal error -- you lose"); - } - break; - } - if (tw) - return OK; /* not an error if subj not found */ - - admonish (NULL, "no %s field in message %d", datesw, msgnum); - return NOTOK; /* NOTOK means use some other date */ -} - - -/* - * sort routines - */ - -static int -msgsort (struct Msg *a, struct Msg *b) -{ - return twsort (&a->m_tb, &b->m_tb); -} - - -static int -subsort (struct Msg *a, struct Msg *b) -{ - register int i; - - if (a->m_scanl && b->m_scanl) - if ((i = strcmp (a->m_scanl, b->m_scanl))) - return (i); - - return twsort (&a->m_tb, &b->m_tb); -} - - -/* - * try to make the subject "canonical": delete leading "re:", everything - * but letters & smash letters to lower case. - */ -static char * -sosmash (char *subj, char *s) -{ - register char *cp, *dp; - register unsigned char c; - - if (s) { - cp = s; - dp = s; /* dst pointer */ - if (!mh_strcasecmp (subj, "subject")) - while ((c = *cp)) { - if (! isspace(c)) { - if(uprf(cp, "re:")) - cp += 2; - else { - if (isalnum(c)) - *dp++ = isupper(c) ? tolower(c) : c; - break; - } - } - cp++; - } - while ((c = *cp++)) { - if (isalnum(c)) - *dp++ = isupper(c) ? tolower(c) : c; - - } - *dp = '\0'; - } - return s; -} - - -static int -process (int msgnum, char *proc, int vecp, char **vec) -{ - int child_id, status; - char tmpfil[BUFSIZ]; - FILE *out; - char *cp; - - if (fmsh) { - strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil)); - context_del (pfolder); - context_replace (pfolder, fmsh);/* update current folder */ - seq_save (mp); - context_save (); /* save the context file */ - goto ready; - } - - cp = m_mktemp(invo_name, NULL, &out); - if (cp == NULL) { - /* Try again, but try to create under /tmp */ - int olderr = errno; - cp = m_mktemp2(NULL, invo_name, NULL, &out); - if (cp == NULL) { - errno = olderr; - advise (NULL, "unable to create temporary file"); - return NOTOK; - } - } - copy_message (msgnum, out); - fclose (out); - strncpy(tmpfil, cp, sizeof(tmpfil)); - -ready: ; - fflush (stdout); - switch (child_id = fork ()) { - case NOTOK: - advise ("fork", "unable to"); - status = NOTOK; - break; - - case OK: - closefds (3); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - - vec[vecp++] = tmpfil; - vec[vecp] = NULL; - - execvp (proc, vec); - fprintf (stderr, "unable to exec "); - perror (proc); - _exit (1); - - default: - status = pidXwait (child_id, NULL); - break; - } - - if (!fmsh) - unlink (tmpfil); - return status; -} - - -static void -copy_message (int msgnum, FILE *out) -{ - long pos; - static char buffer[BUFSIZ]; - register FILE *zp; - - zp = msh_ready (msgnum, 1); - if (fmsh) { - while (fgets (buffer, sizeof buffer, zp) != NULL) { - fputs (buffer, out); - if (interrupted && out == stdout) - break; - } - } - else { - pos = ftell (zp); - while (fgets (buffer, sizeof buffer, zp) != NULL - && pos < Msgs[msgnum].m_stop) { - fputs (buffer, out); - pos += (long) strlen (buffer); - if (interrupted && out == stdout) - break; - } - } -} - - -static void -copy_digest (int msgnum, FILE *out) -{ - char c; - long pos = 0L; - static char buffer[BUFSIZ]; - register FILE *zp; - - c = '\n'; - zp = msh_ready (msgnum, 1); - if (!fmsh) - pos = ftell (zp); - while (fgets (buffer, sizeof buffer, zp) != NULL - && !fmsh && pos < Msgs[msgnum].m_stop) { - if (c == '\n' && *buffer == '-') - fputc (' ', out); - fputs (buffer, out); - c = buffer[strlen (buffer) - 1]; - if (!fmsh) - pos += (long) strlen (buffer); - if (interrupted && out == stdout) - break; - } -} diff --git a/uip/new.c b/uip/new.c index 99d8528..a79845c 100644 --- a/uip/new.c +++ b/uip/new.c @@ -1,15 +1,14 @@ - /* - * new.c -- as new, list all folders with unseen messages - * -- as fnext, move to next folder with unseen messages - * -- as fprev, move to previous folder with unseen messages - * -- as unseen, scan all unseen messages - * This code is Copyright (c) 2008, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - * - * Inspired by Luke Mewburn's new: http://www.mewburn.net/luke/src/new - */ +** new.c -- as new, list all folders with unseen messages +** -- as fnext, move to next folder with unseen messages +** -- as fprev, move to previous folder with unseen messages +** -- as unseen, scan all unseen messages +** This code is Copyright (c) 2008, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** Inspired by Luke Mewburn's new: http://www.mewburn.net/luke/src/new +*/ #include @@ -23,492 +22,529 @@ static struct swit switches[] = { #define MODESW 0 - { "mode", 1 }, + { "mode", 0 }, #define FOLDERSSW 1 - { "folders", 1 }, + { "folders", 0 }, #define VERSIONSW 2 - { "version", 1 }, + { "Version", 0 }, #define HELPSW 3 - { "help", 1 }, - { NULL, 0 } + { "help", 0 }, + { NULL, 0 } }; static enum { NEW, FNEXT, FPREV, UNSEEN } run_mode = NEW; -/* check_folders uses this to maintain state with both .folders list of - * folders and with crawl_folders. */ +/* +** check_folders uses this to maintain state with both .folders list of +** folders and with crawl_folders. +*/ struct list_state { - struct node **first, **cur_node; - size_t *maxlen; - char *cur; - char **sequences; - struct node *node; + struct node **first, **cur_node; + size_t *maxlen; + char *cur; + char **sequences; + struct node *node; }; /* Return the number of messages in a string list of message numbers. */ static int count_messages(char *field) { - int total = 0; - int j, k; - char *cp, **ap; + int total = 0; + int j, k; + char *cp, **ap; - field = getcpy(field); + field = getcpy(field); - /* copied from seq_read.c:seq_init */ - for (ap = brkstring (field, " ", "\n"); *ap; ap++) { - if ((cp = strchr(*ap, '-'))) - *cp++ = '\0'; - if ((j = m_atoi (*ap)) > 0) { - k = cp ? m_atoi (cp) : j; + /* copied from seq_read.c:seq_init */ + for (ap = brkstring(field, " ", "\n"); *ap; ap++) { + if ((cp = strchr(*ap, '-'))) + *cp++ = '\0'; + if ((j = m_atoi(*ap)) > 0) { + k = cp ? m_atoi(cp) : j; - total += k - j + 1; - } - } + total += k - j + 1; + } + } - free(field); + free(field); - return total; + return total; } /* Return TRUE if the sequence 'name' is in 'sequences'. */ static boolean seq_in_list(char *name, char *sequences[]) { - int i; + int i; - for (i = 0; sequences[i] != NULL; i++) { - if (strcmp(name, sequences[i]) == 0) { - return TRUE; + for (i = 0; sequences[i] != NULL; i++) { + if (strcmp(name, sequences[i]) == 0) { + return TRUE; + } } - } - return FALSE; + return FALSE; } -/* Return the string list of message numbers from the sequences file, or NULL - * if none. */ +/* +** Return the string list of message numbers from the sequences file, +** or NULL if none. +*/ static char * get_msgnums(char *folder, char *sequences[]) { - char *seqfile = concat(m_maildir(folder), "/", mh_seq, (void *)NULL); - FILE *fp = fopen(seqfile, "r"); - int state; - char name[NAMESZ], field[BUFSIZ]; - char *cp; - char *msgnums = NULL, *this_msgnums, *old_msgnums; - - /* no sequences file -> no messages */ - if (fp == NULL) { - return NULL; - } - - /* copied from seq_read.c:seq_public */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - if (state == FLDPLUS) { - cp = getcpy (field); - while (state == FLDPLUS) { - state = m_getfld (state, name, field, - sizeof(field), fp); - cp = add (field, cp); - } - - /* Here's where we differ from seq_public: if it's in a - * sequence we want, save the list of messages. */ - if (seq_in_list(name, sequences)) { - this_msgnums = trimcpy(cp); - if (msgnums == NULL) { - msgnums = this_msgnums; - } else { - old_msgnums = msgnums; - msgnums = concat(old_msgnums, " ", - this_msgnums, (void *)NULL); - free(old_msgnums); - free(this_msgnums); - } - } - free (cp); - } else { - /* and here */ - if (seq_in_list(name, sequences)) { - this_msgnums = trimcpy(field); - if (msgnums == NULL) { - msgnums = this_msgnums; + char *seqfile = concat(toabsdir(folder), "/", mh_seq, (void *)NULL); + FILE *fp = fopen(seqfile, "r"); + int state; + char name[NAMESZ], field[BUFSIZ]; + char *cp; + char *msgnums = NULL, *this_msgnums, *old_msgnums; + + /* no sequences file -> no messages */ + if (fp == NULL) { + return NULL; + } + + /* copied from seq_read.c:seq_public */ + for (state = FLD;;) { + switch (state = m_getfld(state, name, field, sizeof(field), + fp)) { + case FLD: + case FLDPLUS: + case FLDEOF: + if (state == FLDPLUS) { + cp = getcpy(field); + while (state == FLDPLUS) { + state = m_getfld(state, name, field, + sizeof(field), fp); + cp = add(field, cp); + } + + /* + ** Here's where we differ from + ** seq_public: if it's in a + ** sequence we want, save the list + ** of messages. + */ + if (seq_in_list(name, sequences)) { + this_msgnums = trimcpy(cp); + if (msgnums == NULL) { + msgnums = this_msgnums; + } else { + old_msgnums = msgnums; + msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL); + free(old_msgnums); + free(this_msgnums); + } + } + free(cp); } else { - old_msgnums = msgnums; - msgnums = concat(old_msgnums, " ", - this_msgnums, (void *)NULL); - free(old_msgnums); - free(this_msgnums); + /* and here */ + if (seq_in_list(name, sequences)) { + this_msgnums = trimcpy(field); + if (msgnums == NULL) { + msgnums = this_msgnums; + } else { + old_msgnums = msgnums; + msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL); + free(old_msgnums); + free(this_msgnums); + } + } } - } - } - if (state == FLDEOF) - break; - continue; + if (state == FLDEOF) + break; + continue; - case BODY: - case BODYEOF: - adios (NULL, "no blank lines are permitted in %s", seqfile); - /* fall */ + case BODY: + case BODYEOF: + adios(NULL, "no blank lines are permitted in %s", + seqfile); + /* fall */ - case FILEEOF: - break; + case FILEEOF: + break; - default: - adios (NULL, "%s is poorly formatted", seqfile); - } - break; /* break from for loop */ - } + default: + adios(NULL, "%s is poorly formatted", seqfile); + } + break; /* break from for loop */ + } - fclose(fp); + fclose(fp); - return msgnums; + return msgnums; } -/* Check `folder' (of length `len') for interesting messages, filling in the - * list in `b'. */ +/* +** Check `folder' (of length `len') for interesting messages, +** filling in the list in `b'. +*/ static void check_folder(char *folder, size_t len, struct list_state *b) { - char *msgnums = get_msgnums(folder, b->sequences); - int is_cur = strcmp(folder, b->cur) == 0; - - if (is_cur || msgnums != NULL) { - if (*b->first == NULL) { - *b->first = b->node = mh_xmalloc(sizeof(*b->node)); - } else { - b->node->n_next = mh_xmalloc(sizeof(*b->node)); - b->node = b->node->n_next; + char *msgnums = get_msgnums(folder, b->sequences); + int is_cur = strcmp(folder, b->cur) == 0; + + if (is_cur || msgnums != NULL) { + if (*b->first == NULL) { + *b->first = b->node = mh_xmalloc(sizeof(*b->node)); + } else { + b->node->n_next = mh_xmalloc(sizeof(*b->node)); + b->node = b->node->n_next; + } + b->node->n_name = folder; + b->node->n_field = msgnums; + + if (*b->maxlen < len) { + *b->maxlen = len; + } } - b->node->n_name = folder; - b->node->n_field = msgnums; - if (*b->maxlen < len) { - *b->maxlen = len; + /* Save the node for the current folder, so we can fall back to it. */ + if (is_cur) { + *b->cur_node = b->node; } - } - - /* Save the node for the current folder, so we can fall back to it. */ - if (is_cur) { - *b->cur_node = b->node; - } } static boolean crawl_callback(char *folder, void *baton) { - check_folder(folder, strlen(folder), baton); - return TRUE; + check_folder(folder, strlen(folder), baton); + return TRUE; } -/* Scan folders, returning: - * first -- list of nodes for all folders which have desired messages; - * if the current folder is listed in .folders, it is also in - * the list regardless of whether it has any desired messages - * last -- last node in list - * cur_node -- node of current folder, if listed in .folders - * maxlen -- length of longest folder name - * - * `cur' points to the name of the current folder, `folders' points to the - * name of a .folder (if NULL, crawl all folders), and `sequences' points to - * the array of sequences for which to look. - * - * An empty list is returned as first=last=NULL. - */ +/* +** Scan folders, returning: +** first -- list of nodes for all folders which have desired messages; +** if the current folder is listed in .folders, it is also in +** the list regardless of whether it has any desired messages +** last -- last node in list +** cur_node -- node of current folder, if listed in .folders +** maxlen -- length of longest folder name +** +** `cur' points to the name of the current folder, `folders' points to the +** name of a .folder (if NULL, crawl all folders), and `sequences' points to +** the array of sequences for which to look. +** +** An empty list is returned as first=last=NULL. +*/ static void check_folders(struct node **first, struct node **last, - struct node **cur_node, size_t *maxlen, - char *cur, char *folders, char *sequences[]) + struct node **cur_node, size_t *maxlen, + char *cur, char *folders, char *sequences[]) { - struct list_state b; - FILE *fp; - char *line; - size_t len; - - *first = *last = *cur_node = NULL; - *maxlen = 0; - - b.first = first; - b.cur_node = cur_node; - b.maxlen = maxlen; - b.cur = cur; - b.sequences = sequences; - - if (folders == NULL) { - chdir(m_maildir("")); - crawl_folders(".", crawl_callback, &b); - } else { - fp = fopen(folders, "r"); - if (fp == NULL) { - adios(NULL, "failed to read %s", folders); - } - while (vfgets(fp, &line) == OK) { - len = strlen(line) - 1; - line[len] = '\0'; - check_folder(getcpy(line), len, &b); + struct list_state b; + FILE *fp; + char *line; + size_t len; + + *first = *last = *cur_node = NULL; + *maxlen = 0; + + b.first = first; + b.cur_node = cur_node; + b.maxlen = maxlen; + b.cur = cur; + b.sequences = sequences; + + if (folders == NULL) { + chdir(toabsdir("+")); + crawl_folders(".", crawl_callback, &b); + } else { + fp = fopen(folders, "r"); + if (fp == NULL) { + adios(NULL, "failed to read %s", folders); + } + while (vfgets(fp, &line) == OK) { + len = strlen(line) - 1; + line[len] = '\0'; + check_folder(getcpy(line), len, &b); + } + fclose(fp); } - fclose(fp); - } - if (*first != NULL) { - b.node->n_next = NULL; - *last = b.node; - } + if (*first != NULL) { + b.node->n_next = NULL; + *last = b.node; + } } /* Return a single string of the `sequences' joined by a space (' '). */ static char * join_sequences(char *sequences[]) { - int i; - size_t len = 0; - char *result, *cp; - - for (i = 0; sequences[i] != NULL; i++) { - len += strlen(sequences[i]) + 1; - } - result = mh_xmalloc(len + 1); - - for (i = 0, cp = result; sequences[i] != NULL; i++, cp += len + 1) { - len = strlen(sequences[i]); - memcpy(cp, sequences[i], len); - cp[len] = ' '; - } - /* -1 to overwrite the last delimiter */ - *--cp = '\0'; - - return result; + int i; + size_t len = 0; + char *result, *cp; + + for (i = 0; sequences[i] != NULL; i++) { + len += strlen(sequences[i]) + 1; + } + result = mh_xmalloc(len + 1); + + for (i = 0, cp = result; sequences[i] != NULL; i++, cp += len + 1) { + len = strlen(sequences[i]); + memcpy(cp, sequences[i], len); + cp[len] = ' '; + } + /* -1 to overwrite the last delimiter */ + *--cp = '\0'; + + return result; } -/* Return a struct node for the folder to change to. This is the next - * (previous, if FPREV mode) folder with desired messages, or the current - * folder if no folders have desired. If NEW or UNSEEN mode, print the - * output but don't change folders. - * - * n_name is the folder to change to, and n_field is the string list of - * desired message numbers. - */ +/* +** Return a struct node for the folder to change to. This is the next +** (previous, if FPREV mode) folder with desired messages, or the current +** folder if no folders have desired. If NEW or UNSEEN mode, print the +** output but don't change folders. +** +** n_name is the folder to change to, and n_field is the string list of +** desired message numbers. +*/ static struct node * doit(char *cur, char *folders, char *sequences[]) { - struct node *first, *cur_node, *node, *last, *prev; - size_t folder_len; - int count, total = 0; - char *command = NULL, *sequences_s = NULL; - - if (cur == NULL || cur[0] == '\0') { - cur = "inbox"; - } - - check_folders(&first, &last, &cur_node, &folder_len, cur, - folders, sequences); - - if (run_mode == FNEXT || run_mode == FPREV) { - if (first == NULL) { - /* No folders at all... */ - return NULL; - } else if (first->n_next == NULL) { - /* We have only one node; any desired messages in it? */ - if (first->n_field == NULL) { - return NULL; - } else { + struct node *first, *cur_node, *node, *last = NULL, *prev; + size_t folder_len; + int count, total = 0; + char *command = NULL, *sequences_s = NULL; + + if (cur == NULL || cur[0] == '\0') { + cur = "inbox"; + } + + check_folders(&first, &last, &cur_node, &folder_len, cur, + folders, sequences); + + if (run_mode == FNEXT || run_mode == FPREV) { + if (first == NULL) { + /* No folders at all... */ + return NULL; + } else if (first->n_next == NULL) { + /* + ** We have only one node; any desired messages in it? + */ + if (first->n_field == NULL) { + return NULL; + } else { + return first; + } + } else if (cur_node == NULL) { + /* + ** Current folder is not listed in .folders, + ** return first. + */ + return first; + } + } else if (run_mode == UNSEEN) { + sequences_s = join_sequences(sequences); + } + + for (node = first, prev = NULL; + node != NULL; + prev = node, node = node->n_next) { + if (run_mode == FNEXT) { + /* + ** If we have a previous node and it is the current + ** folder, return this node. + */ + if (prev != NULL && strcmp(prev->n_name, cur) == 0) { + return node; + } + } else if (run_mode == FPREV) { + if (strcmp(node->n_name, cur) == 0) { + /* + ** Found current folder in fprev mode; + ** if we have a previous node in the list, + ** return it; else return the last node. + */ + if (prev == NULL) { + return last; + } + return prev; + } + } else if (run_mode == UNSEEN) { + if (node->n_field == NULL) { + continue; + } + + printf("\n%d %s messages in %s", + count_messages(node->n_field), + sequences_s, + node->n_name); + if (strcmp(node->n_name, cur) == 0) { + puts(" (*: current folder)"); + } else { + puts(""); + } + fflush(stdout); + + /* + ** TODO: Split enough of scan.c out so that we can + ** call it here. + */ + command = concat("scan +", node->n_name, " ", + sequences_s, (void *)NULL); + system(command); + free(command); + } else { + if (node->n_field == NULL) { + continue; + } + + count = count_messages(node->n_field); + total += count; + + printf("%-*s %6d.%c %s\n", (int) folder_len, + node->n_name, count, + (strcmp(node->n_name, cur) == 0 ? '*' : ' '), + node->n_field); + } + } + + /* + ** If we're fnext, we haven't checked the last node yet. If it's the + ** current folder, return the first node. + */ + if (run_mode == FNEXT && strcmp(last->n_name, cur) == 0) { return first; - } - } else if (cur_node == NULL) { - /* Current folder is not listed in .folders, return first. */ - return first; } - } else if (run_mode == UNSEEN) { - sequences_s = join_sequences(sequences); - } - - for (node = first, prev = NULL; - node != NULL; - prev = node, node = node->n_next) { - if (run_mode == FNEXT) { - /* If we have a previous node and it is the current - * folder, return this node. */ - if (prev != NULL && strcmp(prev->n_name, cur) == 0) { - return node; - } - } else if (run_mode == FPREV) { - if (strcmp(node->n_name, cur) == 0) { - /* Found current folder in fprev mode; if we have a - * previous node in the list, return it; else return - * the last node. */ - if (prev == NULL) { - return last; - } - return prev; - } - } else if (run_mode == UNSEEN) { - if (node->n_field == NULL) { - continue; - } - - printf("\n%d %s messages in %s", - count_messages(node->n_field), - sequences_s, - node->n_name); - if (strcmp(node->n_name, cur) == 0) { - puts(" (*: current folder)"); - } else { - puts(""); - } - fflush(stdout); - - /* TODO: Split enough of scan.c out so that we can call it here. */ - command = concat("scan +", node->n_name, " ", sequences_s, - (void *)NULL); - system(command); - free(command); - } else { - if (node->n_field == NULL) { - continue; - } - - count = count_messages(node->n_field); - total += count; - - printf("%-*s %6d.%c %s\n", - (int) folder_len, node->n_name, - count, - (strcmp(node->n_name, cur) == 0 ? '*' : ' '), - node->n_field); - } - } - - /* If we're fnext, we haven't checked the last node yet. If it's the - * current folder, return the first node. */ - if (run_mode == FNEXT && strcmp(last->n_name, cur) == 0) { - return first; - } - - if (run_mode == NEW) { - printf("%-*s %6d.\n", (int) folder_len, " total", total); - } - - return cur_node; + + if (run_mode == NEW) { + printf("%-*s %6d.\n", (int) folder_len, " total", total); + } + + return cur_node; } int main(int argc, char **argv) { - char **ap, *cp, **argp, **arguments; - char help[BUFSIZ]; - char *folders = NULL; - char *sequences[NUMATTRS + 1]; - int i = 0; - char *unseen; - struct node *folder; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex(argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (help, sizeof(help), "%s [switches] [sequences]", - invo_name); - print_help (help, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FOLDERSSW: - if (!(folders = *argp++) || *folders == '-') - adios(NULL, "missing argument to %s", argp[-2]); - continue; - case MODESW: - if (!(invo_name = *argp++) || *invo_name == '-') - adios(NULL, "missing argument to %s", argp[-2]); - invo_name = r1bindex(invo_name, '/'); - continue; - } + char **ap, *cp, **argp, **arguments; + char help[BUFSIZ]; + char *folders = NULL; + char *sequences[NUMATTRS + 1]; + int i = 0; + char *unseen; + struct node *folder; + + sequences[0] = NULL; + sequences[1] = NULL; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(help, sizeof(help), + "%s [switches] [sequences]", + invo_name); + print_help(help, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FOLDERSSW: + if (!(folders = *argp++) || *folders == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + case MODESW: + if (!(invo_name = *argp++) || *invo_name == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + invo_name = mhbasename(invo_name); + continue; + } + } + /* have a sequence argument */ + if (!seq_in_list(cp, sequences)) { + sequences[i++] = cp; + sequences[i] = NULL; + } } - /* have a sequence argument */ - if (!seq_in_list(cp, sequences)) { - sequences[i++] = cp; + + if (strcmp(invo_name, "fnext") == 0) { + run_mode = FNEXT; + } else if (strcmp(invo_name, "fprev") == 0) { + run_mode = FPREV; + } else if (strcmp(invo_name, "unseen") == 0) { + run_mode = UNSEEN; } - } - - if (strcmp(invo_name, "fnext") == 0) { - run_mode = FNEXT; - } else if (strcmp(invo_name, "fprev") == 0) { - run_mode = FPREV; - } else if (strcmp(invo_name, "unseen") == 0) { - run_mode = UNSEEN; - } - - if (folders == NULL) { - /* will flists */ - } else { - if (folders[0] != '/') { - folders = m_maildir(folders); + + if (folders == NULL) { + /* will flists */ + } else { + if (folders[0] != '/') { + folders = toabsdir(folders); + } } - } - if (i == 0) { - /* no sequence arguments; use unseen */ - unseen = context_find(usequence); - if (unseen == NULL || unseen[0] == '\0') { - adios(NULL, "must specify sequences or set %s", usequence); + if (i == 0) { + char *dp; + /* no sequence arguments; use unseen */ + if ((unseen = context_find(usequence))) { + if (!*unseen) { + adios(NULL, "profile entry %s set, but empty, and no sequences given", usequence); + } + } else { + unseen = seq_unseen; /* use default */ + } + dp = getcpy(unseen); + for (ap = brkstring(dp, " ", "\n"); *ap; ap++) { + sequences[i++] = *ap; + } } - for (ap = brkstring(unseen, " ", "\n"); *ap; ap++) { - sequences[i++] = *ap; + sequences[i] = NULL; + + folder = doit(context_find(curfolder), folders, sequences); + if (folder == NULL) { + done(0); + return 1; } - } - sequences[i] = NULL; - - folder = doit(context_find(pfolder), folders, sequences); - if (folder == NULL) { - done(0); - return 1; - } - - if (run_mode == UNSEEN) { - /* All the scan(1)s it runs change the current folder, so we - * need to put it back. Unfortunately, context_replace lamely - * ignores the new value you give it if it is the same one it - * has in memory. So, we'll be lame, too. I'm not sure if i - * should just change context_replace... */ - context_replace(pfolder, "defeat_context_replace_optimization"); - } - - /* update current folder */ - context_replace(pfolder, folder->n_name); - - if (run_mode == FNEXT || run_mode == FPREV) { - printf("%s %s\n", folder->n_name, folder->n_field); - } - - context_save(); - - done (0); - return 1; + + if (run_mode == UNSEEN) { + /* + ** All the scan(1)s it runs change the current folder, so we + ** need to put it back. Unfortunately, context_replace lamely + ** ignores the new value you give it if it is the same one it + ** has in memory. So, we'll be lame, too. I'm not sure if i + ** should just change context_replace... + */ + context_replace(curfolder, "defeat_context_replace_optimization"); + } + + /* update current folder */ + context_replace(curfolder, folder->n_name); + + if (run_mode == FNEXT || run_mode == FPREV) { + printf("%s %s\n", folder->n_name, folder->n_field); + } + + context_save(); + + done(0); + return 1; } diff --git a/uip/packf.c b/uip/packf.c index c365440..763b6e7 100644 --- a/uip/packf.c +++ b/uip/packf.c @@ -1,11 +1,10 @@ - /* - * packf.c -- pack a nmh folder into a file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** packf.c -- pack a nmh folder into a file +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,176 +13,106 @@ #include static struct swit switches[] = { -#define FILESW 0 - { "file name", 0 }, -#define MBOXSW 1 - { "mbox", 0 }, -#define MMDFSW 2 - { "mmdf", 0 }, -#define VERSIONSW 3 - { "version", 0 }, -#define HELPSW 4 - { "help", 0 }, - { NULL, 0 } +#define VERSIONSW 0 + { "Version", 0 }, +#define HELPSW 1 + { "help", 0 }, + { NULL, 0 } }; -static int md = NOTOK; -static int mbx_style = MBOX_FORMAT; -static int mapping = 0; - -static void mbxclose_done(int) NORETURN; - -char *file = NULL; - int -main (int argc, char **argv) +main(int argc, char **argv) { - int fd, msgnum; - char *cp, *maildir, *msgnam, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - struct stat st; - - done=mbxclose_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FILESW: - if (file) - adios (NULL, "only one file at a time!"); - if (!(file = *argp++) || *file == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case MBOXSW: - mbx_style = MBOX_FORMAT; - mapping = 0; - continue; - case MMDFSW: - mbx_style = MMDF_FORMAT; - mapping = 1; - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!file) - file = "./msgbox"; - file = path (file, TFILE); - - /* - * Check if file to be created (or appended to) - * exists. If not, ask for confirmation. - */ - if (stat (file, &st) == NOTOK) { - if (errno != ENOENT) - adios (file, "error on file"); - cp = concat ("Create file \"", file, "\"? ", NULL); - if (!getanswer (cp)) - done (1); - free (cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* default is to pack whole folder */ - if (!msgs.size) - app_msgarg(&msgs, "all"); - - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to "); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - /* open and lock new maildrop file */ - if ((md = mbx_open(file, mbx_style, getuid(), getgid(), m_gmprot())) == NOTOK) - adios (file, "unable to open"); - - /* copy all the SELECTED messages to the file */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected(mp, msgnum)) { - if ((fd = open (msgnam = m_name (msgnum), O_RDONLY)) == NOTOK) { - admonish (msgnam, "unable to read message"); - break; - } - - if (mbx_copy (file, mbx_style, md, fd, mapping, NULL, 1) == NOTOK) - adios (file, "error writing to file"); - - close (fd); + int fd, msgnum; + char *cp, *maildir, *msgnam, *folder = NULL, buf[BUFSIZ]; + char **argp, **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); } - /* close and unlock maildrop file */ - mbx_close (file, md); - - context_replace (pfolder, folder); /* update current folder */ - if (mp->hghsel != mp->curmsg) - seq_setcur (mp, mp->lowsel); - seq_save (mp); - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; -} - -static void -mbxclose_done (int status) -{ - mbx_close (file, md); - exit (status); + /* default is to pack whole folder */ + if (!msgs.size) + app_msgarg(&msgs, seq_all); + + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to "); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + /* copy all the SELECTED messages to stdout */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if ((fd = open(msgnam = m_name(msgnum), O_RDONLY)) + == NOTOK) { + admonish(msgnam, "unable to read message"); + break; + } + if (mbox_copy(fileno(stdout), fd) == NOTOK) { + adios(NULL, "error writing to stdout"); + } + close(fd); + } + } + context_replace(curfolder, folder); + if (mp->hghsel != mp->curmsg) + seq_setcur(mp, mp->lowsel); + seq_save(mp); + context_save(); + folder_free(mp); + done(0); + return 1; } diff --git a/uip/pick.c b/uip/pick.c index 24e6862..e94c259 100644 --- a/uip/pick.c +++ b/uip/pick.c @@ -1,306 +1,1285 @@ - /* - * pick.c -- search for messages by content - * - * This code is Copyright (c) 2002, 2008, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** pick.c -- search for messages by content +** +** This code is Copyright (c) 2002, 2008, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include -#include #include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + static struct swit switches[] = { -#define ANDSW 0 - { "and", 0 }, -#define ORSW 1 - { "or", 0 }, -#define NOTSW 2 - { "not", 0 }, -#define LBRSW 3 - { "lbrace", 0 }, -#define RBRSW 4 - { "rbrace", 0 }, -#define CCSW 5 - { "cc pattern", 0 }, -#define DATESW 6 - { "date pattern", 0 }, -#define FROMSW 7 - { "from pattern", 0 }, -#define SRCHSW 8 - { "search pattern", 0 }, -#define SUBJSW 9 - { "subject pattern", 0 }, -#define TOSW 10 - { "to pattern", 0 }, -#define OTHRSW 11 - { "-othercomponent pattern", 0 }, -#define AFTRSW 12 - { "after date", 0 }, -#define BEFRSW 13 - { "before date", 0 }, -#define DATFDSW 14 - { "datefield field", 5 }, -#define SEQSW 15 - { "sequence name", 0 }, -#define PUBLSW 16 - { "public", 0 }, -#define NPUBLSW 17 - { "nopublic", 0 }, -#define ZEROSW 18 - { "zero", 0 }, -#define NZEROSW 19 - { "nozero", 0 }, -#define LISTSW 20 - { "list", 0 }, -#define NLISTSW 21 - { "nolist", 0 }, -#define VERSIONSW 22 - { "version", 0 }, -#define HELPSW 23 - { "help", 0 }, - { NULL, 0 } +#define ANDSW 0 + { "and", 0 }, +#define ORSW 1 + { "or", 0 }, +#define NOTSW 2 + { "not", 0 }, +#define LBRSW 3 + { "lbrace", 0 }, +#define RBRSW 4 + { "rbrace", 0 }, +#define CCSW 5 + { "cc pattern", 0 }, +#define DATESW 6 + { "date pattern", 0 }, +#define FROMSW 7 + { "from pattern", 0 }, +#define SRCHSW 8 + { "search pattern", 0 }, +#define SUBJSW 9 + { "subject pattern", 0 }, +#define TOSW 10 + { "to pattern", 0 }, +#define OTHRSW 11 + { "-othercomponent pattern", 0 }, +#define AFTRSW 12 + { "after date", 0 }, +#define BEFRSW 13 + { "before date", 0 }, +#define DATFDSW 14 + { "datefield field", 5 }, /* 5 chars required to differ from -date */ +#define SEQSW 15 + { "sequence name", 0 }, +#define PUBLSW 16 + { "public", 0 }, +#define NPUBLSW 17 + { "nopublic", 2 }, +#define ZEROSW 18 + { "zero", 0 }, +#define NZEROSW 19 + { "nozero", 2 }, +#define LISTSW 20 + { "list", 0 }, +#define NLISTSW 21 + { "nolist", 2 }, +#define VERSIONSW 22 + { "Version", 0 }, +#define HELPSW 23 + { "help", 0 }, + { NULL, 0 } }; +/* +** static prototypes +*/ +static int pcompile(char **, char *); +static int pmatches(FILE *, int, long, long); + + static int listsw = -1; -static void putzero_done (int) NORETURN; +static void putzero_done(int) NORETURN; int -main (int argc, char **argv) +main(int argc, char **argv) { - int publicsw = -1, zerosw = 1, seqp = 0, vecp = 0; - int lo, hi, msgnum; - char *maildir, *folder = NULL, buf[100]; - char *cp, **argp, **arguments; - char *seqs[NUMATTRS + 1], *vec[MAXARGS]; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - register FILE *fp; - - done=putzero_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); + int publicsw = -1, zerosw = 1, vecp = 0; + unsigned int seqp = 0; + int lo, hi, msgnum; + char *maildir, *folder = NULL, buf[100]; + char *cp, **argp, **arguments; + char *seqs[NUMATTRS + 1], *vec[MAXARGS]; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + register FILE *fp; - /* read user profile/context */ - context_read(); + done=putzero_done; - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); - while ((cp = *argp++)) { - if (*cp == '-') { - if (*++cp == '-') { - vec[vecp++] = --cp; - goto pattern; - } - switch (smatch (cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - listsw = 0; /* HACK */ - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - listsw = 0; /* HACK */ - done (1); - case VERSIONSW: - print_version(invo_name); - listsw = 0; /* HACK */ - done (1); - - case CCSW: - case DATESW: - case FROMSW: - case SUBJSW: - case TOSW: - case DATFDSW: - case AFTRSW: - case BEFRSW: - case SRCHSW: - vec[vecp++] = --cp; - pattern: - if (!(cp = *argp++))/* allow -xyz arguments */ - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; - case OTHRSW: - adios (NULL, "internal error!"); - - case ANDSW: - case ORSW: - case NOTSW: - case LBRSW: - case RBRSW: - vec[vecp++] = --cp; - continue; - - case SEQSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - - /* check if too many sequences specified */ - if (seqp >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) specified", NUMATTRS); - - if (!seq_nameok (cp)) - done (1); - - seqs[seqp++] = cp; - continue; - case PUBLSW: - publicsw = 1; - continue; - case NPUBLSW: - publicsw = 0; - continue; - case ZEROSW: - zerosw++; - continue; - case NZEROSW: - zerosw = 0; - continue; - - case LISTSW: - listsw = 1; - continue; - case NLISTSW: - listsw = 0; - continue; - } + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + if (*++cp == '-') { + vec[vecp++] = --cp; + goto pattern; + } + switch (smatch(cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + listsw = 0; /* HACK */ + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + listsw = 0; /* HACK */ + done(1); + case VERSIONSW: + print_version(invo_name); + listsw = 0; /* HACK */ + done(1); + + case CCSW: + case DATESW: + case FROMSW: + case SUBJSW: + case TOSW: + case DATFDSW: + case AFTRSW: + case BEFRSW: + case SRCHSW: + vec[vecp++] = --cp; + pattern: + if (!(cp = *argp++)) /* allow -xyz arguments */ + adios(NULL, "missing argument to %s", + argp[-2]); + vec[vecp++] = cp; + continue; + case OTHRSW: + adios(NULL, "internal error!"); + + case ANDSW: + case ORSW: + case NOTSW: + case LBRSW: + case RBRSW: + vec[vecp++] = --cp; + continue; + + case SEQSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + + /* check if too many sequences specified */ + if (seqp >= NUMATTRS) + adios(NULL, "too many sequences (more than %d) specified", NUMATTRS); + + if (!seq_nameok(cp)) + done(1); + + seqs[seqp++] = cp; + continue; + case PUBLSW: + publicsw = 1; + continue; + case NPUBLSW: + publicsw = 0; + continue; + case ZEROSW: + zerosw++; + continue; + case NZEROSW: + zerosw = 0; + continue; + + case LISTSW: + listsw = 1; + continue; + case NLISTSW: + listsw = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + vec[vecp] = NULL; + + /* + ** If we didn't specify which messages to search, + ** then search the whole folder. + */ + if (!msgs.size) + app_msgarg(&msgs, seq_all); + + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + /* + ** If we aren't saving the results to a sequence, + ** we default to list the results. + */ + if (listsw == -1) + listsw = !seqp; + + if (publicsw == 1 && is_readonly(mp)) + adios(NULL, "folder %s is read-only, so -public not allowed", + folder); + + if (!pcompile(vec, NULL)) + done(1); + + lo = mp->lowsel; + hi = mp->hghsel; + + /* + ** If printing message numbers to standard out, + ** force line buffering on. + */ + if (listsw) + setvbuf(stdout, NULL, _IOLBF, 0); + + /* + ** Scan through all the SELECTED messages and check for a + ** match. If the message does not match, then unselect it. + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if ((fp = fopen(cp = m_name(msgnum), "r")) == NULL) + admonish(cp, "unable to read message"); + if (fp && pmatches(fp, msgnum, 0L, 0L)) { + if (msgnum < lo) + lo = msgnum; + if (msgnum > hi) + hi = msgnum; + + if (listsw) + printf("%s\n", m_name(msgnum)); + } else { + /* if it doesn't match, then unselect it */ + unset_selected(mp, msgnum); + mp->numsel--; + } + if (fp) + fclose(fp); + } + } + + mp->lowsel = lo; + mp->hghsel = hi; + + if (mp->numsel <= 0) + adios(NULL, "no messages match specification"); + + seqs[seqp] = NULL; + + /* + ** Add the matching messages to sequences + */ + for (seqp = 0; seqs[seqp]; seqp++) + if (!seq_addsel(mp, seqs[seqp], publicsw, zerosw)) + done(1); + + /* + ** Print total matched if not printing each matched message number. + */ + if (!listsw) { + printf("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s"); + } + + context_replace(curfolder, folder); /* update current folder */ + seq_save(mp); /* synchronize message sequences */ + context_save(); /* save the context file */ + folder_free(mp); /* free folder/message structure */ + done(0); + return 1; +} + + +static void +putzero_done(int status) +{ + if (listsw && status && !isatty(fileno(stdout))) + printf("0\n"); + exit(status); +} + + +static struct swit parswit[] = { +#define PRAND 0 + { "and", 0 }, +#define PROR 1 + { "or", 0 }, +#define PRNOT 2 + { "not", 0 }, +#define PRLBR 3 + { "lbrace", 0 }, +#define PRRBR 4 + { "rbrace", 0 }, +#define PRCC 5 + { "cc pattern", 0 }, +#define PRDATE 6 + { "date pattern", 0 }, +#define PRFROM 7 + { "from pattern", 0 }, +#define PRSRCH 8 + { "search pattern", 0 }, +#define PRSUBJ 9 + { "subject pattern", 0 }, +#define PRTO 10 + { "to pattern", 0 }, +#define PROTHR 11 + { "-othercomponent pattern", 15 }, +#define PRAFTR 12 + { "after date", 0 }, +#define PRBEFR 13 + { "before date", 0 }, +#define PRDATF 14 + { "datefield field", 5 }, + { NULL, 0 } +}; + +/* DEFINITIONS FOR PATTERN MATCHING */ + +/* +** We really should be using re_comp() and re_exec() here. Unfortunately, +** pick advertises that lowercase characters matches characters of both +** cases. Since re_exec() doesn't exhibit this behavior, we are stuck +** with this version. Furthermore, we need to be able to save and restore +** the state of the pattern matcher in order to do things "efficiently". +** +** The matching power of this algorithm isn't as powerful as the re_xxx() +** routines (no \(xxx\) and \n constructs). Such is life. +*/ + +#define CCHR 2 +#define CDOT 4 +#define CCL 6 +#define NCCL 8 +#define CDOL 10 +#define CEOF 11 + +#define STAR 01 + +#define LBSIZE 1024 +#define ESIZE 1024 + + +static char linebuf[LBSIZE + 1]; + +/* the magic array for case-independence */ +static char cc[] = { + 0000,0001,0002,0003,0004,0005,0006,0007, + 0010,0011,0012,0013,0014,0015,0016,0017, + 0020,0021,0022,0023,0024,0025,0026,0027, + 0030,0031,0032,0033,0034,0035,0036,0037, + 0040,0041,0042,0043,0044,0045,0046,0047, + 0050,0051,0052,0053,0054,0055,0056,0057, + 0060,0061,0062,0063,0064,0065,0066,0067, + 0070,0071,0072,0073,0074,0075,0076,0077, + 0100,0141,0142,0143,0144,0145,0146,0147, + 0150,0151,0152,0153,0154,0155,0156,0157, + 0160,0161,0162,0163,0164,0165,0166,0167, + 0170,0171,0172,0133,0134,0135,0136,0137, + 0140,0141,0142,0143,0144,0145,0146,0147, + 0150,0151,0152,0153,0154,0155,0156,0157, + 0160,0161,0162,0163,0164,0165,0166,0167, + 0170,0171,0172,0173,0174,0175,0176,0177, + + 0200,0201,0202,0203,0204,0205,0206,0207, + 0210,0211,0212,0213,0214,0215,0216,0217, + 0220,0221,0222,0223,0224,0225,0226,0227, + 0230,0231,0232,0233,0234,0235,0236,0237, + 0240,0241,0242,0243,0244,0245,0246,0247, + 0250,0251,0252,0253,0254,0255,0256,0257, + 0260,0261,0262,0263,0264,0265,0266,0267, + 0270,0271,0272,0273,0274,0275,0276,0277, + 0300,0301,0302,0303,0304,0305,0306,0307, + 0310,0311,0312,0313,0314,0315,0316,0317, + 0320,0321,0322,0323,0324,0325,0326,0327, + 0330,0331,0332,0333,0334,0335,0336,0337, + 0340,0341,0342,0343,0344,0345,0346,0347, + 0350,0351,0352,0353,0354,0355,0356,0357, + 0360,0361,0362,0363,0364,0365,0366,0367, + 0370,0371,0372,0373,0374,0375,0376,0377, +}; + +/* +** DEFINITIONS FOR NEXUS +*/ + +#define nxtarg() (*argp ? *argp++ : NULL) +#define prvarg() argp-- + +#define padvise if (!talked++) advise + +struct nexus { + int (*n_action)(); + + union { + /* for {OR,AND,NOT}action */ + struct { + struct nexus *un_L_child; + struct nexus *un_R_child; + } st1; + + /* for GREPaction */ + struct { + int un_header; + int un_circf; + char un_expbuf[ESIZE]; + char *un_patbuf; + } st2; + + /* for TWSaction */ + struct { + char *un_datef; + int un_after; + struct tws un_tws; + } st3; + } un; +}; + +#define n_L_child un.st1.un_L_child +#define n_R_child un.st1.un_R_child + +#define n_header un.st2.un_header +#define n_circf un.st2.un_circf +#define n_expbuf un.st2.un_expbuf +#define n_patbuf un.st2.un_patbuf + +#define n_datef un.st3.un_datef +#define n_after un.st3.un_after +#define n_tws un.st3.un_tws + +static int talked; +static int pdebug = 0; + +static char *datesw; +static char **argp; + +static struct nexus *head; + +/* +** prototypes for date routines +*/ +static struct tws *tws_parse(char *, int); +static struct tws *tws_special(char *); + +/* +** static prototypes +*/ +static void PRaction(struct nexus *, int); +static int gcompile(struct nexus *, char *); +static int advance(char *, char *); +static int cclass(unsigned char *, int, int); +static int tcompile(char *, struct tws *, int); + +static struct nexus *parse(void); +static struct nexus *nexp1(void); +static struct nexus *nexp2(void); +static struct nexus *nexp3(void); +static struct nexus *newnexus(int (*)()); + +static int ORaction(); +static int ANDaction(); +static int NOTaction(); +static int GREPaction(); +static int TWSaction(); + + +static int +pcompile(char **vec, char *date) +{ + register char *cp; + + if ((cp = getenv("MHPDEBUG")) && *cp) + pdebug++; + + argp = vec; + if ((datesw = date) == NULL) + datesw = "date"; + talked = 0; + + if ((head = parse()) == NULL) + return (talked ? 0 : 1); + + if (*argp) { + padvise(NULL, "%s unexpected", *argp); + return 0; + } + + return 1; +} + + +static struct nexus * +parse(void) +{ + register char *cp; + register struct nexus *n, *o; + + if ((n = nexp1()) == NULL || (cp = nxtarg()) == NULL) + return n; + + if (*cp != '-') { + padvise(NULL, "%s unexpected", cp); + return NULL; + } + + if (*++cp == '-') + goto header; + switch (smatch(cp, parswit)) { + case AMBIGSW: + ambigsw(cp, parswit); + talked++; + return NULL; + case UNKWNSW: + fprintf(stderr, "-%s unknown\n", cp); + talked++; + return NULL; + + case PROR: + o = newnexus(ORaction); + o->n_L_child = n; + if ((o->n_R_child = parse())) + return o; + padvise(NULL, "missing disjunctive"); + return NULL; + +header: ; + default: + prvarg(); + return n; + } +} + +static struct nexus * +nexp1(void) +{ + register char *cp; + register struct nexus *n, *o; + + if ((n = nexp2()) == NULL || (cp = nxtarg()) == NULL) + return n; + + if (*cp != '-') { + padvise(NULL, "%s unexpected", cp); + return NULL; + } + + if (*++cp == '-') + goto header; + switch (smatch(cp, parswit)) { + case AMBIGSW: + ambigsw(cp, parswit); + talked++; + return NULL; + case UNKWNSW: + fprintf(stderr, "-%s unknown\n", cp); + talked++; + return NULL; + + case PRAND: + o = newnexus(ANDaction); + o->n_L_child = n; + if ((o->n_R_child = nexp1())) + return o; + padvise(NULL, "missing conjunctive"); + return NULL; + +header: ; + default: + prvarg(); + return n; + } +} + + +static struct nexus * +nexp2(void) +{ + register char *cp; + register struct nexus *n; + + if ((cp = nxtarg()) == NULL) + return NULL; + + if (*cp != '-') { + prvarg(); + return nexp3(); + } + + if (*++cp == '-') + goto header; + switch (smatch(cp, parswit)) { + case AMBIGSW: + ambigsw(cp, parswit); + talked++; + return NULL; + case UNKWNSW: + fprintf(stderr, "-%s unknown\n", cp); + talked++; + return NULL; + + case PRNOT: + n = newnexus(NOTaction); + if ((n->n_L_child = nexp3())) + return n; + padvise(NULL, "missing negation"); + return NULL; + +header: ; + default: + prvarg(); + return nexp3(); + } +} + +static struct nexus * +nexp3(void) +{ + int i; + register char *cp, *dp; + char buffer[BUFSIZ], temp[64]; + register struct nexus *n; + + if ((cp = nxtarg()) == NULL) + return NULL; + + if (*cp != '-') { + padvise(NULL, "%s unexpected", cp); + return NULL; + } + + if (*++cp == '-') { + dp = ++cp; + goto header; } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - vec[vecp] = NULL; - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* - * If we didn't specify which messages to search, - * then search the whole folder. - */ - if (!msgs.size) - app_msgarg(&msgs, "all"); - - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - /* - * If we aren't saving the results to a sequence, - * we default to list the results. - */ - if (listsw == -1) - listsw = !seqp; - - if (publicsw == 1 && is_readonly(mp)) - adios (NULL, "folder %s is read-only, so -public not allowed", folder); - - if (!pcompile (vec, NULL)) - done (1); - - lo = mp->lowsel; - hi = mp->hghsel; - - /* If printing message numbers to standard out, force line buffering on. - */ - if (listsw) - setvbuf (stdout, NULL, _IOLBF, 0); - - /* - * Scan through all the SELECTED messages and check for a - * match. If the message does not match, then unselect it. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - if ((fp = fopen (cp = m_name (msgnum), "r")) == NULL) - admonish (cp, "unable to read message"); - if (fp && pmatches (fp, msgnum, 0L, 0L)) { - if (msgnum < lo) - lo = msgnum; - if (msgnum > hi) - hi = msgnum; - - if (listsw) - printf ("%s\n", m_name (msgnum)); - } else { - /* if it doesn't match, then unselect it */ - unset_selected (mp, msgnum); - mp->numsel--; - } - if (fp) - fclose (fp); + switch (i = smatch(cp, parswit)) { + case AMBIGSW: + ambigsw(cp, parswit); + talked++; + return NULL; + case UNKWNSW: + fprintf(stderr, "-%s unknown\n", cp); + talked++; + return NULL; + + case PRLBR: + if ((n = parse()) == NULL) { + padvise(NULL, "missing group"); + return NULL; + } + if ((cp = nxtarg()) == NULL) { + padvise(NULL, "missing -rbrace"); + return NULL; + } + if (*cp++ == '-' && smatch(cp, parswit) == PRRBR) + return n; + padvise(NULL, "%s unexpected", --cp); + return NULL; + + default: + prvarg(); + return NULL; + + case PRCC: + case PRDATE: + case PRFROM: + case PRTO: + case PRSUBJ: + strncpy(temp, parswit[i].sw, sizeof(temp)); + temp[sizeof(temp) - 1] = '\0'; + dp = *brkstring(temp, " ", NULL); +header: ; + if (!(cp = nxtarg())) { /* allow -xyz arguments */ + padvise(NULL, "missing argument to %s", argp[-2]); + return NULL; + } + n = newnexus(GREPaction); + n->n_header = 1; + snprintf(buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp); + dp = buffer; + goto pattern; + + case PRSRCH: + n = newnexus(GREPaction); + n->n_header = 0; + if (!(cp = nxtarg())) { /* allow -xyz arguments */ + padvise(NULL, "missing argument to %s", argp[-2]); + return NULL; + } + dp = cp; +pattern: ; + if (!gcompile(n, dp)) { + padvise(NULL, "pattern error in %s %s", argp[-2], cp); + return NULL; + } + n->n_patbuf = getcpy(dp); + return n; + + case PROTHR: + padvise(NULL, "internal error!"); + return NULL; + + case PRDATF: + if (!(datesw = nxtarg()) || *datesw == '-') { + padvise(NULL, "missing argument to %s", + argp[-2]); + return NULL; + } + return nexp3(); + + case PRAFTR: + case PRBEFR: + if (!(cp = nxtarg())) { /* allow -xyz arguments */ + padvise(NULL, "missing argument to %s", argp[-2]); + return NULL; + } + n = newnexus(TWSaction); + n->n_datef = datesw; + if (!tcompile(cp, &n->n_tws, n->n_after = i == PRAFTR)) { + padvise(NULL, "unable to parse %s %s", argp[-2], cp); + return NULL; + } + return n; } - } - - mp->lowsel = lo; - mp->hghsel = hi; - - if (mp->numsel <= 0) - adios (NULL, "no messages match specification"); - - seqs[seqp] = NULL; - - /* - * Add the matching messages to sequences - */ - for (seqp = 0; seqs[seqp]; seqp++) - if (!seq_addsel (mp, seqs[seqp], publicsw, zerosw)) - done (1); - - /* - * Print total matched if not printing each matched message number. - */ - if (!listsw) { - printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s"); - } - - context_replace (pfolder, folder); /* update current folder */ - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; +} + + +static struct nexus * +newnexus(int (*action)()) +{ + register struct nexus *p; + + if ((p = (struct nexus *) calloc((size_t) 1, sizeof *p)) == NULL) + adios(NULL, "unable to allocate component storage"); + + p->n_action = action; + return p; +} + + +#define args(a) a, fp, msgnum, start, stop +#define params args(n) +#define plist \ + register struct nexus *n; \ + register FILE *fp; \ + int msgnum; \ + long start, \ + stop; + +static int +pmatches(FILE *fp, int msgnum, long start, long stop) +{ + if (!head) + return 1; + + if (!talked++ && pdebug) + PRaction(head, 0); + + return (*head->n_action) (args(head)); } static void -putzero_done (int status) +PRaction(struct nexus *n, int level) +{ + register int i; + + for (i = 0; i < level; i++) + fprintf(stderr, "| "); + + if (n->n_action == ORaction) { + fprintf(stderr, "OR\n"); + PRaction(n->n_L_child, level + 1); + PRaction(n->n_R_child, level + 1); + return; + } + if (n->n_action == ANDaction) { + fprintf(stderr, "AND\n"); + PRaction(n->n_L_child, level + 1); + PRaction(n->n_R_child, level + 1); + return; + } + if (n->n_action == NOTaction) { + fprintf(stderr, "NOT\n"); + PRaction(n->n_L_child, level + 1); + return; + } + if (n->n_action == GREPaction) { + fprintf(stderr, "PATTERN(%s) %s\n", + n->n_header ? "header" : "body", n->n_patbuf); + return; + } + if (n->n_action == TWSaction) { + fprintf(stderr, "TEMPORAL(%s) %s: %s\n", + n->n_after ? "after" : "before", n->n_datef, + dasctime(&n->n_tws)); + return; + } + fprintf(stderr, "UNKNOWN(0x%x)\n", + (unsigned int)(unsigned long) (*n->n_action)); +} + + +static int +ORaction(params) +plist +{ + if ((*n->n_L_child->n_action) (args(n->n_L_child))) + return 1; + return (*n->n_R_child->n_action) (args(n->n_R_child)); +} + + +static int +ANDaction(params) +plist +{ + if (!(*n->n_L_child->n_action) (args(n->n_L_child))) + return 0; + return (*n->n_R_child->n_action) (args(n->n_R_child)); +} + + +static int +NOTaction(params) +plist +{ + return (!(*n->n_L_child->n_action) (args(n->n_L_child))); +} + + +static int +gcompile(struct nexus *n, char *astr) +{ + register int c; + int cclcnt; + register unsigned char *ep, *dp, *sp, *lastep = 0; + + dp = (ep = n->n_expbuf) + sizeof n->n_expbuf; + sp = astr; + if (*sp == '^') { + n->n_circf = 1; + sp++; + } + else + n->n_circf = 0; + for (;;) { + if (ep >= dp) + goto cerror; + if ((c = *sp++) != '*') + lastep = ep; + switch (c) { + case '\0': + *ep++ = CEOF; + return 1; + + case '.': + *ep++ = CDOT; + continue; + + case '*': + if (lastep == 0) + goto defchar; + *lastep |= STAR; + continue; + + case '$': + if (*sp != '\0') + goto defchar; + *ep++ = CDOL; + continue; + + case '[': + *ep++ = CCL; + *ep++ = 0; + cclcnt = 0; + if ((c = *sp++) == '^') { + c = *sp++; + ep[-2] = NCCL; + } + if (c == '-') { + *ep++ = c; + cclcnt++; + c = *sp++; + } + do { + if (c == '-' && *sp != '\0' && *sp != ']') { + for (c = ep[-1]+1; c < *sp; c++) { + *ep++ = c; + cclcnt++; + if (c == '\0' || ep >= dp) + goto cerror; + } + } else { + *ep++ = c; + cclcnt++; + if (c == '\0' || ep >= dp) + goto cerror; + } + } while ((c = *sp++) != ']'); + if (cclcnt > 255) + goto cerror; + lastep[1] = cclcnt; + continue; + + case '\\': + if ((c = *sp++) == '\0') + goto cerror; +defchar: + default: + *ep++ = CCHR; + *ep++ = c; + } + } + +cerror: ; + return 0; +} + + +static int +GREPaction(params) +plist +{ + int c, body, lf; + long pos = start; + register char *p1, *p2, *ebp, *cbp; + char ibuf[BUFSIZ]; + + fseek(fp, start, SEEK_SET); + body = 0; + ebp = cbp = ibuf; + for (;;) { + if (body && n->n_header) + return 0; + p1 = linebuf; + p2 = cbp; + lf = 0; + for (;;) { + if (p2 >= ebp) { + if (fgets(ibuf, sizeof ibuf, fp) == NULL + || (stop && pos >= stop)) { + if (lf) + break; + return 0; + } + pos += (long) strlen(ibuf); + p2 = ibuf; + ebp = ibuf + strlen(ibuf); + } + c = *p2++; + if (lf && c != '\n') { + if (c != ' ' && c != '\t') { + --p2; + break; + } + else + lf = 0; + } + if (c == '\n') { + if (body) + break; + else { + if (lf) { + body++; + break; + } + lf++; + c = ' '; + } + } + if (c && p1 < &linebuf[LBSIZE - 1]) + *p1++ = c; + } + + *p1++ = 0; + cbp = p2; + p1 = linebuf; + p2 = n->n_expbuf; + + if (n->n_circf) { + if (advance(p1, p2)) + return 1; + continue; + } + + if (*p2 == CCHR) { + c = p2[1]; + do { + if (*p1 == c || cc[(unsigned char)*p1] == c) + if (advance(p1, p2)) + return 1; + } while (*p1++); + continue; + } + + do { + if (advance(p1, p2)) + return 1; + } while (*p1++); + } +} + + +static int +advance(char *alp, char *aep) +{ + register unsigned char *lp, *ep, *curlp; + + lp = (unsigned char *)alp; + ep = (unsigned char *)aep; + for (;;) + switch (*ep++) { + case CCHR: + if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]]) + continue; + return 0; + + case CDOT: + if (*lp++) + continue; + return 0; + + case CDOL: + if (*lp == 0) + continue; + return 0; + + case CEOF: + return 1; + + case CCL: + if (cclass(ep, *lp++, 1)) { + ep += *ep + 1; + continue; + } + return 0; + + case NCCL: + if (cclass(ep, *lp++, 0)) { + ep += *ep + 1; + continue; + } + return 0; + + case CDOT | STAR: + curlp = lp; + while (*lp++) + continue; + goto star; + + case CCHR | STAR: + curlp = lp; + while (*lp++ == *ep || cc[lp[-1]] == *ep) + continue; + ep++; + goto star; + + case CCL | STAR: + case NCCL | STAR: + curlp = lp; + while (cclass(ep, *lp++, ep[-1] == (CCL | STAR))) + continue; + ep += *ep + 1; + goto star; + +star: + do { + lp--; + if (advance(lp, ep)) + return (1); + } while (lp > curlp); + return 0; + + default: + admonish(NULL, "advance() botch -- you lose big"); + return 0; + } +} + + +static int +cclass(unsigned char *aset, int ac, int af) +{ + register unsigned int n; + register unsigned char c, *set; + + set = aset; + if ((c = ac) == 0) + return (0); + + n = *set++; + while (n--) + if (*set++ == c || set[-1] == cc[c]) + return (af); + + return (!af); +} + + +static int +tcompile(char *ap, struct tws *tb, int isafter) { - if (listsw && status && !isatty (fileno (stdout))) - printf ("0\n"); - exit (status); + register struct tws *tw; + + if ((tw = tws_parse(ap, isafter)) == NULL) + return 0; + + twscopy(tb, tw); + return 1; +} + + +static struct tws * +tws_parse(char *ap, int isafter) +{ + char buffer[BUFSIZ]; + register struct tws *tw, *ts; + + if ((tw = tws_special(ap)) != NULL) { + tw->tw_sec = tw->tw_min = isafter ? 59 : 0; + tw->tw_hour = isafter ? 23 : 0; + return tw; + } + if ((tw = dparsetime(ap)) != NULL) + return tw; + + if ((ts = dlocaltimenow()) == NULL) + return NULL; + + snprintf(buffer, sizeof(buffer), "%s %s", ap, dtwszone(ts)); + if ((tw = dparsetime(buffer)) != NULL) + return tw; + + snprintf(buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap, + ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone(ts)); + if ((tw = dparsetime(buffer)) != NULL) + return tw; + + snprintf(buffer, sizeof(buffer), "%02d %s %04d %s", + ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap); + if ((tw = dparsetime(buffer)) != NULL) + return tw; + + snprintf(buffer, sizeof(buffer), "%02d %s %04d %s %s", + ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, + ap, dtwszone(ts)); + if ((tw = dparsetime(buffer)) != NULL) + return tw; + + return NULL; +} + + +static struct tws * +tws_special(char *ap) +{ + int i; + time_t clock; + register struct tws *tw; + + time(&clock); + if (!mh_strcasecmp(ap, "today")) + return dlocaltime(&clock); + if (!mh_strcasecmp(ap, "yesterday")) { + clock -= (long) (60 * 60 * 24); + return dlocaltime(&clock); + } + if (!mh_strcasecmp(ap, "tomorrow")) { + clock += (long) (60 * 60 * 24); + return dlocaltime(&clock); + } + + for (i = 0; tw_ldotw[i]; i++) + if (!mh_strcasecmp(ap, tw_ldotw[i])) + break; + if (tw_ldotw[i]) { + if ((tw = dlocaltime(&clock)) == NULL) + return NULL; + if ((i -= tw->tw_wday) > 0) + i -= 7; + } + else + if (*ap != '-') + return NULL; + else /* -ddd days ago */ + i = atoi(ap); /* we should error check this */ + + clock += (long) ((60 * 60 * 24) * i); + return dlocaltime(&clock); +} + + +static int +TWSaction(params) +plist +{ + int state; + register char *bp; + char buf[BUFSIZ], name[NAMESZ]; + register struct tws *tw; + + fseek(fp, start, SEEK_SET); + for (state = FLD, bp = NULL;;) { + switch (state = m_getfld(state, name, buf, sizeof buf, fp)) { + case FLD: + case FLDEOF: + case FLDPLUS: + if (bp != NULL) { + free(bp); + bp = NULL; + } + bp = getcpy(buf); + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof buf, fp); + bp = add(buf, bp); + } + if (!mh_strcasecmp(name, n->n_datef)) + break; + if (state != FLDEOF) + continue; + + case BODY: + case BODYEOF: + case FILEEOF: + case LENERR: + case FMTERR: + if (state == LENERR || state == FMTERR) + advise(NULL, "format error in message %d", msgnum); + if (bp != NULL) + free(bp); + return 0; + + default: + adios(NULL, "internal error -- you lose"); + } + break; + } + + if ((tw = dparsetime(bp)) == NULL) + advise(NULL, "unable to parse %s field in message %d, matching...", + n->n_datef, msgnum), state = 1; + else + state = n->n_after ? (twsort(tw, &n->n_tws) > 0) + : (twsort(tw, &n->n_tws) < 0); + + if (bp != NULL) + free(bp); + return state; } diff --git a/uip/picksbr.c b/uip/picksbr.c deleted file mode 100644 index bd4c263..0000000 --- a/uip/picksbr.c +++ /dev/null @@ -1,988 +0,0 @@ - -/* - * picksbr.c -- routines to help pick along... - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif - -static struct swit parswit[] = { -#define PRAND 0 - { "and", 0 }, -#define PROR 1 - { "or", 0 }, -#define PRNOT 2 - { "not", 0 }, -#define PRLBR 3 - { "lbrace", 0 }, -#define PRRBR 4 - { "rbrace", 0 }, -#define PRCC 5 - { "cc pattern", 0 }, -#define PRDATE 6 - { "date pattern", 0 }, -#define PRFROM 7 - { "from pattern", 0 }, -#define PRSRCH 8 - { "search pattern", 0 }, -#define PRSUBJ 9 - { "subject pattern", 0 }, -#define PRTO 10 - { "to pattern", 0 }, -#define PROTHR 11 - { "-othercomponent pattern", 15 }, -#define PRAFTR 12 - { "after date", 0 }, -#define PRBEFR 13 - { "before date", 0 }, -#define PRDATF 14 - { "datefield field", 5 }, - { NULL, 0 } -}; - -/* DEFINITIONS FOR PATTERN MATCHING */ - -/* - * We really should be using re_comp() and re_exec() here. Unfortunately, - * pick advertises that lowercase characters matches characters of both - * cases. Since re_exec() doesn't exhibit this behavior, we are stuck - * with this version. Furthermore, we need to be able to save and restore - * the state of the pattern matcher in order to do things "efficiently". - * - * The matching power of this algorithm isn't as powerful as the re_xxx() - * routines (no \(xxx\) and \n constructs). Such is life. - */ - -#define CCHR 2 -#define CDOT 4 -#define CCL 6 -#define NCCL 8 -#define CDOL 10 -#define CEOF 11 - -#define STAR 01 - -#define LBSIZE 1024 -#define ESIZE 1024 - - -static char linebuf[LBSIZE + 1]; - -/* the magic array for case-independence */ -static char cc[] = { - 0000,0001,0002,0003,0004,0005,0006,0007, - 0010,0011,0012,0013,0014,0015,0016,0017, - 0020,0021,0022,0023,0024,0025,0026,0027, - 0030,0031,0032,0033,0034,0035,0036,0037, - 0040,0041,0042,0043,0044,0045,0046,0047, - 0050,0051,0052,0053,0054,0055,0056,0057, - 0060,0061,0062,0063,0064,0065,0066,0067, - 0070,0071,0072,0073,0074,0075,0076,0077, - 0100,0141,0142,0143,0144,0145,0146,0147, - 0150,0151,0152,0153,0154,0155,0156,0157, - 0160,0161,0162,0163,0164,0165,0166,0167, - 0170,0171,0172,0133,0134,0135,0136,0137, - 0140,0141,0142,0143,0144,0145,0146,0147, - 0150,0151,0152,0153,0154,0155,0156,0157, - 0160,0161,0162,0163,0164,0165,0166,0167, - 0170,0171,0172,0173,0174,0175,0176,0177, - - 0200,0201,0202,0203,0204,0205,0206,0207, - 0210,0211,0212,0213,0214,0215,0216,0217, - 0220,0221,0222,0223,0224,0225,0226,0227, - 0230,0231,0232,0233,0234,0235,0236,0237, - 0240,0241,0242,0243,0244,0245,0246,0247, - 0250,0251,0252,0253,0254,0255,0256,0257, - 0260,0261,0262,0263,0264,0265,0266,0267, - 0270,0271,0272,0273,0274,0275,0276,0277, - 0300,0301,0302,0303,0304,0305,0306,0307, - 0310,0311,0312,0313,0314,0315,0316,0317, - 0320,0321,0322,0323,0324,0325,0326,0327, - 0330,0331,0332,0333,0334,0335,0336,0337, - 0340,0341,0342,0343,0344,0345,0346,0347, - 0350,0351,0352,0353,0354,0355,0356,0357, - 0360,0361,0362,0363,0364,0365,0366,0367, - 0370,0371,0372,0373,0374,0375,0376,0377, -}; - -/* - * DEFINITIONS FOR NEXUS - */ - -#define nxtarg() (*argp ? *argp++ : NULL) -#define prvarg() argp-- - -#define padvise if (!talked++) advise - -struct nexus { - int (*n_action)(); - - union { - /* for {OR,AND,NOT}action */ - struct { - struct nexus *un_L_child; - struct nexus *un_R_child; - } st1; - - /* for GREPaction */ - struct { - int un_header; - int un_circf; - char un_expbuf[ESIZE]; - char *un_patbuf; - } st2; - - /* for TWSaction */ - struct { - char *un_datef; - int un_after; - struct tws un_tws; - } st3; - } un; -}; - -#define n_L_child un.st1.un_L_child -#define n_R_child un.st1.un_R_child - -#define n_header un.st2.un_header -#define n_circf un.st2.un_circf -#define n_expbuf un.st2.un_expbuf -#define n_patbuf un.st2.un_patbuf - -#define n_datef un.st3.un_datef -#define n_after un.st3.un_after -#define n_tws un.st3.un_tws - -static int talked; -static int pdebug = 0; - -static char *datesw; -static char **argp; - -static struct nexus *head; - -/* - * prototypes for date routines - */ -static struct tws *tws_parse(); -static struct tws *tws_special(); - -/* - * static prototypes - */ -static void PRaction(); -static int gcompile(); -static int advance(); -static int cclass(); -static int tcompile(); - -static struct nexus *parse(); -static struct nexus *nexp1(); -static struct nexus *nexp2(); -static struct nexus *nexp3(); -static struct nexus *newnexus(); - -static int ORaction(); -static int ANDaction(); -static int NOTaction(); -static int GREPaction(); -static int TWSaction(); - - -int -pcompile (char **vec, char *date) -{ - register char *cp; - - if ((cp = getenv ("MHPDEBUG")) && *cp) - pdebug++; - - argp = vec; - if ((datesw = date) == NULL) - datesw = "date"; - talked = 0; - - if ((head = parse ()) == NULL) - return (talked ? 0 : 1); - - if (*argp) { - padvise (NULL, "%s unexpected", *argp); - return 0; - } - - return 1; -} - - -static struct nexus * -parse (void) -{ - register char *cp; - register struct nexus *n, *o; - - if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL) - return n; - - if (*cp != '-') { - padvise (NULL, "%s unexpected", cp); - return NULL; - } - - if (*++cp == '-') - goto header; - switch (smatch (cp, parswit)) { - case AMBIGSW: - ambigsw (cp, parswit); - talked++; - return NULL; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - talked++; - return NULL; - - case PROR: - o = newnexus (ORaction); - o->n_L_child = n; - if ((o->n_R_child = parse ())) - return o; - padvise (NULL, "missing disjunctive"); - return NULL; - -header: ; - default: - prvarg (); - return n; - } -} - -static struct nexus * -nexp1 (void) -{ - register char *cp; - register struct nexus *n, *o; - - if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL) - return n; - - if (*cp != '-') { - padvise (NULL, "%s unexpected", cp); - return NULL; - } - - if (*++cp == '-') - goto header; - switch (smatch (cp, parswit)) { - case AMBIGSW: - ambigsw (cp, parswit); - talked++; - return NULL; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - talked++; - return NULL; - - case PRAND: - o = newnexus (ANDaction); - o->n_L_child = n; - if ((o->n_R_child = nexp1 ())) - return o; - padvise (NULL, "missing conjunctive"); - return NULL; - -header: ; - default: - prvarg (); - return n; - } -} - - -static struct nexus * -nexp2 (void) -{ - register char *cp; - register struct nexus *n; - - if ((cp = nxtarg ()) == NULL) - return NULL; - - if (*cp != '-') { - prvarg (); - return nexp3 (); - } - - if (*++cp == '-') - goto header; - switch (smatch (cp, parswit)) { - case AMBIGSW: - ambigsw (cp, parswit); - talked++; - return NULL; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - talked++; - return NULL; - - case PRNOT: - n = newnexus (NOTaction); - if ((n->n_L_child = nexp3 ())) - return n; - padvise (NULL, "missing negation"); - return NULL; - -header: ; - default: - prvarg (); - return nexp3 (); - } -} - -static struct nexus * -nexp3 (void) -{ - int i; - register char *cp, *dp; - char buffer[BUFSIZ], temp[64]; - register struct nexus *n; - - if ((cp = nxtarg ()) == NULL) - return NULL; - - if (*cp != '-') { - padvise (NULL, "%s unexpected", cp); - return NULL; - } - - if (*++cp == '-') { - dp = ++cp; - goto header; - } - switch (i = smatch (cp, parswit)) { - case AMBIGSW: - ambigsw (cp, parswit); - talked++; - return NULL; - case UNKWNSW: - fprintf (stderr, "-%s unknown\n", cp); - talked++; - return NULL; - - case PRLBR: - if ((n = parse ()) == NULL) { - padvise (NULL, "missing group"); - return NULL; - } - if ((cp = nxtarg ()) == NULL) { - padvise (NULL, "missing -rbrace"); - return NULL; - } - if (*cp++ == '-' && smatch (cp, parswit) == PRRBR) - return n; - padvise (NULL, "%s unexpected", --cp); - return NULL; - - default: - prvarg (); - return NULL; - - case PRCC: - case PRDATE: - case PRFROM: - case PRTO: - case PRSUBJ: - strncpy(temp, parswit[i].sw, sizeof(temp)); - temp[sizeof(temp) - 1] = '\0'; - dp = *brkstring (temp, " ", NULL); - header: ; - if (!(cp = nxtarg ())) {/* allow -xyz arguments */ - padvise (NULL, "missing argument to %s", argp[-2]); - return NULL; - } - n = newnexus (GREPaction); - n->n_header = 1; - snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp); - dp = buffer; - goto pattern; - - case PRSRCH: - n = newnexus (GREPaction); - n->n_header = 0; - if (!(cp = nxtarg ())) {/* allow -xyz arguments */ - padvise (NULL, "missing argument to %s", argp[-2]); - return NULL; - } - dp = cp; - pattern: ; - if (!gcompile (n, dp)) { - padvise (NULL, "pattern error in %s %s", argp[-2], cp); - return NULL; - } - n->n_patbuf = getcpy (dp); - return n; - - case PROTHR: - padvise (NULL, "internal error!"); - return NULL; - - case PRDATF: - if (!(datesw = nxtarg ()) || *datesw == '-') { - padvise (NULL, "missing argument to %s", argp[-2]); - return NULL; - } - return nexp3 (); - - case PRAFTR: - case PRBEFR: - if (!(cp = nxtarg ())) {/* allow -xyz arguments */ - padvise (NULL, "missing argument to %s", argp[-2]); - return NULL; - } - n = newnexus (TWSaction); - n->n_datef = datesw; - if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) { - padvise (NULL, "unable to parse %s %s", argp[-2], cp); - return NULL; - } - return n; - } -} - - -static struct nexus * -newnexus (int (*action)()) -{ - register struct nexus *p; - - if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL) - adios (NULL, "unable to allocate component storage"); - - p->n_action = action; - return p; -} - - -#define args(a) a, fp, msgnum, start, stop -#define params args (n) -#define plist \ - register struct nexus *n; \ - register FILE *fp; \ - int msgnum; \ - long start, \ - stop; - -int -pmatches (FILE *fp, int msgnum, long start, long stop) -{ - if (!head) - return 1; - - if (!talked++ && pdebug) - PRaction (head, 0); - - return (*head->n_action) (args (head)); -} - - -static void -PRaction (struct nexus *n, int level) -{ - register int i; - - for (i = 0; i < level; i++) - fprintf (stderr, "| "); - - if (n->n_action == ORaction) { - fprintf (stderr, "OR\n"); - PRaction (n->n_L_child, level + 1); - PRaction (n->n_R_child, level + 1); - return; - } - if (n->n_action == ANDaction) { - fprintf (stderr, "AND\n"); - PRaction (n->n_L_child, level + 1); - PRaction (n->n_R_child, level + 1); - return; - } - if (n->n_action == NOTaction) { - fprintf (stderr, "NOT\n"); - PRaction (n->n_L_child, level + 1); - return; - } - if (n->n_action == GREPaction) { - fprintf (stderr, "PATTERN(%s) %s\n", - n->n_header ? "header" : "body", n->n_patbuf); - return; - } - if (n->n_action == TWSaction) { - fprintf (stderr, "TEMPORAL(%s) %s: %s\n", - n->n_after ? "after" : "before", n->n_datef, - dasctime (&n->n_tws, TW_NULL)); - return; - } - fprintf (stderr, "UNKNOWN(0x%x)\n", - (unsigned int)(unsigned long) (*n->n_action)); -} - - -static int -ORaction (params) -plist -{ - if ((*n->n_L_child->n_action) (args (n->n_L_child))) - return 1; - return (*n->n_R_child->n_action) (args (n->n_R_child)); -} - - -static int -ANDaction (params) -plist -{ - if (!(*n->n_L_child->n_action) (args (n->n_L_child))) - return 0; - return (*n->n_R_child->n_action) (args (n->n_R_child)); -} - - -static int -NOTaction (params) -plist -{ - return (!(*n->n_L_child->n_action) (args (n->n_L_child))); -} - - -static int -gcompile (struct nexus *n, char *astr) -{ - register int c; - int cclcnt; - register unsigned char *ep, *dp, *sp, *lastep = 0; - - dp = (ep = n->n_expbuf) + sizeof n->n_expbuf; - sp = astr; - if (*sp == '^') { - n->n_circf = 1; - sp++; - } - else - n->n_circf = 0; - for (;;) { - if (ep >= dp) - goto cerror; - if ((c = *sp++) != '*') - lastep = ep; - switch (c) { - case '\0': - *ep++ = CEOF; - return 1; - - case '.': - *ep++ = CDOT; - continue; - - case '*': - if (lastep == 0) - goto defchar; - *lastep |= STAR; - continue; - - case '$': - if (*sp != '\0') - goto defchar; - *ep++ = CDOL; - continue; - - case '[': - *ep++ = CCL; - *ep++ = 0; - cclcnt = 0; - if ((c = *sp++) == '^') { - c = *sp++; - ep[-2] = NCCL; - } - if (c == '-') { - *ep++ = c; - cclcnt++; - c = *sp++; - } - do { - if (c == '-' && *sp != '\0' && *sp != ']') { - for (c = ep[-1]+1; c < *sp; c++) { - *ep++ = c; - cclcnt++; - if (c == '\0' || ep >= dp) - goto cerror; - } - } else { - *ep++ = c; - cclcnt++; - if (c == '\0' || ep >= dp) - goto cerror; - } - } while ((c = *sp++) != ']'); - if (cclcnt > 255) - goto cerror; - lastep[1] = cclcnt; - continue; - - case '\\': - if ((c = *sp++) == '\0') - goto cerror; - defchar: - default: - *ep++ = CCHR; - *ep++ = c; - } - } - -cerror: ; - return 0; -} - - -static int -GREPaction (params) -plist -{ - int c, body, lf; - long pos = start; - register char *p1, *p2, *ebp, *cbp; - char ibuf[BUFSIZ]; - - fseek (fp, start, SEEK_SET); - body = 0; - ebp = cbp = ibuf; - for (;;) { - if (body && n->n_header) - return 0; - p1 = linebuf; - p2 = cbp; - lf = 0; - for (;;) { - if (p2 >= ebp) { - if (fgets (ibuf, sizeof ibuf, fp) == NULL - || (stop && pos >= stop)) { - if (lf) - break; - return 0; - } - pos += (long) strlen (ibuf); - p2 = ibuf; - ebp = ibuf + strlen (ibuf); - } - c = *p2++; - if (lf && c != '\n') { - if (c != ' ' && c != '\t') { - --p2; - break; - } - else - lf = 0; - } - if (c == '\n') { - if (body) - break; - else { - if (lf) { - body++; - break; - } - lf++; - c = ' '; - } - } - if (c && p1 < &linebuf[LBSIZE - 1]) - *p1++ = c; - } - - *p1++ = 0; - cbp = p2; - p1 = linebuf; - p2 = n->n_expbuf; - - if (n->n_circf) { - if (advance (p1, p2)) - return 1; - continue; - } - - if (*p2 == CCHR) { - c = p2[1]; - do { - if (*p1 == c || cc[(unsigned char)*p1] == c) - if (advance (p1, p2)) - return 1; - } while (*p1++); - continue; - } - - do { - if (advance (p1, p2)) - return 1; - } while (*p1++); - } -} - - -static int -advance (char *alp, char *aep) -{ - register unsigned char *lp, *ep, *curlp; - - lp = (unsigned char *)alp; - ep = (unsigned char *)aep; - for (;;) - switch (*ep++) { - case CCHR: - if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]]) - continue; - return 0; - - case CDOT: - if (*lp++) - continue; - return 0; - - case CDOL: - if (*lp == 0) - continue; - return 0; - - case CEOF: - return 1; - - case CCL: - if (cclass (ep, *lp++, 1)) { - ep += *ep + 1; - continue; - } - return 0; - - case NCCL: - if (cclass (ep, *lp++, 0)) { - ep += *ep + 1; - continue; - } - return 0; - - case CDOT | STAR: - curlp = lp; - while (*lp++) - continue; - goto star; - - case CCHR | STAR: - curlp = lp; - while (*lp++ == *ep || cc[lp[-1]] == *ep) - continue; - ep++; - goto star; - - case CCL | STAR: - case NCCL | STAR: - curlp = lp; - while (cclass (ep, *lp++, ep[-1] == (CCL | STAR))) - continue; - ep += *ep + 1; - goto star; - - star: - do { - lp--; - if (advance (lp, ep)) - return (1); - } while (lp > curlp); - return 0; - - default: - admonish (NULL, "advance() botch -- you lose big"); - return 0; - } -} - - -static int -cclass (unsigned char *aset, int ac, int af) -{ - register unsigned int n; - register unsigned char c, *set; - - set = aset; - if ((c = ac) == 0) - return (0); - - n = *set++; - while (n--) - if (*set++ == c || set[-1] == cc[c]) - return (af); - - return (!af); -} - - -static int -tcompile (char *ap, struct tws *tb, int isafter) -{ - register struct tws *tw; - - if ((tw = tws_parse (ap, isafter)) == NULL) - return 0; - - twscopy (tb, tw); - return 1; -} - - -static struct tws * -tws_parse (char *ap, int isafter) -{ - char buffer[BUFSIZ]; - register struct tws *tw, *ts; - - if ((tw = tws_special (ap)) != NULL) { - tw->tw_sec = tw->tw_min = isafter ? 59 : 0; - tw->tw_hour = isafter ? 23 : 0; - return tw; - } - if ((tw = dparsetime (ap)) != NULL) - return tw; - - if ((ts = dlocaltimenow ()) == NULL) - return NULL; - - snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts)); - if ((tw = dparsetime (buffer)) != NULL) - return tw; - - snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap, - ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts)); - if ((tw = dparsetime (buffer)) != NULL) - return tw; - - snprintf (buffer, sizeof(buffer), "%02d %s %04d %s", - ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap); - if ((tw = dparsetime (buffer)) != NULL) - return tw; - - snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s", - ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, - ap, dtwszone (ts)); - if ((tw = dparsetime (buffer)) != NULL) - return tw; - - return NULL; -} - - -static struct tws * -tws_special (char *ap) -{ - int i; - time_t clock; - register struct tws *tw; - - time (&clock); - if (!mh_strcasecmp (ap, "today")) - return dlocaltime (&clock); - if (!mh_strcasecmp (ap, "yesterday")) { - clock -= (long) (60 * 60 * 24); - return dlocaltime (&clock); - } - if (!mh_strcasecmp (ap, "tomorrow")) { - clock += (long) (60 * 60 * 24); - return dlocaltime (&clock); - } - - for (i = 0; tw_ldotw[i]; i++) - if (!mh_strcasecmp (ap, tw_ldotw[i])) - break; - if (tw_ldotw[i]) { - if ((tw = dlocaltime (&clock)) == NULL) - return NULL; - if ((i -= tw->tw_wday) > 0) - i -= 7; - } - else - if (*ap != '-') - return NULL; - else /* -ddd days ago */ - i = atoi (ap); /* we should error check this */ - - clock += (long) ((60 * 60 * 24) * i); - return dlocaltime (&clock); -} - - -static int -TWSaction (params) -plist -{ - int state; - register char *bp; - char buf[BUFSIZ], name[NAMESZ]; - register struct tws *tw; - - fseek (fp, start, SEEK_SET); - for (state = FLD, bp = NULL;;) { - switch (state = m_getfld (state, name, buf, sizeof buf, fp)) { - case FLD: - case FLDEOF: - case FLDPLUS: - if (bp != NULL) - free (bp), bp = NULL; - bp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); - bp = add (buf, bp); - } - if (!mh_strcasecmp (name, n->n_datef)) - break; - if (state != FLDEOF) - continue; - - case BODY: - case BODYEOF: - case FILEEOF: - case LENERR: - case FMTERR: - if (state == LENERR || state == FMTERR) - advise (NULL, "format error in message %d", msgnum); - if (bp != NULL) - free (bp); - return 0; - - default: - adios (NULL, "internal error -- you lose"); - } - break; - } - - if ((tw = dparsetime (bp)) == NULL) - advise (NULL, "unable to parse %s field in message %d, matching...", - n->n_datef, msgnum), state = 1; - else - state = n->n_after ? (twsort (tw, &n->n_tws) > 0) - : (twsort (tw, &n->n_tws) < 0); - - if (bp != NULL) - free (bp); - return state; -} diff --git a/uip/popsbr.c b/uip/popsbr.c deleted file mode 100644 index 2d03efd..0000000 --- a/uip/popsbr.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - * popsbr.c -- POP client subroutines - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - -#ifdef CYRUS_SASL -# include -# include -#endif /* CYRUS_SASL */ - -#include -#include -#include -#include - -#define TRM "." -#define TRMLEN (sizeof TRM - 1) - -static int poprint = 0; -static int pophack = 0; - -char response[BUFSIZ]; - -static FILE *input; -static FILE *output; - -#ifdef CYRUS_SASL -static sasl_conn_t *conn; /* SASL connection state */ -static int sasl_complete = 0; /* Has sasl authentication succeeded? */ -static int maxoutbuf; /* Maximum output buffer size */ -static sasl_ssf_t sasl_ssf = 0; /* Security strength factor */ -static int sasl_get_user(void *, int, const char **, unsigned *); -static int sasl_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **); -struct pass_context { - char *user; - char *host; -}; - -static sasl_callback_t callbacks[] = { - { SASL_CB_USER, sasl_get_user, NULL }, -#define POP_SASL_CB_N_USER 0 - { SASL_CB_PASS, sasl_get_pass, NULL }, -#define POP_SASL_CB_N_PASS 1 - { SASL_CB_LOG, NULL, NULL }, - { SASL_CB_LIST_END, NULL, NULL }, - -#define SASL_BUFFER_SIZE 262144 -}; -#else /* CYRUS_SASL */ -# define sasl_fgetc fgetc -#endif /* CYRUS_SASL */ - -/* - * static prototypes - */ - -static int command(const char *, ...); -static int multiline(void); - -#ifdef CYRUS_SASL -static int pop_auth_sasl(char *, char *, char *); -static int sasl_fgetc(FILE *); -#endif /* CYRUS_SASL */ - -static int traverse (int (*)(char *), const char *, ...); -static int vcommand(const char *, va_list); -static int sasl_getline (char *, int, FILE *); -static int putline (char *, FILE *); - - -#ifdef CYRUS_SASL -/* - * This function implements the AUTH command for various SASL mechanisms - * - * We do the whole SASL dialog here. If this completes, then we've - * authenticated successfully and have (possibly) negotiated a security - * layer. - */ - -int -pop_auth_sasl(char *user, char *host, char *mech) -{ - int result, status, sasl_capability = 0; - unsigned int buflen, outlen; - char server_mechs[256], *buf, outbuf[BUFSIZ]; - const char *chosen_mech; - sasl_security_properties_t secprops; - struct pass_context p_context; - sasl_ssf_t *ssf; - int *moutbuf; - - /* - * First off, we're going to send the CAPA command to see if we can - * even support the AUTH command, and if we do, then we'll get a - * list of mechanisms the server supports. If we don't support - * the CAPA command, then it's unlikely that we will support - * SASL - */ - - if (command("CAPA") == NOTOK) { - snprintf(response, sizeof(response), - "The POP CAPA command failed; POP server does not " - "support SASL"); - return NOTOK; - } - - while ((status = multiline()) != DONE) - switch (status) { - case NOTOK: - return NOTOK; - break; - case DONE: /* Shouldn't be possible, but just in case */ - break; - case OK: - if (strncasecmp(response, "SASL ", 5) == 0) { - /* - * We've seen the SASL capability. Grab the mech list - */ - sasl_capability++; - strncpy(server_mechs, response + 5, sizeof(server_mechs)); - } - break; - } - - if (!sasl_capability) { - snprintf(response, sizeof(response), "POP server does not support " - "SASL"); - return NOTOK; - } - - /* - * If we received a preferred mechanism, see if the server supports it. - */ - - if (mech && stringdex(mech, server_mechs) == -1) { - snprintf(response, sizeof(response), "Requested SASL mech \"%s\" is " - "not in list of supported mechanisms:\n%s", - mech, server_mechs); - return NOTOK; - } - - /* - * Start the SASL process. First off, initialize the SASL library. - */ - - callbacks[POP_SASL_CB_N_USER].context = user; - p_context.user = user; - p_context.host = host; - callbacks[POP_SASL_CB_N_PASS].context = &p_context; - - result = sasl_client_init(callbacks); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "SASL library initialization " - "failed: %s", sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - result = sasl_client_new("pop", host, NULL, NULL, NULL, 0, &conn); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "SASL client initialization " - "failed: %s", sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - /* - * Initialize the security properties - */ - - memset(&secprops, 0, sizeof(secprops)); - secprops.maxbufsize = SASL_BUFFER_SIZE; - secprops.max_ssf = UINT_MAX; - - result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "SASL security property " - "initialization failed: %s", sasl_errdetail(conn)); - return NOTOK; - } - - /* - * Start the actual protocol. Feed the mech list into the library - * and get out a possible initial challenge - */ - - result = sasl_client_start(conn, - (const char *) (mech ? mech : server_mechs), - NULL, (const char **) &buf, - &buflen, &chosen_mech); - - if (result != SASL_OK && result != SASL_CONTINUE) { - snprintf(response, sizeof(response), "SASL client start failed: %s", - sasl_errdetail(conn)); - return NOTOK; - } - - if (buflen) { - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - if (status != SASL_OK) { - snprintf(response, sizeof(response), "SASL base64 encode " - "failed: %s", sasl_errstring(status, NULL, NULL)); - return NOTOK; - } - - status = command("AUTH %s %s", chosen_mech, outbuf); - } else - status = command("AUTH %s", chosen_mech); - - while (result == SASL_CONTINUE) { - if (status == NOTOK) - return NOTOK; - - /* - * If we get a "+OK" prefix to our response, then we should - * exit out of this exchange now (because authenticated should - * have succeeded) - */ - - if (strncmp(response, "+OK", 3) == 0) - break; - - /* - * Otherwise, make sure the server challenge is correctly formatted - */ - - if (strncmp(response, "+ ", 2) != 0) { - command("*"); - snprintf(response, sizeof(response), - "Malformed authentication message from server"); - return NOTOK; - } - - result = sasl_decode64(response + 2, strlen(response + 2), - outbuf, sizeof(outbuf), &outlen); - - if (result != SASL_OK) { - command("*"); - snprintf(response, sizeof(response), "SASL base64 decode " - "failed: %s", sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - result = sasl_client_step(conn, outbuf, outlen, NULL, - (const char **) &buf, &buflen); - - if (result != SASL_OK && result != SASL_CONTINUE) { - command("*"); - snprintf(response, sizeof(response), "SASL client negotiaton " - "failed: %s", sasl_errdetail(conn)); - return NOTOK; - } - - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - - if (status != SASL_OK) { - command("*"); - snprintf(response, sizeof(response), "SASL base64 encode " - "failed: %s", sasl_errstring(status, NULL, NULL)); - return NOTOK; - } - - status = command(outbuf); - } - - /* - * If we didn't get a positive final response, then error out - * (that probably means we failed an authorization check). - */ - - if (status != OK) - return NOTOK; - - /* - * We _should_ be okay now. Get a few properties now that negotiation - * has completed. - */ - - result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &moutbuf); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated " - "output buffer size: %s", sasl_errdetail(conn)); - return NOTOK; - } - - maxoutbuf = *moutbuf; - - result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf); - - sasl_ssf = *ssf; - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated " - "security strength factor: %s", sasl_errdetail(conn)); - return NOTOK; - } - - /* - * Limit this to what we can deal with. Shouldn't matter much because - * this is only outgoing data (which should be small) - */ - - if (maxoutbuf == 0 || maxoutbuf > BUFSIZ) - maxoutbuf = BUFSIZ; - - sasl_complete = 1; - - return status; -} - -/* - * Callback to return the userid sent down via the user parameter - */ - -static int -sasl_get_user(void *context, int id, const char **result, unsigned *len) -{ - char *user = (char *) context; - - if (! result || id != SASL_CB_USER) - return SASL_BADPARAM; - - *result = user; - if (len) - *len = strlen(user); - - return SASL_OK; -} - -/* - * Callback to return the password (we call ruserpass, which can get it - * out of the .netrc - */ - -static int -sasl_get_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret) -{ - struct pass_context *p_context = (struct pass_context *) context; - char *pass = NULL; - int len; - - if (! psecret || id != SASL_CB_PASS) - return SASL_BADPARAM; - - ruserpass(p_context->user, &(p_context->host), &pass); - - len = strlen(pass); - - *psecret = (sasl_secret_t *) mh_xmalloc(sizeof(sasl_secret_t) + len); - - (*psecret)->len = len; - strcpy((char *) (*psecret)->data, pass); - - return SASL_OK; -} -#endif /* CYRUS_SASL */ - - -/* - * Split string containing proxy command into an array of arguments - * suitable for passing to exec. Returned array must be freed. Shouldn't - * be possible to call this with host set to NULL. - */ -char ** -parse_proxy(char *proxy, char *host) -{ - char **pargv, **p; - int pargc = 2; - int hlen = strlen(host); - int plen = 1; - unsigned char *cur, *pro; - char *c; - - /* skip any initial space */ - for (pro = (unsigned char *) proxy; isspace(*pro); pro++) - continue; - - /* calculate required size for argument array */ - for (cur = pro; *cur; cur++) { - if (isspace(*cur) && cur[1] && !isspace(cur[1])) - plen++, pargc++; - else if (*cur == '%' && cur[1] == 'h') { - plen += hlen; - cur++; - } else if (!isspace(*cur)) - plen++; - } - - /* put together list of arguments */ - p = pargv = mh_xmalloc(pargc * sizeof(char *)); - c = *pargv = mh_xmalloc(plen * sizeof(char)); - for (cur = pro; *cur; cur++) { - if (isspace(*cur) && cur[1] && !isspace(cur[1])) { - *c++ = '\0'; - *++p = c; - } else if (*cur == '%' && cur[1] == 'h') { - strcpy (c, host); - c += hlen; - cur++; - } else if (!isspace(*cur)) - *c++ = *cur; - } - *++p = NULL; - return pargv; -} - -int -pop_init (char *host, char *port, char *user, char *pass, char *proxy, - int snoop, int sasl, char *mech) -{ - int fd1, fd2; - char buffer[BUFSIZ]; - - if (proxy && *proxy) { - int pid; - int inpipe[2]; /* for reading from the server */ - int outpipe[2]; /* for sending to the server */ - - /* first give up any root priviledges we may have for rpop */ - setuid(getuid()); - - pipe(inpipe); - pipe(outpipe); - - pid=fork(); - if (pid==0) { - char **argv; - - /* in child */ - close(0); - close(1); - dup2(outpipe[0],0); /* connect read end of connection */ - dup2(inpipe[1], 1); /* connect write end of connection */ - if(inpipe[0]>1) close(inpipe[0]); - if(inpipe[1]>1) close(inpipe[1]); - if(outpipe[0]>1) close(outpipe[0]); - if(outpipe[1]>1) close(outpipe[1]); - - /* run the proxy command */ - argv=parse_proxy(proxy, host); - execvp(argv[0],argv); - - perror(argv[0]); - close(0); - close(1); - free(*argv); - free(argv); - exit(10); - } - - /* okay in the parent we do some stuff */ - close(inpipe[1]); /* child uses this */ - close(outpipe[0]); /* child uses this */ - - /* we read on fd1 */ - fd1=inpipe[0]; - /* and write on fd2 */ - fd2=outpipe[1]; - - } else { - - if ((fd1 = client (host, port ? port : "pop3", response, - sizeof(response), snoop)) == NOTOK) { - return NOTOK; - } - - if ((fd2 = dup (fd1)) == NOTOK) { - char *s; - - if ((s = strerror(errno))) - snprintf (response, sizeof(response), - "unable to dup connection descriptor: %s", s); - else - snprintf (response, sizeof(response), - "unable to dup connection descriptor: unknown error"); - close (fd1); - return NOTOK; - } - } - if (pop_set (fd1, fd2, snoop) == NOTOK) - return NOTOK; - - SIGNAL (SIGPIPE, SIG_IGN); - - switch (sasl_getline (response, sizeof response, input)) { - case OK: - if (poprint) - fprintf (stderr, "<--- %s\n", response); - if (*response == '+') { -# ifdef CYRUS_SASL - if (sasl) { - if (pop_auth_sasl(user, host, mech) != NOTOK) - return OK; - } else -# endif /* CYRUS_SASL */ - if (command ("USER %s", user) != NOTOK - && command ("%s %s", (pophack++, "PASS"), - pass) != NOTOK) - return OK; - } - strncpy (buffer, response, sizeof(buffer)); - command ("QUIT"); - strncpy (response, buffer, sizeof(response)); - /* and fall */ - - case NOTOK: - case DONE: - if (poprint) - fprintf (stderr, "%s\n", response); - fclose (input); - fclose (output); - return NOTOK; - } - - return NOTOK; /* NOTREACHED */ -} - -int -pop_set (int in, int out, int snoop) -{ - - if ((input = fdopen (in, "r")) == NULL - || (output = fdopen (out, "w")) == NULL) { - strncpy (response, "fdopen failed on connection descriptor", sizeof(response)); - if (input) - fclose (input); - else - close (in); - close (out); - return NOTOK; - } - - poprint = snoop; - - return OK; -} - - -int -pop_fd (char *in, int inlen, char *out, int outlen) -{ - snprintf (in, inlen, "%d", fileno (input)); - snprintf (out, outlen, "%d", fileno (output)); - return OK; -} - - -/* - * Find out number of messages available - * and their total size. - */ - -int -pop_stat (int *nmsgs, int *nbytes) -{ - - if (command ("STAT") == NOTOK) - return NOTOK; - - *nmsgs = *nbytes = 0; - sscanf (response, "+OK %d %d", nmsgs, nbytes); - - return OK; -} - - -int -pop_list (int msgno, int *nmsgs, int *msgs, int *bytes) -{ - int i; - int *ids = NULL; - - if (msgno) { - if (command ("LIST %d", msgno) == NOTOK) - return NOTOK; - *msgs = *bytes = 0; - if (ids) { - *ids = 0; - sscanf (response, "+OK %d %d %d", msgs, bytes, ids); - } - else - sscanf (response, "+OK %d %d", msgs, bytes); - return OK; - } - - if (command ("LIST") == NOTOK) - return NOTOK; - - for (i = 0; i < *nmsgs; i++) - switch (multiline ()) { - case NOTOK: - return NOTOK; - case DONE: - *nmsgs = ++i; - return OK; - case OK: - *msgs = *bytes = 0; - if (ids) { - *ids = 0; - sscanf (response, "%d %d %d", - msgs++, bytes++, ids++); - } - else - sscanf (response, "%d %d", msgs++, bytes++); - break; - } - for (;;) - switch (multiline ()) { - case NOTOK: - return NOTOK; - case DONE: - return OK; - case OK: - break; - } -} - - -int -pop_retr (int msgno, int (*action)(char *)) -{ - return traverse (action, "RETR %d", msgno); -} - - -static int -traverse (int (*action)(char *), const char *fmt, ...) -{ - int result; - va_list ap; - char buffer[sizeof(response)]; - - va_start(ap, fmt); - result = vcommand (fmt, ap); - va_end(ap); - - if (result == NOTOK) - return NOTOK; - strncpy (buffer, response, sizeof(buffer)); - - for (;;) - switch (multiline ()) { - case NOTOK: - return NOTOK; - - case DONE: - strncpy (response, buffer, sizeof(response)); - return OK; - - case OK: - (*action) (response); - break; - } -} - - -int -pop_dele (int msgno) -{ - return command ("DELE %d", msgno); -} - - -int -pop_noop (void) -{ - return command ("NOOP"); -} - - -int -pop_rset (void) -{ - return command ("RSET"); -} - - -int -pop_top (int msgno, int lines, int (*action)(char *)) -{ - return traverse (action, "TOP %d %d", msgno, lines); -} - - -int -pop_quit (void) -{ - int i; - - i = command ("QUIT"); - pop_done (); - - return i; -} - - -int -pop_done (void) -{ -#ifdef CYRUS_SASL - if (conn) - sasl_dispose(&conn); -#endif /* CYRUS_SASL */ - fclose (input); - fclose (output); - - return OK; -} - - -int -command(const char *fmt, ...) -{ - va_list ap; - int result; - - va_start(ap, fmt); - result = vcommand(fmt, ap); - va_end(ap); - - return result; -} - - -static int -vcommand (const char *fmt, va_list ap) -{ - char *cp, buffer[BUFSIZ]; - - vsnprintf (buffer, sizeof(buffer), fmt, ap); - if (poprint) { -#ifdef CYRUS_SASL - if (sasl_ssf) - fprintf(stderr, "(encrypted) "); -#endif /* CYRUS_SASL */ - if (pophack) { - if ((cp = strchr (buffer, ' '))) - *cp = 0; - fprintf (stderr, "---> %s ********\n", buffer); - if (cp) - *cp = ' '; - pophack = 0; - } - else - fprintf (stderr, "---> %s\n", buffer); - } - - if (putline (buffer, output) == NOTOK) - return NOTOK; - -#ifdef CYRUS_SASL - if (poprint && sasl_ssf) - fprintf(stderr, "(decrypted) "); -#endif /* CYRUS_SASL */ - - switch (sasl_getline (response, sizeof response, input)) { - case OK: - if (poprint) - fprintf (stderr, "<--- %s\n", response); - return (*response == '+' ? OK : NOTOK); - - case NOTOK: - case DONE: - if (poprint) - fprintf (stderr, "%s\n", response); - return NOTOK; - } - - return NOTOK; /* NOTREACHED */ -} - - -int -multiline (void) -{ - char buffer[BUFSIZ + TRMLEN]; - - if (sasl_getline (buffer, sizeof buffer, input) != OK) - return NOTOK; -#ifdef DEBUG - if (poprint) { -#ifdef CYRUS_SASL - if (sasl_ssf) - fprintf(stderr, "(decrypted) "); -#endif /* CYRUS_SASL */ - fprintf (stderr, "<--- %s\n", response); - } -#endif /* DEBUG */ - if (strncmp (buffer, TRM, TRMLEN) == 0) { - if (buffer[TRMLEN] == 0) - return DONE; - else - strncpy (response, buffer + TRMLEN, sizeof(response)); - } - else - strncpy (response, buffer, sizeof(response)); - - return OK; -} - -/* - * Note that these functions have been modified to deal with layer encryption - * in the SASL case - */ - -static int -sasl_getline (char *s, int n, FILE *iop) -{ - int c = -2; - char *p; - - p = s; - while (--n > 0 && (c = sasl_fgetc (iop)) != EOF && c != -2) - if ((*p++ = c) == '\n') - break; - if (c == -2) - return NOTOK; - if (ferror (iop) && c != EOF) { - strncpy (response, "error on connection", sizeof(response)); - return NOTOK; - } - if (c == EOF && p == s) { - strncpy (response, "connection closed by foreign host", sizeof(response)); - return DONE; - } - *p = 0; - if (*--p == '\n') - *p = 0; - if (*--p == '\r') - *p = 0; - - return OK; -} - - -static int -putline (char *s, FILE *iop) -{ -#ifdef CYRUS_SASL - char outbuf[BUFSIZ], *buf; - int result; - unsigned int buflen; - - if (!sasl_complete) { -#endif /* CYRUS_SASL */ - fprintf (iop, "%s\r\n", s); -#ifdef CYRUS_SASL - } else { - /* - * Build an output buffer, encrypt it using sasl_encode, and - * squirt out the results. - */ - strncpy(outbuf, s, sizeof(outbuf) - 3); - outbuf[sizeof(outbuf) - 3] = '\0'; /* Just in case */ - strcat(outbuf, "\r\n"); - - result = sasl_encode(conn, outbuf, strlen(outbuf), - (const char **) &buf, &buflen); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "SASL encoding error: %s", - sasl_errdetail(conn)); - return NOTOK; - } - - fwrite(buf, buflen, 1, iop); - } -#endif /* CYRUS_SASL */ - - fflush (iop); - if (ferror (iop)) { - strncpy (response, "lost connection", sizeof(response)); - return NOTOK; - } - - return OK; -} - -#ifdef CYRUS_SASL -/* - * Okay, our little fgetc replacement. Hopefully this is a little more - * efficient than the last one. - */ -static int -sasl_fgetc(FILE *f) -{ - static unsigned char *buffer = NULL, *ptr; - static int size = 0; - static int cnt = 0; - unsigned int retbufsize = 0; - int cc, result; - char *retbuf, tmpbuf[SASL_BUFFER_SIZE]; - - /* - * If we have some leftover data, return that - */ - - if (cnt) { - cnt--; - return (int) *ptr++; - } - - /* - * Otherwise, fill our buffer until we have some data to return. - */ - - while (retbufsize == 0) { - - cc = read(fileno(f), tmpbuf, sizeof(tmpbuf)); - - if (cc == 0) - return EOF; - - if (cc < 0) { - snprintf(response, sizeof(response), "Error during read from " - "network: %s", strerror(errno)); - return -2; - } - - /* - * We're not allowed to call sasl_decode until sasl_complete is - * true, so we do these gyrations ... - */ - - if (!sasl_complete) { - - retbuf = tmpbuf; - retbufsize = cc; - - } else { - - result = sasl_decode(conn, tmpbuf, cc, - (const char **) &retbuf, &retbufsize); - - if (result != SASL_OK) { - snprintf(response, sizeof(response), "Error during SASL " - "decoding: %s", sasl_errdetail(conn)); - return -2; - } - } - } - - if (retbufsize > size) { - buffer = mh_xrealloc(buffer, retbufsize); - size = retbufsize; - } - - memcpy(buffer, retbuf, retbufsize); - ptr = buffer + 1; - cnt = retbufsize - 1; - - return (int) buffer[0]; -} -#endif /* CYRUS_SASL */ diff --git a/uip/post.c b/uip/post.c deleted file mode 100644 index d5760a2..0000000 --- a/uip/post.c +++ /dev/null @@ -1,1740 +0,0 @@ - -/* - * post.c -- enter messages into the mail transport system - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif - -#ifdef SMTPMTS -# include -#endif - -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else /* CYRUS_SASL */ -# define SASLminc(a) 0 -#endif /* CYRUS_SASL */ - -#ifndef TLS_SUPPORT -# define TLSminc(a) (a) -#else /* TLS_SUPPORT */ -# define TLSminc(a) 0 -#endif /* TLS_SUPPORT */ - -#define FCCS 10 /* max number of fccs allowed */ - -#define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : c) - -/* In the following array of structures, the numeric second field of the - structures (minchars) is apparently used like this: - - -# : Switch can be abbreviated to # characters; switch hidden in -help. - 0 : Switch can't be abbreviated; switch shown in -help. - # : Switch can be abbreviated to # characters; switch shown in -help. */ - -static struct swit switches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define CHKSW 1 - { "check", -5 }, /* interface from whom */ -#define NCHKSW 2 - { "nocheck", -7 }, /* interface from whom */ -#define DEBUGSW 3 - { "debug", -5 }, -#define DISTSW 4 - { "dist", -4 }, /* interface from dist */ -#define FILTSW 5 - { "filter filterfile", 0 }, -#define NFILTSW 6 - { "nofilter", 0 }, -#define FRMTSW 7 - { "format", 0 }, -#define NFRMTSW 8 - { "noformat", 0 }, -#define LIBSW 9 - { "library directory", -7 }, /* interface from send, whom */ -#define MIMESW 10 - { "mime", 0 }, -#define NMIMESW 11 - { "nomime", 0 }, -#define MSGDSW 12 - { "msgid", 0 }, -#define NMSGDSW 13 - { "nomsgid", 0 }, -#define VERBSW 14 - { "verbose", 0 }, -#define NVERBSW 15 - { "noverbose", 0 }, -#define WATCSW 16 - { "watch", 0 }, -#define NWATCSW 17 - { "nowatch", 0 }, -#define WHOMSW 18 - { "whom", -4 }, /* interface from whom */ -#define WIDTHSW 19 - { "width columns", 0 }, -#define VERSIONSW 20 - { "version", 0 }, -#define HELPSW 21 - { "help", 0 }, -#define BITSTUFFSW 22 - { "dashstuffing", -12 }, /* should we dashstuff BCC messages? */ -#define NBITSTUFFSW 23 - { "nodashstuffing", -14 }, -#define MAILSW 24 - { "mail", -4 }, /* specify MAIL smtp mode */ -#define SAMLSW 25 - { "saml", -4 }, /* specify SAML smtp mode */ -#define SENDSW 26 - { "send", -4 }, /* specify SEND smtp mode */ -#define SOMLSW 27 - { "soml", -4 }, /* specify SOML smtp mode */ -#define ANNOSW 28 - { "idanno number", -6 }, /* interface from send */ -#define DLVRSW 29 - { "deliver address-list", -7 }, -#define CLIESW 30 - { "client host", -6 }, -#define SERVSW 31 - { "server host", -6 }, /* specify alternate SMTP server */ -#define SNOOPSW 32 - { "snoop", -5 }, /* snoop the SMTP transaction */ -#define FILLSW 33 - { "fill-in file", -7 }, -#define FILLUSW 34 - { "fill-up", -7 }, -#define PARTSW 35 - { "partno", -6 }, -#define QUEUESW 36 - { "queued", -6 }, -#define SASLSW 37 - { "sasl", SASLminc(-4) }, -#define SASLMECHSW 38 - { "saslmech", SASLminc(-5) }, -#define USERSW 39 - { "user", SASLminc(-4) }, -#define PORTSW 40 - { "port server port name/number", 4 }, -#define TLSSW 41 - { "tls", TLSminc(-3) }, - { NULL, 0 } -}; - - -struct headers { - char *value; - unsigned int flags; - unsigned int set; -}; - -/* - * flags for headers->flags - */ -#define HNOP 0x0000 /* just used to keep .set around */ -#define HBAD 0x0001 /* bad header - don't let it through */ -#define HADR 0x0002 /* header has an address field */ -#define HSUB 0x0004 /* Subject: header */ -#define HTRY 0x0008 /* try to send to addrs on header */ -#define HBCC 0x0010 /* don't output this header */ -#define HMNG 0x0020 /* munge this header */ -#define HNGR 0x0040 /* no groups allowed in this header */ -#define HFCC 0x0080 /* FCC: type header */ -#define HNIL 0x0100 /* okay for this header not to have addrs */ -#define HIGN 0x0200 /* ignore this header */ -#define HDCC 0x0400 /* another undocumented feature */ - -/* - * flags for headers->set - */ -#define MFRM 0x0001 /* we've seen a From: */ -#define MDAT 0x0002 /* we've seen a Date: */ -#define MRFM 0x0004 /* we've seen a Resent-From: */ -#define MVIS 0x0008 /* we've seen sighted addrs */ -#define MINV 0x0010 /* we've seen blind addrs */ - - -static struct headers NHeaders[] = { - { "Return-Path", HBAD, 0 }, - { "Received", HBAD, 0 }, - { "Reply-To", HADR|HNGR, 0 }, - { "From", HADR|HNGR, MFRM }, - { "Sender", HADR|HBAD, 0 }, - { "Date", HBAD, 0 }, - { "Subject", HSUB, 0 }, - { "To", HADR|HTRY, MVIS }, - { "cc", HADR|HTRY, MVIS }, - { "Bcc", HADR|HTRY|HBCC|HNIL, MINV }, - { "Dcc", HADR|HTRY|HDCC|HNIL, MVIS }, /* sorta cc & bcc combined */ - { "Message-ID", HBAD, 0 }, - { "Fcc", HFCC, 0 }, - { NULL, 0, 0 } -}; - -static struct headers RHeaders[] = { - { "Resent-Reply-To", HADR|HNGR, 0 }, - { "Resent-From", HADR|HNGR, MRFM }, - { "Resent-Sender", HADR|HBAD, 0 }, - { "Resent-Date", HBAD, 0 }, - { "Resent-Subject", HSUB, 0 }, - { "Resent-To", HADR|HTRY, MVIS }, - { "Resent-cc", HADR|HTRY, MVIS }, - { "Resent-Bcc", HADR|HTRY|HBCC, MINV }, - { "Resent-Message-ID", HBAD, 0 }, - { "Resent-Fcc", HFCC, 0 }, - { "Reply-To", HADR, 0 }, - { "From", HADR|HNGR, MFRM }, - { "Sender", HADR|HNGR, 0 }, - { "Date", HNOP, MDAT }, - { "To", HADR|HNIL, 0 }, - { "cc", HADR|HNIL, 0 }, - { "Bcc", HADR|HTRY|HBCC|HNIL, 0 }, - { "Fcc", HIGN, 0 }, - { NULL, 0, 0 } -}; - -static short fccind = 0; /* index into fccfold[] */ -static short outputlinelen = OUTPUTLINELEN; - -static int pfd = NOTOK; /* fd to write annotation list to */ -static uid_t myuid= -1; /* my user id */ -static gid_t mygid= -1; /* my group id */ -static int recipients = 0; /* how many people will get a copy */ -static int unkadr = 0; /* how many of those were unknown */ -static int badadr = 0; /* number of bad addrs */ -static int badmsg = 0; /* message has bad semantics */ -static int verbose = 0; /* spell it out */ -static int format = 1; /* format addresses */ -static int mime = 0; /* use MIME-style encapsulations for Bcc */ -static int msgid = 0; /* add msgid */ -static int debug = 0; /* debugging post */ -static int watch = 0; /* watch the delivery process */ -static int whomsw = 0; /* we are whom not post */ -static int checksw = 0; /* whom -check */ -static int linepos=0; /* putadr()'s position on the line */ -static int nameoutput=0; /* putadr() has output header name */ -static int sasl=0; /* Use SASL auth for SMTP */ -static char *saslmech=NULL; /* Force use of particular SASL mech */ -static char *user=NULL; /* Authenticate as this user */ -static char *port="smtp"; /* Name of server port for SMTP */ -static int tls=0; /* Use TLS for encryption */ - -static unsigned msgflags = 0; /* what we've seen */ - -#define NORMAL 0 -#define RESENT 1 -static int msgstate = NORMAL; - -static time_t tclock = 0; /* the time we started (more or less) */ - -static SIGNAL_HANDLER hstat, istat, qstat, tstat; - -static char tmpfil[BUFSIZ]; -static char bccfil[BUFSIZ]; - -static char from[BUFSIZ]; /* my network address */ -static char signature[BUFSIZ]; /* my signature */ -static char *filter = NULL; /* the filter for BCC'ing */ -static char *subject = NULL; /* the subject field for BCC'ing */ -static char *fccfold[FCCS]; /* foldernames for FCC'ing */ - -static struct headers *hdrtab; /* table for the message we're doing */ - -static struct mailname localaddrs={NULL}; /* local addrs */ -static struct mailname netaddrs={NULL}; /* network addrs */ -static struct mailname uuaddrs={NULL}; /* uucp addrs */ -static struct mailname tmpaddrs={NULL}; /* temporary queue */ - -#ifdef SMTPMTS -static int snoop = 0; -static int smtpmode = S_MAIL; -static char *clientsw = NULL; -static char *serversw = NULL; - -extern struct smtp sm_reply; -#endif /* SMTPMTS */ - -static char prefix[] = "----- =_aaaaaaaaaa"; - -static int fill_up = 0; -static char *fill_in = NULL; -static char *partno = NULL; -static int queued = 0; - -extern boolean draft_from_masquerading; /* defined in mts.c */ - -/* - * static prototypes - */ -static void putfmt (char *, char *, FILE *); -static void start_headers (void); -static void finish_headers (FILE *); -static int get_header (char *, struct headers *); -static int putadr (char *, char *, struct mailname *, FILE *, unsigned int); -static void putgrp (char *, char *, FILE *, unsigned int); -static int insert (struct mailname *); -static void pl (void); -static void anno (void); -static int annoaux (struct mailname *); -static void insert_fcc (struct headers *, unsigned char *); -static void make_bcc_file (int); -static void verify_all_addresses (int); -static void chkadr (void); -static void sigon (void); -static void sigoff (void); -static void p_refile (char *); -static void fcc (char *, char *); -static void die (char *, char *, ...); -static void post (char *, int, int); -static void do_text (char *file, int fd); -static void do_an_address (struct mailname *, int); -static void do_addresses (int, int); -static int find_prefix (void); - - -int -main (int argc, char **argv) -{ - int state, compnum, dashstuff = 0; - char *cp, *msg = NULL, **argp, **arguments; - char buf[BUFSIZ], name[NAMESZ]; - FILE *in, *out; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); - print_help (buf, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case LIBSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - /* create a minimal context */ - if (context_foil (cp) == -1) - done (1); - continue; - - case ALIASW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((state = alias (cp)) != AK_OK) - adios (NULL, "aliasing error in %s - %s", - cp, akerror (state)); - continue; - - case CHKSW: - checksw++; - continue; - case NCHKSW: - checksw = 0; - continue; - - case DEBUGSW: - debug++; - continue; - - case DISTSW: - msgstate = RESENT; - continue; - - case FILTSW: - if (!(filter = *argp++) || *filter == '-') - adios (NULL, "missing argument to %s", argp[-2]); - mime = 0; - continue; - case NFILTSW: - filter = NULL; - continue; - - case FRMTSW: - format++; - continue; - case NFRMTSW: - format = 0; - continue; - - case BITSTUFFSW: - dashstuff = 1; - continue; - case NBITSTUFFSW: - dashstuff = -1; - continue; - - case MIMESW: - mime++; - filter = NULL; - continue; - case NMIMESW: - mime = 0; - continue; - - case MSGDSW: - msgid++; - continue; - case NMSGDSW: - msgid = 0; - continue; - - case VERBSW: - verbose++; - continue; - case NVERBSW: - verbose = 0; - continue; - - case WATCSW: - watch++; - continue; - case NWATCSW: - watch = 0; - continue; - - case WHOMSW: - whomsw++; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((outputlinelen = atoi (cp)) < 10) - adios (NULL, "impossible width %d", outputlinelen); - continue; - - case ANNOSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((pfd = atoi (cp)) <= 2) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - - case DLVRSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - -#ifndef SMTPMTS - case CLIESW: - case SERVSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case SNOOPSW: - continue; -#else /* SMTPMTS */ - case MAILSW: - smtpmode = S_MAIL; - continue; - case SAMLSW: - smtpmode = S_SAML; - continue; - case SOMLSW: - smtpmode = S_SOML; - continue; - case SENDSW: - smtpmode = S_SEND; - continue; - case CLIESW: - if (!(clientsw = *argp++) || *clientsw == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case SERVSW: - if (!(serversw = *argp++) || *serversw == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case SNOOPSW: - snoop++; - continue; -#endif /* SMTPMTS */ - - case FILLSW: - if (!(fill_in = *argp++) || *fill_in == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case FILLUSW: - fill_up++; - continue; - case PARTSW: - if (!(partno = *argp++) || *partno == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case QUEUESW: - queued++; - continue; - - case SASLSW: - sasl++; - continue; - - case SASLMECHSW: - if (!(saslmech = *argp++) || *saslmech == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case USERSW: - if (!(user = *argp++) || *user == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PORTSW: - if (!(port = *argp++) || *port == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case TLSSW: - tls++; - continue; - } - } - if (msg) - adios (NULL, "only one message at a time!"); - else - msg = cp; - } - - alias (AliasFile); - - if (!msg) - adios (NULL, "usage: %s [switches] file", invo_name); - - if (outputlinelen < 10) - adios (NULL, "impossible width %d", outputlinelen); - - if ((in = fopen (msg, "r")) == NULL) - adios (msg, "unable to open"); - - start_headers (); - if (debug) { - verbose++; - discard (out = stdout); /* XXX: reference discard() to help loader */ - } else { - if (whomsw) { - if ((out = fopen (fill_in ? fill_in : "/dev/null", "w")) == NULL) - adios ("/dev/null", "unable to open"); - } else { - char *cp = m_mktemp(m_maildir(invo_name), NULL, &out); - if (cp == NULL) { - cp = m_mktemp2(NULL, invo_name, NULL, &out); - if (cp == NULL) { - adios ("post", "unable to create temporary file"); - } - } - strncpy(tmpfil, cp, sizeof(tmpfil)); - chmod (tmpfil, 0600); - } - } - - hdrtab = msgstate == NORMAL ? NHeaders : RHeaders; - - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), in)) { - case FLD: - case FLDEOF: - case FLDPLUS: - compnum++; - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); - cp = add (buf, cp); - } - putfmt (name, cp, out); - free (cp); - if (state != FLDEOF) - continue; - finish_headers (out); - break; - - case BODY: - case BODYEOF: - finish_headers (out); - if (whomsw && !fill_in) - break; - fprintf (out, "\n%s", buf); - while (state == BODY) { - state = m_getfld (state, name, buf, sizeof(buf), in); - fputs (buf, out); - } - break; - - case FILEEOF: - finish_headers (out); - break; - - case LENERR: - case FMTERR: - adios (NULL, "message format error in component #%d", compnum); - - default: - adios (NULL, "getfld() returned %d", state); - } - break; - } - - if (pfd != NOTOK) - anno (); - fclose (in); - - if (debug) { - pl (); - done (0); - } else { - fclose (out); - } - - /* If we are doing a "whom" check */ - if (whomsw) { - if (!fill_up) - verify_all_addresses (1); - done (0); - } - - if (msgflags & MINV) { - make_bcc_file (dashstuff); - if (msgflags & MVIS) { - verify_all_addresses (verbose); - post (tmpfil, 0, verbose); - } - post (bccfil, 1, verbose); - unlink (bccfil); - } else { - post (tmpfil, 0, isatty (1)); - } - - p_refile (tmpfil); - unlink (tmpfil); - - if (verbose) - printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n", - partno); - done (0); - return 1; -} - - -/* - * DRAFT GENERATION - */ - -static void -putfmt (char *name, char *str, FILE *out) -{ - int count, grp, i, keep; - char *cp, *pp, *qp; - char namep[BUFSIZ]; - struct mailname *mp = NULL, *np = NULL; - struct headers *hdr; - - while (*str == ' ' || *str == '\t') - str++; - - if (msgstate == NORMAL && uprf (name, "resent")) { - advise (NULL, "illegal header line -- %s:", name); - badmsg++; - return; - } - - if ((i = get_header (name, hdrtab)) == NOTOK) { - fprintf (out, "%s: %s", name, str); - return; - } - - hdr = &hdrtab[i]; - if (hdr->flags & HIGN) { - if (fill_in) - fprintf (out, "%s: %s", name, str); - return; - } - if (hdr->flags & HBAD) { - if (fill_in) - fprintf (out, "%s: %s", name, str); - else { - advise (NULL, "illegal header line -- %s:", name); - badmsg++; - } - return; - } - msgflags |= (hdr->set & ~(MVIS | MINV)); - - if (hdr->flags & HSUB) - subject = subject ? add (str, add ("\t", subject)) : getcpy (str); - if (hdr->flags & HFCC) { - if (fill_in) { - fprintf (out, "%s: %s", name, str); - return; - } - - if ((cp = strrchr(str, '\n'))) - *cp = 0; - for (cp = pp = str; (cp = strchr(pp, ',')); pp = cp) { - *cp++ = 0; - insert_fcc (hdr, pp); - } - insert_fcc (hdr, pp); - return; - } - - if (!(hdr->flags & HADR)) { - fprintf (out, "%s: %s", name, str); - return; - } - - tmpaddrs.m_next = NULL; - for (count = 0; (cp = getname (str)); count++) - if ((mp = getm (cp, NULL, 0, AD_HOST, NULL))) { - if (tmpaddrs.m_next) - np->m_next = mp; - else - tmpaddrs.m_next = mp; - np = mp; - } - else - if (hdr->flags & HTRY) - badadr++; - else - badmsg++; - - if (count < 1) { - if (hdr->flags & HNIL) - fprintf (out, "%s: %s", name, str); - else { -#ifdef notdef - advise (NULL, "%s: field requires at least one address", name); - badmsg++; -#endif /* notdef */ - } - return; - } - - nameoutput = linepos = 0; - snprintf (namep, sizeof(namep), "%s%s", - !fill_in && (hdr->flags & HMNG) ? "Original-" : "", name); - - for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np) - if (mp->m_nohost) { /* also used to test (hdr->flags & HTRY) */ - /* The address doesn't include a host, so it might be an alias. */ - pp = akvalue (mp->m_mbox); /* do mh alias substitution */ - qp = akvisible () ? mp->m_mbox : ""; - np = mp; - if (np->m_gname) - putgrp (namep, np->m_gname, out, hdr->flags); - while ((cp = getname (pp))) { - if (!(mp = getm (cp, NULL, 0, AD_HOST, NULL))) { - badadr++; - continue; - } - - if (draft_from_masquerading && ((msgstate == RESENT) - ? (hdr->set & MRFM) - : (hdr->set & MFRM))) - /* The user manually specified a [Resent-]From: address in - their draft and the "masquerade:" line in mts.conf - doesn't contain "draft_from", so we'll set things up to - use the actual email address embedded in the draft - [Resent-]From: (after alias substitution, and without the - GECOS full name or angle brackets) as the envelope - From:. */ - strncpy(from, auxformat(mp, 0), sizeof(from) - 1); - - if (hdr->flags & HBCC) - mp->m_bcc++; - if (np->m_ingrp) - mp->m_ingrp = np->m_ingrp; - else - if (mp->m_gname) - putgrp (namep, mp->m_gname, out, hdr->flags); - if (mp->m_ingrp) - grp++; - if (putadr (namep, qp, mp, out, hdr->flags)) - msgflags |= (hdr->set & (MVIS | MINV)); - else - mnfree (mp); - } - mp = np; - np = np->m_next; - mnfree (mp); - } - else { - /* Address includes a host, so no alias substitution is needed. */ - if (draft_from_masquerading && ((msgstate == RESENT) - ? (hdr->set & MRFM) - : (hdr->set & MFRM))) - /* The user manually specified a [Resent-]From: address in - their draft and the "masquerade:" line in mts.conf - doesn't contain "draft_from", so we'll set things up to - use the actual email address embedded in the draft - [Resent-]From: (after alias substitution, and without the - GECOS full name or angle brackets) as the envelope - From:. */ - strncpy(from, auxformat(mp, 0), sizeof(from) - 1); - - if (hdr->flags & HBCC) - mp->m_bcc++; - if (mp->m_gname) - putgrp (namep, mp->m_gname, out, hdr->flags); - if (mp->m_ingrp) - grp++; - keep = putadr (namep, "", mp, out, hdr->flags); - np = mp->m_next; - if (keep) { - mp->m_next = NULL; - msgflags |= (hdr->set & (MVIS | MINV)); - } - else - mnfree (mp); - } - - if (grp > 0 && (hdr->flags & HNGR)) { - advise (NULL, "%s: field does not allow groups", name); - badmsg++; - } - if (linepos) { - if (fill_in && grp > 0) - putc (';', out); - putc ('\n', out); - } -} - - -static void -start_headers (void) -{ - unsigned char *cp; - char myhost[BUFSIZ], sigbuf[BUFSIZ]; - struct mailname *mp; - - myuid = getuid (); - mygid = getgid (); - time (&tclock); - - strncpy (from, adrsprintf (NULL, NULL), sizeof(from)); - strncpy (myhost, LocalName (), sizeof(myhost)); - - for (cp = myhost; *cp; cp++) - *cp = uptolow (*cp); - - if ((cp = getfullname ()) && *cp) { - strncpy (sigbuf, cp, sizeof(sigbuf)); - snprintf (signature, sizeof(signature), "%s <%s>", - sigbuf, adrsprintf (NULL, NULL)); - if ((cp = getname (signature)) == NULL) - adios (NULL, "getname () failed -- you lose extraordinarily big"); - if ((mp = getm (cp, NULL, 0, AD_HOST, NULL)) == NULL) - adios (NULL, "bad signature '%s'", sigbuf); - mnfree (mp); - while (getname ("")) - continue; - } else { - strncpy (signature, adrsprintf (NULL, NULL), sizeof(signature)); - } -} - - -/* - * Now that we've outputted the header fields in the draft - * message, we will now output any remaining header fields - * that we need to add/create. - */ - -static void -finish_headers (FILE *out) -{ - switch (msgstate) { - case NORMAL: - if (whomsw && !fill_up) - break; - - fprintf (out, "Date: %s\n", dtime (&tclock, 0)); - if (msgid) - fprintf (out, "Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - if (msgflags & MFRM) { - /* There was already a From: in the draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Sender: %s\n", from); - } - else - /* Construct a From: header. */ - fprintf (out, "From: %s\n", signature); - if (whomsw) - break; - - if (!(msgflags & MVIS)) - fprintf (out, "Bcc: Blind Distribution List: ;\n"); - break; - - case RESENT: - if (!(msgflags & MDAT)) { - advise (NULL, "message has no Date: header"); - badmsg++; - } - if (!(msgflags & MFRM)) { - advise (NULL, "message has no From: header"); - badmsg++; - } - if (whomsw && !fill_up) - break; - - fprintf (out, "Resent-Date: %s\n", dtime (&tclock, 0)); - if (msgid) - fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - if (msgflags & MRFM) { - /* There was already a Resent-From: in draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Resent-Sender: %s\n", from); - } - else - /* Construct a Resent-From: header. */ - fprintf (out, "Resent-From: %s\n", signature); - if (whomsw) - break; - if (!(msgflags & MVIS)) - fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n"); - break; - } - - if (badmsg) - adios (NULL, "re-format message and try again"); - if (!recipients) - adios (NULL, "no addressees"); -} - - -static int -get_header (char *header, struct headers *table) -{ - struct headers *h; - - for (h = table; h->value; h++) - if (!mh_strcasecmp (header, h->value)) - return (h - table); - - return NOTOK; -} - - -static int -putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flags) -{ - int len; - char *cp; - char buffer[BUFSIZ]; - - if (mp->m_mbox == NULL || ((flags & HTRY) && !insert (mp))) - return 0; - if ((!fill_in && (flags & (HBCC | HDCC))) || mp->m_ingrp) - return 1; - - if (!nameoutput) { - fprintf (out, "%s: ", name); - linepos += (nameoutput = strlen (name) + 2); - } - - if (*aka && mp->m_type != UUCPHOST && !mp->m_pers) - mp->m_pers = getcpy (aka); - if (format) { - if (mp->m_gname && !fill_in) { - snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname); - cp = buffer; - } else { - cp = adrformat (mp); - } - } else { - cp = mp->m_text; - } - len = strlen (cp); - - if (linepos != nameoutput) { - if (len + linepos + 2 > outputlinelen) - fprintf (out, ",\n%*s", linepos = nameoutput, ""); - else { - fputs (", ", out); - linepos += 2; - } - } - - fputs (cp, out); - linepos += len; - - return (flags & HTRY); -} - - -static void -putgrp (char *name, char *group, FILE *out, unsigned int flags) -{ - int len; - char *cp; - - if (!fill_in && (flags & HBCC)) - return; - - if (!nameoutput) { - fprintf (out, "%s: ", name); - linepos += (nameoutput = strlen (name) + 2); - if (fill_in) - linepos -= strlen (group); - } - - cp = fill_in ? group : concat (group, ";", NULL); - len = strlen (cp); - - if (linepos > nameoutput) { - if (len + linepos + 2 > outputlinelen) { - fprintf (out, ",\n%*s", nameoutput, ""); - linepos = nameoutput; - } - else { - fputs (", ", out); - linepos += 2; - } - } - - fputs (cp, out); - linepos += len; -} - - -static int -insert (struct mailname *np) -{ - struct mailname *mp; - - if (np->m_mbox == NULL) - return 0; - - for (mp = np->m_type == LOCALHOST ? &localaddrs - : np->m_type == UUCPHOST ? &uuaddrs - : &netaddrs; - mp->m_next; - mp = mp->m_next) - if (!mh_strcasecmp (np->m_host, mp->m_next->m_host) - && !mh_strcasecmp (np->m_mbox, mp->m_next->m_mbox) - && np->m_bcc == mp->m_next->m_bcc) - return 0; - - mp->m_next = np; - recipients++; - return 1; -} - - -static void -pl (void) -{ - int i; - struct mailname *mp; - - printf ("-------\n\t-- Addresses --\nlocal:\t"); - for (mp = localaddrs.m_next; mp; mp = mp->m_next) - printf ("%s%s%s", mp->m_mbox, - mp->m_bcc ? "[BCC]" : "", - mp->m_next ? ",\n\t" : ""); - - printf ("\nnet:\t"); - for (mp = netaddrs.m_next; mp; mp = mp->m_next) - printf ("%s%s@%s%s%s", mp->m_path ? mp->m_path : "", - mp->m_mbox, mp->m_host, - mp->m_bcc ? "[BCC]" : "", - mp->m_next ? ",\n\t" : ""); - - printf ("\nuucp:\t"); - for (mp = uuaddrs.m_next; mp; mp = mp->m_next) - printf ("%s!%s%s%s", mp->m_host, mp->m_mbox, - mp->m_bcc ? "[BCC]" : "", - mp->m_next ? ",\n\t" : ""); - - printf ("\n\t-- Folder Copies --\nfcc:\t"); - for (i = 0; i < fccind; i++) - printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : ""); - printf ("\n"); -} - - -static void -anno (void) -{ - struct mailname *mp; - - for (mp = localaddrs.m_next; mp; mp = mp->m_next) - if (annoaux (mp) == NOTOK) - goto oops; - - for (mp = netaddrs.m_next; mp; mp = mp->m_next) - if (annoaux (mp) == NOTOK) - goto oops; - - for (mp = uuaddrs.m_next; mp; mp = mp->m_next) - if (annoaux (mp) == NOTOK) - break; - -oops: ; - close (pfd); - pfd = NOTOK; -} - - -static int -annoaux (struct mailname *mp) -{ - int i; - char buffer[BUFSIZ]; - - snprintf (buffer, sizeof(buffer), "%s\n", adrformat (mp)); - i = strlen (buffer); - - return (write (pfd, buffer, i) == i ? OK : NOTOK); -} - - -static void -insert_fcc (struct headers *hdr, unsigned char *pp) -{ - unsigned char *cp; - - for (cp = pp; isspace (*cp); cp++) - continue; - for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--) - continue; - if (pp >= cp) - *++pp = 0; - if (*cp == 0) - return; - - if (fccind >= FCCS) - adios (NULL, "too many %ss", hdr->value); - fccfold[fccind++] = getcpy (cp); -} - -/* - * BCC GENERATION - */ - -static void -make_bcc_file (int dashstuff) -{ - int fd, i; - pid_t child_id; - char *vec[6]; - FILE *out; - char *tfile = NULL; - - tfile = m_mktemp2(NULL, "bccs", NULL, &out); - if (tfile == NULL) adios("bcc", "unable to create temporary file"); - chmod (bccfil, 0600); - strncpy (bccfil, tfile, sizeof(bccfil)); - - fprintf (out, "Date: %s\n", dtime (&tclock, 0)); - if (msgid) - fprintf (out, "Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - if (msgflags & MFRM) { - /* There was already a From: in the draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Sender: %s\n", from); - } - else - /* Construct a From: header. */ - fprintf (out, "From: %s\n", signature); - if (subject) - fprintf (out, "Subject: %s", subject); - fprintf (out, "BCC:\n"); - - /* - * Use MIME encapsulation for Bcc messages - */ - if (mime) { - char *cp; - - /* - * Check if any lines in the message clash with the - * prefix for the MIME multipart separator. If there - * is a clash, increment one of the letters in the - * prefix and check again. - */ - if ((cp = strchr(prefix, 'a')) == NULL) - adios (NULL, "lost prefix start"); - while (find_prefix () == NOTOK) { - if (*cp < 'z') - (*cp)++; - else - if (*++cp == 0) - adios (NULL, "can't find a unique delimiter string"); - else - (*cp)++; - } - - fprintf (out, "%s: %s\n%s: multipart/digest; boundary=\"", - VRSN_FIELD, VRSN_VALUE, TYPE_FIELD); - fprintf (out, "%s\"\n\n--%s\n\n", prefix, prefix); - } else { - fprintf (out, "\n------- Blind-Carbon-Copy\n\n"); - } - - fflush (out); - - /* - * Do mhl filtering of Bcc messages instead - * of MIME encapsulation. - */ - if (filter != NULL) { - vec[0] = r1bindex (mhlproc, '/'); - - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - adios ("fork", "unable to"); - - case OK: - dup2 (fileno (out), 1); - - i = 1; - vec[i++] = "-forward"; - vec[i++] = "-form"; - vec[i++] = filter; - vec[i++] = tmpfil; - - /* was the flag -[no]dashstuffing specified? */ - if (dashstuff > 0) - vec[i++] = "-dashstuffing"; - else if (dashstuff < 0) - vec[i++] = "-nodashstuffing"; - vec[i] = NULL; - - execvp (mhlproc, vec); - fprintf (stderr, "unable to exec "); - perror (mhlproc); - _exit (-1); - - default: - pidXwait (child_id, mhlproc); - break; - } - } else { - if ((fd = open (tmpfil, O_RDONLY)) == NOTOK) - adios (tmpfil, "unable to re-open"); - - /* - * If using MIME encapsulation, or if the -nodashstuffing - * flag was given, then just copy message. Else do - * RFC934 quoting (dashstuffing). - */ - if (mime || dashstuff < 0) - cpydata (fd, fileno (out), tmpfil, bccfil); - else - cpydgst (fd, fileno (out), tmpfil, bccfil); - close (fd); - } - - fseek (out, 0L, SEEK_END); - if (mime) - fprintf (out, "\n--%s--\n", prefix); - else - fprintf (out, "\n------- End of Blind-Carbon-Copy\n"); - fclose (out); -} - - -/* - * Scan message to check if any lines clash with - * the prefix of the MIME multipart separator. - */ - -static int -find_prefix (void) -{ - int len, result; - unsigned char buffer[BUFSIZ]; - FILE *in; - - if ((in = fopen (tmpfil, "r")) == NULL) - adios (tmpfil, "unable to re-open"); - - len = strlen (prefix); - - result = OK; - while (fgets (buffer, sizeof(buffer) - 1, in)) - if (buffer[0] == '-' && buffer[1] == '-') { - unsigned char *cp; - - for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (!isspace (*cp)) - break; - *++cp = '\0'; - if (strcmp (buffer + 2, prefix) == 0) { - result = NOTOK; - break; - } - } - - fclose (in); - return result; -} - - -#define plural(x) (x == 1 ? "" : "s") - -static void -chkadr (void) -{ - if (badadr && unkadr) - die (NULL, "%d address%s unparsable, %d addressee%s undeliverable", - badadr, plural (badadr), unkadr, plural (badadr)); - if (badadr) - die (NULL, "%d address%s unparsable", badadr, plural (badadr)); - if (unkadr) - die (NULL, "%d addressee%s undeliverable", unkadr, plural (unkadr)); -} - - -static void -do_addresses (int bccque, int talk) -{ - int retval; - int state; - struct mailname *lp; - - state = 0; - for (lp = localaddrs.m_next; lp; lp = lp->m_next) - if (lp->m_bcc ? bccque : !bccque) { - if (talk && !state) - printf (" -- Local Recipients --\n"); - do_an_address (lp, talk); - state++; - } - - state = 0; - for (lp = uuaddrs.m_next; lp; lp = lp->m_next) - if (lp->m_bcc ? bccque : !bccque) { - if (talk && !state) - printf (" -- UUCP Recipients --\n"); - do_an_address (lp, talk); - state++; - } - - state = 0; - for (lp = netaddrs.m_next; lp; lp = lp->m_next) - if (lp->m_bcc ? bccque : !bccque) { - if (talk && !state) - printf (" -- Network Recipients --\n"); - do_an_address (lp, talk); - state++; - } - - chkadr (); - -#ifdef SMTPMTS - if (rp_isbad (retval = sm_waend ())) - die (NULL, "problem ending addresses; %s", rp_string (retval)); -#endif /* SMTPMTS */ -} - - -/* - * MTS-SPECIFIC INTERACTION - */ - - -/* - * SENDMAIL/SMTP routines - */ - -#ifdef SMTPMTS - -static void -post (char *file, int bccque, int talk) -{ - int fd, onex; - int retval; - - onex = !(msgflags & MINV) || bccque; - if (verbose) { - if (msgflags & MINV) - printf (" -- Posting for %s Recipients --\n", - bccque ? "Blind" : "Sighted"); - else - printf (" -- Posting for All Recipients --\n"); - } - - sigon (); - - if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose, - snoop, onex, queued, sasl, saslmech, - user, tls)) - || rp_isbad (retval = sm_winit (smtpmode, from))) - die (NULL, "problem initializing server; %s", rp_string (retval)); - - do_addresses (bccque, talk && verbose); - if ((fd = open (file, O_RDONLY)) == NOTOK) - die (file, "unable to re-open"); - do_text (file, fd); - close (fd); - fflush (stdout); - - sm_end (onex ? OK : DONE); - sigoff (); - - if (verbose) { - if (msgflags & MINV) - printf (" -- %s Recipient Copies Posted --\n", - bccque ? "Blind" : "Sighted"); - else - printf (" -- Recipient Copies Posted --\n"); - } - - fflush (stdout); -} - - -/* Address Verification */ - -static void -verify_all_addresses (int talk) -{ - int retval; - struct mailname *lp; - - sigon (); - - if (!whomsw || checksw) - if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, - verbose, snoop, 0, queued, sasl, - saslmech, user, tls)) - || rp_isbad (retval = sm_winit (smtpmode, from))) - die (NULL, "problem initializing server; %s", rp_string (retval)); - - if (talk && !whomsw) - printf (" -- Address Verification --\n"); - if (talk && localaddrs.m_next) - printf (" -- Local Recipients --\n"); - for (lp = localaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - if (talk && uuaddrs.m_next) - printf (" -- UUCP Recipients --\n"); - for (lp = uuaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - if (talk && netaddrs.m_next) - printf (" -- Network Recipients --\n"); - for (lp = netaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - chkadr (); - if (talk && !whomsw) - printf (" -- Address Verification Successful --\n"); - - if (!whomsw || checksw) - sm_end (DONE); - - fflush (stdout); - sigoff (); -} - - -static void -do_an_address (struct mailname *lp, int talk) -{ - int retval; - char *mbox, *host; - char addr[BUFSIZ]; - - switch (lp->m_type) { - case LOCALHOST: - mbox = lp->m_mbox; - host = lp->m_host; - strncpy (addr, mbox, sizeof(addr)); - break; - - case UUCPHOST: - mbox = auxformat (lp, 0); - host = NULL; - snprintf (addr, sizeof(addr), "%s!%s", lp->m_host, lp->m_mbox); - break; - - default: /* let SendMail decide if the host is bad */ - mbox = lp->m_mbox; - host = lp->m_host; - snprintf (addr, sizeof(addr), "%s at %s", mbox, host); - break; - } - - if (talk) - printf (" %s%s", addr, whomsw && lp->m_bcc ? "[BCC]" : ""); - - if (whomsw && !checksw) { - putchar ('\n'); - return; - } - if (talk) - printf (": "); - fflush (stdout); - - switch (retval = sm_wadr (mbox, host, - lp->m_type != UUCPHOST ? lp->m_path : NULL)) { - case RP_OK: - if (talk) - printf ("address ok\n"); - break; - - case RP_NO: - case RP_USER: - if (!talk) - fprintf (stderr, " %s: ", addr); - fprintf (talk ? stdout : stderr, "loses; %s\n", - rp_string (retval)); - unkadr++; - break; - - default: - if (!talk) - fprintf (stderr, " %s: ", addr); - die (NULL, "unexpected response; %s", rp_string (retval)); - } - - fflush (stdout); -} - - -static void -do_text (char *file, int fd) -{ - int retval, state; - char buf[BUFSIZ]; - - lseek (fd, (off_t) 0, SEEK_SET); - - while ((state = read (fd, buf, sizeof(buf))) > 0) { - if (rp_isbad (retval = sm_wtxt (buf, state))) - die (NULL, "problem writing text; %s\n", rp_string (retval)); - } - - if (state == NOTOK) - die (file, "problem reading from"); - - switch (retval = sm_wtend ()) { - case RP_OK: - break; - - case RP_NO: - case RP_NDEL: - die (NULL, "posting failed; %s", rp_string (retval)); - - default: - die (NULL, "unexpected response; %s", rp_string (retval)); - } -} - -#endif /* SMTPMTS */ - - -/* - * SIGNAL HANDLING - */ - -static RETSIGTYPE -sigser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (i, SIG_IGN); -#endif - - unlink (tmpfil); - if (msgflags & MINV) - unlink (bccfil); - -#ifdef SMTPMTS - if (!whomsw || checksw) - sm_end (NOTOK); -#endif /* SMTPMTS */ - - done (1); -} - - -static void -sigon (void) -{ - if (debug) - return; - - hstat = SIGNAL2 (SIGHUP, sigser); - istat = SIGNAL2 (SIGINT, sigser); - qstat = SIGNAL2 (SIGQUIT, sigser); - tstat = SIGNAL2 (SIGTERM, sigser); -} - - -static void -sigoff (void) -{ - if (debug) - return; - - SIGNAL (SIGHUP, hstat); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - SIGNAL (SIGTERM, tstat); -} - -/* - * FCC INTERACTION - */ - -static void -p_refile (char *file) -{ - int i; - - if (fccind == 0) - return; - - if (verbose) - printf (" -- Filing Folder Copies --\n"); - for (i = 0; i < fccind; i++) - fcc (file, fccfold[i]); - if (verbose) - printf (" -- Folder Copies Filed --\n"); -} - - -/* - * Call the `fileproc' to add the file to the folder. - */ - -static void -fcc (char *file, char *folder) -{ - pid_t child_id; - int i, status; - char fold[BUFSIZ]; - - if (verbose) - printf (" %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder); - fflush (stdout); - - for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case NOTOK: - if (!verbose) - fprintf (stderr, " %sFcc %s: ", - msgstate == RESENT ? "Resent-" : "", folder); - fprintf (verbose ? stdout : stderr, "no forks, so not ok\n"); - break; - - case OK: - /* see if we need to add `+' */ - snprintf (fold, sizeof(fold), "%s%s", - *folder == '+' || *folder == '@' ? "" : "+", folder); - - /* now exec the fileproc */ - execlp (fileproc, r1bindex (fileproc, '/'), - "-link", "-file", file, fold, NULL); - _exit (-1); - - default: - if ((status = pidwait (child_id, OK))) { - if (!verbose) - fprintf (stderr, " %sFcc %s: ", - msgstate == RESENT ? "Resent-" : "", folder); - pidstatus (status, verbose ? stdout : stderr, NULL); - } else { - if (verbose) - printf ("folder ok\n"); - } - } - - fflush (stdout); -} - -/* - * TERMINATION - */ - -static void -die (char *what, char *fmt, ...) -{ - va_list ap; - - unlink (tmpfil); - if (msgflags & MINV) - unlink (bccfil); - -#ifdef SMTPMTS - if (!whomsw || checksw) - sm_end (NOTOK); -#endif /* SMTPMTS */ - - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); - done (1); -} diff --git a/uip/print-mimetype.sh b/uip/print-mimetype.sh new file mode 100755 index 0000000..2149902 --- /dev/null +++ b/uip/print-mimetype.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# print mime type of file, depending on file name extension + +if [ $# -eq 0 ] ; then + echo "Usage: $0 FILE..." >&2 + exit 1 +fi + +for i do + +case "$i" in +*.xls) type=application/excel;; +*.ppt) type=application/mspowerpoint;; +*.doc) type=application/msword;; +*.pdf) type=application/pdf;; +*.deb) type=application/x-debian-package;; +*.tar) type=application/x-tar;; +*.[1-9]) type=application/x-troff-man;; +*.zip) type=application/zip;; +*.au) type=audio/basic;; +*.gif) type=image/gif;; +*.jpg|*.jpeg) type=image/jpeg;; +*.png) type=image/png;; +*.ps) type=application/postscript;; +*.eps) type=image/eps;; +*.tif|*.tiff) type=image/tiff;; +*.ico) type=image/x-icon;; +*.bmp) type=image/x-ms-bmp;; +*.pnm) type=image/x-portable-anymap;; +*.pbm) type=image/x-portable-bitmap;; +*.pgm) type=image/x-portable-graymap;; +*.ppm) type=image/x-portable-pixmap;; +*.xbm) type=image/x-xbitmap;; +*.xpm) type=image/x-xpixmap;; +*.xwd) type=image/x-xwindowdump;; +*.eml) type=message/rfc822;; +*.rtf) type=text/richtext;; +*.html|*.htm) type=text/html;; +*.txt) type=text/plain;; +*.mpg|*.mpeg) video/mpeg;; +*) + if file "$i" | grep -q ' text$' ; then + type=text/plain;; + else + type=application/octet-stream;; + fi +esac +echo "$type" + +done + diff --git a/uip/prompter.c b/uip/prompter.c index 7c28aec..823760e 100644 --- a/uip/prompter.c +++ b/uip/prompter.c @@ -1,11 +1,10 @@ - /* - * prompter.c -- simple prompting editor front-end - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** prompter.c -- simple prompting editor front-end +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,471 +13,305 @@ #include #include -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# else -# include -# endif -#endif - -#define QUOTE '\\' - -#ifndef CKILL -# define CKILL '@' -#endif - -#ifndef CERASE -# define CERASE '#' -#endif - static struct swit switches[] = { -#define ERASESW 0 - { "erase chr", 0 }, -#define KILLSW 1 - { "kill chr", 0 }, -#define PREPSW 2 - { "prepend", 0 }, -#define NPREPSW 3 - { "noprepend", 0 }, -#define RAPDSW 4 - { "rapid", 0 }, -#define NRAPDSW 5 - { "norapid", 0 }, -#define BODYSW 6 - { "body", -4 }, -#define NBODYSW 7 - { "nobody", -6 }, -#define DOTSW 8 - { "doteof", 0 }, -#define NDOTSW 9 - { "nodoteof", 0 }, -#define VERSIONSW 10 - { "version", 0 }, -#define HELPSW 11 - { "help", 0 }, - { NULL, 0 } +#define PREPSW 0 + { "prepend", 0 }, +#define NPREPSW 1 + { "noprepend", 2 }, +#define RAPDSW 2 + { "rapid", 0 }, +#define NRAPDSW 3 + { "norapid", 2 }, +#define BODYSW 4 + { "body", 0 }, +#define NBODYSW 5 + { "nobody", 2 }, +#define VERSIONSW 6 + { "Version", 0 }, +#define HELPSW 7 + { "help", 0 }, + { NULL, 0 } }; -#ifdef HAVE_TERMIOS_H -static struct termios tio; -# define ERASE tio.c_cc[VERASE] -# define KILL tio.c_cc[VKILL] -# define INTR tio.c_cc[VINTR] -#else -# ifdef HAVE_TERMIO_H -static struct termio tio; -# define ERASE tio.c_cc[VERASE] -# define KILL tio.c_cc[VKILL] -# define INTR tio.c_cc[VINTR] -# else -static struct sgttyb tio; -static struct tchars tc; -# define ERASE tio.sg_erase -# define KILL tio.sg_kill -# define INTR tc.t_intrc -# endif -#endif - static int wtuser = 0; static int sigint = 0; static jmp_buf sigenv; /* - * prototypes - */ -int getln (char *, int); -static int chrcnv (char *); -static void chrdsp (char *, char); -static RETSIGTYPE intrser (int); +** prototypes +*/ +int getln(char *, int); +static void intrser(int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int body = 1, prepend = 1, rapid = 0; - int doteof = 0, fdi, fdo, i, state; - char *cp, *drft = NULL, *erasep = NULL; - char *killp = NULL, name[NAMESZ], field[BUFSIZ]; - char buffer[BUFSIZ], tmpfil[BUFSIZ]; - char **arguments, **argp; - FILE *in, *out; - char *tfile = NULL; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buffer, sizeof(buffer), "%s [switches] file", - invo_name); - print_help (buffer, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ERASESW: - if (!(erasep = *argp++) || *erasep == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case KILLSW: - if (!(killp = *argp++) || *killp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PREPSW: - prepend++; - continue; - case NPREPSW: - prepend = 0; - continue; - - case RAPDSW: - rapid++; - continue; - case NRAPDSW: - rapid = 0; - continue; - - case BODYSW: - body++; - continue; - case NBODYSW: - body = 0; - continue; - - case DOTSW: - doteof++; - continue; - case NDOTSW: - doteof = 0; - continue; - } - } else { - if (!drft) - drft = cp; + int qbody = 1, prepend = 1, rapid = 0; + int fdi, fdo, i, state; + char *cp, *drft = NULL; + char name[NAMESZ], field[BUFSIZ]; + char buffer[BUFSIZ], tmpfil[BUFSIZ]; + char **arguments, **argp; + FILE *in, *out; + char *tfile = NULL; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buffer, sizeof(buffer), + "%s [switches] file", + invo_name); + print_help(buffer, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case PREPSW: + prepend++; + continue; + case NPREPSW: + prepend = 0; + continue; + + case RAPDSW: + rapid++; + continue; + case NRAPDSW: + rapid = 0; + continue; + + case BODYSW: + qbody++; + continue; + case NBODYSW: + qbody = 0; + continue; + } + } else if (!drft) { + drft = cp; + } } - if (!drft) - adios (NULL, "usage: %s [switches] file", invo_name); - if ((in = fopen (drft, "r")) == NULL) - adios (drft, "unable to open"); - - tfile = m_mktemp2(NULL, invo_name, NULL, &out); - if (tfile == NULL) adios("prompter", "unable to create temporary file"); - chmod (tmpfil, 0600); - strncpy (tmpfil, tfile, sizeof(tmpfil)); - - /* - * Are we changing the kill or erase character? - */ - if (killp || erasep) { -#ifdef HAVE_TERMIOS_H - cc_t save_erase, save_kill; -#else - int save_erase, save_kill; -#endif - - /* get the current terminal attributes */ -#ifdef HAVE_TERMIOS_H - tcgetattr(0, &tio); -#else -# ifdef HAVE_TERMIO_H - ioctl(0, TCGETA, &tio); -# else - ioctl (0, TIOCGETP, (char *) &tio); - ioctl (0, TIOCGETC, (char *) &tc); -# endif -#endif - - /* save original kill, erase character for later */ - save_kill = KILL; - save_erase = ERASE; - - /* set new kill, erase character in terminal structure */ - KILL = killp ? chrcnv (killp) : save_kill; - ERASE = erasep ? chrcnv (erasep) : save_erase; - - /* set the new terminal attributes */ -#ifdef HAVE_TERMIOS_H - tcsetattr(0, TCSADRAIN, &tio); -#else -# ifdef HAVE_TERMIO_H - ioctl(0, TCSETAW, &tio); -# else - ioctl (0, TIOCSETN, (char *) &tio); -# endif -#endif - - /* print out new kill erase characters */ - chrdsp ("erase", ERASE); - chrdsp (", kill", KILL); - chrdsp (", intr", INTR); - putchar ('\n'); - fflush (stdout); + if (!drft) + adios(NULL, "usage: %s [switches] file", invo_name); + if ((in = fopen(drft, "r")) == NULL) + adios(drft, "unable to open"); - /* - * We set the kill and erase character back to original - * setup in terminal structure so we can easily - * restore it upon exit. - */ - KILL = save_kill; - ERASE = save_erase; - } - - sigint = 0; - SIGNAL2 (SIGINT, intrser); - - /* - * Loop through the lines of the draft skeleton. - */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), in)) { - case FLD: - case FLDEOF: - case FLDPLUS: - /* - * Check if the value of field contains anything - * other than space or tab. - */ - for (cp = field; *cp; cp++) - if (*cp != ' ' && *cp != '\t') - break; + tfile = m_mktemp2(NULL, invo_name, NULL, &out); + if (tfile == NULL) + adios("prompter", "unable to create temporary file"); + chmod(tmpfil, 0600); + strncpy(tmpfil, tfile, sizeof(tmpfil)); + + sigint = 0; + SIGNAL2(SIGINT, intrser); - /* If so, just add header line to draft */ - if (*cp++ != '\n' || *cp != 0) { - printf ("%s:%s", name, field); - fprintf (out, "%s:%s", name, field); - while (state == FLDPLUS) { - state = - m_getfld (state, name, field, sizeof(field), in); - printf ("%s", field); - fprintf (out, "%s", field); - } - } else { - /* Else, get value of header field */ - printf ("%s: ", name); - fflush (stdout); - i = getln (field, sizeof(field)); - if (i == -1) { + /* + ** Loop through the lines of the draft skeleton. + */ + for (state = FLD;;) { + switch (state = m_getfld(state, name, field, sizeof(field), + in)) { + case FLD: + case FLDEOF: + case FLDPLUS: + /* + ** Check if the value of field contains + ** anything other than space or tab. + */ + for (cp = field; *cp; cp++) + if (*cp != ' ' && *cp != '\t') + break; + + /* If so, just add header line to draft */ + if (*cp++ != '\n' || *cp) { + printf("%s:%s", name, field); + fprintf(out, "%s:%s", name, field); + while (state == FLDPLUS) { + state = m_getfld(state, name, field, + sizeof(field), in); + printf("%s", field); + fprintf(out, "%s", field); + } + } else { + /* Else, get value of header field */ + printf("%s: ", name); + fflush(stdout); + i = getln(field, sizeof(field)); + if (i == -1) { abort: - if (killp || erasep) { -#ifdef HAVE_TERMIOS_H - tcsetattr(0, TCSADRAIN, &tio); -#else -# ifdef HAVE_TERMIO - ioctl (0, TCSETA, &tio); -# else - ioctl (0, TIOCSETN, (char *) &tio); -# endif -#endif + unlink(tmpfil); + done(1); + } + if (i || (field[0]!='\n' && field[0]!='\0')) { + fprintf(out, "%s:", name); + do { + if (field[0] != ' ' && field[0] != '\t') + putc(' ', out); + fprintf(out, "%s", field); + } while (i == 1 && (i = getln(field, sizeof(field))) >= 0); + if (i == -1) + goto abort; + } } - unlink (tmpfil); - done (1); - } - if (i != 0 || (field[0] != '\n' && field[0] != 0)) { - fprintf (out, "%s:", name); + + if (state == FLDEOF) { /* moby hack */ + /* draft has no body separator; only headers */ + fprintf(out, "--------\n"); + if (!qbody) + break; + printf("--------\n"); + goto has_no_body; + } + continue; + + case BODY: + case BODYEOF: + case FILEEOF: + fprintf(out, "--------\n"); + if (qbody) { + if (!*field) { + printf("--------\n"); + goto has_no_body; + } + + if (prepend) { + printf("--------Enter initial text\n"); + fflush(stdout); + for (;;) { + getln(buffer, sizeof(buffer)); + if (!*buffer) + break; + fprintf(out, "%s", buffer); + } + } else { + printf("--------\n"); + } + } + do { - if (field[0] != ' ' && field[0] != '\t') - putc (' ', out); - fprintf (out, "%s", field); - } while (i == 1 - && (i = getln (field, sizeof(field))) >= 0); - if (i == -1) - goto abort; - } - } + fprintf(out, "%s", field); + if (!rapid && !sigint) + printf("%s", field); + } while (state == BODY && + (state = m_getfld(state, name, + field, sizeof(field), in))); + + if (prepend || !qbody) + break; - if (state == FLDEOF) { /* moby hack */ - fprintf (out, "--------\n"); - printf ("--------\n"); - if (!body) - break; - goto no_body; - } - continue; - - case BODY: - case BODYEOF: - case FILEEOF: - if (!body) - break; - fprintf (out, "--------\n"); - if (field[0] == 0 || !prepend) - printf ("--------\n"); - if (field[0]) { - if (prepend && body) { - printf ("\n--------Enter initial text\n\n"); - fflush (stdout); + printf("--------Enter additional text\n"); +has_no_body: + fflush(stdout); for (;;) { - getln (buffer, sizeof(buffer)); - if (doteof && buffer[0] == '.' && buffer[1] == '\n') - break; - if (buffer[0] == 0) - break; - fprintf (out, "%s", buffer); + getln(field, sizeof(field)); + if (!*field) + break; + fprintf(out, "%s", field); } - } - - do { - fprintf (out, "%s", field); - if (!rapid && !sigint) - printf ("%s", field); - } while (state == BODY && - (state = m_getfld (state, name, field, sizeof(field), in))); - if (prepend || !body) break; - else - printf ("\n--------Enter additional text\n\n"); - } -no_body: - fflush (stdout); - for (;;) { - getln (field, sizeof(field)); - if (doteof && field[0] == '.' && field[1] == '\n') - break; - if (field[0] == 0) - break; - fprintf (out, "%s", field); + + default: + adios(NULL, "skeleton is poorly formatted"); } break; - - default: - adios (NULL, "skeleton is poorly formatted"); } - break; - } - - if (body) - printf ("--------\n"); - - fflush (stdout); - fclose (in); - fclose (out); - SIGNAL (SIGINT, SIG_IGN); - - if (killp || erasep) { -#ifdef HAVE_TERMIOS_H - tcsetattr(0, TCSADRAIN, &tio); -#else -# ifdef HAVE_TERMIO_H - ioctl (0, TCSETAW, &tio); -# else - ioctl (0, TIOCSETN, (char *) &tio); -# endif -#endif - } - - if ((fdi = open (tmpfil, O_RDONLY)) == NOTOK) - adios (tmpfil, "unable to re-open"); - if ((fdo = creat (drft, m_gmprot ())) == NOTOK) - adios (drft, "unable to write"); - cpydata (fdi, fdo, tmpfil, drft); - close (fdi); - close (fdo); - unlink (tmpfil); - - context_save (); /* save the context file */ - done (0); - return 1; + + if (qbody) + printf("--------\n"); + + fflush(stdout); + fclose(in); + fclose(out); + SIGNAL(SIGINT, SIG_IGN); + + if ((fdi = open(tmpfil, O_RDONLY)) == NOTOK) + adios(tmpfil, "unable to re-open"); + if ((fdo = creat(drft, m_gmprot())) == NOTOK) + adios(drft, "unable to write"); + cpydata(fdi, fdo, tmpfil, drft); + close(fdi); + close(fdo); + unlink(tmpfil); + + context_save(); /* save the context file */ + done(0); + return 1; } int -getln (char *buffer, int n) +getln(char *buffer, int n) { - int c; - char *cp; - - cp = buffer; - *cp = 0; - - switch (setjmp (sigenv)) { - case OK: - wtuser = 1; - break; - - case DONE: - wtuser = 0; - return 0; - - default: - wtuser = 0; - return NOTOK; - } - - for (;;) { - switch (c = getchar ()) { - case EOF: - clearerr (stdin); - longjmp (sigenv, DONE); - - case '\n': - if (cp[-1] == QUOTE) { - cp[-1] = c; - wtuser = 0; - return 1; - } - *cp++ = c; - *cp = 0; - wtuser = 0; - return 0; - - default: - if (cp < buffer + n) - *cp++ = c; - *cp = 0; - } - } -} + int c; + char *cp; + cp = buffer; + *cp = '\0'; -static RETSIGTYPE -intrser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGINT, intrser); -#endif + switch (setjmp(sigenv)) { + case OK: + wtuser = 1; + break; - if (wtuser) - longjmp (sigenv, NOTOK); - sigint++; -} + case DONE: + wtuser = 0; + return 0; + default: + wtuser = 0; + return NOTOK; + } -static int -chrcnv (char *cp) -{ - return (*cp != QUOTE ? *cp : m_atoi (++cp)); + for (;;) { + switch (c = getchar()) { + case EOF: + clearerr(stdin); + longjmp(sigenv, DONE); + + case '\n': + if (cp[-1] == '\\') { + cp[-1] = c; + wtuser = 0; + return 1; + } + *cp++ = c; + *cp = '\0'; + wtuser = 0; + return 0; + + default: + if (cp < buffer + n) + *cp++ = c; + *cp = '\0'; + } + } } static void -chrdsp (char *s, char c) +intrser(int i) { - printf ("%s ", s); - if (c < ' ' || c == 0177) - printf ("^%c", c ^ 0100); - else - printf ("%c", c); + if (wtuser) + longjmp(sigenv, NOTOK); + sigint++; } diff --git a/uip/rcvdist.c b/uip/rcvdist.c index 9038d5f..2ba6097 100644 --- a/uip/rcvdist.c +++ b/uip/rcvdist.c @@ -1,27 +1,25 @@ - /* - * rcvdist.c -- asynchronously redistribute messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** rcvdist.c -- asynchronously redistribute messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include -#include #include static struct swit switches[] = { -#define FORMSW 0 - { "form formfile", 4 }, -#define VERSIONSW 1 - { "version", 0 }, -#define HELPSW 2 - { "help", 0 }, - { NULL, 0 } +#define FORMSW 0 + { "form formfile", 0 }, +#define VERSIONSW 1 + { "Version", 0 }, +#define HELPSW 2 + { "help", 0 }, + { NULL, 0 } }; static char backup[BUFSIZ] = ""; @@ -29,116 +27,100 @@ static char drft[BUFSIZ] = ""; static char tmpfil[BUFSIZ] = ""; /* - * prototypes - */ -static void rcvdistout (FILE *, char *, char *); -static void unlink_done (int) NORETURN; +** prototypes +*/ +static void rcvdistout(FILE *, char *, char *); +static void unlink_done(int) NORETURN; int -main (int argc, char **argv) +main(int argc, char **argv) { - pid_t child_id; - int i, vecp = 1; - char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ]; - char **argp, **arguments, *vec[MAXARGS]; - FILE *fp; - char *tfile = NULL; - - done=unlink_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - vec[vecp++] = --cp; - continue; - - case HELPSW: - snprintf (buf, sizeof(buf), - "%s [switches] [switches for postproc] address ...", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - } + int vecp = 1; + char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ]; + char **argp, **arguments, *vec[MAXARGS]; + FILE *fp; + char *tfile = NULL; + + done=unlink_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + vec[vecp++] = --cp; + continue; + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] [switches for spost] address ...", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') { + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + } + } + addrs = addrs ? add(cp, add(", ", addrs)) : getcpy(cp); } - addrs = addrs ? add (cp, add (", ", addrs)) : getcpy (cp); - } - - if (addrs == NULL) - adios (NULL, "usage: %s [switches] [switches for postproc] address ...", - invo_name); - umask (~m_gmprot ()); - - tfile = m_mktemp2(NULL, invo_name, NULL, &fp); - if (tfile == NULL) adios("rcvdist", "unable to create temporary file"); - strncpy (tmpfil, tfile, sizeof(tmpfil)); + if (!addrs) { + adios(NULL, "usage: %s [switches] [switches for spost] address ...", invo_name); + } - cpydata (fileno (stdin), fileno (fp), "message", tmpfil); - fseek (fp, 0L, SEEK_SET); + umask(~m_gmprot()); - tfile = m_mktemp2(NULL, invo_name, NULL, NULL); - if (tfile == NULL) adios("forw", "unable to create temporary file"); - strncpy (drft, tfile, sizeof(tmpfil)); + tfile = m_mktemp2(NULL, invo_name, NULL, &fp); + if (tfile == NULL) adios("rcvdist", "unable to create temporary file"); + strncpy(tmpfil, tfile, sizeof(tmpfil)); - rcvdistout (fp, form, addrs); - fclose (fp); + cpydata(fileno(stdin), fileno(fp), "message", tmpfil); + fseek(fp, 0L, SEEK_SET); - if (distout (drft, tmpfil, backup) == NOTOK) - done (1); + tfile = m_mktemp2(NULL, invo_name, NULL, NULL); + if (tfile == NULL) adios("forw", "unable to create temporary file"); + strncpy(drft, tfile, sizeof(tmpfil)); - vec[0] = r1bindex (postproc, '/'); - vec[vecp++] = "-dist"; - vec[vecp++] = drft; - vec[vecp] = NULL; + rcvdistout(fp, form, addrs); + fclose(fp); - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - admonish (NULL, "unable to fork");/* fall */ - case OK: - execvp (postproc, vec); - fprintf (stderr, "unable to exec "); - perror (postproc); - _exit (1); + if (distout(drft, tmpfil, backup) == NOTOK) { + done(1); + } - default: - done (pidXwait(child_id, postproc)); - } + vec[0] = "spost"; + vec[vecp++] = "-dist"; + vec[vecp++] = drft; + vec[vecp] = NULL; - return 0; /* dead code to satisfy the compiler */ + execvp(*vec, vec); + fprintf(stderr, "unable to exec "); + perror(*vec); + _exit(1); + return 0; /* dead code to satisfy the compiler */ } /* very similar to routine in replsbr.c */ -#define SBUFSIZ 256 - -static int outputlinelen = OUTPUTLINELEN; +#define SBUFSIZ 256 static struct format *fmt; @@ -149,141 +131,160 @@ static struct comp **used_buf = 0; static int dat[5]; static char *addrcomps[] = { - "from", - "sender", - "reply-to", - "to", - "cc", - "bcc", - "resent-from", - "resent-sender", - "resent-reply-to", - "resent-to", - "resent-cc", - "resent-bcc", - NULL + "from", + "sender", + "reply-to", + "to", + "cc", + "bcc", + "resent-from", + "resent-sender", + "resent-reply-to", + "resent-to", + "resent-cc", + "resent-bcc", + NULL }; static void -rcvdistout (FILE *inb, char *form, char *addrs) +rcvdistout(FILE *inb, char *form, char *addrs) { - register int char_read = 0, format_len, i, state; - register char *tmpbuf, **nxtbuf, **ap; - char *cp, *scanl, name[NAMESZ]; - register struct comp *cptr, **savecomp; - FILE *out; - - if (!(out = fopen (drft, "w"))) - adios (drft, "unable to create"); - - /* get new format string */ - cp = new_fs (form ? form : rcvdistcomps, NULL, NULL); - format_len = strlen (cp); - ncomps = fmt_compile (cp, &fmt) + 1; - if (!(nxtbuf = compbuffers = (char **) calloc ((size_t) ncomps, sizeof(char *)))) - adios (NULL, "unable to allocate component buffers"); - if (!(savecomp = used_buf = (struct comp **) calloc ((size_t) (ncomps + 1), sizeof(struct comp *)))) - adios (NULL, "unable to allocate component buffer stack"); - savecomp += ncomps + 1; - *--savecomp = 0; - - for (i = ncomps; i--;) - *nxtbuf++ = mh_xmalloc (SBUFSIZ); - nxtbuf = compbuffers; - tmpbuf = *nxtbuf++; - - for (ap = addrcomps; *ap; ap++) { - FINDCOMP (cptr, *ap); - if (cptr) - cptr->c_type |= CT_ADDR; - } - - FINDCOMP (cptr, "addresses"); - if (cptr) - cptr->c_text = addrs; - - for (state = FLD;;) { - switch (state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) { - case FLD: - case FLDPLUS: - if ((cptr = wantcomp[CHASH (name)])) - do { - if (!mh_strcasecmp (name, cptr->c_name)) { - char_read += msg_count; - if (!cptr->c_text) { - cptr->c_text = tmpbuf; - *--savecomp = cptr; - tmpbuf = *nxtbuf++; - } - else { - i = strlen (cp = cptr->c_text) - 1; - if (cp[i] == '\n') { - if (cptr->c_type & CT_ADDR) { - cp[i] = 0; - cp = add (",\n\t", cp); - } - else - cp = add ("\t", cp); - } - cptr->c_text = add (tmpbuf, cp); - } - while (state == FLDPLUS) { - state = m_getfld (state, name, tmpbuf, - SBUFSIZ, inb); - cptr->c_text = add (tmpbuf, cptr->c_text); - char_read += msg_count; - } - break; + register int char_read = 0, format_len, i, state; + register char *tmpbuf, **nxtbuf, **ap; + char *cp, *scanl, name[NAMESZ]; + register struct comp *cptr, **savecomp; + FILE *out; + + if (!(out = fopen(drft, "w"))) { + adios(drft, "unable to create"); + } + + /* get new format string */ + cp = new_fs(form ? form : rcvdistcomps, NULL); + format_len = strlen(cp); + ncomps = fmt_compile(cp, &fmt) + 1; + if (!(nxtbuf = compbuffers = + (char **) calloc((size_t) ncomps, sizeof(char *)))) { + adios(NULL, "unable to allocate component buffers"); + } + if (!(savecomp = used_buf = + (struct comp **) calloc((size_t) (ncomps + 1), + sizeof(struct comp *)))) { + adios(NULL, "unable to allocate component buffer stack"); + } + savecomp += ncomps + 1; + *--savecomp = 0; + + for (i = ncomps; i--;) { + *nxtbuf++ = mh_xmalloc(SBUFSIZ); + } + nxtbuf = compbuffers; + tmpbuf = *nxtbuf++; + + for (ap = addrcomps; *ap; ap++) { + FINDCOMP(cptr, *ap); + if (cptr) { + cptr->c_type |= CT_ADDR; + } + } + + FINDCOMP(cptr, "addresses"); + if (cptr) { + cptr->c_text = addrs; + } + state = FLD; + while (1) { + state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb); + switch (state) { + case FLD: + case FLDPLUS: + if ((cptr = wantcomp[CHASH(name)])) { + do { + if (mh_strcasecmp(name, cptr->c_name)!=0) { + continue; + } + char_read += msg_count; + if (!cptr->c_text) { + cptr->c_text = tmpbuf; + *--savecomp = cptr; + tmpbuf = *nxtbuf++; + } else { + cp = cptr->c_text; + i = strlen(cp) - 1; + if (cp[i] == '\n') { + if (cptr->c_type & CT_ADDR) { + cp[i] = 0; + cp = add(",\n\t", cp); + } else { + cp = add("\t", cp); + } + } + cptr->c_text = add(tmpbuf, cp); + } + while (state == FLDPLUS) { + state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb); + cptr->c_text = add(tmpbuf, cptr->c_text); + char_read += msg_count; + } + break; + } while ((cptr = cptr->c_next)); } - } while ((cptr = cptr->c_next)); - while (state == FLDPLUS) - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); - break; + while (state == FLDPLUS) { + state = m_getfld(state, name, tmpbuf, + SBUFSIZ, inb); + } + break; - case LENERR: - case FMTERR: - case BODY: - case FILEEOF: - goto finished; + case LENERR: + case FMTERR: + case BODY: + case FILEEOF: + goto finished; - default: - adios (NULL, "m_getfld() returned %d", state); + default: + adios(NULL, "m_getfld() returned %d", state); + } } - } finished: ; - i = format_len + char_read + 256; - scanl = mh_xmalloc ((size_t) i + 2); - dat[0] = dat[1] = dat[2] = dat[4] = 0; - dat[3] = outputlinelen; - fmt_scan (fmt, scanl, i, dat); - fputs (scanl, out); - - if (ferror (out)) - adios (drft, "error writing"); - fclose (out); - - free (scanl); - for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++); nxtbuf++, i--) - free (cptr->c_text); - while (i-- > 0) - free (*nxtbuf++); - free ((char *) compbuffers); - free ((char *) used_buf); + i = format_len + char_read + 256; + scanl = mh_xmalloc((size_t) i + 2); + dat[0] = dat[1] = dat[2] = dat[4] = 0; + dat[3] = OUTPUTLINELEN; + fmt_scan(fmt, scanl, i, dat); + fputs(scanl, out); + + if (ferror(out)) { + adios(drft, "error writing"); + } + fclose(out); + + free(scanl); + for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++); + nxtbuf++, i--) { + free(cptr->c_text); + } + while (i-- > 0) { + free(*nxtbuf++); + } + free(compbuffers); + free(used_buf); } static void -unlink_done (int status) +unlink_done(int status) { - if (backup[0]) - unlink (backup); - if (drft[0]) - unlink (drft); - if (tmpfil[0]) - unlink (tmpfil); - - exit (status ? RCV_MBX : RCV_MOK); + if (*backup) { + unlink(backup); + } + if (*drft) { + unlink(drft); + } + if (*tmpfil) { + unlink(tmpfil); + } + exit(status ? RCV_MBX : RCV_MOK); } diff --git a/uip/rcvpack.c b/uip/rcvpack.c index 0b4dc9f..79c3450 100644 --- a/uip/rcvpack.c +++ b/uip/rcvpack.c @@ -1,106 +1,92 @@ - /* - * rcvpack.c -- append message to a file - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** rcvpack.c -- append message to a file +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include -#include static struct swit switches[] = { -#define MBOXSW 0 - { "mbox", 0 }, -#define MMDFSW 1 - { "mmdf", 0 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, 0 } +#define VERSIONSW 0 + { "Version", 0 }, +#define HELPSW 1 + { "help", 0 }, + { NULL, 0 } }; -/* - * default format in which to save messages - */ -static int mbx_style = MBOX_FORMAT; - int -main (int argc, char **argv) +main(int argc, char **argv) { - int md; - char *cp, *file = NULL, buf[BUFSIZ]; - char **argp, **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* parse arguments */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case MBOXSW: - mbx_style = MBOX_FORMAT; - continue; - case MMDFSW: - mbx_style = MMDF_FORMAT; - continue; - } + int md; + char *cp, *file = NULL, buf[BUFSIZ]; + char **argp, **arguments; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* parse arguments */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [switches] file", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + } + } + if (file) + adios(NULL, "only one file at a time!"); + else + file = cp; } - if (file) - adios (NULL, "only one file at a time!"); - else - file = cp; - } - if (!file) - adios (NULL, "%s [switches] file", invo_name); - - rewind (stdin); + /* copy stdin to stdout, converting rfc822 message to mbox */ + if (!file) { + if (mbox_copy(fileno(stdout), fileno(stdin)) == NOTOK) { + done(RCV_MBX); + } + done(RCV_MOK); + return 1; + } - /* open and lock the file */ - if ((md = mbx_open (file, mbx_style, getuid(), getgid(), m_gmprot())) == NOTOK) - done (RCV_MBX); + /* open and lock the file */ + if ((md = mbox_open(file, getuid(), getgid(), m_gmprot())) + == NOTOK) + done(RCV_MBX); - /* append the message */ - if (mbx_copy (file, mbx_style, md, fileno(stdin), 1, NULL, 0) == NOTOK) { - mbx_close (file, md); - done (RCV_MBX); - } + /* append the message */ + if (mbox_copy(md, fileno(stdin)) == NOTOK) { + mbox_close(file, md); + done(RCV_MBX); + } - /* close and unlock the file */ - if (mbx_close (file, md) == NOTOK) - done (RCV_MBX); + /* close and unlock the file */ + if (mbox_close(file, md) == NOTOK) + done(RCV_MBX); - done (RCV_MOK); - return 1; + done(RCV_MOK); + return 1; } diff --git a/uip/rcvstore.c b/uip/rcvstore.c index 3131076..bb14ed9 100644 --- a/uip/rcvstore.c +++ b/uip/rcvstore.c @@ -1,240 +1,236 @@ - /* - * rcvstore.c -- asynchronously add mail to a folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** rcvstore.c -- asynchronously add mail to a folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include #include -#include static struct swit switches[] = { -#define CRETSW 0 - { "create", 0 }, -#define NCRETSW 1 - { "nocreate", 0 }, -#define UNSEENSW 2 - { "unseen", 0 }, -#define NUNSEENSW 3 - { "nounseen", 0 }, -#define PUBSW 4 - { "public", 0 }, -#define NPUBSW 5 - { "nopublic", 0 }, -#define ZEROSW 6 - { "zero", 0 }, -#define NZEROSW 7 - { "nozero", 0 }, -#define SEQSW 8 - { "sequence name", 0 }, -#define VERSIONSW 9 - { "version", 0 }, -#define HELPSW 10 - { "help", 0 }, - { NULL, 0 } +#define CRETSW 0 + { "create", 0 }, +#define NCRETSW 1 + { "nocreate", 2 }, +#define UNSEENSW 2 + { "unseen", 0 }, +#define NUNSEENSW 3 + { "nounseen", 2 }, +#define PUBSW 4 + { "public", 0 }, +#define NPUBSW 5 + { "nopublic", 2 }, +#define ZEROSW 6 + { "zero", 0 }, +#define NZEROSW 7 + { "nozero", 2 }, +#define SEQSW 8 + { "sequence name", 0 }, +#define VERSIONSW 9 + { "Version", 0 }, +#define HELPSW 10 + { "help", 0 }, + { NULL, 0 } }; /* - * name of temporary file to store incoming message - */ +** name of temporary file to store incoming message +*/ static char *tmpfilenam = NULL; static void unlink_done(int) NORETURN; int -main (int argc, char **argv) +main(int argc, char **argv) { - int publicsw = -1, zerosw = 0; - int create = 1, unseensw = 1; - int fd, msgnum, seqp = 0; - char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments, *seqs[NUMATTRS+1]; - struct msgs *mp; - struct stat st; - - done=unlink_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* parse arguments */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case SEQSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument name to %s", argp[-2]); - - /* check if too many sequences specified */ - if (seqp >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) specified", NUMATTRS); - seqs[seqp++] = cp; - continue; - - case UNSEENSW: - unseensw = 1; - continue; - case NUNSEENSW: - unseensw = 0; - continue; - - case PUBSW: - publicsw = 1; - continue; - case NPUBSW: - publicsw = 0; - continue; - - case ZEROSW: - zerosw++; - continue; - case NZEROSW: - zerosw = 0; - continue; - - case CRETSW: - create++; - continue; - case NCRETSW: - create = 0; - continue; - } + int publicsw = -1, zerosw = 0; + int create = 1, unseensw = 1; + int fd, msgnum; + size_t seqp = 0; + char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; + char **argp, **arguments, *seqs[NUMATTRS+1]; + struct msgs *mp; + struct stat st; + + done=unlink_done; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* parse arguments */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [+folder] [switches]", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case SEQSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument name to %s", argp[-2]); + + /* check if too many sequences specified */ + if (seqp >= NUMATTRS) + adios(NULL, "too many sequences (more than %d) specified", NUMATTRS); + seqs[seqp++] = cp; + continue; + + case UNSEENSW: + unseensw = 1; + continue; + case NUNSEENSW: + unseensw = 0; + continue; + + case PUBSW: + publicsw = 1; + continue; + case NPUBSW: + publicsw = 0; + continue; + + case ZEROSW: + zerosw++; + continue; + case NZEROSW: + zerosw = 0; + continue; + + case CRETSW: + create++; + continue; + case NCRETSW: + create = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + adios(NULL, "usage: %s [+folder] [switches]", + invo_name); + } + } + + seqs[seqp] = NULL; /* NULL terminate list of sequences */ + + /* if no folder is given, use default folder */ + if (!folder) + folder = getdeffol(); + maildir = toabsdir(folder); + + /* check if folder exists */ + if (stat(maildir, &st) == NOTOK) { + if (errno != ENOENT) + adios(maildir, "error on folder"); + if (!create) + adios(NULL, "folder %s doesn't exist", maildir); + if (!makedir(maildir)) + adios(NULL, "unable to create folder %s", maildir); } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - adios (NULL, "usage: %s [+folder] [switches]", invo_name); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* ignore a few signals */ + SIGNAL(SIGHUP, SIG_IGN); + SIGNAL(SIGINT, SIG_IGN); + SIGNAL(SIGQUIT, SIG_IGN); + SIGNAL(SIGTERM, SIG_IGN); + + /* create a temporary file */ + tmpfilenam = m_mktemp(invo_name, &fd, NULL); + if (tmpfilenam == NULL) { + adios("rcvstore", "unable to create temporary file"); } - } - - seqs[seqp] = NULL; /* NULL terminate list of sequences */ - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* if no folder is given, use default folder */ - if (!folder) - folder = getfolder (0); - maildir = m_maildir (folder); - - /* check if folder exists */ - if (stat (maildir, &st) == NOTOK) { - if (errno != ENOENT) - adios (maildir, "error on folder"); - if (!create) - adios (NULL, "folder %s doesn't exist", maildir); - if (!makedir (maildir)) - adios (NULL, "unable to create folder %s", maildir); - } - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* ignore a few signals */ - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); - - /* create a temporary file */ - tmpfilenam = m_mktemp (invo_name, &fd, NULL); - if (tmpfilenam == NULL) { - adios ("rcvstore", "unable to create temporary file"); - } - chmod (tmpfilenam, m_gmprot()); - - /* copy the message from stdin into temp file */ - cpydata (fileno (stdin), fd, "standard input", tmpfilenam); - - if (fstat (fd, &st) == NOTOK) { - unlink (tmpfilenam); - adios (tmpfilenam, "unable to fstat"); - } - if (close (fd) == NOTOK) - adios (tmpfilenam, "error closing"); - - /* don't add file if it is empty */ - if (st.st_size == 0) { - unlink (tmpfilenam); - advise (NULL, "empty file"); - done (0); - } - - /* - * read folder and create message structure - */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* - * Link message into folder, and possibly add - * to the Unseen-Sequence's. - */ - if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0, 0, (char *)0)) == -1) - done (1); - - /* - * Add the message to any extra sequences - * that have been specified. - */ - for (seqp = 0; seqs[seqp]; seqp++) { - if (!seq_addmsg (mp, seqs[seqp], msgnum, publicsw, zerosw)) - done (1); - } - - seq_setunseen (mp, 0); /* synchronize any Unseen-Sequence's */ - seq_save (mp); /* synchronize and save message sequences */ - folder_free (mp); /* free folder/message structure */ - - context_save (); /* save the global context file */ - unlink (tmpfilenam); /* remove temporary file */ - tmpfilenam = NULL; - - done (0); - return 1; + chmod(tmpfilenam, m_gmprot()); + + /* copy the message from stdin into temp file */ + cpydata(fileno(stdin), fd, "standard input", tmpfilenam); + + if (fstat(fd, &st) == NOTOK) { + unlink(tmpfilenam); + adios(tmpfilenam, "unable to fstat"); + } + if (close(fd) == NOTOK) + adios(tmpfilenam, "error closing"); + + /* don't add file if it is empty */ + if (st.st_size == 0) { + unlink(tmpfilenam); + advise(NULL, "empty file"); + done(0); + } + + /* + ** read folder and create message structure + */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* + ** Link message into folder, and possibly add + ** to the Unseen-Sequence's. + */ + if ((msgnum = folder_addmsg(&mp, tmpfilenam, 0, unseensw, 0, 0, NULL)) + == -1) + done(1); + + /* + ** Add the message to any extra sequences + ** that have been specified. + */ + for (seqp = 0; seqs[seqp]; seqp++) { + if (!seq_addmsg(mp, seqs[seqp], msgnum, publicsw, zerosw)) + done(1); + } + + seq_setunseen(mp, 1); /* add new msgs to unseen sequences */ + seq_save(mp); /* synchronize and save message sequences */ + folder_free(mp); /* free folder/message structure */ + + context_save(); /* save the global context file */ + unlink(tmpfilenam); /* remove temporary file */ + tmpfilenam = NULL; + + done(0); + return 1; } /* - * Clean up and exit - */ +** Clean up and exit +*/ static void unlink_done(int status) { - if (tmpfilenam && *tmpfilenam) - unlink (tmpfilenam); - exit (status); + if (tmpfilenam && *tmpfilenam) + unlink(tmpfilenam); + exit(status); } diff --git a/uip/rcvtty.c b/uip/rcvtty.c deleted file mode 100644 index 8b04d61..0000000 --- a/uip/rcvtty.c +++ /dev/null @@ -1,347 +0,0 @@ - -/* - * rcvtty.c -- a rcvmail program (a lot like rcvalert) handling IPC ttys - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* Changed to use getutent() and friends. Assumes that when getutent() exists, - * a number of other things also exist. Please check. - * Ruud de Rooij Sun, 28 May 2000 17:28:55 +0200 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef HAVE_GETUTENT -# ifndef UTMP_FILE -# ifdef _PATH_UTMP -# define UTMP_FILE _PATH_UTMP -# else -# define UTMP_FILE "/etc/utmp" -# endif -# endif -#endif - -#define SCANFMT \ -"%2(hour{dtimenow}):%02(min{dtimenow}): %<(size)%5(size) %>%<{encrypted}E%>\ -%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>%<(zero)%17(friendly{from})%> \ -%{subject}%<{body}<<%{body}>>%>" - -static struct swit switches[] = { -#define BIFFSW 0 - { "biff", 0 }, -#define FORMSW 1 - { "form formatfile", 0 }, -#define FMTSW 2 - { "format string", 5 }, -#define WIDTHSW 3 - { "width columns", 0 }, -#define NLSW 4 - { "newline", 0 }, -#define NNLSW 5 - { "nonewline", 0 }, -#define BELSW 6 - { "bell", 0 }, -#define NBELSW 7 - { "nobell", 0 }, -#define VERSIONSW 8 - { "version", 0 }, -#define HELPSW 9 - { "help", 0 }, - { NULL, 0 } -}; - -static jmp_buf myctx; -static int bell = 1; -static int newline = 1; -static int biff = 0; -static int width = 0; -static char *form = NULL; -static char *format = NULL; - -/* - * external prototypes - */ -char *getusername(void); - -/* - * static prototypes - */ -static RETSIGTYPE alrmser (int); -static int message_fd (char **); -static int header_fd (void); -static void alert (char *, int); - - -int -main (int argc, char **argv) -{ - int md, vecp = 0; - char *cp, *user, buf[BUFSIZ], tty[BUFSIZ]; - char **argp, **arguments, *vec[MAXARGS]; -#ifdef HAVE_GETUTENT - struct utmp * utp; -#else - struct utmp ut; - register FILE *uf; -#endif - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - vec[vecp++] = --cp; - continue; - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [command ...]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case BIFFSW: - biff = 1; - continue; - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios(NULL, "missing argument to %s", argp[-2]); - width = atoi(cp); - continue; - case NLSW: - newline = 1; - continue; - case NNLSW: - newline = 0; - continue; - case BELSW: - bell = 1; - continue; - case NBELSW: - bell = 0; - continue; - - } - } - vec[vecp++] = cp; - } - vec[vecp] = 0; - - if ((md = vecp ? message_fd (vec) : header_fd ()) == NOTOK) - exit (RCV_MBX); - - user = getusername(); - -#ifdef HAVE_GETUTENT - setutent(); - while ((utp = getutent()) != NULL) { - if ( -#ifdef HAVE_STRUCT_UTMP_UT_TYPE - utp->ut_type == USER_PROCESS - && -#endif - utp->ut_name[0] != 0 - && utp->ut_line[0] != 0 - && strncmp (user, utp->ut_name, sizeof(utp->ut_name)) == 0) { - strncpy (tty, utp->ut_line, sizeof(utp->ut_line)); - alert (tty, md); - } - } - endutent(); -#else - if ((uf = fopen (UTMP_FILE, "r")) == NULL) - exit (RCV_MBX); - while (fread ((char *) &ut, sizeof(ut), 1, uf) == 1) - if (ut.ut_name[0] != 0 - && strncmp (user, ut.ut_name, sizeof(ut.ut_name)) == 0) { - strncpy (tty, ut.ut_line, sizeof(ut.ut_line)); - alert (tty, md); - } - fclose (uf); -#endif - - exit (RCV_MOK); - return 0; /* dead code to satisfy the compiler */ -} - - -static RETSIGTYPE -alrmser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGALRM, alrmser); -#endif - - longjmp (myctx, 1); -} - - -static int -message_fd (char **vec) -{ - pid_t child_id; - int bytes, fd, seconds; - char tmpfil[BUFSIZ]; - struct stat st; - -#ifdef HAVE_MKSTEMP - fd = mkstemp (strncpy (tmpfil, "/tmp/rcvttyXXXXX", sizeof(tmpfil))); -#else - unlink (mktemp (strncpy (tmpfil, "/tmp/rcvttyXXXXX", sizeof(tmpfil)))); - if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK) - return header_fd (); -#endif - unlink (tmpfil); - - if ((child_id = vfork()) == NOTOK) { - /* fork error */ - close (fd); - return header_fd (); - } else if (child_id) { - /* parent process */ - if (!setjmp (myctx)) { - SIGNAL (SIGALRM, alrmser); - bytes = fstat(fileno (stdin), &st) != NOTOK ? (int) st.st_size : 100; - - /* amount of time to wait depends on message size */ - if (bytes <= 100) { - /* give at least 5 minutes */ - seconds = 300; - } else if (bytes >= 90000) { - /* but 30 minutes should be long enough */ - seconds = 1800; - } else { - seconds = (bytes / 60) + 300; - } - alarm ((unsigned int) seconds); - pidwait(child_id, OK); - alarm (0); - - if (fstat (fd, &st) != NOTOK && st.st_size > (off_t) 0) - return fd; - } else { - /* - * Ruthlessly kill the child and anything - * else in its process group. - */ - KILLPG(child_id, SIGKILL); - } - close (fd); - return header_fd (); - } - - /* child process */ - rewind (stdin); - if (dup2 (fd, 1) == NOTOK || dup2 (fd, 2) == NOTOK) - _exit (-1); - closefds (3); - setpgid ((pid_t) 0, getpid ()); /* put in own process group */ - execvp (vec[0], vec); - _exit (-1); - return 1; /* dead code to satisfy compiler */ -} - - -static int -header_fd (void) -{ - int fd; - char *nfs; - char *tfile = NULL; - - tfile = m_mktemp2(NULL, invo_name, &fd, NULL); - if (tfile == NULL) return NOTOK; - unlink (tfile); - - rewind (stdin); - - /* get new format string */ - nfs = new_fs (form, format, SCANFMT); - scan (stdin, 0, 0, nfs, width, 0, 0, NULL, 0L, 0); - if (newline) - write (fd, "\n\r", 2); - write (fd, scanl, strlen (scanl)); - if (bell) - write (fd, "\007", 1); - - return fd; -} - - -static void -alert (char *tty, int md) -{ - int i, td, mask; - char buffer[BUFSIZ], ttyspec[BUFSIZ]; - struct stat st; - - snprintf (ttyspec, sizeof(ttyspec), "/dev/%s", tty); - - /* - * The mask depends on whether we are checking for - * write permission based on `biff' or `mesg'. - */ - mask = biff ? S_IEXEC : (S_IWRITE >> 3); - if (stat (ttyspec, &st) == NOTOK || (st.st_mode & mask) == 0) - return; - - if (!setjmp (myctx)) { - SIGNAL (SIGALRM, alrmser); - alarm (2); - td = open (ttyspec, O_WRONLY); - alarm (0); - if (td == NOTOK) - return; - } else { - alarm (0); - return; - } - - lseek (md, (off_t) 0, SEEK_SET); - - while ((i = read (md, buffer, sizeof(buffer))) > 0) - if (write (td, buffer, i) != i) - break; - - close (td); -} - diff --git a/uip/refile.c b/uip/refile.c index 25f7629..b07c32d 100644 --- a/uip/refile.c +++ b/uip/refile.c @@ -1,12 +1,11 @@ - /* - * refile.c -- move or link message(s) from a source folder - * -- into one or more destination folders - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** refile.c -- move or link message(s) from a source folder +** -- into one or more destination folders +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -14,357 +13,268 @@ #include static struct swit switches[] = { -#define DRAFTSW 0 - { "draft", 0 }, -#define LINKSW 1 - { "link", 0 }, -#define NLINKSW 2 - { "nolink", 0 }, -#define PRESSW 3 - { "preserve", 0 }, -#define NPRESSW 4 - { "nopreserve", 0 }, -#define UNLINKSW 5 - { "unlink", 0 }, -#define NUNLINKSW 6 - { "nounlink", 0 }, -#define SRCSW 7 - { "src +folder", 0 }, -#define FILESW 8 - { "file file", 0 }, -#define RPROCSW 9 - { "rmmproc program", 0 }, -#define NRPRCSW 10 - { "normmproc", 0 }, -#define VERSIONSW 11 - { "version", 0 }, -#define HELPSW 12 - { "help", 0 }, - { NULL, 0 } +#define LINKSW 0 + { "link", 0 }, +#define NLINKSW 1 + { "nolink", 2 }, +#define SRCSW 2 + { "src +folder", 0 }, +#define FILESW 3 + { "file file", 0 }, +#define VERSIONSW 4 + { "Version", 0 }, +#define HELPSW 5 + { "help", 0 }, + { NULL, 0 } }; static char maildir[BUFSIZ]; struct st_fold { - char *f_name; - struct msgs *f_mp; + char *f_name; + struct msgs *f_mp; }; /* - * static prototypes - */ -static void opnfolds (struct st_fold *, int); -static void clsfolds (struct st_fold *, int); -static void remove_files (int, char **); -static int m_file (char *, struct st_fold *, int, int, int); +** static prototypes +*/ +static void opnfolds(struct st_fold *, int); +static void clsfolds(struct st_fold *, int); +static int m_file(char *, struct st_fold *, int, int); int -main (int argc, char **argv) +main(int argc, char **argv) { - int linkf = 0, preserve = 0, filep = 0; - int foldp = 0, isdf = 0, unlink_msgs = 0; - int i, msgnum; - char *cp, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments; - char *filevec[NFOLDERS + 2]; - char **files = &filevec[1]; /* leave room for remove_files:vec[0] */ - struct st_fold folders[NFOLDERS + 1]; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [msgs] [switches] +folder ...", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case LINKSW: - linkf++; - continue; - case NLINKSW: - linkf = 0; - continue; - - case PRESSW: - preserve++; - continue; - case NPRESSW: - preserve = 0; - continue; - - case UNLINKSW: - unlink_msgs++; - continue; - case NUNLINKSW: - unlink_msgs = 0; - continue; - - case SRCSW: - if (folder) - adios (NULL, "only one source folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - folder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DRAFTSW: - if (filep > NFOLDERS) - adios (NULL, "only %d files allowed!", NFOLDERS); - isdf = 0; - files[filep++] = getcpy (m_draft (NULL, NULL, 1, &isdf)); - continue; - case FILESW: - if (filep > NFOLDERS) - adios (NULL, "only %d files allowed!", NFOLDERS); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - files[filep++] = path (cp, TFILE); - continue; - - case RPROCSW: - if (!(rmmproc = *argp++) || *rmmproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NRPRCSW: - rmmproc = NULL; - continue; - } + int linkf = 0, filep = 0; + int foldp = 0; + int i, msgnum; + char *cp, *folder = NULL, buf[BUFSIZ]; + char **argp, **arguments; + char *filevec[NFOLDERS + 1]; + char **files = filevec; + struct st_fold folders[NFOLDERS + 1]; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [msgs] [switches] +folder ...", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case LINKSW: + linkf++; + continue; + case NLINKSW: + linkf = 0; + continue; + + case SRCSW: + if (folder) + adios(NULL, "only one source folder at a time!"); + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + folder = getcpy(expandfol(cp)); + continue; + case FILESW: + if (filep > NFOLDERS) + adios(NULL, "only %d files allowed!", + NFOLDERS); + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + files[filep++] = getcpy(expanddir(cp)); + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (foldp > NFOLDERS) + adios(NULL, "only %d folders allowed!", + NFOLDERS); + folders[foldp++].f_name = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + + if (foldp == 0) + adios(NULL, "no folder specified"); + + /* + ** We are refiling a file to the folders + */ + if (filep > 0) { + if (folder || msgs.size) + adios(NULL, "use -file or msgs, not both"); + opnfolds(folders, foldp); + for (i = 0; i < filep; i++) + if (m_file(files[i], folders, foldp, 0)) + done(1); + /* If -nolink, then unlink files */ + if (!linkf) { + int i; + char **files = filevec; + + /* just unlink the files */ + for (i = 0; i < filep; i++) { + if (unlink(files[i]) == NOTOK) + admonish(files[i], "unable to unlink"); + } + } + done(0); + } + + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + strncpy(maildir, toabsdir(folder), sizeof(maildir)); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read source folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse the message range/sequence/name and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + /* create folder structures for each destination folder */ + opnfolds(folders, foldp); + + /* Link all the selected messages into destination folders. + ** + ** This causes the add hook to be run for messages that are + ** linked into another folder. The refile hook is run for + ** messages that are moved to another folder. + */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + cp = getcpy(m_name(msgnum)); + if (m_file(cp, folders, foldp, !linkf)) + done(1); + free(cp); + } + } + + /* + ** If -nolink, then remove (= unlink) messages from source folder. + ** + ** Note that folder_delmsgs does not call the delete hook + ** because the message has already been handled above. + */ + if (!linkf) { + folder_delmsgs(mp, 0); } - if (*cp == '+' || *cp == '@') { - if (foldp > NFOLDERS) - adios (NULL, "only %d folders allowed!", NFOLDERS); - folders[foldp++].f_name = - pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (foldp == 0) - adios (NULL, "no folder specified"); - -#ifdef WHATNOW - if (!msgs.size && !foldp && !filep && (cp = getenv ("mhdraft")) && *cp) - files[filep++] = cp; -#endif /* WHATNOW */ - - /* - * We are refiling a file to the folders - */ - if (filep > 0) { - if (folder || msgs.size) - adios (NULL, "use -file or some messages, not both"); - opnfolds (folders, foldp); - for (i = 0; i < filep; i++) - if (m_file (files[i], folders, foldp, preserve, 0)) - done (1); - /* If -nolink, then "remove" files */ - if (!linkf) - remove_files (filep, filevec); - done (0); - } - - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - strncpy (maildir, m_maildir (folder), sizeof(maildir)); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read source folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse the message range/sequence/name and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - /* create folder structures for each destination folder */ - opnfolds (folders, foldp); - - /* Link all the selected messages into destination folders. - * - * This causes the add hook to be run for messages that are - * linked into another folder. The refile hook is run for - * messages that are moved to another folder. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - cp = getcpy (m_name (msgnum)); - if (m_file (cp, folders, foldp, preserve, !linkf)) - done (1); - free (cp); + + clsfolds(folders, foldp); + + if (linkf) { + seq_setcur(mp, mp->hghsel); } - } - - /* - * This is a hack. If we are using an external rmmproc, - * then save the current folder to the context file, - * so the external rmmproc will remove files from the correct - * directory. This should be moved to folder_delmsgs(). - */ - if (rmmproc) { - context_replace (pfolder, folder); - context_save (); - fflush (stdout); - } - - /* If -nolink, then "remove" messages from source folder. - * - * Note that folder_delmsgs does not call the delete hook - * because the message has already been handled above. - */ - if (!linkf) { - folder_delmsgs (mp, unlink_msgs, 1); - } - - clsfolds (folders, foldp); - - if (mp->hghsel != mp->curmsg - && (mp->numsel != mp->nummsg || linkf)) - seq_setcur (mp, mp->hghsel); - seq_save (mp); /* synchronize message sequences */ - - context_replace (pfolder, folder); /* update current folder */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder structure */ - done (0); - return 1; + seq_save(mp); /* synchronize message sequences */ + + context_replace(curfolder, folder); + context_save(); + folder_free(mp); + done(0); + return 1; } /* - * Read all the destination folders and - * create folder structures for all of them. - */ - +** Read all the destination folders and +** create folder structures for all of them. +*/ static void -opnfolds (struct st_fold *folders, int nfolders) +opnfolds(struct st_fold *folders, int nfolders) { - char nmaildir[BUFSIZ]; - register struct st_fold *fp, *ep; - register struct msgs *mp; + char nmaildir[BUFSIZ]; + register struct st_fold *fp, *ep; + register struct msgs *mp; - for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { - chdir (m_maildir ("")); - strncpy (nmaildir, m_maildir (fp->f_name), sizeof(nmaildir)); + for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { + chdir(toabsdir("+")); + strncpy(nmaildir, toabsdir(fp->f_name), sizeof(nmaildir)); - create_folder (nmaildir, 0, done); + create_folder(nmaildir, 0, done); - if (chdir (nmaildir) == NOTOK) - adios (nmaildir, "unable to change directory to"); - if (!(mp = folder_read (fp->f_name))) - adios (NULL, "unable to read folder %s", fp->f_name); - mp->curmsg = 0; + if (chdir(nmaildir) == NOTOK) + adios(nmaildir, "unable to change directory to"); + if (!(mp = folder_read(fp->f_name))) + adios(NULL, "unable to read folder %s", fp->f_name); + mp->curmsg = 0; - fp->f_mp = mp; + fp->f_mp = mp; - chdir (maildir); - } + chdir(maildir); + } } /* - * Set the Previous-Sequence and then sychronize the - * sequence file, for each destination folder. - */ - +** Set the Previous-Sequence and then sychronize the +** sequence file, for each destination folder. +*/ static void -clsfolds (struct st_fold *folders, int nfolders) +clsfolds(struct st_fold *folders, int nfolders) { - register struct st_fold *fp, *ep; - register struct msgs *mp; - - for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { - mp = fp->f_mp; - seq_setprev (mp); - seq_save (mp); - } -} - + register struct st_fold *fp, *ep; + register struct msgs *mp; -/* - * If you have a "rmmproc" defined, we called that - * to remove all the specified files. If "rmmproc" - * is not defined, then just unlink the files. - */ - -static void -remove_files (int filep, char **files) -{ - int i; - char **vec; - - /* If rmmproc is defined, we use that */ - if (rmmproc) { - vec = files++; /* vec[0] = filevec[0] */ - files[filep] = NULL; /* NULL terminate list */ - - fflush (stdout); - vec[0] = r1bindex (rmmproc, '/'); - execvp (rmmproc, vec); - adios (rmmproc, "unable to exec"); - } - - /* Else just unlink the files */ - files++; /* advance past filevec[0] */ - for (i = 0; i < filep; i++) { - if (unlink (files[i]) == NOTOK) - admonish (files[i], "unable to unlink"); - } + for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { + mp = fp->f_mp; + seq_setprev(mp); + seq_save(mp); + } } /* - * Link (or copy) the message into each of - * the destination folders. - */ - +** Link (or copy) the message into each of +** the destination folders. +*/ static int -m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve, int refile) +m_file(char *msgfile, struct st_fold *folders, int nfolders, int refile) { - int msgnum; - struct st_fold *fp, *ep; - - for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { - if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0, preserve, nfolders == 1 && refile, maildir)) == -1) - return 1; - } - return 0; + int msgnum; + struct st_fold *fp, *ep; + + for (fp = folders, ep = folders + nfolders; fp < ep; fp++) { + if ((msgnum = folder_addmsg(&fp->f_mp, msgfile, 1, 0, + 0, nfolders == 1 && refile, maildir)) == -1) + return 1; + } + return 0; } diff --git a/uip/repl.c b/uip/repl.c index d2b75df..9c9e5ce 100644 --- a/uip/repl.c +++ b/uip/repl.c @@ -1,473 +1,778 @@ - /* - * repl.c -- reply to a message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** repl.c -- reply to a message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include +#include +#include +#include /* L_SET */ +#include static struct swit switches[] = { -#define GROUPSW 0 - { "group", 0 }, -#define NGROUPSW 1 - { "nogroup", 0 }, -#define ANNOSW 2 - { "annotate", 0 }, -#define NANNOSW 3 - { "noannotate", 0 }, -#define CCSW 4 - { "cc all|to|cc|me", 0 }, -#define NCCSW 5 - { "nocc type", 0 }, -#define DFOLDSW 6 - { "draftfolder +folder", 0 }, -#define DMSGSW 7 - { "draftmessage msg", 0 }, -#define NDFLDSW 8 - { "nodraftfolder", 0 }, -#define EDITRSW 9 - { "editor editor", 0 }, -#define NEDITSW 10 - { "noedit", 0 }, -#define FCCSW 11 - { "fcc folder", 0 }, -#define FILTSW 12 - { "filter filterfile", 0 }, -#define FORMSW 13 - { "form formfile", 0 }, -#define FRMTSW 14 - { "format", 5 }, -#define NFRMTSW 15 - { "noformat", 7 }, -#define INPLSW 16 - { "inplace", 0 }, -#define NINPLSW 17 - { "noinplace", 0 }, -#define MIMESW 18 - { "mime", 0 }, -#define NMIMESW 19 - { "nomime", 0 }, -#define QURYSW 20 - { "query", 0 }, -#define NQURYSW 21 - { "noquery", 0 }, -#define WHATSW 22 - { "whatnowproc program", 0 }, -#define NWHATSW 23 - { "nowhatnowproc", 0 }, -#define WIDTHSW 24 - { "width columns", 0 }, -#define VERSIONSW 25 - { "version", 0 }, -#define HELPSW 26 - { "help", 0 }, -#define FILESW 27 - { "file file", 4 }, /* interface from msh */ - -#ifdef MHE -#define BILDSW 28 - { "build", 5 }, /* interface from mhe */ -#endif - - { NULL, 0 } +#define GROUPSW 0 + { "group", 0 }, +#define NGROUPSW 1 + { "nogroup", 2 }, +#define ANNOSW 2 + { "annotate", 0 }, +#define NANNOSW 3 + { "noannotate", 2 }, +#define CCSW 4 + { "cc all|to|cc|me", 0 }, +#define NCCSW 5 + { "nocc type", 2 }, +#define EDITRSW 6 + { "editor editor", 0 }, +#define FILTSW 7 + { "filter filterfile", 0 }, +#define NFILTSW 8 + { "nofilter", 2 }, +#define FORMSW 9 + { "form formfile", 0 }, +#define MIMESW 10 + { "mime", 0 }, +#define NMIMESW 11 + { "nomime", 2 }, +#define QURYSW 12 + { "query", 0 }, +#define NQURYSW 13 + { "noquery", 2 }, +#define WHATSW 14 + { "whatnowproc program", 0 }, +#define VERSIONSW 15 + { "Version", 0 }, +#define HELPSW 16 + { "help", 0 }, +#define FILESW 17 + { "file file", 4 }, /* interface from msh */ +#define BILDSW 18 + { "build", 5 }, /* interface from mhe */ + { NULL, 0 } }; static struct swit ccswitches[] = { -#define CTOSW 0 - { "to", 0 }, -#define CCCSW 1 - { "cc", 0 }, -#define CMESW 2 - { "me", 0 }, -#define CALSW 3 - { "all", 0 }, - { NULL, 0 } +#define CTOSW 0 + { "to", 0 }, +#define CCCSW 1 + { "cc", 0 }, +#define CMESW 2 + { "me", 0 }, +#define CALSW 3 + { "all", 0 }, + { NULL, 0 } }; -static struct swit aqrnl[] = { -#define NOSW 0 - { "quit", 0 }, -#define YESW 1 - { "replace", 0 }, -#define LISTDSW 2 - { "list", 0 }, -#define REFILSW 3 - { "refile +folder", 0 }, -#define NEWSW 4 - { "new", 0 }, - { NULL, 0 } +/* +** Buffer size for content part of header fields. +** We want this to be large enough so that we don't +** do a lot of extra FLDPLUS calls on m_getfld but +** small enough so that we don't snarf the entire +** message body when we're not going to use any of it. +*/ +#define SBUFSIZ 256 + +static short ccto = -1; +static short cccc = -1; +static short ccme = -1; +static short querysw = 0; + +static short groupreply = 0; /* Is this a group reply? */ + +static int mime = 0; /* include original as MIME part */ +static char *form = NULL; /* form (components) file */ +static char *filter = NULL; /* message filter file */ + +static int dftype=0; + +static char *badaddrs = NULL; +static char *dfhost = NULL; + +static struct mailname mq; + +static struct format *fmt; + +static int ncomps = 0; /* # of interesting components */ +static char **compbuffers = NULL; /* buffers for component text */ +static struct comp **used_buf = NULL; /* stack for comp that use buffers */ + +static int dat[5]; /* aux. data for format routine */ + +static char *addrcomps[] = { + "from", + "sender", + "reply-to", + "to", + "cc", + "bcc", + "resent-from", + "resent-sender", + "resent-reply-to", + "resent-to", + "resent-cc", + "resent-bcc", + NULL }; -static struct swit aqrl[] = { - { "quit", 0 }, - { "replace", 0 }, - { "list", 0 }, - { "refile +folder", 0 }, - { NULL, 0 } -}; +/* +** static prototypes +*/ +static void docc(char *, int); +static int insert(struct mailname *); +static void replfilter(FILE *, FILE *, char *); +static void replout(FILE *, char *, struct msgs *, int, + char *, char *); -short ccto = -1; /* global for replsbr */ -short cccc = -1; -short ccme = -1; -short querysw = 0; -short outputlinelen = OUTPUTLINELEN; -short groupreply = 0; /* Is this a group reply? */ +int +main(int argc, char **argv) +{ + int anot = 0; + char *cp, *cwd, *maildir, *file = NULL; + char *folder = NULL, *msg = NULL; + char *ed = NULL, drft[BUFSIZ], buf[BUFSIZ]; + char **argp, **arguments; + struct msgs *mp = NULL; + FILE *in; + int buildsw = 0; + + filter = getcpy(etcpath(mhlreply)); + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s: [+folder] [msg] [switches]", invo_name); + print_help(buf, switches, 1); + done(0); + case VERSIONSW: + print_version(invo_name); + done(1); + + case GROUPSW: + groupreply++; + continue; + case NGROUPSW: + groupreply = 0; + continue; + + case ANNOSW: + anot++; + continue; + case NANNOSW: + anot = 0; + continue; + + case CCSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + docc(cp, 1); + continue; + case NCCSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + docc(cp, 0); + continue; + + case EDITRSW: + if (!(ed = *argp++) || *ed == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WHATSW: + if (!(whatnowproc = *argp++) || + *whatnowproc == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case BILDSW: + buildsw++; + continue; + + case FILESW: + if (file) + adios(NULL, "only one file at a time!"); + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + file = getcpy(expanddir(cp)); + continue; + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case FILTSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + filter = getcpy(etcpath(cp)); + continue; + case NFILTSW: + filter = NULL; + continue; + + case MIMESW: + mime++; + continue; + case NMIMESW: + mime = 0; + continue; + + case QURYSW: + querysw++; + continue; + case NQURYSW: + querysw = 0; + continue; + + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + if (msg) + adios(NULL, "only one message at a time!"); + else + msg = cp; + } + } -int mime = 0; /* include original as MIME part */ -char *form = NULL; /* form (components) file */ -char *filter = NULL; /* message filter file */ -char *fcc = NULL; /* folders to add to Fcc: header */ + if (ccto == -1) + ccto = groupreply; + if (cccc == -1) + cccc = groupreply; + if (ccme == -1) + ccme = groupreply; + cwd = getcpy(pwd()); -/* - * prototypes - */ -void docc (char *, int); + if (file && (msg || folder)) + adios(NULL, "can't mix files and folders/msgs"); + + strncpy(drft, buildsw ? toabsdir("reply") : m_draft(seq_beyond), + sizeof(drft)); + /* + ** FIXME: (concerning MHE support (buildsw) only) + ** There's no check if the draft already exists. mmh has removed + ** this case by having the draft folder. I won't add code only to + ** handle this legacy issue for MHE. -- meillo@marmaro.de 2012-05 + */ + + if (file) { + /* + ** We are replying to a file. + */ + anot = 0; /* we don't want to annotate a file */ + } else { + /* + ** We are replying to a message. + */ + if (!msg) + msg = seq_cur; + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse the message range/sequence/name and set SELECTED */ + if (!m_convert(mp, msg)) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + if (mp->numsel > 1) + adios(NULL, "only one message at a time!"); + + context_replace(curfolder, folder); /* update current folder */ + seq_setcur(mp, mp->lowsel); /* update current message */ + seq_save(mp); /* synchronize sequences */ + context_save(); /* save the context file */ + } + msg = file ? file : getcpy(m_name(mp->lowsel)); -int -main (int argc, char **argv) + if ((in = fopen(msg, "r")) == NULL) + adios(msg, "unable to open"); + + /* find form (components) file */ + if (!form) { + if (groupreply) + form = etcpath(replgroupcomps); + else + form = etcpath(replcomps); + } + + replout(in, drft, mp, mime, form, filter); + fclose(in); + + if (buildsw) + done(0); + what_now(ed, NOUSE, drft, msg, 0, mp, anot ? "Replied" : NULL, cwd); + done(1); + return 1; +} + +static void +docc(char *cp, int ccflag) { - int i, isdf = 0; - int anot = 0, inplace = 1; - int nedit = 0, nwhat = 0; - char *cp, *cwd, *dp, *maildir, *file = NULL; - char *folder = NULL, *msg = NULL, *dfolder = NULL; - char *dmsg = NULL, *ed = NULL, drft[BUFSIZ], buf[BUFSIZ]; - char **argp, **arguments; - struct msgs *mp = NULL; - struct stat st; - FILE *in; - -#ifdef MHE - int buildsw = 0; -#endif /* MHE */ - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s: [+folder] [msg] [switches]", - invo_name); - print_help (buf, switches, 1); - done (0); - case VERSIONSW: - print_version(invo_name); - done (1); - - case GROUPSW: - groupreply++; - continue; - case NGROUPSW: - groupreply = 0; - continue; - - case ANNOSW: - anot++; - continue; - case NANNOSW: - anot = 0; - continue; - - case CCSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - docc (cp, 1); - continue; - case NCCSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - docc (cp, 0); - continue; - - case EDITRSW: - if (!(ed = *argp++) || *ed == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nedit = 0; - continue; - case NEDITSW: - nedit++; - continue; - - case WHATSW: - if (!(whatnowproc = *argp++) || *whatnowproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nwhat = 0; - continue; -#ifdef MHE - case BILDSW: - buildsw++; /* fall... */ -#endif /* MHE */ - case NWHATSW: - nwhat++; - continue; - - case FCCSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dp = NULL; - if (*cp == '@') - cp = dp = path (cp + 1, TSUBCWF); - if (fcc) - fcc = add (", ", fcc); - fcc = add (cp, fcc); - if (dp) - free (dp); - continue; - - case FILESW: - if (file) - adios (NULL, "only one file at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - file = path (cp, TFILE); - continue; - case FILTSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - filter = getcpy (etcpath (cp)); - mime = 0; - continue; - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case FRMTSW: - filter = getcpy (etcpath (mhlreply)); - mime = 0; - continue; - case NFRMTSW: - filter = NULL; - continue; - - case INPLSW: - inplace++; - continue; - case NINPLSW: - inplace = 0; - continue; - - case MIMESW: - mime++; - filter = NULL; - continue; - case NMIMESW: - mime = 0; - continue; - - case QURYSW: - querysw++; - continue; - case NQURYSW: - querysw = 0; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((outputlinelen = atoi (cp)) < 10) - adios (NULL, "impossible width %d", outputlinelen); - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - } + switch (smatch(cp, ccswitches)) { + case AMBIGSW: + ambigsw(cp, ccswitches); + done(1); + case UNKWNSW: + adios(NULL, "-%scc %s unknown", ccflag ? "" : "no", cp); + + case CTOSW: + ccto = ccflag; + break; + + case CCCSW: + cccc = ccflag; + break; + + case CMESW: + ccme = ccflag; + break; + + case CALSW: + ccto = cccc = ccme = ccflag; + break; } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - if (msg) - adios (NULL, "only one message at a time!"); - else - msg = cp; +} + + + + +static void +replout(FILE *inb, char *drft, struct msgs *mp, + int mime, char *form, char *filter) +{ + register int state, i; + register struct comp *cptr; + register char *tmpbuf; + register char **nxtbuf; + register char **ap; + register struct comp **savecomp; + int char_read = 0, format_len, mask; + char name[NAMESZ], *scanl; + unsigned char *cp; + FILE *out; + + mask = umask(~m_gmprot()); + if ((out = fopen(drft, "w")) == NULL) + adios(drft, "unable to create"); + + umask(mask); + + /* get new format string */ + cp = new_fs(form, NULL); + format_len = strlen(cp); + + /* compile format string */ + ncomps = fmt_compile(cp, &fmt) + 1; + + if (!(nxtbuf = compbuffers = (char **) + calloc((size_t) ncomps, sizeof(char *)))) + adios(NULL, "unable to allocate component buffers"); + if (!(savecomp = used_buf = (struct comp **) + calloc((size_t) (ncomps+1), sizeof(struct comp *)))) + adios(NULL, "unable to allocate component buffer stack"); + savecomp += ncomps + 1; + *--savecomp = NULL; /* point at zero'd end minus 1 */ + + for (i = ncomps; i--; ) + *nxtbuf++ = mh_xmalloc(SBUFSIZ); + + nxtbuf = compbuffers; /* point at start */ + tmpbuf = *nxtbuf++; + + for (ap = addrcomps; *ap; ap++) { + FINDCOMP(cptr, *ap); + if (cptr) + cptr->c_type |= CT_ADDR; + } + + /* + ** ignore any components killed by command line switches + */ + if (!ccto) { + FINDCOMP(cptr, "to"); + if (cptr) + cptr->c_name = ""; + } + if (!cccc) { + FINDCOMP(cptr, "cc"); + if (cptr) + cptr->c_name = ""; } - } - - if (ccto == -1) - ccto = groupreply; - if (cccc == -1) - cccc = groupreply; - if (ccme == -1) - ccme = groupreply; - - cwd = getcpy (pwd ()); - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (file && (msg || folder)) - adios (NULL, "can't mix files and folders/msgs"); - -try_it_again: - -#ifdef MHE - strncpy (drft, buildsw ? m_maildir ("reply") - : m_draft (dfolder, NULL, NOUSE, &isdf), sizeof(drft)); - - /* Check if a draft exists */ - if (!buildsw && stat (drft, &st) != NOTOK) { -#else - strncpy (drft, m_draft (dfolder, dmsg, NOUSE, &isdf), sizeof(drft)); - - /* Check if a draft exists */ - if (stat (drft, &st) != NOTOK) { -#endif /* MHE */ - printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size); - for (i = LISTDSW; i != YESW;) { - if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl))) - done (1); - switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) { - case NOSW: - done (0); - case NEWSW: - dmsg = NULL; - goto try_it_again; - case YESW: - break; - case LISTDSW: - showfile (++argp, drft); - break; - case REFILSW: - if (refile (++argp, drft) == 0) - i = YESW; - break; - default: - advise (NULL, "say what?"); - break; - } + if ((cp = getenv("USER"))) { + FINDCOMP(cptr, "user"); + if (cptr) + cptr->c_text = getcpy(cp); } - } + if (!ccme) + ismymbox(NULL); - if (file) { /* - * We are replying to a file. - */ - anot = 0; /* we don't want to annotate a file */ - } else { + ** pick any interesting stuff out of msg "inb" + */ + for (state = FLD;;) { + state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb); + switch (state) { + case FLD: + case FLDPLUS: + /* + ** if we're interested in this component, save + ** a pointer to the component text, then start + ** using our next free buffer as the component + ** temp buffer (buffer switching saves an extra + ** copy of the component text). + */ + if ((cptr = wantcomp[CHASH(name)])) + do { + if (!mh_strcasecmp(name, cptr->c_name)) { + char_read += msg_count; + if (! cptr->c_text) { + i = strlen(cptr->c_text = tmpbuf) - 1; + if (tmpbuf[i] == '\n') + tmpbuf[i] = '\0'; + *--savecomp = cptr; + tmpbuf = *nxtbuf++; + } else { + i = strlen(cp = cptr->c_text) - 1; + if (cp[i] == '\n') { + if (cptr->c_type & CT_ADDR) { + cp[i] = '\0'; + cp = add(",\n\t", cp); + } else { + cp = add("\t", cp); + } + } + cptr->c_text = add(tmpbuf, cp); + } + while (state == FLDPLUS) { + state = m_getfld(state, name, tmpbuf, + SBUFSIZ, inb); + cptr->c_text = add(tmpbuf, cptr->c_text); + char_read += msg_count; + } + break; + } + } while ((cptr = cptr->c_next)); + + while (state == FLDPLUS) + state = m_getfld(state, name, tmpbuf, + SBUFSIZ, inb); + break; + + case LENERR: + case FMTERR: + case BODY: + case FILEEOF: + goto finished; + + default: + adios(NULL, "m_getfld() returned %d", state); + } + } + + /* + ** format and output the header lines. + */ +finished: + + /* + ** if there's a "Subject" component, strip any "Re:"s off it + */ + FINDCOMP(cptr, "subject") + if (cptr && (cp = cptr->c_text)) { + register char *sp = cp; + + for (;;) { + while (isspace(*cp)) + cp++; + if(uprf(cp, "re:")) + cp += 3; + else + break; + sp = cp; + } + if (sp != cptr->c_text) { + cp = cptr->c_text; + cptr->c_text = getcpy(sp); + free(cp); + } + } + i = format_len + char_read + 256; + scanl = mh_xmalloc((size_t) i + 2); + dat[0] = 0; + dat[1] = 0; + dat[2] = 0; + dat[3] = OUTPUTLINELEN; + dat[4] = 0; + fmt_scan(fmt, scanl, i, dat); + fputs(scanl, out); + if (badaddrs) { + fputs("\nrepl: bad addresses:\n", out); + fputs( badaddrs, out); + } + + /* Check if we should filter the message */ + if (filter) { + fflush(out); + if (ferror(out)) + adios(drft, "error writing"); + + replfilter(inb, out, filter); + } + + fflush(out); + if (ferror(out)) + adios(drft, "error writing"); + fclose(out); + + if (mime && mp) { + /* add an attachment header */ + char buffer[BUFSIZ]; + + snprintf(buffer, sizeof buffer, "anno -append -nodate '%s' " + "-comp '%s' -text '+%s %s'", + drft, + attach_hdr, mp->foldpath, m_name(mp->lowsel)); + if (system(buffer) != 0) { + advise(NULL, "unable to add attachment header"); + } + } + + /* return dynamically allocated buffers */ + free(scanl); + for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++); + nxtbuf++, i--) + free(cptr->c_text); /* if not nxtbuf, nxtbuf already freed */ + while ( i-- > 0) + free(*nxtbuf++); /* free unused nxtbufs */ + free((char *) compbuffers); + free((char *) used_buf); +} + +static char *buf; /* our current working buffer */ +static char *bufend; /* end of working buffer */ +static char *last_dst; /* buf ptr at end of last call */ +static unsigned int bufsiz=0; /* current size of buf */ + +#define BUFINCR 512 /* how much to expand buf when if fills */ + +#define CPY(s) { cp = (s); while ((*dst++ = *cp++)) ; --dst; } + +/* +** check if there's enough room in buf for str. +** add more mem if needed +*/ +#define CHECKMEM(str) \ + if ((len = strlen(str)) >= bufend - dst) {\ + int i = dst - buf;\ + int n = last_dst - buf;\ + bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\ + buf = mh_xrealloc(buf, bufsiz);\ + dst = buf + i;\ + last_dst = buf + n;\ + bufend = buf + bufsiz;\ + } + + +/* +** fmt_scan will call this routine if the user includes the function +** "(formataddr {component})" in a format string. "orig" is the +** original contents of the string register. "str" is the address +** string to be formatted and concatenated onto orig. This routine +** returns a pointer to the concatenated address string. +** +** We try to not do a lot of malloc/copy/free's (which is why we +** don't call "getcpy") but still place no upper limit on the +** length of the result string. +** +** This routine is an override for the equally named one in sbr/fmt_addr.c. +** Don't delete it! +*/ +char * +formataddr(char *orig, char *str) +{ + register int len; + char baddr[BUFSIZ], error[BUFSIZ]; + register int isgroup; + register char *dst; + register char *cp; + register char *sp; + register struct mailname *mp = NULL; + + /* if we don't have a buffer yet, get one */ + if (bufsiz == 0) { + buf = mh_xmalloc(BUFINCR); + last_dst = buf; /* XXX */ + bufsiz = BUFINCR - 6; /* leave some slop */ + bufend = buf + bufsiz; + } /* - * We are replying to a message. - */ - if (!msg) - msg = "cur"; - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse the message range/sequence/name and set SELECTED */ - if (!m_convert (mp, msg)) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - if (mp->numsel > 1) - adios (NULL, "only one message at a time!"); - - context_replace (pfolder, folder); /* update current folder */ - seq_setcur (mp, mp->lowsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_save (); /* save the context file */ - } - - msg = file ? file : getcpy (m_name (mp->lowsel)); - - if ((in = fopen (msg, "r")) == NULL) - adios (msg, "unable to open"); - - /* find form (components) file */ - if (!form) { - if (groupreply) - form = etcpath (replgroupcomps); - else - form = etcpath (replcomps); - } - - replout (in, msg, drft, mp, outputlinelen, mime, form, filter, fcc); - fclose (in); - - if (nwhat) - done (0); - what_now (ed, nedit, NOUSE, drft, msg, 0, mp, - anot ? "Replied" : NULL, inplace, cwd); - done (1); - return 1; + ** If "orig" points to our buffer we can just pick up where we + ** left off. Otherwise we have to copy orig into our buffer. + */ + if (orig == buf) + dst = last_dst; + else if (!orig || !*orig) { + dst = buf; + *dst = '\0'; + } else { + dst = last_dst; /* XXX */ + CHECKMEM(orig); + CPY(orig); + } + + /* concatenate all the new addresses onto 'buf' */ + for (isgroup = 0; (cp = getname(str)); ) { + if ((mp = getm(cp, dfhost, dftype, AD_NAME, error)) == NULL) { + snprintf(baddr, sizeof(baddr), "\t%s -- %s\n", + cp, error); + badaddrs = add(baddr, badaddrs); + continue; + } + if (isgroup && (mp->m_gname || !mp->m_ingrp)) { + *dst++ = ';'; + isgroup = 0; + } + if (insert(mp)) { + /* if we get here we're going to add an address */ + if (dst != buf) { + *dst++ = ','; + *dst++ = ' '; + } + if (mp->m_gname) { + CHECKMEM(mp->m_gname); + CPY(mp->m_gname); + isgroup++; + } + sp = adrformat(mp); + CHECKMEM(sp); + CPY(sp); + } + } + + if (isgroup) + *dst++ = ';'; + + *dst = '\0'; + last_dst = dst; + return (buf); +} + + +static int +insert(struct mailname *np) +{ + char buffer[BUFSIZ]; + register struct mailname *mp; + + if (np->m_mbox == NULL) + return 0; + + for (mp = &mq; mp->m_next; mp = mp->m_next) { + if (!mh_strcasecmp(np->m_host, mp->m_next->m_host) && + !mh_strcasecmp(np->m_mbox, mp->m_next->m_mbox)) + return 0; + } + if (!ccme && ismymbox(np)) + return 0; + + if (querysw) { + snprintf(buffer, sizeof(buffer), "Reply to %s? ", + adrformat(np)); + if (!gans(buffer, anoyes)) + return 0; + } + mp->m_next = np; + return 1; } -void -docc (char *cp, int ccflag) + +/* +** Call mhl +** +** This function expects that argument out has been fflushed by the caller. +*/ +static void +replfilter(FILE *in, FILE *out, char *filter) { - switch (smatch (cp, ccswitches)) { - case AMBIGSW: - ambigsw (cp, ccswitches); - done (1); - case UNKWNSW: - adios (NULL, "-%scc %s unknown", ccflag ? "" : "no", cp); - - case CTOSW: - ccto = ccflag; - break; - - case CCCSW: - cccc = ccflag; - break; - - case CMESW: - ccme = ccflag; - break; - - case CALSW: - ccto = cccc = ccme = ccflag; - break; - } + int pid, n; + char *errstr; + + if (filter == NULL) + return; + + if (access(filter, R_OK) == NOTOK) + adios(filter, "unable to read"); + + rewind(in); + lseek(fileno(in), (off_t) 0, SEEK_SET); + + switch (pid = fork()) { + case NOTOK: + adios("fork", "unable to"); + + case OK: + dup2(fileno(in), fileno(stdin)); + dup2(fileno(out), fileno(stdout)); + for (n=3; n -#include -#include -#include -#include /* L_SET */ -#include - -extern short ccto; /* from repl.c */ -extern short cccc; -extern short ccme; -extern short querysw; - -static int dftype=0; - -static char *badaddrs = NULL; -static char *dfhost = NULL; - -static struct mailname mq = { NULL }; - -/* - * Buffer size for content part of header fields. - * We want this to be large enough so that we don't - * do a lot of extra FLDPLUS calls on m_getfld but - * small enough so that we don't snarf the entire - * message body when we're not going to use any of it. - */ -#define SBUFSIZ 256 - -static struct format *fmt; - -static int ncomps = 0; /* # of interesting components */ -static char **compbuffers = NULL; /* buffers for component text */ -static struct comp **used_buf = NULL; /* stack for comp that use buffers */ - -static int dat[5]; /* aux. data for format routine */ - -static char *addrcomps[] = { - "from", - "sender", - "reply-to", - "to", - "cc", - "bcc", - "resent-from", - "resent-sender", - "resent-reply-to", - "resent-to", - "resent-cc", - "resent-bcc", - NULL -}; - -/* - * static prototypes - */ -static int insert (struct mailname *); -static void replfilter (FILE *, FILE *, char *); - - -void -replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, - int mime, char *form, char *filter, char *fcc) -{ - register int state, i; - register struct comp *cptr; - register char *tmpbuf; - register char **nxtbuf; - register char **ap; - register struct comp **savecomp; - int char_read = 0, format_len, mask; - char name[NAMESZ], *scanl; - unsigned char *cp; - FILE *out; - - mask = umask(~m_gmprot()); - if ((out = fopen (drft, "w")) == NULL) - adios (drft, "unable to create"); - - umask(mask); - - /* get new format string */ - cp = new_fs (form, NULL, NULL); - format_len = strlen (cp); - - /* compile format string */ - ncomps = fmt_compile (cp, &fmt) + 1; - - if (!(nxtbuf = compbuffers = (char **) - calloc((size_t) ncomps, sizeof(char *)))) - adios (NULL, "unable to allocate component buffers"); - if (!(savecomp = used_buf = (struct comp **) - calloc((size_t) (ncomps+1), sizeof(struct comp *)))) - adios (NULL, "unable to allocate component buffer stack"); - savecomp += ncomps + 1; - *--savecomp = NULL; /* point at zero'd end minus 1 */ - - for (i = ncomps; i--; ) - *nxtbuf++ = mh_xmalloc(SBUFSIZ); - - nxtbuf = compbuffers; /* point at start */ - tmpbuf = *nxtbuf++; - - for (ap = addrcomps; *ap; ap++) { - FINDCOMP (cptr, *ap); - if (cptr) - cptr->c_type |= CT_ADDR; - } - - /* - * ignore any components killed by command line switches - */ - if (!ccto) { - FINDCOMP (cptr, "to"); - if (cptr) - cptr->c_name = ""; - } - if (!cccc) { - FINDCOMP (cptr, "cc"); - if (cptr) - cptr->c_name = ""; - } - /* set up the "fcc" pseudo-component */ - if (fcc) { - FINDCOMP (cptr, "fcc"); - if (cptr) - cptr->c_text = getcpy (fcc); - } - if ((cp = getenv("USER"))) { - FINDCOMP (cptr, "user"); - if (cptr) - cptr->c_text = getcpy(cp); - } - if (!ccme) - ismymbox (NULL); - - /* - * pick any interesting stuff out of msg "inb" - */ - for (state = FLD;;) { - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); - switch (state) { - case FLD: - case FLDPLUS: - /* - * if we're interested in this component, save a pointer - * to the component text, then start using our next free - * buffer as the component temp buffer (buffer switching - * saves an extra copy of the component text). - */ - if ((cptr = wantcomp[CHASH(name)])) - do { - if (!mh_strcasecmp(name, cptr->c_name)) { - char_read += msg_count; - if (! cptr->c_text) { - i = strlen(cptr->c_text = tmpbuf) - 1; - if (tmpbuf[i] == '\n') - tmpbuf[i] = '\0'; - *--savecomp = cptr; - tmpbuf = *nxtbuf++; - } else { - i = strlen (cp = cptr->c_text) - 1; - if (cp[i] == '\n') { - if (cptr->c_type & CT_ADDR) { - cp[i] = '\0'; - cp = add (",\n\t", cp); - } else { - cp = add ("\t", cp); - } - } - cptr->c_text = add (tmpbuf, cp); - } - while (state == FLDPLUS) { - state = m_getfld (state, name, tmpbuf, - SBUFSIZ, inb); - cptr->c_text = add (tmpbuf, cptr->c_text); - char_read += msg_count; - } - break; - } - } while ((cptr = cptr->c_next)); - - while (state == FLDPLUS) - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); - break; - - case LENERR: - case FMTERR: - case BODY: - case FILEEOF: - goto finished; - - default: - adios (NULL, "m_getfld() returned %d", state); - } - } - - /* - * format and output the header lines. - */ -finished: - - /* - * if there's a "Subject" component, strip any "Re:"s off it - */ - FINDCOMP (cptr, "subject") - if (cptr && (cp = cptr->c_text)) { - register char *sp = cp; - - for (;;) { - while (isspace(*cp)) - cp++; - if(uprf(cp, "re:")) - cp += 3; - else - break; - sp = cp; - } - if (sp != cptr->c_text) { - cp = cptr->c_text; - cptr->c_text = getcpy (sp); - free (cp); - } - } - i = format_len + char_read + 256; - scanl = mh_xmalloc ((size_t) i + 2); - dat[0] = 0; - dat[1] = 0; - dat[2] = 0; - dat[3] = outputlinelen; - dat[4] = 0; - fmt_scan (fmt, scanl, i, dat); - fputs (scanl, out); - if (badaddrs) { - fputs ("\nrepl: bad addresses:\n", out); - fputs ( badaddrs, out); - } - - /* - * Check if we should filter the message - * or add mhn directives - */ - if (filter) { - fflush(out); - if (ferror (out)) - adios (drft, "error writing"); - - replfilter (inb, out, filter); - } else if (mime && mp) { - fprintf (out, "#forw [original message] +%s %s\n", - mp->foldpath, m_name (mp->lowsel)); - } - - fflush(out); - if (ferror (out)) - adios (drft, "error writing"); - fclose (out); - - /* return dynamically allocated buffers */ - free (scanl); - for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++); nxtbuf++, i--) - free (cptr->c_text); /* if not nxtbuf, nxtbuf already freed */ - while ( i-- > 0) - free (*nxtbuf++); /* free unused nxtbufs */ - free ((char *) compbuffers); - free ((char *) used_buf); -} - -static char *buf; /* our current working buffer */ -static char *bufend; /* end of working buffer */ -static char *last_dst; /* buf ptr at end of last call */ -static unsigned int bufsiz=0; /* current size of buf */ - -#define BUFINCR 512 /* how much to expand buf when if fills */ - -#define CPY(s) { cp = (s); while ((*dst++ = *cp++)) ; --dst; } - -/* - * check if there's enough room in buf for str. - * add more mem if needed - */ -#define CHECKMEM(str) \ - if ((len = strlen (str)) >= bufend - dst) {\ - int i = dst - buf;\ - int n = last_dst - buf;\ - bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\ - buf = mh_xrealloc (buf, bufsiz);\ - dst = buf + i;\ - last_dst = buf + n;\ - bufend = buf + bufsiz;\ - } - - -/* - * fmt_scan will call this routine if the user includes the function - * "(formataddr {component})" in a format string. "orig" is the - * original contents of the string register. "str" is the address - * string to be formatted and concatenated onto orig. This routine - * returns a pointer to the concatenated address string. - * - * We try to not do a lot of malloc/copy/free's (which is why we - * don't call "getcpy") but still place no upper limit on the - * length of the result string. - */ -char * -formataddr (char *orig, char *str) -{ - register int len; - char baddr[BUFSIZ], error[BUFSIZ]; - register int isgroup; - register char *dst; - register char *cp; - register char *sp; - register struct mailname *mp = NULL; - - /* if we don't have a buffer yet, get one */ - if (bufsiz == 0) { - buf = mh_xmalloc (BUFINCR); - last_dst = buf; /* XXX */ - bufsiz = BUFINCR - 6; /* leave some slop */ - bufend = buf + bufsiz; - } - /* - * If "orig" points to our buffer we can just pick up where we - * left off. Otherwise we have to copy orig into our buffer. - */ - if (orig == buf) - dst = last_dst; - else if (!orig || !*orig) { - dst = buf; - *dst = '\0'; - } else { - dst = last_dst; /* XXX */ - CHECKMEM (orig); - CPY (orig); - } - - /* concatenate all the new addresses onto 'buf' */ - for (isgroup = 0; (cp = getname (str)); ) { - if ((mp = getm (cp, dfhost, dftype, AD_NAME, error)) == NULL) { - snprintf (baddr, sizeof(baddr), "\t%s -- %s\n", cp, error); - badaddrs = add (baddr, badaddrs); - continue; - } - if (isgroup && (mp->m_gname || !mp->m_ingrp)) { - *dst++ = ';'; - isgroup = 0; - } - if (insert (mp)) { - /* if we get here we're going to add an address */ - if (dst != buf) { - *dst++ = ','; - *dst++ = ' '; - } - if (mp->m_gname) { - CHECKMEM (mp->m_gname); - CPY (mp->m_gname); - isgroup++; - } - sp = adrformat (mp); - CHECKMEM (sp); - CPY (sp); - } - } - - if (isgroup) - *dst++ = ';'; - - *dst = '\0'; - last_dst = dst; - return (buf); -} - - -static int -insert (struct mailname *np) -{ - char buffer[BUFSIZ]; - register struct mailname *mp; - - if (np->m_mbox == NULL) - return 0; - - for (mp = &mq; mp->m_next; mp = mp->m_next) { - if (!mh_strcasecmp (np->m_host, mp->m_next->m_host) - && !mh_strcasecmp (np->m_mbox, mp->m_next->m_mbox)) - return 0; - } - if (!ccme && ismymbox (np)) - return 0; - - if (querysw) { - snprintf (buffer, sizeof(buffer), "Reply to %s? ", adrformat (np)); - if (!gans (buffer, anoyes)) - return 0; - } - mp->m_next = np; - -#ifdef ISI - if (ismymbox (np)) - ccme = 0; -#endif - - return 1; -} - - -/* - * Call the mhlproc - * - * This function expects that argument out has been fflushed by the caller. - */ - -static void -replfilter (FILE *in, FILE *out, char *filter) -{ - int pid; - char *mhl; - char *errstr; - - if (filter == NULL) - return; - - if (access (filter, R_OK) == NOTOK) - adios (filter, "unable to read"); - - mhl = r1bindex (mhlproc, '/'); - - rewind (in); - lseek (fileno(in), (off_t) 0, SEEK_SET); - - switch (pid = vfork ()) { - case NOTOK: - adios ("fork", "unable to"); - - case OK: - dup2 (fileno (in), fileno (stdin)); - dup2 (fileno (out), fileno (stdout)); - closefds (3); - - execlp (mhlproc, mhl, "-form", filter, "-noclear", NULL); - errstr = strerror(errno); - write(2, "unable to exec ", 15); - write(2, mhlproc, strlen(mhlproc)); - write(2, ": ", 2); - write(2, errstr, strlen(errstr)); - write(2, "\n", 1); - _exit (-1); - - default: - if (pidXwait (pid, mhl)) - done (1); - fseek (out, 0L, SEEK_END); - break; - } -} diff --git a/uip/rmf.c b/uip/rmf.c index a49ba4c..a0c68a3 100644 --- a/uip/rmf.c +++ b/uip/rmf.c @@ -1,253 +1,249 @@ - /* - * rmf.c -- remove a folder - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** rmf.c -- remove a folder +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include static struct swit switches[] = { -#define INTRSW 0 - { "interactive", 0 }, -#define NINTRSW 1 - { "nointeractive", 0 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, 0 } +#define INTRSW 0 + { "interactive", 0 }, +#define NINTRSW 1 + { "nointeractive", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, + { NULL, 0 } }; /* - * static prototypes - */ +** static prototypes +*/ static int rmf(char *); -static void rma (char *); +static void rma(char *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int defolder = 0, interactive = -1; - char *cp, *folder = NULL, newfolder[BUFSIZ]; - char buf[BUFSIZ], **argp, **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case INTRSW: - interactive = 1; - continue; - case NINTRSW: - interactive = 0; - continue; - } + int defolder = 0, interactive = -1; + char *cp, *folder = NULL, newfolder[BUFSIZ]; + char buf[BUFSIZ], **argp, **arguments; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case INTRSW: + interactive = 1; + continue; + case NINTRSW: + interactive = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else { + adios(NULL, "usage: %s [+folder] [switches]", + invo_name); + } + } + + if (!folder) { + folder = getcurfol(); + defolder++; } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); + if (strcmp(toabsdir(folder), pwd()) == 0) + adios(NULL, "You can't remove the current working directory"); + + if (interactive == -1) + interactive = defolder; + + if (strchr(folder, '/') && (*folder != '/') && (*folder != '.')) { + strcpy(newfolder, folder); + cp = newfolder + strlen(newfolder); + while (cp > newfolder && *cp != '/') + cp--; + if (cp > newfolder) + *cp = '\0'; + else + strncpy(newfolder, getdeffol(), sizeof(newfolder)); } else { - adios (NULL, "usage: %s [+folder] [switches]", invo_name); + strncpy(newfolder, getdeffol(), sizeof(newfolder)); } - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!folder) { - folder = getfolder (1); - defolder++; - } - if (strcmp (m_mailpath (folder), pwd ()) == 0) - adios (NULL, "sorry, you can't remove the current working directory"); - - if (interactive == -1) - interactive = defolder; - - if (strchr (folder, '/') && (*folder != '/') && (*folder != '.')) { - for (cp = copy (folder, newfolder); cp > newfolder && *cp != '/'; cp--) - continue; - if (cp > newfolder) - *cp = '\0'; - else - strncpy (newfolder, getfolder(0), sizeof(newfolder)); - } else { - strncpy (newfolder, getfolder(0), sizeof(newfolder)); - } - - if (interactive) { - cp = concat ("Remove folder \"", folder, "\"? ", NULL); - if (!getanswer (cp)) - done (0); - free (cp); - } - - if (rmf (folder) == OK) { - char *cfolder = context_find(pfolder); - if (cfolder && strcmp (cfolder, newfolder)) { - printf ("[+%s now current]\n", newfolder); - context_replace (pfolder, newfolder); /* update current folder */ + + if (interactive) { + cp = concat("Remove folder \"", folder, "\"? ", NULL); + if (!getanswer(cp)) + done(0); + free(cp); + } + + if (rmf(folder) == OK) { + char *cfolder = context_find(curfolder); + if (cfolder && strcmp(cfolder, newfolder)!=0) { + printf("[+%s now current]\n", newfolder); + /* update current folder */ + context_replace(curfolder, newfolder); + } } - } - context_save (); /* save the context file */ - done (0); - return 1; + context_save(); /* save the context file */ + done(0); + return 1; } static int -rmf (char *folder) +rmf(char *folder) { - int i, j, others; - register char *maildir; - char cur[BUFSIZ]; - register struct dirent *dp; - register DIR *dd; - - switch (i = chdir (maildir = m_maildir (folder))) { - case OK: - if (access (".", W_OK) != NOTOK && access ("..", W_OK) != NOTOK) - break; /* fall otherwise */ - - case NOTOK: - snprintf (cur, sizeof(cur), "atr-%s-%s", - current, m_mailpath (folder)); - if (!context_del (cur)) { - printf ("[+%s de-referenced]\n", folder); - return OK; - } - advise (NULL, "you have no profile entry for the %s folder +%s", - i == NOTOK ? "unreadable" : "read-only", folder); - return NOTOK; - } - - if ((dd = opendir (".")) == NULL) - adios (NULL, "unable to read folder +%s", folder); - others = 0; - - /* - * Run the external delete hook program. - */ - - (void)ext_hook("del-hook", maildir, (char *)0); - - j = strlen(BACKUP_PREFIX); - while ((dp = readdir (dd))) { - switch (dp->d_name[0]) { - case '.': - if (strcmp (dp->d_name, ".") == 0 - || strcmp (dp->d_name, "..") == 0) - continue; /* else fall */ - - case ',': -#ifdef MHE - case '+': -#endif /* MHE */ -#ifdef UCI - case '_': - case '#': -#endif /* UCI */ - break; - - default: - if (m_atoi (dp->d_name)) - break; - if (strcmp (dp->d_name, LINK) == 0 - || strncmp (dp->d_name, BACKUP_PREFIX, j) == 0) - break; - - admonish (NULL, "file \"%s/%s\" not deleted", - folder, dp->d_name); - others++; - continue; + int i, others; + register char *maildir; + char cur[BUFSIZ]; + register struct dirent *dp; + register DIR *dd; + + switch (i = chdir(maildir = toabsdir(folder))) { + case OK: + if (access(".", W_OK) != NOTOK && access("..", W_OK) != NOTOK) + break; /* fall otherwise */ + + case NOTOK: + snprintf(cur, sizeof(cur), "atr-%s-%s", seq_cur, + toabsdir(folder)); + if (!context_del(cur)) { + printf("[+%s de-referenced]\n", folder); + return OK; + } + advise(NULL, "you have no profile entry for the %s folder +%s", + i == NOTOK ? "unreadable" : "read-only", + folder); + return NOTOK; } - if (unlink (dp->d_name) == NOTOK) { - admonish (dp->d_name, "unable to unlink %s:", folder); - others++; - } - } - - closedir (dd); - /* - * Remove any relevant private sequences - * or attributes from context file. - */ - rma (folder); + if ((dd = opendir(".")) == NULL) + adios(NULL, "unable to read folder +%s", folder); + others = 0; + + /* + ** Run the external delete hook program. + */ + + ext_hook("del-hook", maildir, NULL); + + while ((dp = readdir(dd))) { + switch (dp->d_name[0]) { + case '.': + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; /* else fall */ + + case ',': + break; + + default: + if (m_atoi(dp->d_name)) + break; + + admonish(NULL, "file \"%s/%s\" not deleted", + folder, dp->d_name); + others++; + continue; + } + if (unlink(dp->d_name) == NOTOK) { + admonish(dp->d_name, "unable to unlink %s:", folder); + others++; + } + } - chdir (".."); - if (others == 0 && remdir (maildir)) - return OK; + closedir(dd); + + /* + ** Remove any relevant private sequences + ** or attributes from context file. + */ + rma(folder); + + chdir(".."); + if (others == 0) { + context_save(); /* Is this needed? meillo 2011-10 */ + fflush(stdout); /* Is this needed? meillo 2011-10 */ + if (rmdir(maildir) != -1) { + return OK; + } + admonish(maildir, "unable to remove directory"); + } - advise (NULL, "folder +%s not removed", folder); - return NOTOK; + advise(NULL, "folder +%s not removed", folder); + return NOTOK; } /* - * Remove all the (private) sequence information for - * this folder from the profile/context list. - */ +** Remove all the (private) sequence information for +** this folder from the profile/context list. +*/ static void -rma (char *folder) +rma(char *folder) { - register int alen, j, plen; - register char *cp; - register struct node *np, *pp; - - alen = strlen ("atr-"); - plen = strlen (cp = m_mailpath (folder)) + 1; - - /* - * Search context list for keys that look like - * "atr-something-folderpath", and remove them. - */ - for (np = m_defs, pp = NULL; np; np = np->n_next) { - if (ssequal ("atr-", np->n_name) - && (j = strlen (np->n_name) - plen) > alen - && *(np->n_name + j) == '-' - && strcmp (cp, np->n_name + j + 1) == 0) { - if (!np->n_context) - admonish (NULL, "bug: context_del(key=\"%s\")", np->n_name); - if (pp) { - pp->n_next = np->n_next; - np = pp; - } else { - m_defs = np->n_next; - } - ctxflags |= CTXMOD; - } else { - pp = np; + register int alen, j, plen; + register char *cp; + register struct node *np, *pp; + + alen = strlen("atr-"); + plen = strlen(cp = getcpy(toabsdir(folder))) + 1; + + /* + ** Search context list for keys that look like + ** "atr-something-folderpath", and remove them. + */ + for (np = m_defs, pp = NULL; np; np = np->n_next) { + if (strncmp(np->n_name, "atr-", alen)==0 && + (j = strlen(np->n_name) - plen) > alen && + *(np->n_name + j) == '-' && + strcmp(cp, np->n_name + j + 1) == 0) { + if (!np->n_context) + admonish(NULL, "bug: context_del(key=\"%s\")", + np->n_name); + if (pp) { + pp->n_next = np->n_next; + np = pp; + } else { + m_defs = np->n_next; + } + ctxflags |= CTXMOD; + } else { + pp = np; + } } - } + free(cp); } diff --git a/uip/rmm.c b/uip/rmm.c index 7680008..51be03a 100644 --- a/uip/rmm.c +++ b/uip/rmm.c @@ -1,130 +1,170 @@ - /* - * rmm.c -- remove a message(s) - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** rmm.c -- remove a message(s) +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include static struct swit switches[] = { -#define UNLINKSW 0 - { "unlink", 0 }, -#define NUNLINKSW 1 - { "nounlink", 0 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, 0 } +#define UNLINKSW 0 + { "unlink", 0 }, +#define NUNLINKSW 1 + { "nounlink", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, + { NULL, 0 } }; int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgnum, unlink_msgs = 0; - char *cp, *maildir, *folder = NULL; - char buf[BUFSIZ], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* parse arguments */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case UNLINKSW: - unlink_msgs++; - continue; - case NUNLINKSW: - unlink_msgs = 0; - continue; - } + int msgnum, unlink_msgs = 0, vecp = 0; + char *cp, *maildir, *folder = NULL, **vec; + char buf[BUFSIZ], **argp; + char **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + pid_t pid; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* parse arguments */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case UNLINKSW: + unlink_msgs++; + continue; + case NUNLINKSW: + unlink_msgs = 0; + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); + } + + if (!msgs.size) + app_msgarg(&msgs, seq_cur); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous-sequence */ + + + if (unlink_msgs) { + /* "remove" the SELECTED messages */ + folder_delmsgs(mp, 1); + + seq_save(mp); + context_replace(curfolder, folder); + context_save(); + folder_free(mp); + done(0); + return 1; } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!msgs.size) - app_msgarg(&msgs, "cur"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ - - /* - * This is hackish. If we are using a external rmmproc, - * then we need to update the current folder in the - * context so the external rmmproc will remove files - * from the correct directory. This should be moved to - * folder_delmsgs(). - */ - if (rmmproc) { - context_replace (pfolder, folder); - context_save (); - fflush (stdout); - } - - /* "remove" the SELECTED messages */ - folder_delmsgs (mp, unlink_msgs, 0); - - seq_save (mp); /* synchronize message sequences */ - context_replace (pfolder, folder); /* update current folder */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder structure */ - done (0); - return 1; + + /* + ** This is hackish. If we don't unlink, but refile, + ** then we need to update the current folder in the + ** context so the external program will refile files + ** from the correct directory. + */ + context_replace(curfolder, folder); + context_save(); + fflush(stdout); + + /* remove by refiling. */ + /* Unset the EXISTS flag for each message to be removed */ + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) + unset_exists(mp, msgnum); + } + + /* Mark that the sequence information has changed */ + mp->msgflags |= SEQMOD; + + if (mp->numsel+4 > MAXARGS) + adios(NULL, "more than %d messages for refile exec", + MAXARGS - 4); + vec = (char **)mh_xmalloc((size_t)(mp->numsel + 4) * sizeof(*vec)); + vec[vecp++] = "refile"; + vec[vecp++] = "-nolink"; + vec[vecp++] = concat("+", trashfolder, NULL); + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (!is_selected(mp, msgnum)) { + continue; + } + if (!(vec[vecp++] = strdup(m_name(msgnum)))) { + adios(NULL, "strdup failed"); + } + } + vec[vecp] = NULL; + + fflush(stdout); + switch (pid = fork()) { + case -1: + adios("fork", "unable to"); + + case 0: + execvp(*vec, vec); + fprintf(stderr, "unable to exec "); + perror(*vec); + _exit(-1); + + default: + pidwait(pid, -1); + } + + folder_free(mp); + done(0); + return 1; } diff --git a/uip/scan.c b/uip/scan.c index 077f824..ba90e40 100644 --- a/uip/scan.c +++ b/uip/scan.c @@ -1,329 +1,227 @@ - /* - * scan.c -- display a one-line "scan" listing of folder or messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** scan.c -- display a one-line "scan" listing of folder or messages +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include -#include #include #include static struct swit switches[] = { -#define CLRSW 0 - { "clear", 0 }, -#define NCLRSW 1 - { "noclear", 0 }, -#define FORMSW 2 - { "form formatfile", 0 }, -#define FMTSW 3 - { "format string", 5 }, -#define HEADSW 4 - { "header", 0 }, -#define NHEADSW 5 - { "noheader", 0 }, -#define WIDTHSW 6 - { "width columns", 0 }, -#define REVSW 7 - { "reverse", 0 }, -#define NREVSW 8 - { "noreverse", 0 }, -#define FILESW 9 - { "file file", 4 }, -#define VERSIONSW 10 - { "version", 0 }, -#define HELPSW 11 - { "help", 0 }, - { NULL, 0 } +#define FORMSW 0 + { "form formatfile", 0 }, +#define WIDTHSW 1 + { "width columns", 0 }, +#define FILESW 2 + { "file file", 0 }, +#define VERSIONSW 3 + { "Version", 0 }, +#define HELPSW 4 + { "help", 0 }, + { NULL, 0 } }; -/* - * global for sbr/formatsbr.c - yech! - */ -#ifdef LBL -extern struct msgs *fmt_current_folder; -#endif - -/* - * prototypes - */ -void clear_screen(void); /* from termsbr.c */ - - int -main (int argc, char **argv) +main(int argc, char **argv) { - int clearflag = 0, hdrflag = 0, ontty; - int width = 0, revflag = 0; - int i, state, msgnum; - int seqnum[NUMATTRS], unseen, num_unseen_seq = 0; - char *cp, *maildir, *file = NULL, *folder = NULL; - char *form = NULL, *format = NULL, buf[BUFSIZ]; - char **argp, *nfs, **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - FILE *in; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case CLRSW: - clearflag++; - continue; - case NCLRSW: - clearflag = 0; - continue; - - case FORMSW: - if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); - format = NULL; - continue; - case FMTSW: - if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); - form = NULL; - continue; - - case HEADSW: - hdrflag++; - continue; - case NHEADSW: - hdrflag = 0; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - width = atoi (cp); - continue; - case REVSW: - revflag++; - continue; - case NREVSW: - revflag = 0; - continue; - - case FILESW: - if (!(cp = *argp++) || (cp[0] == '-' && cp[1])) - adios (NULL, "missing argument to %s", argp[-2]); - if (strcmp (file = cp, "-")) - file = path (cp, TFILE); - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - /* - * Get new format string. Must be before chdir(). - */ - nfs = new_fs (form, format, FORMAT); - - /* - * We are scanning a maildrop file - */ - if (file) { - if (msgs.size) - adios (NULL, "\"msgs\" not allowed with -file"); - if (folder) - adios (NULL, "\"+folder\" not allowed with -file"); - - /* check if "file" is really stdin */ - if (strcmp (file, "-") == 0) { - in = stdin; - file = "stdin"; - } else { - if ((in = fopen (file, "r")) == NULL) - adios (file, "unable to open"); + int width = 0; + int i, state, msgnum; + int seqnum[NUMATTRS], unseen, num_unseen_seq = 0; + char *cp, *maildir, *file = NULL, *folder = NULL; + char *form = NULL, buf[BUFSIZ]; + char **argp, *fmtstr, **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + FILE *in; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case WIDTHSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + width = atoi(cp); + continue; + + case FILESW: + if (!(cp = *argp++) || (cp[0] == '-' && cp[1])) + adios(NULL, "missing argument to %s", + argp[-2]); + if (strcmp(file = cp, "-")!=0) + file = getcpy(expanddir(cp)); + continue; + } + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); } -#ifndef JLR - if (hdrflag) { - printf ("FOLDER %s\t%s\n", file, dtimenow (1)); + /* + ** Get new format string. Must be before chdir(). + */ + fmtstr = new_fs(form, FORMAT); + + /* + ** We are scanning a maildrop file + */ + if (file) { + if (msgs.size) + adios(NULL, "\"msgs\" not allowed with -file"); + if (folder) + adios(NULL, "\"+folder\" not allowed with -file"); + + /* check if "file" is really stdin */ + if (strcmp(file, "-") == 0) { + in = stdin; + file = "stdin"; + } else if (!(in = fopen(file, "r"))) { + adios(file, "unable to open"); + } + + thisisanmbox(in); + for (msgnum = 1; ; ++msgnum) { + state = scan(in, msgnum, SCN_MBOX, fmtstr, width, 0, 0); + if (state != SCNMSG) + break; + } + fclose(in); + done(0); } -#endif /* JLR */ - - m_unknown (in); - for (msgnum = 1; ; ++msgnum) { - state = scan (in, msgnum, -1, nfs, width, 0, 0, - hdrflag ? file : NULL, 0L, 1); - if (state != SCNMSG && state != SCNENC) - break; + + /* + ** We are scanning a folder + */ + + if (!msgs.size) + app_msgarg(&msgs, seq_all); + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the Previous-Sequence */ + + context_replace(curfolder, folder); /* update current folder */ + seq_save(mp); /* synchronize message sequences */ + context_save(); /* save the context file */ + + /* + ** Get the sequence number for each `unseen' sequence + */ + if (!(cp = context_find(usequence))) { + cp = seq_unseen; /* use default, if not set */ } - fclose (in); - done (0); - } - - /* - * We are scanning a folder - */ - - if (!msgs.size) - app_msgarg(&msgs, "all"); - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done(1); - seq_setprev (mp); /* set the Previous-Sequence */ - - context_replace (pfolder, folder); /* update current folder */ - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ - - /* - * Get the sequence number for each sequence - * specified by Unseen-Sequence - */ - if ((cp = context_find (usequence)) && *cp) { - char **ap, *dp; - - dp = getcpy(cp); - ap = brkstring (dp, " ", "\n"); - for (i = 0; ap && *ap; i++, ap++) - seqnum[i] = seq_getnum (mp, *ap); - - num_unseen_seq = i; - if (dp) - free(dp); - } - - ontty = isatty (fileno (stdout)); - -#ifdef LBL - else - fmt_current_folder = mp; -#endif - - for (msgnum = revflag ? mp->hghsel : mp->lowsel; - (revflag ? msgnum >= mp->lowsel : msgnum <= mp->hghsel); - msgnum += (revflag ? -1 : 1)) { - if (is_selected(mp, msgnum)) { - if ((in = fopen (cp = m_name (msgnum), "r")) == NULL) { -#if 0 - if (errno != EACCES) -#endif - admonish (cp, "unable to open message"); -#if 0 - else - printf ("%*d unreadable\n", DMAXFOLDER, msgnum); -#endif - continue; - } - -#ifndef JLR - if (hdrflag) { - printf ("FOLDER %s\t%s\n", folder, dtimenow(1)); - } -#endif /* JLR */ - - /* - * Check if message is in any sequence given - * by Unseen-Sequence profile entry. - */ - unseen = 0; - for (i = 0; i < num_unseen_seq; i++) { - if (in_sequence(mp, seqnum[i], msgnum)) { - unseen = 1; - break; + if (*cp) { + char **ap, *dp; + + dp = getcpy(cp); + ap = brkstring(dp, " ", "\n"); + for (i = 0; ap && *ap; i++, ap++) { + seqnum[i] = seq_getnum(mp, *ap); + } + num_unseen_seq = i; + if (dp) { + free(dp); } - } - - switch (state = scan (in, msgnum, 0, nfs, width, - msgnum == mp->curmsg, unseen, - folder, 0L, 1)) { - case SCNMSG: - case SCNENC: - case SCNERR: - break; - - default: - adios (NULL, "scan() botch (%d)", state); - - case SCNEOF: -#if 0 - printf ("%*d empty\n", DMAXFOLDER, msgnum); -#else - advise (NULL, "message %d: empty", msgnum); -#endif - break; - } - hdrflag = 0; - fclose (in); - if (ontty) - fflush (stdout); } - } -#ifdef LBL - seq_save (mp); /* because formatsbr might have made changes */ -#endif + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) { + admonish(cp, "unable to open message"); + continue; + } + + /* + ** Check if message is in any sequence given + ** by Unseen-Sequence profile entry. + */ + unseen = 0; + for (i = 0; i < num_unseen_seq; i++) { + if (in_sequence(mp, seqnum[i], msgnum)) { + unseen = 1; + break; + } + } + + switch (state = scan(in, msgnum, SCN_FOLD, fmtstr, + width, msgnum==mp->curmsg, unseen)) { + case SCNMSG: + case SCNERR: + break; + + default: + adios(NULL, "scan() botch(%d)", state); + + case SCNEOF: + advise(NULL, "message %d: empty", msgnum); + break; + } + fclose(in); + } + } - folder_free (mp); /* free folder/message structure */ - if (clearflag) - clear_screen (); + folder_free(mp); /* free folder/message structure */ - done (0); - return 1; + done(0); + return 1; } diff --git a/uip/scansbr.c b/uip/scansbr.c index 04dc215..865f2f7 100644 --- a/uip/scansbr.c +++ b/uip/scansbr.c @@ -1,11 +1,10 @@ - /* - * scansbr.c -- routines to help scan along... - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** scansbr.c -- routines to help scan along... +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -15,56 +14,39 @@ #include #ifdef _FSTDIO -# define _ptr _p /* Gag */ -# define _cnt _w /* Wretch */ -#endif - -#ifdef SCO_5_STDIO -# define _ptr __ptr -# define _cnt __cnt -# define _base __base -# define _filbuf(fp) ((fp)->__cnt = 0, __filbuf(fp)) +# define _ptr _p /* Gag */ +# define _cnt _w /* Wretch */ #endif -#define MAXSCANL 256 /* longest possible scan line */ +#define MAXSCANL 256 /* longest possible scan line */ /* - * Buffer size for content part of header fields. We want this - * to be large enough so that we don't do a lot of extra FLDPLUS - * calls on m_getfld but small enough so that we don't snarf - * the entire message body when we're only going to display 30 - * characters of it. - */ +** Buffer size for content part of header fields. We want this +** to be large enough so that we don't do a lot of extra FLDPLUS +** calls on m_getfld. +*/ #define SBUFSIZ 512 static struct format *fmt; -#ifdef JLR -static struct format *fmt_top; -#endif /* JLR */ - -static struct comp *datecomp; /* pntr to "date" comp */ -static struct comp *bodycomp; /* pntr to "body" pseudo-comp * - * (if referenced) */ -static int ncomps = 0; /* # of interesting components */ -static char **compbuffers = 0; /* buffers for component text */ -static struct comp **used_buf = 0; /* stack for comp that use buffers */ -static int dat[5]; /* aux. data for format routine */ +static struct comp *datecomp; /* pntr to "date" comp */ +static int ncomps = 0; /* # of interesting components */ +static char **compbuffers = NULL; /* buffers for component text */ +static struct comp **used_buf = NULL; /* stack for comp that use buffers */ -char *scanl = 0; /* text of most recent scanline */ +static int dat[5]; /* aux. data for format routine */ -#define DIEWRERR() adios (scnmsg, "write error on") +char *scanl = NULL; /* text of most recent scanline */ #define FPUTS(buf) {\ - if (mh_fputs(buf,scnout) == EOF)\ - DIEWRERR();\ - } + if (fputs(buf, scnout) == EOF)\ + adios(scnmsg, "write error on");\ + } /* - * prototypes - */ -int sc_width (void); /* from termsbr.c */ -static int mh_fputs(char *, FILE *); +** prototypes +*/ +int sc_width(void); /* from termsbr.c */ #ifdef MULTIBYTE_SUPPORT #define SCAN_CHARWIDTH MB_CUR_MAX @@ -73,332 +55,235 @@ static int mh_fputs(char *, FILE *); #endif int -scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, - int unseen, char *folder, long size, int noisy) +scan(FILE *inb, int innum, int outnum, char *fmtstr, int width, int curflg, + int unseen) { - int i, compnum, encrypted, state; - unsigned char *cp, *tmpbuf; - char **nxtbuf; - char *saved_c_text = NULL; - struct comp *cptr; - struct comp **savecomp; - char *scnmsg = NULL; - FILE *scnout = NULL; - char name[NAMESZ]; - static int rlwidth, slwidth; - -#ifdef RPATHS - char returnpath[BUFSIZ]; - char deliverydate[BUFSIZ]; -#endif + static int slwidth; + int i, compnum, state; + unsigned char *cp, *tmpbuf; + char **nxtbuf; + struct comp *cptr; + struct comp **savecomp; + char *scnmsg = NULL; + FILE *scnout = NULL; + char name[NAMESZ]; + int incing = (outnum != SCN_MBOX && outnum != SCN_FOLD); + int scanfolder = (outnum == SCN_FOLD); + long fpos; + struct stat st; - /* first-time only initialization */ - if (!scanl) { - if (width == 0) { - if ((width = sc_width ()) < WIDTH/2) - width = WIDTH/2; - else if (width > MAXSCANL) - width = MAXSCANL; - } - dat[3] = slwidth = width; - scanl = (char *) mh_xmalloc((size_t) SCAN_CHARWIDTH * (slwidth + 2) ); - if (outnum) - umask(~m_gmprot()); - - /* Compile format string */ - ncomps = fmt_compile (nfs, &fmt) + 1; - -#ifdef JLR - fmt_top = fmt; -#endif /* JLR */ - FINDCOMP(bodycomp, "body"); - FINDCOMP(datecomp, "date"); - FINDCOMP(cptr, "folder"); - if (cptr && folder) - cptr->c_text = folder; - FINDCOMP(cptr, "encrypted"); - if (!cptr) - if ((cptr = (struct comp *) calloc (1, sizeof(*cptr)))) { - cptr->c_name = "encrypted"; - cptr->c_next = wantcomp[i = CHASH (cptr->c_name)]; - wantcomp[i] = cptr; - ncomps++; - } - FINDCOMP (cptr, "dtimenow"); - if (cptr) - cptr->c_text = getcpy(dtimenow (0)); - nxtbuf = compbuffers = (char **) calloc((size_t) ncomps, sizeof(char *)); - if (nxtbuf == NULL) - adios (NULL, "unable to allocate component buffers"); - used_buf = (struct comp **) calloc((size_t) (ncomps+1), - sizeof(struct comp *)); - if (used_buf == NULL) - adios (NULL, "unable to allocate component buffer stack"); - used_buf += ncomps+1; *--used_buf = 0; - rlwidth = bodycomp && (width > SBUFSIZ) ? width : SBUFSIZ; - for (i = ncomps; i--; ) - *nxtbuf++ = mh_xmalloc(rlwidth); - } - - /* - * each-message initialization - */ - nxtbuf = compbuffers; - savecomp = used_buf; - tmpbuf = *nxtbuf++; - dat[0] = innum ? innum : outnum; - dat[1] = curflg; - dat[4] = unseen; - - /* - * Get the first field. If the message is non-empty - * and we're doing an "inc", open the output file. - */ - if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF) { - if (ferror(inb)) { - advise("read", "unable to"); /* "read error" */ - return SCNFAT; - } else { - return SCNEOF; - } - } - - if (outnum) { - if (outnum > 0) { - scnmsg = m_name (outnum); - if (*scnmsg == '?') /* msg num out of range */ - return SCNNUM; - } else { - scnmsg = "/dev/null"; - } - if ((scnout = fopen (scnmsg, "w")) == NULL) - adios (scnmsg, "unable to write"); -#ifdef RPATHS - /* - * Add the Return-Path and Delivery-Date - * header fields to message. - */ - if (get_returnpath (returnpath, sizeof(returnpath), - deliverydate, sizeof(deliverydate))) { - FPUTS ("Return-Path: "); - FPUTS (returnpath); - FPUTS ("Delivery-Date: "); - FPUTS (deliverydate); - } -#endif /* RPATHS */ - } - - /* scan - main loop */ - for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) { - switch (state) { - case FLD: - case FLDPLUS: - compnum++; - if (outnum) { - FPUTS (name); - if ( putc (':', scnout) == EOF) DIEWRERR(); - FPUTS (tmpbuf); - } - /* - * if we're interested in this component, save a pointer - * to the component text, then start using our next free - * buffer as the component temp buffer (buffer switching - * saves an extra copy of the component text). - */ - if ((cptr = wantcomp[CHASH(name)])) { - do { - if (!mh_strcasecmp(name, cptr->c_name)) { - if (! cptr->c_text) { - cptr->c_text = tmpbuf; - for (cp = tmpbuf + strlen (tmpbuf) - 1; - cp >= tmpbuf; cp--) - if (isspace (*cp)) - *cp = 0; - else - break; - *--savecomp = cptr; - tmpbuf = *nxtbuf++; - } - break; + /* first-time only initialization */ + if (!scanl) { + if (incing) + umask(~m_gmprot()); + + if (fmtstr) { + if (width == 0) { + if ((width = sc_width()) < WIDTH/2) + width = WIDTH/2; + else if (width > MAXSCANL) + width = MAXSCANL; } - } while ((cptr = cptr->c_next)); - } - - while (state == FLDPLUS) { - state = m_getfld (state, name, tmpbuf, rlwidth, inb); - if (outnum) - FPUTS (tmpbuf); + dat[3] = slwidth = width; + scanl = (char *) mh_xmalloc((size_t) SCAN_CHARWIDTH * + (slwidth + 2)); /* probably for \n and \0 */ + /* Compile format string */ + ncomps = fmt_compile(fmtstr, &fmt) + 1; + FINDCOMP(datecomp, "date"); + } else { + ncomps = 1; + datecomp = NULL; } - break; - case BODY: - compnum = -1; - if (! outnum) { - state = FILEEOF; /* stop now if scan cmd */ - goto finished; - } - if (putc ('\n', scnout) == EOF) DIEWRERR(); - FPUTS (tmpbuf); - /* - * performance hack: some people like to run "inc" on - * things like net.sources or large digests. We do a - * copy directly into the output buffer rather than - * going through an intermediate buffer. - * - * We need the amount of data m_getfld found & don't - * want to do a strlen on the long buffer so there's - * a hack in m_getfld to save the amount of data it - * returned in the global "msg_count". - */ -body:; - while (state == BODY) { -#ifdef LINUX_STDIO - if (scnout->_IO_write_ptr == scnout->_IO_write_end) { -#elif defined(__DragonFly__) - if (((struct __FILE_public *)scnout)->_w <= 0) { -#else - if (scnout->_cnt <= 0) { -#endif - if (fflush(scnout) == EOF) - DIEWRERR (); - } -#ifdef LINUX_STDIO - state = m_getfld(state, name, scnout->_IO_write_ptr, - (long)scnout->_IO_write_ptr-(long)scnout->_IO_write_end , inb); - scnout->_IO_write_ptr += msg_count; -#elif defined(__DragonFly__) - state = m_getfld( state, name, ((struct __FILE_public *)scnout)->_p, -(((struct __FILE_public *)scnout)->_w), inb ); - ((struct __FILE_public *)scnout)->_w -= msg_count; - ((struct __FILE_public *)scnout)->_p += msg_count; -#else - state = m_getfld( state, name, scnout->_ptr, -(scnout->_cnt), inb ); - scnout->_cnt -= msg_count; - scnout->_ptr += msg_count; -#endif - } - goto finished; - - case LENERR: - case FMTERR: - fprintf (stderr, - innum ? "??Format error (message %d) in " - : "??Format error in ", - outnum ? outnum : innum); - fprintf (stderr, "component %d\n", compnum); - - if (outnum) { - FPUTS ("\n\nBAD MSG:\n"); - FPUTS (name); - if (putc ('\n', scnout) == EOF) DIEWRERR(); - state = BODY; - goto body; - } - /* fall through */ - - case FILEEOF: - goto finished; - - default: - adios (NULL, "getfld() returned %d", state); + nxtbuf = compbuffers = (char **) calloc((size_t) ncomps, + sizeof(char *)); + if (!nxtbuf) + adios(NULL, "unable to allocate component buffers"); + used_buf = (struct comp **) calloc((size_t) (ncomps+1), + sizeof(struct comp *)); + if (!used_buf) + adios(NULL, "unable to allocate component buffer stack"); + /* NULL-terminate array */ + used_buf += ncomps; + *used_buf = NULL; + /* allocate space for the items */ + for (i = ncomps; i--; ) + *nxtbuf++ = mh_xmalloc(SBUFSIZ); } - } - /* - * format and output the scan line. - */ -finished: - if (ferror(inb)) { - advise("read", "unable to"); /* "read error" */ - return SCNFAT; - } - - /* Save and restore buffer so we don't trash our dynamic pool! */ - if (bodycomp) { - saved_c_text = bodycomp->c_text; - bodycomp->c_text = tmpbuf; - } - - if (size) - dat[2] = size; - else if (outnum > 0) - { - dat[2] = ftell(scnout); - if (dat[2] == EOF) DIEWRERR(); - } - - if ((datecomp && !datecomp->c_text) || (!size && !outnum)) { - struct stat st; + /* + ** each-message initialization + */ + nxtbuf = compbuffers; + savecomp = used_buf; + tmpbuf = *nxtbuf++; + dat[0] = innum ? innum : outnum; + dat[1] = curflg; + dat[4] = unseen; + fpos = ftell(inb); - fstat (fileno(inb), &st); - if (!size && !outnum) - dat[2] = st.st_size; - if (datecomp) { - if (! datecomp->c_text) { - if (datecomp->c_tws == NULL) - datecomp->c_tws = (struct tws *) - calloc((size_t) 1, sizeof(*datecomp->c_tws)); - if (datecomp->c_tws == NULL) - adios (NULL, "unable to allocate tws buffer"); - *datecomp->c_tws = *dlocaltime ((time_t *) &st.st_mtime); - datecomp->c_flags |= CF_DATEFAB|CF_TRUE; - } else { - datecomp->c_flags &= ~CF_DATEFAB; - } + /* + ** Get the first field. If the message is non-empty + ** and we're doing an "inc", open the output file. + */ + if ((state = m_getfld(FLD, name, tmpbuf, SBUFSIZ, inb)) == FILEEOF) { + if (ferror(inb)) { + advise("read", "unable to"); /* "read error" */ + return SCNFAT; + } else { + return SCNEOF; + } } - } - fmt_scan (fmt, scanl, slwidth, dat); + if (incing) { + scnmsg = m_name(outnum); + if (*scnmsg == '?') /* msg num out of range */ + return SCNNUM; + if (!(scnout = fopen(scnmsg, "w"))) + adios(scnmsg, "unable to write"); + } -#if 0 - fmt = fmt_scan (fmt, scanl, slwidth, dat); - if (!fmt) - fmt = fmt_top; /* reset for old format files */ -#endif + /* scan - main loop */ + for (compnum = 1; ; + state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb)) { + switch (state) { + case FLD: + case FLDPLUS: + compnum++; + if (incing) { + FPUTS(name); + FPUTS(":"); + FPUTS(tmpbuf); + } + /* + ** if we're interested in this component, save + ** a pointer to the component text, then start + ** using our next free buffer as the component + ** temp buffer (buffer switching saves an extra + ** copy of the component text). + */ + if (fmtstr && (cptr = wantcomp[CHASH(name)])) { + do { + if (mh_strcasecmp(name, cptr->c_name)!=0) { + continue; + } + if (!cptr->c_text) { + cptr->c_text = tmpbuf; + cp = tmpbuf+strlen(tmpbuf)-1; + for (; cp >= tmpbuf; cp--) { + if (isspace(*cp)) + *cp = '\0'; + else + break; + } + *--savecomp = cptr; + tmpbuf = *nxtbuf++; + } + break; + } while ((cptr = cptr->c_next)); + } - if (bodycomp) - bodycomp->c_text = saved_c_text; + while (state == FLDPLUS) { + state = m_getfld(state, name, tmpbuf, SBUFSIZ, + inb); + if (incing) + FPUTS(tmpbuf); + } + break; + + case BODY: + compnum = -1; + if (scanfolder) { + /* stop here if we scan a msg in a folder */ + state = FILEEOF; + goto finished; + } + /* otherwise (mbox): snarf the body */ + if (incing) { + FPUTS("\n"); + FPUTS(tmpbuf); + } +body:; + while (state == BODY) { + state = m_getfld(state, name, tmpbuf, SBUFSIZ, + inb); + if (incing) { + FPUTS(tmpbuf); + } + } + goto finished; + + case LENERR: + case FMTERR: + fprintf(stderr, innum ? "??Format error (message %d) in " : "??Format error in ", outnum ? outnum : innum); + fprintf(stderr, "component %d\n", compnum); + + if (incing) { + FPUTS("\n\nBAD MSG:\n"); + FPUTS(name); + FPUTS("\n"); + state = BODY; + goto body; + } + /* fall through if we scan only */ - if (noisy) - fputs (scanl, stdout); + case FILEEOF: + goto finished; - FINDCOMP (cptr, "encrypted"); - encrypted = cptr && cptr->c_text; + default: + adios(NULL, "getfld() returned %d", state); + } + } - /* return dynamically allocated buffers to pool */ - while ((cptr = *savecomp++)) { - *--nxtbuf = cptr->c_text; - cptr->c_text = NULL; - } - *--nxtbuf = tmpbuf; +finished: - if (outnum && (ferror(scnout) || fclose (scnout) == EOF)) - DIEWRERR(); + /* Format and output the scan line. */ + if (ferror(inb)) { + advise("read", "unable to"); + return SCNFAT; + } - return (state != FILEEOF ? SCNERR : encrypted ? SCNENC : SCNMSG); -} + if (incing) { + if ((dat[2] = ftell(scnout)) == EOF) + adios(scnmsg, "write error on"); + } else if (!scanfolder) { + if ((dat[2] = ftell(inb)) == EOF) + adios(scnmsg, "write error on"); + dat[2] -= fpos; + } + if (fmtstr) { + fstat(fileno(inb), &st); + if (scanfolder) { + dat[2] = st.st_size; + } + if (datecomp && !datecomp->c_text) { + if (!datecomp->c_text) { + if (!datecomp->c_tws) + datecomp->c_tws = (struct tws *) calloc((size_t) 1, sizeof(*datecomp->c_tws)); + if (!datecomp->c_tws) + adios(NULL, "unable to allocate tws buffer"); + *datecomp->c_tws = *dlocaltime((time_t *) &st.st_mtime); + datecomp->c_flags |= CF_DATEFAB|CF_TRUE; + } else { + datecomp->c_flags &= ~CF_DATEFAB; + } + } -/* - * Cheat: we are loaded with adrparse, which wants a routine called - * OfficialName(). We call adrparse:getm() with the correct arguments - * to prevent OfficialName() from being called. Hence, the following - * is to keep the loader happy. - */ -char * -OfficialName (char *name) -{ - return name; -} + /* print the scan line */ + fmt_scan(fmt, scanl, slwidth, dat); + fputs(scanl, stdout); + } + /* return dynamically allocated buffers to pool */ + while ((cptr = *savecomp++)) { + *--nxtbuf = cptr->c_text; + cptr->c_text = NULL; + } + *--nxtbuf = tmpbuf; -static int -mh_fputs(char *s, FILE *stream) -{ - char c; + if (incing && (ferror(scnout) || fclose(scnout) == EOF)) + adios(scnmsg, "write error on"); - while ((c = *s++)) - if (putc (c,stream) == EOF ) - return(EOF); - return (0); + return (state != FILEEOF ? SCNERR : SCNMSG); } - diff --git a/uip/send.c b/uip/send.c index d06b6c4..76280aa 100644 --- a/uip/send.c +++ b/uip/send.c @@ -1,488 +1,693 @@ - /* - * send.c -- send a composed message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** send.c -- send a composed message +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include #include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +int debugsw = 0; /* global */ +char *altmsg = NULL; +char *annotext = NULL; +char *distfile = NULL; -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else /* CYRUS_SASL */ -# define SASLminc(a) 0 -#endif /* CYRUS_SASL */ - -#ifndef TLS_SUPPORT -# define TLSminc(a) (a) -#else /* TLS_SUPPORT */ -# define TLSminc(a) 0 -#endif /* TLS_SUPPORT */ +static jmp_buf env; -static struct swit switches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define DEBUGSW 1 - { "debug", -5 }, -#define DRAFTSW 2 - { "draft", 0 }, -#define DFOLDSW 3 - { "draftfolder +folder", 6 }, -#define DMSGSW 4 - { "draftmessage msg", 6 }, -#define NDFLDSW 5 - { "nodraftfolder", 0 }, -#define FILTSW 6 - { "filter filterfile", 0 }, -#define NFILTSW 7 - { "nofilter", 0 }, -#define FRMTSW 8 - { "format", 0 }, -#define NFRMTSW 9 - { "noformat", 0 }, -#define FORWSW 10 - { "forward", 0 }, -#define NFORWSW 11 - { "noforward", 0 }, -#define MIMESW 12 - { "mime", 0 }, -#define NMIMESW 13 - { "nomime", 0 }, -#define MSGDSW 14 - { "msgid", 0 }, -#define NMSGDSW 15 - { "nomsgid", 0 }, -#define PUSHSW 16 - { "push", 0 }, -#define NPUSHSW 17 - { "nopush", 0 }, -#define SPLITSW 18 - { "split seconds", 0 }, -#define UNIQSW 19 - { "unique", -6 }, -#define NUNIQSW 20 - { "nounique", -8 }, -#define VERBSW 21 - { "verbose", 0 }, -#define NVERBSW 22 - { "noverbose", 0 }, -#define WATCSW 23 - { "watch", 0 }, -#define NWATCSW 24 - { "nowatch", 0 }, -#define WIDTHSW 25 - { "width columns", 0 }, -#define VERSIONSW 26 - { "version", 0 }, -#define HELPSW 27 - { "help", 0 }, -#define BITSTUFFSW 28 - { "dashstuffing", -12 }, -#define NBITSTUFFSW 29 - { "nodashstuffing", -14 }, -#define MAILSW 30 - { "mail", -4 }, -#define SAMLSW 31 - { "saml", -4 }, -#define SENDSW 32 - { "send", -4 }, -#define SOMLSW 33 - { "soml", -4 }, -#define CLIESW 34 - { "client host", -6 }, -#define SERVSW 35 - { "server host", 6 }, -#define SNOOPSW 36 - { "snoop", 5 }, -#define SASLSW 37 - { "sasl", SASLminc(4) }, -#define SASLMECHSW 38 - { "saslmech mechanism", SASLminc(-5) }, -#define USERSW 39 - { "user username", SASLminc(-4) }, -#define ATTACHSW 40 - { "attach", 6 }, -#define ATTACHFORMATSW 41 - { "attachformat", 7 }, -#define PORTSW 42 - { "port server-port-name/number" , 4 }, -#define TLSSW 43 - { "tls", TLSminc(-3) }, - { NULL, 0 } -}; +/* name of temp file for body content */ +static char body_file_name[MAXPATHLEN + 1]; +/* name of mhbuild composition temporary file */ +static char composition_file_name[MAXPATHLEN + 1]; +static int field_size; /* size of header field buffer */ +static char *field; /* header field buffer */ +static FILE *draft_file; /* draft file pointer */ +static FILE *body_file; /* body file pointer */ +static FILE *composition_file; /* composition file pointer */ -static struct swit anyl[] = { -#define NOSW 0 - { "no", 0 }, -#define YESW 1 - { "yes", 0 }, -#define LISTDSW 2 - { "list", 0 }, - { NULL, 0 } -}; +/* +** static prototypes +*/ +static int sendsbr(char **, int, char *, struct stat *); +static void armed_done(int) NORETURN; +static void anno(struct stat *); +static int sendaux(char **, int, char *, struct stat *); +static int attach(char *); +static int signandenc(char *); +static void clean_up_temporary_files(void); +static int get_line(void); +static void make_mime_composition_file_entry(char *); -extern int debugsw; /* from sendsbr.c */ -extern int forwsw; -extern int inplace; -extern int pushsw; -extern int splitsw; -extern int unique; -extern int verbsw; -extern char *altmsg; /* .. */ -extern char *annotext; -extern char *distfile; +static struct swit switches[] = { +#define DEBUGSW 0 + { "debug", -5 }, +#define VERBSW 1 + { "verbose", 0 }, +#define NVERBSW 2 + { "noverbose", 2 }, +#define VERSIONSW 3 + { "Version", 0 }, +#define HELPSW 4 + { "help", 0 }, + { NULL, 0 } +}; int -main (int argc, char **argv) +main(int argc, char **argv) { - int msgp = 0, distsw = 0, vecp = 1; - int isdf = 0, mime = 0; - int msgnum, status; - char *cp, *dfolder = NULL, *maildir = NULL; - char buf[BUFSIZ], **ap, **argp, **arguments; - char *msgs[MAXARGS], *vec[MAXARGS]; - struct msgs *mp; - struct stat st; - char *attach = (char *)0; /* header field name for attachments */ - int attachformat = 0; /* mhbuild format specifier for attachments */ -#ifdef UCI - FILE *fp; -#endif /* UCI */ - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - vec[vecp++] = "-library"; - vec[vecp++] = getcpy (m_maildir ("")); - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown\n", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [file] [switches]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DRAFTSW: - msgs[msgp++] = draft; - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - msgs[msgp++] = cp; - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - - case PUSHSW: - pushsw++; - continue; - case NPUSHSW: - pushsw = 0; - continue; - - case SPLITSW: - if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case UNIQSW: - unique++; - continue; - case NUNIQSW: - unique = 0; - continue; - - case FORWSW: - forwsw++; - continue; - case NFORWSW: - forwsw = 0; - continue; - - case VERBSW: - verbsw++; - vec[vecp++] = --cp; - continue; - case NVERBSW: - verbsw = 0; - vec[vecp++] = --cp; - continue; - - case MIMESW: - mime++; - vec[vecp++] = --cp; - continue; - case NMIMESW: - mime = 0; - vec[vecp++] = --cp; - continue; - - case DEBUGSW: - debugsw++; /* fall */ - case NFILTSW: - case FRMTSW: - case NFRMTSW: - case BITSTUFFSW: - case NBITSTUFFSW: - case MSGDSW: - case NMSGDSW: - case WATCSW: - case NWATCSW: - case MAILSW: - case SAMLSW: - case SENDSW: - case SOMLSW: - case SNOOPSW: - case SASLSW: - case TLSSW: - vec[vecp++] = --cp; - continue; - - case ALIASW: - case FILTSW: - case WIDTHSW: - case CLIESW: - case SERVSW: - case SASLMECHSW: - case USERSW: - case PORTSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; - - case ATTACHSW: - if (!(attach = *argp++) || *attach == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case ATTACHFORMATSW: - if (! *argp || **argp == '-') - adios (NULL, "missing argument to %s", argp[-1]); - else { - attachformat = atoi (*argp); - if (attachformat < 0 || - attachformat > ATTACHFORMATS - 1) { - advise (NULL, "unsupported attachformat %d", - attachformat); - continue; + int msgp = 0, nfiles = 0, distsw = 0, vecp = 1; + int msgnum, status; + int in, out; + int n; + char *cp, *maildir = NULL; + char buf[BUFSIZ], **argp, **arguments; + char *msgs[MAXARGS], *vec[MAXARGS]; + char *files[MAXARGS]; + struct msgs *mp; + struct stat st; + struct stat st2; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown\n", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [file] [switches]", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case DEBUGSW: + debugsw++; + /* fall */ + case VERBSW: + case NVERBSW: + vec[vecp++] = --cp; + continue; + } + } else { + if (*cp == '/') { + files[nfiles++] = cp; + } else { + msgs[msgp++] = cp; } - } - ++argp; - continue; - } + } + } + + if (!msgp && !nfiles) { + msgs[msgp++] = seq_cur; + } + maildir = toabsdir(draftfolder); + + if (chdir(maildir) == NOTOK) { + adios(maildir, "unable to change directory to"); + } + + if (!(mp = folder_read(draftfolder))) { + adios(NULL, "unable to read draft folder %s", draftfolder); + } + if (mp->nummsg == 0) { + adios(NULL, "no messages in draft folder %s", draftfolder); + } + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgp; msgnum++) { + if (!m_convert(mp, msgs[msgnum])) { + done(1); + } + } + seq_setprev(mp); + + for (msgp = 0, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + files[nfiles++] = getcpy(m_name(msgnum)); + unset_exists(mp, msgnum); + } + } + + mp->msgflags |= SEQMOD; + seq_save(mp); + + if (!(cp = getenv("SIGNATURE")) || !*cp) { + if ((cp = context_find("signature")) && *cp) { + m_putenv("SIGNATURE", cp); + } + } + + for (msgnum = 0; msgnum < nfiles; msgnum++) { + if (stat(files[msgnum], &st) == NOTOK) { + adios(files[msgnum], "unable to stat draft file"); + } + } + + if (!(annotext = getenv("mhannotate")) || !*annotext) { + annotext = NULL; + } + if (!(altmsg = getenv("mhaltmsg")) || !*altmsg) { + altmsg = NULL; /* used by dist interface - see below */ + } + + if ((cp = getenv("mhdist")) && *cp && (distsw = atoi(cp)) && altmsg) { + vec[vecp++] = "-dist"; + if ((in = open(altmsg, O_RDONLY)) == NOTOK) { + adios(altmsg, "unable to open for reading"); + } + fstat(in, &st2); + distfile = getcpy(m_mktemp2(NULL, invo_name, NULL, NULL)); + if ((out = creat(distfile, (int)st2.st_mode & 0777))==NOTOK) { + adios(distfile, "unable to open for writing"); + } + cpydata(in, out, altmsg, distfile); + close(in); + close(out); } else { - msgs[msgp++] = cp; - } - } - - /* - * check for "Aliasfile:" profile entry - */ - if ((cp = context_find ("Aliasfile"))) { - char *dp = NULL; - - for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++) { - vec[vecp++] = "-alias"; - vec[vecp++] = *ap; - } - } - - if (dfolder == NULL) { - if (msgp == 0) { -#ifdef WHATNOW - if ((cp = getenv ("mhdraft")) && *cp) { - msgs[msgp++] = cp; - goto go_to_it; - } -#endif /* WHATNOW */ - msgs[msgp++] = getcpy (m_draft (NULL, NULL, 1, &isdf)); - if (stat (msgs[0], &st) == NOTOK) - adios (msgs[0], "unable to stat draft file"); - cp = concat ("Use \"", msgs[0], "\"? ", NULL); - for (status = LISTDSW; status != YESW;) { - if (!(argp = getans (cp, anyl))) - done (1); - switch (status = smatch (*argp, anyl)) { - case NOSW: - done (0); - case YESW: + distfile = NULL; + } + + if (!altmsg || stat(altmsg, &st) == NOTOK) { + st.st_mtime = 0; + st.st_dev = 0; + st.st_ino = 0; + } + status = 0; + vec[0] = "spost"; + for (n=3; n 127 || *p < 0) { + non_ascii = 1; + } + } + if (has_body && non_ascii) { + break; /* that's been already enough information */ + } + } + + if (!has_attachment && non_ascii==0) { + /* We don't need to convert it to MIME. */ + return DONE; + } + + /* + ** Else: mimify + */ + + /* Make names for the temporary files. */ + strncpy(body_file_name, + m_mktemp(toabsdir(invo_name), NULL, NULL), + sizeof (body_file_name)); + strncpy(composition_file_name, + m_mktemp(toabsdir(invo_name), NULL, NULL), + sizeof (composition_file_name)); + + if (has_body) { + body_file = fopen(body_file_name, "w"); + } + composition_file = fopen(composition_file_name, "w"); + + if ((has_body && !body_file) || !composition_file) { + clean_up_temporary_files(); + adios(NULL, "unable to open all of the temporary files."); + } + + /* Copy non-attachment header fields to the temp composition file. */ + rewind(draft_file); + while (get_line() != EOF && *field && *field != '-') { + if (strncasecmp(field, attach_hdr, length) != 0 || + field[length] != ':') { + fprintf(composition_file, "%s\n", field); + } + } + fputs("--------\n", composition_file); + + if (has_body) { + /* Copy the message body to the temporary file. */ + while ((c = getc(draft_file)) != EOF) { + putc(c, body_file); + } + fclose(body_file); + + /* Add a mhbuild MIME composition file line for the body */ + /* charset will be discovered/guessed by mhbuild */ + fprintf(composition_file, "#text/plain %s\n", body_file_name); + } + + /* + ** Now, go back to the beginning of the draft file and look for + ** header fields that specify attachments. Add a mhbuild MIME + ** composition file for each. + */ + rewind(draft_file); + while (get_line() != EOF && *field && *field != '-') { + if (strncasecmp(field, attach_hdr, length) == 0 && + field[length] == ':') { + for (p = field+length+1; *p==' ' || *p=='\t'; p++) { + continue; + } + if (*p == '+') { + /* forwarded message */ + fprintf(composition_file, "#forw [forwarded message(s)] %s\n", p); + } else { + /* regular attachment */ + make_mime_composition_file_entry(p); + } + } + } + fclose(composition_file); + + /* We're ready to roll! */ + sprintf(buf, "mhbuild %s", composition_file_name); + if (system(buf) != 0) { + /* some problem */ + clean_up_temporary_files(); + return (NOTOK); + } + /* Remove the automatically created backup of mhbuild. */ + snprintf(buf, sizeof buf, "%s.orig", composition_file_name); + if (unlink(buf) == -1) { + advise(NULL, "unable to remove original composition file."); + } + + return (OK); +} + +static int +signandenc(char *draft_file_name) +{ + char buf[BUFSIZ]; + int dosign = 0; + int doenc = 0; + + if (!(draft_file = fopen(draft_file_name, "r"))) { + adios(NULL, "can't open draft file `%s'.", draft_file_name); + } + + /* We'll grow the buffer as needed. */ + field = (char *)mh_xmalloc(field_size = 256); + + /* Scan the draft file for an attachment header field name. */ + while (get_line() != EOF && *field != '\0' && *field != '-') { + if (strncasecmp(field, sign_hdr, strlen(sign_hdr))==0 && + field[strlen(sign_hdr)] == ':') { + dosign = 1; + } + if (strncasecmp(field, enc_hdr, strlen(enc_hdr))==0 && + field[strlen(enc_hdr)] == ':') { + doenc = 1; + } + } + if (!dosign && !doenc) { + return DONE; + } + + strcpy(composition_file_name, draft_file_name); + + /* We're ready to roll! */ + sprintf(buf, "mhsign -m%s '%s'", doenc ? " -e" : "", + draft_file_name); + if (system(buf) != 0) { + /* some problem */ + return (NOTOK); + } + /* Remove the automatically created backup of mhsign. */ + snprintf(buf, sizeof buf, "%s.orig", draft_file_name); + if (unlink(buf) == -1) { + advise(NULL, "unable to remove original draft file."); + } + + return (OK); +} + +static void +clean_up_temporary_files(void) +{ + unlink(body_file_name); + unlink(composition_file_name); + + return; +} + +static int +get_line(void) +{ + int c; /* current character */ + int n; /* number of bytes in buffer */ + char *p; + + /* + ** Get a line from the input file, growing the field buffer as + ** needed. We do this so that we can fit an entire line in the + ** buffer making it easy to do a string comparison on both the + ** field name and the field body which might be a long path name. + */ + for (n = 0, p = field; (c = getc(draft_file)) != EOF; *p++ = c) { + if (c == '\n' && (c = getc(draft_file)) != ' ' && c != '\t') { + ungetc(c, draft_file); + c = '\n'; break; - default: - advise (NULL, "say what?"); + } + if (++n >= field_size - 1) { + field = (char *)mh_xrealloc(field, field_size += 256); + p = field + n - 1; + } + } + *p = '\0'; + + return (c); +} + +static void +make_mime_composition_file_entry(char *file_name) +{ + FILE *fp; + struct node *np; + char *cp; + char content_type[BUFSIZ]; + char cmdbuf[BUFSIZ]; + char *cmd = mimetypequeryproc; + + for (np = m_defs; np; np = np->n_next) { + if (strcasecmp(np->n_name, mimetypequery)==0) { + cmd = np->n_field; break; } - } + } + snprintf(cmdbuf, sizeof cmdbuf, "%s %s", cmd, file_name); + + if (!(fp = popen(cmdbuf, "r"))) { + clean_up_temporary_files(); + adios(NULL, "unable to determine content type with `%s'", + cmdbuf); + } + if (fgets(content_type, sizeof content_type, fp) && + (cp = strrchr(content_type, '\n'))) { + *cp = '\0'; } else { - for (msgnum = 0; msgnum < msgp; msgnum++) - msgs[msgnum] = getcpy (m_maildir (msgs[msgnum])); + strcpy(content_type, "application/octet-stream"); + admonish(NULL, "problems with `%s', using fall back type `%s'", + cmdbuf, content_type); } - } else { - if (!context_find ("path")) - free (path ("./", TFOLDER)); + pclose(fp); - if (!msgp) - msgs[msgp++] = "cur"; - maildir = m_maildir (dfolder); + /* TODO: don't use access(2) because it checks for ruid, not euid */ + if (access(file_name, R_OK) != 0) { + clean_up_temporary_files(); + adios(NULL, "unable to access file `%s'", file_name); + } - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); + cp = (!(cp = strrchr(file_name, '/'))) ? file_name : cp + 1; + fprintf(composition_file, "#%s; name=\"%s\" <> [%s] {attachment}", + content_type, cp, cp); - /* read folder and create message structure */ - if (!(mp = folder_read (dfolder))) - adios (NULL, "unable to read folder %s", dfolder); + fprintf(composition_file, " %s\n", file_name); - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", dfolder); + return; +} - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous-sequence */ +/* +** The back-end of the message sending back-end. +** Annotate original message, and call `spost' to send message. +*/ +static int +sendaux(char **vec, int vecp, char *drft, struct stat *st) +{ + pid_t child_id; + int status; + char backup[BUFSIZ]; - for (msgp = 0, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected (mp, msgnum)) { - msgs[msgp++] = getcpy (m_name (msgnum)); - unset_exists (mp, msgnum); - } + vec[vecp++] = drft; + if (distfile && distout(drft, distfile, backup) == NOTOK) { + done(1); } - - mp->msgflags |= SEQMOD; - seq_save (mp); - } - -#ifdef WHATNOW -go_to_it: -#endif /* WHATNOW */ - - if ((cp = getenv ("SIGNATURE")) == NULL || *cp == 0) - if ((cp = context_find ("signature")) && *cp) - m_putenv ("SIGNATURE", cp); -#ifdef UCI - else { - snprintf (buf, sizeof(buf), "%s/.signature", mypath); - if ((fp = fopen (buf, "r")) != NULL - && fgets (buf, sizeof buf, fp) != NULL) { - fclose (fp); - if (cp = strchr (buf, '\n')) - *cp = 0; - m_putenv ("SIGNATURE", buf); - } - } -#endif /* UCI */ - - for (msgnum = 0; msgnum < msgp; msgnum++) - if (stat (msgs[msgnum], &st) == NOTOK) - adios (msgs[msgnum], "unable to stat draft file"); - - if ((annotext = getenv ("mhannotate")) == NULL || *annotext == 0) - annotext = NULL; - if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != 0)) - inplace = atoi (cp); - if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == 0) - altmsg = NULL; /* used by dist interface - see below */ - - if ((cp = getenv ("mhdist")) - && *cp - && (distsw = atoi (cp)) - && altmsg) { - vec[vecp++] = "-dist"; - distfile = getcpy (m_mktemp2 (altmsg, invo_name, NULL, NULL)); - if (link (altmsg, distfile) == NOTOK) { - if (errno != EXDEV -#ifdef EISREMOTE - && errno != EISREMOTE -#endif /* EISREMOTE */ - ) - adios (distfile, "unable to link %s to", altmsg); - free (distfile); - distfile = getcpy (m_mktemp2(NULL, invo_name, NULL, NULL)); - { - int in, out; - struct stat st; - - if ((in = open (altmsg, O_RDONLY)) == NOTOK) - adios (altmsg, "unable to open"); - fstat(in, &st); - if ((out = creat (distfile, (int) st.st_mode & 0777)) == NOTOK) - adios (distfile, "unable to write"); - cpydata (in, out, altmsg, distfile); - close (in); - close (out); - } - } - } else { - distfile = NULL; - } - - if (altmsg == NULL || stat (altmsg, &st) == NOTOK) { - st.st_mtime = 0; - st.st_dev = 0; - st.st_ino = 0; - } - if (pushsw) - push (); - - status = 0; - vec[0] = r1bindex (postproc, '/'); - closefds (3); - - for (msgnum = 0; msgnum < msgp; msgnum++) { - switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach, - attachformat)) { - case DONE: - done (++status); - case NOTOK: - status++; /* fall */ - case OK: + vec[vecp] = NULL; + + switch (child_id = fork()) { + case -1: + /* oops -- fork error */ + adios("fork", "unable to"); + break; /* NOT REACHED */ + + case 0: + /* child process -- send it */ + execvp(*vec, vec); + fprintf(stderr, "unable to exec "); + perror(*vec); + _exit(-1); + break; /* NOT REACHED */ + + default: + /* parent process -- wait for it */ + if ((status = pidwait(child_id, NOTOK)) == OK) { + if (annotext) { + anno(st); + } + } else { + /* spost failed */ + advise(NULL, "message not delivered to anyone"); + if (distfile) { + unlink(drft); + if (rename(backup, drft) == NOTOK) { + advise(drft, "unable to rename %s to", + backup); + } + } + } break; } - } - context_save (); /* save the context file */ - done (status); - return 1; + return status; +} + + +static void +anno(struct stat *st) +{ + struct stat st2; + char *msgs, *folder; + char buf[BUFSIZ]; + + if (altmsg && (stat(altmsg, &st2) == NOTOK || + st->st_mtime != st2.st_mtime || + st->st_dev != st2.st_dev || + st->st_ino != st2.st_ino)) { + if (debugsw) { + admonish(NULL, "$mhaltmsg mismatch"); + } + return; + } + + if (!(folder = getenv("mhfolder")) || !*folder) { + if (debugsw) { + admonish(NULL, "$mhfolder not set"); + } + return; + } + if (!(msgs = getenv("mhmessages")) || !*msgs) { + if (debugsw) { + admonish(NULL, "$mhmessages not set"); + } + return; + } + if (debugsw) { + advise(NULL, "annotate as `%s': %s %s", annotext, + folder, msgs); + } + snprintf(buf, sizeof buf, "anno -comp '%s' '+%s' %s", + annotext, folder, msgs); + if (system(buf) != 0) { + advise(NULL, "unable to annotate"); + } +} + + +static void +armed_done(int status) +{ + longjmp(env, status ? status : NOTOK); + + exit(status); } diff --git a/uip/sendfiles.sh b/uip/sendfiles.sh new file mode 100755 index 0000000..40d8f72 --- /dev/null +++ b/uip/sendfiles.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Send multiples files non-interactively + +# adjust if needed +attachment_header='Attach' + + +if [ $# -lt 3 ]; then + echo 'usage: sendfiles RECIPIENT SUBJECT FILES...' 1>&2 + exit 1; +fi + +rcpt="$1" +shift +subject="$1" +shift + +cat 1>&2 <"$draft" <>"$draft" +done + +send "$draft" diff --git a/uip/sendsbr.c b/uip/sendsbr.c deleted file mode 100644 index 57ef007..0000000 --- a/uip/sendsbr.c +++ /dev/null @@ -1,1091 +0,0 @@ - -/* - * sendsbr.c -- routines to help WhatNow/Send along - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif -#endif - -int debugsw = 0; /* global */ -int forwsw = 1; -int inplace = 1; -int pushsw = 0; -int splitsw = -1; -int unique = 0; -int verbsw = 0; - -char *altmsg = NULL; /* .. */ -char *annotext = NULL; -char *distfile = NULL; - -static jmp_buf env; - -static char body_file_name[MAXPATHLEN + 1]; /* name of temporary file for body content */ -static char composition_file_name[MAXPATHLEN + 1]; /* name of mhbuild composition temporary file */ -static int field_size; /* size of header field buffer */ -static char *field; /* header field buffer */ -static FILE *draft_file; /* draft file pointer */ -static FILE *body_file; /* body file pointer */ -static FILE *composition_file; /* composition file pointer */ - -/* - * external prototypes - */ -int sendsbr (char **, int, char *, struct stat *, int, char *, int); -char *getusername (void); - -/* - * static prototypes - */ -static void armed_done (int) NORETURN; -static void alert (char *, int); -static int tmp_fd (void); -static void anno (int, struct stat *); -static void annoaux (int); -static int splitmsg (char **, int, char *, struct stat *, int); -static int sendaux (char **, int, char *, struct stat *); - -static int attach(char *, char *, int); -static void clean_up_temporary_files(void); -static int get_line(void); -static void make_mime_composition_file_entry(char *, int); - - -/* - * Entry point into (back-end) routines to send message. - */ - -int -sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name, int attachformat) -{ - int status; - char buffer[BUFSIZ], file[BUFSIZ]; - struct stat sts; - char *original_draft; /* name of original draft file */ - char *p; /* string pointer for building file name */ - - /* - * Save the original name of the draft file. The name of the draft file is changed - * to a temporary file containing the built MIME message if there are attachments. - * We need the original name so that it can be renamed after the message is sent. - */ - - original_draft = drft; - - /* - * There might be attachments if a header field name for attachments is supplied. - * Convert the draft to a MIME message. Use the mhbuild composition file for the - * draft if there was a successful conversion because that now contains the MIME - * message. A nice side effect of this is that it leaves the original draft file - * untouched so that it can be retrieved and modified if desired. - */ - - if (attachment_header_field_name != (char *)0) { - switch (attach(attachment_header_field_name, drft, attachformat)) { - case OK: - drft = composition_file_name; - break; - - case NOTOK: - return (NOTOK); - - case DONE: - break; - } - } - - done=armed_done; - switch (setjmp (env)) { - case OK: - /* - * If given -push and -unique (which is undocumented), then - * rename the draft file. I'm not quite sure why. - */ - if (pushsw && unique) { - char *cp = m_mktemp2(drft, invo_name, NULL, NULL); - if (cp == NULL) { - adios ("sendsbr", "unable to create temporary file"); - } - if (rename (drft, strncpy(file, cp, sizeof(file))) == NOTOK) - adios (file, "unable to rename %s to", drft); - drft = file; - } - - /* - * Check if we need to split the message into - * multiple messages of type "message/partial". - */ - if (splitsw >= 0 && !distfile && stat (drft, &sts) != NOTOK - && sts.st_size >= CPERMSG) { - status = splitmsg (vec, vecp, drft, st, splitsw) ? NOTOK : OK; - } else { - status = sendaux (vec, vecp, drft, st) ? NOTOK : OK; - } - - /* rename the original draft */ - if (rename_drft && status == OK && - rename (original_draft, strncpy (buffer, m_backup (original_draft), sizeof(buffer))) == NOTOK) - advise (buffer, "unable to rename %s to", drft); - break; - - default: - status = DONE; - break; - } - - done=exit; - if (distfile) - unlink (distfile); - - /* - * Get rid of any temporary files that we created for attachments. Also get rid of - * the renamed composition file that mhbuild leaves as a turd. It looks confusing, - * but we use the body file name to help build the renamed composition file name. - */ - - if (drft == composition_file_name) { - clean_up_temporary_files(); - - if (strlen(composition_file_name) >= sizeof (composition_file_name) - 6) - advise((char *)0, "unable to remove original composition file."); - - else { - if ((p = strrchr(composition_file_name, '/')) == (char *)0) - p = composition_file_name; - else - p++; - - (void)strcpy(body_file_name, p); - *p++ = ','; - (void)strcpy(p, body_file_name); - (void)strcat(p, ".orig"); - - (void)unlink(composition_file_name); - } - } - - return status; -} - -static int -attach(char *attachment_header_field_name, char *draft_file_name, - int attachformat) -{ - char buf[MAXPATHLEN + 6]; /* miscellaneous buffer */ - int c; /* current character for body copy */ - int has_attachment; /* draft has at least one attachment */ - int has_body; /* draft has a message body */ - int length; /* length of attachment header field name */ - char *p; /* miscellaneous string pointer */ - - /* - * Open up the draft file. - */ - - if ((draft_file = fopen(draft_file_name, "r")) == (FILE *)0) - adios((char *)0, "can't open draft file `%s'.", draft_file_name); - - /* - * Allocate a buffer to hold the header components as they're read in. - * This buffer might need to be quite large, so we grow it as needed. - */ - - field = (char *)mh_xmalloc(field_size = 256); - - /* - * Scan the draft file for a header field name that matches the -attach - * argument. The existence of one indicates that the draft has attachments. - * Bail out if there are no attachments because we're done. Read to the - * end of the headers even if we have no attachments. - */ - - length = strlen(attachment_header_field_name); - - has_attachment = 0; - - while (get_line() != EOF && *field != '\0' && *field != '-') - if (strncasecmp(field, attachment_header_field_name, length) == 0 && field[length] == ':') - has_attachment = 1; - - if (has_attachment == 0) - return (DONE); - - /* - * We have at least one attachment. Look for at least one non-blank line - * in the body of the message which indicates content in the body. - */ - - has_body = 0; - - while (get_line() != EOF) { - for (p = field; *p != '\0'; p++) { - if (*p != ' ' && *p != '\t') { - has_body = 1; - break; - } - } - - if (has_body) - break; - } - - /* - * Make names for the temporary files. - */ - - (void)strncpy(body_file_name, - m_mktemp(m_maildir(invo_name), NULL, NULL), - sizeof (body_file_name)); - (void)strncpy(composition_file_name, - m_mktemp(m_maildir(invo_name), NULL, NULL), - sizeof (composition_file_name)); - - if (has_body) - body_file = fopen(body_file_name, "w"); - - composition_file = fopen(composition_file_name, "w"); - - if ((has_body && body_file == (FILE *)0) || composition_file == (FILE *)0) { - clean_up_temporary_files(); - adios((char *)0, "unable to open all of the temporary files."); - } - - /* - * Start at the beginning of the draft file. Copy all non-attachment header fields - * to the temporary composition file. Then add the dashed line separator. - */ - - rewind(draft_file); - - while (get_line() != EOF && *field != '\0' && *field != '-') - if (strncasecmp(field, attachment_header_field_name, length) != 0 || field[length] != ':') - (void)fprintf(composition_file, "%s\n", field); - - (void)fputs("--------\n", composition_file); - - /* - * Copy the message body to a temporary file. - */ - - if (has_body) { - while ((c = getc(draft_file)) != EOF) - putc(c, body_file); - - (void)fclose(body_file); - } - - /* - * Add a mhbuild MIME composition file line for the body if there was one. - */ - - if (has_body) - make_mime_composition_file_entry(body_file_name, attachformat); - - /* - * Now, go back to the beginning of the draft file and look for header fields - * that specify attachments. Add a mhbuild MIME composition file for each. - */ - - rewind(draft_file); - - while (get_line() != EOF && *field != '\0' && *field != '-') { - if (strncasecmp(field, attachment_header_field_name, length) == 0 && field[length] == ':') { - for (p = field + length + 1; *p == ' ' || *p == '\t'; p++) - ; - - make_mime_composition_file_entry(p, attachformat); - } - } - - (void)fclose(composition_file); - - /* - * We're ready to roll! Run mhbuild on the composition file. Note that mhbuild - * is in the context as buildmimeproc. - */ - - (void)sprintf(buf, "%s %s", buildmimeproc, composition_file_name); - - if (system(buf) != 0) { - clean_up_temporary_files(); - return (NOTOK); - } - - return (OK); -} - -static void -clean_up_temporary_files(void) -{ - (void)unlink(body_file_name); - (void)unlink(composition_file_name); - - return; -} - -static int -get_line(void) -{ - int c; /* current character */ - int n; /* number of bytes in buffer */ - char *p; /* buffer pointer */ - - /* - * Get a line from the input file, growing the field buffer as needed. We do this - * so that we can fit an entire line in the buffer making it easy to do a string - * comparison on both the field name and the field body which might be a long path - * name. - */ - - for (n = 0, p = field; (c = getc(draft_file)) != EOF; *p++ = c) { - if (c == '\n' && (c = getc(draft_file)) != ' ' && c != '\t') { - (void)ungetc(c, draft_file); - c = '\n'; - break; - } - - if (++n >= field_size - 1) { - field = (char *)mh_xrealloc((void *)field, field_size += 256); - - p = field + n - 1; - } - } - - /* - * NUL-terminate the field.. - */ - - *p = '\0'; - - return (c); -} - -static void -make_mime_composition_file_entry(char *file_name, int attachformat) -{ - int binary; /* binary character found flag */ - int c; /* current character */ - char cmd[MAXPATHLEN + 6]; /* file command buffer */ - char *content_type; /* mime content type */ - FILE *fp; /* content and pipe file pointer */ - struct node *np; /* context scan node pointer */ - char *p; /* miscellaneous string pointer */ - struct stat st; /* file status buffer */ - - content_type = (char *)0; - - /* - * Check the file name for a suffix. Scan the context for that suffix on a - * mhshow-suffix- entry. We use these entries to be compatible with mhnshow, - * and there's no reason to make the user specify each suffix twice. Context - * entries of the form "mhshow-suffix-contenttype" in the name have the suffix - * in the field, including the dot. - */ - - if ((p = strrchr(file_name, '.')) != (char *)0) { - for (np = m_defs; np; np = np->n_next) { - if (strncasecmp(np->n_name, "mhshow-suffix-", 14) == 0 && mh_strcasecmp(p, np->n_field) == 0) { - content_type = np->n_name + 14; - break; - } - } - } - - /* - * No content type was found, either because there was no matching entry in the - * context or because the file name has no suffix. Open the file and check for - * non-ASCII characters. Choose the content type based on this check. - */ - - if (content_type == (char *)0) { - if ((fp = fopen(file_name, "r")) == (FILE *)0) { - clean_up_temporary_files(); - adios((char *)0, "unable to access file \"%s\"", file_name); - } - - binary = 0; - - while ((c = getc(fp)) != EOF) { - if (c > 127 || c < 0) { - binary = 1; - break; - } - } - - (void)fclose(fp); - - content_type = binary ? "application/octet-stream" : "text/plain"; - } - - /* - * Make sure that the attachment file exists and is readable. Append a mhbuild - * directive to the draft file. This starts with the content type. Append a - * file name attribute and a private x-unix-mode attribute. Also append a - * description obtained (if possible) by running the "file" command on the file. - */ - - if (stat(file_name, &st) == -1 || access(file_name, R_OK) != 0) { - clean_up_temporary_files(); - adios((char *)0, "unable to access file \"%s\"", file_name); - } - - switch (attachformat) { - case 0: - /* Insert name, file mode, and Content-Id. */ - (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho", - content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, (unsigned short)(st.st_mode & 0777)); - - if (strlen(file_name) > MAXPATHLEN) { - clean_up_temporary_files(); - adios((char *)0, "attachment file name `%s' too long.", file_name); - } - - (void)sprintf(cmd, "file '%s'", file_name); - - if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp) != (char *)0) { - *strchr(cmd, '\n') = '\0'; - - /* - * The output of the "file" command is of the form - * - * file: description - * - * Strip off the "file:" and subsequent white space. - */ - - for (p = cmd; *p != '\0'; p++) { - if (*p == ':') { - for (p++; *p != '\0'; p++) { - if (*p != '\t') - break; - } - break; - } - } - - if (*p != '\0') - /* Insert Content-Description. */ - (void)fprintf(composition_file, " [ %s ]", p); - - (void)pclose(fp); - } - - break; - case 1: - if (stringdex (m_maildir(invo_name), file_name) == 0) { - /* Content had been placed by send into a temp file. - Don't generate Content-Disposition header, because - it confuses Microsoft Outlook, Build 10.0.6626, at - least. */ - (void) fprintf (composition_file, "#%s <>", content_type); - } else { - /* Suppress Content-Id, insert simple Content-Disposition. */ - (void) fprintf (composition_file, - "#%s; name=\"%s\" <>{attachment}", - content_type, - ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1); - } - - break; - case 2: - if (stringdex (m_maildir(invo_name), file_name) == 0) { - /* Content had been placed by send into a temp file. - Don't generate Content-Disposition header, because - it confuses Microsoft Outlook, Build 10.0.6626, at - least. */ - (void) fprintf (composition_file, "#%s <>", content_type); - } else { - /* Suppress Content-Id, insert Content-Disposition with - modification date. */ - (void) fprintf (composition_file, - "#%s; name=\"%s\" <>{attachment; modification-date=\"%s\"}", - content_type, - ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, - dtime (&st.st_mtime, 0)); - } - - break; - default: - adios ((char *)0, "unsupported attachformat %d", attachformat); - } - - /* - * Finish up with the file name. - */ - - (void)fprintf(composition_file, " %s\n", file_name); - - return; -} - -/* - * Split large message into several messages of - * type "message/partial" and send them. - */ - -static int -splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) -{ - int compnum, nparts, partno, state, status; - long pos, start; - time_t clock; - char *cp, *dp, buffer[BUFSIZ], msgid[BUFSIZ]; - char subject[BUFSIZ]; - char name[NAMESZ], partnum[BUFSIZ]; - FILE *in; - - if ((in = fopen (drft, "r")) == NULL) - adios (drft, "unable to open for reading"); - - cp = dp = NULL; - start = 0L; - - /* - * Scan through the message and examine the various header fields, - * as well as locate the beginning of the message body. - */ - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buffer, sizeof(buffer), in)) { - case FLD: - case FLDPLUS: - case FLDEOF: - compnum++; - - /* - * This header field is discarded. - */ - if (!mh_strcasecmp (name, "Message-ID")) { - while (state == FLDPLUS) - state = m_getfld (state, name, buffer, sizeof(buffer), in); - } else if (uprf (name, XXX_FIELD_PRF) - || !mh_strcasecmp (name, VRSN_FIELD) - || !mh_strcasecmp (name, "Subject") - || !mh_strcasecmp (name, "Encrypted")) { - /* - * These header fields are copied to the enclosed - * header of the first message in the collection - * of message/partials. For the "Subject" header - * field, we also record it, so that a modified - * version of it, can be copied to the header - * of each messsage/partial in the collection. - */ - if (!mh_strcasecmp (name, "Subject")) { - size_t sublen; - - strncpy (subject, buffer, BUFSIZ); - sublen = strlen (subject); - if (sublen > 0 && subject[sublen - 1] == '\n') - subject[sublen - 1] = '\0'; - } - - dp = add (concat (name, ":", buffer, NULL), dp); - while (state == FLDPLUS) { - state = m_getfld (state, name, buffer, sizeof(buffer), in); - dp = add (buffer, dp); - } - } else { - /* - * These header fields are copied to the header of - * each message/partial in the collection. - */ - cp = add (concat (name, ":", buffer, NULL), cp); - while (state == FLDPLUS) { - state = m_getfld (state, name, buffer, sizeof(buffer), in); - cp = add (buffer, cp); - } - } - - if (state != FLDEOF) { - start = ftell (in) + 1; - continue; - } - /* else fall... */ - - case BODY: - case BODYEOF: - case FILEEOF: - break; - - case LENERR: - case FMTERR: - adios (NULL, "message format error in component #%d", compnum); - - default: - adios (NULL, "getfld () returned %d", state); - } - - break; - } - if (cp == NULL) - adios (NULL, "headers missing from draft"); - - nparts = 1; - pos = start; - while (fgets (buffer, sizeof(buffer) - 1, in)) { - long len; - - if ((pos += (len = strlen (buffer))) > CPERMSG) { - nparts++; - pos = len; - } - } - - /* Only one part, nothing to split */ - if (nparts == 1) { - free (cp); - if (dp) - free (dp); - - fclose (in); - return sendaux (vec, vecp, drft, st); - } - - if (!pushsw) { - printf ("Sending as %d Partial Messages\n", nparts); - fflush (stdout); - } - status = OK; - - vec[vecp++] = "-partno"; - vec[vecp++] = partnum; - if (delay == 0) - vec[vecp++] = "-queued"; - - time (&clock); - snprintf (msgid, sizeof(msgid), "<%d.%ld@%s>", - (int) getpid(), (long) clock, LocalName()); - - fseek (in, start, SEEK_SET); - for (partno = 1; partno <= nparts; partno++) { - char tmpdrf[BUFSIZ]; - FILE *out; - - char *cp = m_mktemp2(drft, invo_name, NULL, &out); - if (cp == NULL) { - adios (drft, "unable to create temporary file for"); - } - strncpy(tmpdrf, cp, sizeof(tmpdrf)); - chmod (tmpdrf, 0600); - - /* - * Output the header fields - */ - fputs (cp, out); - fprintf (out, "Subject: %s (part %d of %d)\n", subject, partno, nparts); - fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE); - fprintf (out, "%s: message/partial; id=\"%s\";\n", TYPE_FIELD, msgid); - fprintf (out, "\tnumber=%d; total=%d\n", partno, nparts); - fprintf (out, "%s: part %d of %d\n\n", DESCR_FIELD, partno, nparts); - - /* - * If this is the first in the collection, output the - * header fields we are encapsulating at the beginning - * of the body of the first message. - */ - if (partno == 1) { - if (dp) - fputs (dp, out); - fprintf (out, "Message-ID: %s\n", msgid); - fprintf (out, "\n"); - } - - pos = 0; - for (;;) { - long len; - - if (!fgets (buffer, sizeof(buffer) - 1, in)) { - if (partno == nparts) - break; - adios (NULL, "premature eof"); - } - - if ((pos += (len = strlen (buffer))) > CPERMSG) { - fseek (in, -len, SEEK_CUR); - break; - } - - fputs (buffer, out); - } - - if (fflush (out)) - adios (tmpdrf, "error writing to"); - - fclose (out); - - if (!pushsw && verbsw) { - printf ("\n"); - fflush (stdout); - } - - /* Pause here, if a delay is specified */ - if (delay > 0 && 1 < partno && partno <= nparts) { - if (!pushsw) { - printf ("pausing %d seconds before sending part %d...\n", - delay, partno); - fflush (stdout); - } - sleep ((unsigned int) delay); - } - - snprintf (partnum, sizeof(partnum), "%d", partno); - status = sendaux (vec, vecp, tmpdrf, st); - unlink (tmpdrf); - if (status != OK) - break; - - /* - * This is so sendaux will only annotate - * the altmsg the first time it is called. - */ - annotext = NULL; - } - - free (cp); - if (dp) - free (dp); - - fclose (in); /* close the draft */ - return status; -} - - -/* - * Annotate original message, and - * call `postproc' to send message. - */ - -static int -sendaux (char **vec, int vecp, char *drft, struct stat *st) -{ - pid_t child_id; - int i, status, fd, fd2; - char backup[BUFSIZ], buf[BUFSIZ]; - - fd = pushsw ? tmp_fd () : NOTOK; - fd2 = NOTOK; - - vec[vecp++] = drft; - if (annotext) { - if ((fd2 = tmp_fd ()) != NOTOK) { - vec[vecp++] = "-idanno"; - snprintf (buf, sizeof(buf), "%d", fd2); - vec[vecp++] = buf; - } else { - admonish (NULL, "unable to create file for annotation list"); - } - } - if (distfile && distout (drft, distfile, backup) == NOTOK) - done (1); - vec[vecp] = NULL; - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case -1: - /* oops -- fork error */ - adios ("fork", "unable to"); - break; /* NOT REACHED */ - - case 0: - /* - * child process -- send it - * - * If fd is ok, then we are pushing and fd points to temp - * file, so capture anything on stdout and stderr there. - */ - if (fd != NOTOK) { - dup2 (fd, fileno (stdout)); - dup2 (fd, fileno (stderr)); - close (fd); - } - execvp (postproc, vec); - fprintf (stderr, "unable to exec "); - perror (postproc); - _exit (-1); - break; /* NOT REACHED */ - - default: - /* - * parent process -- wait for it - */ - if ((status = pidwait(child_id, NOTOK)) == OK) { - if (annotext && fd2 != NOTOK) - anno (fd2, st); - } else { - /* - * If postproc failed, and we have good fd (which means - * we pushed), then mail error message (and possibly the - * draft) back to the user. - */ - if (fd != NOTOK) { - alert (drft, fd); - close (fd); - } else { - advise (NULL, "message not delivered to anyone"); - } - if (annotext && fd2 != NOTOK) - close (fd2); - if (distfile) { - unlink (drft); - if (rename (backup, drft) == NOTOK) - advise (drft, "unable to rename %s to", backup); - } - } - break; - } - - return status; -} - - -/* - * Mail error notification (and possibly a copy of the - * message) back to the user, using the mailproc - */ - -static void -alert (char *file, int out) -{ - pid_t child_id; - int i, in; - char buf[BUFSIZ]; - - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case NOTOK: - /* oops -- fork error */ - advise ("fork", "unable to"); - - case OK: - /* child process -- send it */ - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); - if (forwsw) { - if ((in = open (file, O_RDONLY)) == NOTOK) { - admonish (file, "unable to re-open"); - } else { - lseek (out, (off_t) 0, SEEK_END); - strncpy (buf, "\nMessage not delivered to anyone.\n", sizeof(buf)); - write (out, buf, strlen (buf)); - strncpy (buf, "\n------- Unsent Draft\n\n", sizeof(buf)); - write (out, buf, strlen (buf)); - cpydgst (in, out, file, "temporary file"); - close (in); - strncpy (buf, "\n------- End of Unsent Draft\n", sizeof(buf)); - write (out, buf, strlen (buf)); - if (rename (file, strncpy (buf, m_backup (file), sizeof(buf))) == NOTOK) - admonish (buf, "unable to rename %s to", file); - } - } - lseek (out, (off_t) 0, SEEK_SET); - dup2 (out, fileno (stdin)); - close (out); - /* create subject for error notification */ - snprintf (buf, sizeof(buf), "send failed on %s", - forwsw ? "enclosed draft" : file); - - execlp (mailproc, r1bindex (mailproc, '/'), getusername (), - "-subject", buf, NULL); - fprintf (stderr, "unable to exec "); - perror (mailproc); - _exit (-1); - - default: /* no waiting... */ - break; - } -} - - -static int -tmp_fd (void) -{ - int fd; - char *tfile = NULL; - - tfile = m_mktemp2(NULL, invo_name, &fd, NULL); - if (tfile == NULL) return NOTOK; - fchmod(fd, 0600); - - if (debugsw) - advise (NULL, "temporary file %s selected", tfile); - else - if (unlink (tfile) == NOTOK) - advise (tfile, "unable to remove"); - - return fd; -} - - -static void -anno (int fd, struct stat *st) -{ - pid_t child_id; - sigset_t set, oset; - static char *cwd = NULL; - struct stat st2; - - if (altmsg && - (stat (altmsg, &st2) == NOTOK - || st->st_mtime != st2.st_mtime - || st->st_dev != st2.st_dev - || st->st_ino != st2.st_ino)) { - if (debugsw) - admonish (NULL, "$mhaltmsg mismatch"); - return; - } - - child_id = debugsw ? NOTOK : fork (); - switch (child_id) { - case NOTOK: /* oops */ - if (!debugsw) - advise (NULL, - "unable to fork, so doing annotations by hand..."); - if (cwd == NULL) - cwd = getcpy (pwd ()); - - case OK: - /* block a few signals */ - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - - annoaux (fd); - if (child_id == OK) - _exit (0); - - /* reset the signal mask */ - SIGPROCMASK (SIG_SETMASK, &oset, &set); - - chdir (cwd); - break; - - default: /* no waiting... */ - close (fd); - break; - } -} - - -static void -annoaux (int fd) -{ - int fd2, fd3, msgnum; - char *cp, *folder, *maildir; - char buffer[BUFSIZ], **ap; - FILE *fp; - struct msgs *mp; - - if ((folder = getenv ("mhfolder")) == NULL || *folder == 0) { - if (debugsw) - admonish (NULL, "$mhfolder not set"); - return; - } - maildir = m_maildir (folder); - if (chdir (maildir) == NOTOK) { - if (debugsw) - admonish (maildir, "unable to change directory to"); - return; - } - if (!(mp = folder_read (folder))) { - if (debugsw) - admonish (NULL, "unable to read folder %s", folder); - return; - } - - /* check for empty folder */ - if (mp->nummsg == 0) { - if (debugsw) - admonish (NULL, "no messages in %s", folder); - goto oops; - } - - if ((cp = getenv ("mhmessages")) == NULL || *cp == 0) { - if (debugsw) - admonish (NULL, "$mhmessages not set"); - goto oops; - } - if (!debugsw /* MOBY HACK... */ - && pushsw - && (fd3 = open ("/dev/null", O_RDWR)) != NOTOK - && (fd2 = dup (fileno (stderr))) != NOTOK) { - dup2 (fd3, fileno (stderr)); - close (fd3); - } - else - fd2 = NOTOK; - for (ap = brkstring (cp = getcpy (cp), " ", NULL); *ap; ap++) - m_convert (mp, *ap); - free (cp); - if (fd2 != NOTOK) - dup2 (fd2, fileno (stderr)); - if (mp->numsel == 0) { - if (debugsw) - admonish (NULL, "no messages to annotate"); - goto oops; - } - - lseek (fd, (off_t) 0, SEEK_SET); - if ((fp = fdopen (fd, "r")) == NULL) { - if (debugsw) - admonish (NULL, "unable to fdopen annotation list"); - goto oops; - } - cp = NULL; - while (fgets (buffer, sizeof(buffer), fp) != NULL) - cp = add (buffer, cp); - fclose (fp); - - if (debugsw) - advise (NULL, "annotate%s with %s: \"%s\"", - inplace ? " inplace" : "", annotext, cp); - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - if (debugsw) - advise (NULL, "annotate message %d", msgnum); - annotate (m_name (msgnum), annotext, cp, inplace, 1, -2, 0); - } - } - - free (cp); - -oops: - folder_free (mp); /* free folder/message structure */ -} - - -static void -armed_done (int status) -{ - longjmp (env, status ? status : NOTOK); - - exit (status); -} diff --git a/uip/show.c b/uip/show.c deleted file mode 100644 index a59e10c..0000000 --- a/uip/show.c +++ /dev/null @@ -1,548 +0,0 @@ - -/* - * show.c -- show/list messages - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include - -static struct swit switches[] = { -#define CHECKMIMESW 0 - { "checkmime", 0 }, -#define NOCHECKMIMESW 1 - { "nocheckmime", 0 }, -#define HEADSW 2 - { "header", 0 }, -#define NHEADSW 3 - { "noheader", 0 }, -#define FORMSW 4 - { "form formfile", 0 }, -#define PROGSW 5 - { "moreproc program", 0 }, -#define NPROGSW 6 - { "nomoreproc", 0 }, -#define LENSW 7 - { "length lines", 0 }, -#define WIDTHSW 8 - { "width columns", 0 }, -#define SHOWSW 9 - { "showproc program", 0 }, -#define SHOWMIMESW 10 - { "showmimeproc program", 0 }, -#define NSHOWSW 11 - { "noshowproc", 0 }, -#define DRFTSW 12 - { "draft", 0 }, -#define FILESW 13 - { "file file", -4 }, /* interface from showfile */ -#define VERSIONSW 14 - { "version", 0 }, -#define HELPSW 15 - { "help", 0 }, - { NULL, 0 } -}; - -/* - * static prototypes - */ -static int is_nontext(char *); - -/* prototype from mhlsbr.c */ -int mhl (int, char **); - -#define SHOW 0 -#define NEXT 1 -#define PREV 2 - - -int -main (int argc, char **argv) -{ - int draftsw = 0, headersw = 1, msgp = 0; - int nshow = 0, checkmime = 1, mime; - int vecp = 1, procp = 1, isdf = 0, mode = SHOW, msgnum; - char *cp, *maildir, *file = NULL, *folder = NULL, *proc; - char buf[BUFSIZ], **argp, **arguments; - char *msgs[MAXARGS], *vec[MAXARGS]; - struct msgs *mp = NULL; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - if (!mh_strcasecmp (invo_name, "next")) { - mode = NEXT; - } else if (!mh_strcasecmp (invo_name, "prev")) { - mode = PREV; - } - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - case NPROGSW: - vec[vecp++] = --cp; - continue; - - case HELPSW: - snprintf (buf, sizeof(buf), - "%s [+folder] %s[switches] [switches for showproc]", - invo_name, mode == SHOW ? "[msgs] ": ""); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DRFTSW: - if (file) - adios (NULL, "only one file at a time!"); - draftsw++; - if (mode == SHOW) - continue; -usage: - adios (NULL, - "usage: %s [+folder] [switches] [switches for showproc]", - invo_name); - case FILESW: - if (mode != SHOW) - goto usage; - if (draftsw || file) - adios (NULL, "only one file at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - file = path (cp, TFILE); - continue; - - case HEADSW: - headersw++; - continue; - case NHEADSW: - headersw = 0; - continue; - - case FORMSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = getcpy (etcpath(cp)); - continue; - - case PROGSW: - case LENSW: - case WIDTHSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; - - case SHOWSW: - if (!(showproc = *argp++) || *showproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nshow = 0; - continue; - case NSHOWSW: - nshow++; - continue; - - case SHOWMIMESW: - if (!(showmimeproc = *argp++) || *showmimeproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nshow = 0; - continue; - case CHECKMIMESW: - checkmime++; - continue; - case NOCHECKMIMESW: - checkmime = 0; - continue; - } - } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else { - if (mode != SHOW) - goto usage; - else - msgs[msgp++] = cp; - } - } - procp = vecp; - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - - if (draftsw || file) { - if (msgp) - adios (NULL, "only one file at a time!"); - vec[vecp++] = draftsw - ? getcpy (m_draft (folder, msgp ? msgs[0] : NULL, 1, &isdf)) - : file; - goto go_to_it; - } - -#ifdef WHATNOW - if (!msgp && !folder && mode == SHOW && (cp = getenv ("mhdraft")) && *cp) { - draftsw++; - vec[vecp++] = cp; - goto go_to_it; - } -#endif /* WHATNOW */ - - if (!msgp) { - switch (mode) { - case NEXT: - msgs[msgp++] = "next"; - break; - case PREV: - msgs[msgp++] = "prev"; - break; - default: - msgs[msgp++] = "cur"; - break; - } - } - - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) - done (1); - - /* - * Set the SELECT_UNSEEN bit for all the SELECTED messages, - * since we will use that as a tag to know which messages - * to remove from the "unseen" sequence. - */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected(mp, msgnum)) - set_unseen (mp, msgnum); - - seq_setprev (mp); /* set the Previous-Sequence */ - seq_setunseen (mp, 1); /* unset the Unseen-Sequence */ - - if (mp->numsel > MAXARGS - 2) - adios (NULL, "more than %d messages for show exec", MAXARGS - 2); - - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected(mp, msgnum)) - vec[vecp++] = getcpy (m_name (msgnum)); - - seq_setcur (mp, mp->hghsel); /* update current message */ - seq_save (mp); /* synchronize sequences */ - context_replace (pfolder, folder); /* update current folder */ - context_save (); /* save the context file */ - - if (headersw && vecp == 2) - printf ("(Message %s:%s)\n", folder, vec[1]); - -go_to_it: ; - fflush (stdout); - - vec[vecp] = NULL; - - /* - * Decide which "proc" to use - */ - mime = 0; - if (nshow) { - proc = catproc; - } else { - /* check if any messages are non-text MIME messages */ - if (checkmime && !getenv ("NOMHNPROC")) { - if (!draftsw && !file) { - /* loop through selected messages and check for MIME */ - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) - if (is_selected (mp, msgnum) && is_nontext (m_name (msgnum))) { - mime = 1; - break; - } - } else { - /* check the file or draft for MIME */ - if (is_nontext (vec[vecp - 1])) - mime = 1; - } - } - - /* Set the "proc" */ - if (mime) - proc = showmimeproc; - else - proc = showproc; - } - - if (folder && !draftsw && !file) - m_putenv ("mhfolder", folder); - - /* - * For backward compatibility, if the "proc" is mhn, - * then add "-show" option. Add "-file" if showing - * file or draft. - */ - if (strcmp (r1bindex (proc, '/'), "mhn") == 0) { - if (draftsw || file) { - vec[vecp] = vec[vecp - 1]; - vec[vecp - 1] = "-file"; - vecp++; - } - vec[vecp++] = "-show"; - vec[vecp] = NULL; - } - - /* If the "proc" is "mhshow", add "-file" if showing file or draft. - */ - if (strcmp (r1bindex (proc, '/'), "mhshow") == 0 && (draftsw || file) ) { - vec[vecp] = vec[vecp - 1]; - vec[vecp - 1] = "-file"; - vec[++vecp] = NULL; - } - - /* - * If "proc" is mhl, then run it internally - * rather than exec'ing it. - */ - if (strcmp (r1bindex (proc, '/'), "mhl") == 0) { - vec[0] = "mhl"; - mhl (vecp, vec); - done (0); - } - - /* - * If you are not using a nmh command as your "proc", then - * add the path to the message names. Currently, we are just - * checking for mhn here, since we've already taken care of mhl. - */ - if (!strcmp (r1bindex (proc, '/'), "mhl") - && !draftsw - && !file - && chdir (maildir = concat (m_maildir (""), "/", NULL)) != NOTOK) { - mp->foldpath = concat (mp->foldpath, "/", NULL); - cp = ssequal (maildir, mp->foldpath) - ? mp->foldpath + strlen (maildir) - : mp->foldpath; - for (msgnum = procp; msgnum < vecp; msgnum++) - vec[msgnum] = concat (cp, vec[msgnum], NULL); - } - - vec[0] = r1bindex (proc, '/'); - execvp (proc, vec); - adios (proc, "unable to exec"); - return 0; /* dead code to satisfy the compiler */ -} - -/* - * Cheat: we are loaded with adrparse, which wants a routine called - * OfficialName(). We call adrparse:getm() with the correct arguments - * to prevent OfficialName() from being called. Hence, the following - * is to keep the loader happy. - */ - -char * -OfficialName (char *name) -{ - return name; -} - - -/* - * Check if a message or file contains any non-text parts - */ -static int -is_nontext (char *msgnam) -{ - int result, state; - unsigned char *bp, *dp; - char *cp; - char buf[BUFSIZ], name[NAMESZ]; - FILE *fp; - - if ((fp = fopen (msgnam, "r")) == NULL) - return 0; - - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - /* - * Check Content-Type field - */ - if (!mh_strcasecmp (name, TYPE_FIELD)) { - int passno; - char c; - - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); - cp = add (buf, cp); - } - bp = cp; - passno = 1; - -again: - for (; isspace (*bp); bp++) - continue; - if (*bp == '(') { - int i; - - for (bp++, i = 0;;) { - switch (*bp++) { - case '\0': -invalid: - result = 0; - goto out; - case '\\': - if (*bp++ == '\0') - goto invalid; - continue; - case '(': - i++; - /* and fall... */ - default: - continue; - case ')': - if (--i < 0) - break; - continue; - } - break; - } - } - if (passno == 2) { - if (*bp != '/') - goto invalid; - bp++; - passno = 3; - goto again; - } - for (dp = bp; istoken (*dp); dp++) - continue; - c = *dp; - *dp = '\0'; - if (!*bp) - goto invalid; - if (passno > 1) { - if ((result = (mh_strcasecmp (bp, "plain") != 0))) - goto out; - *dp = c; - for (dp++; isspace (*dp); dp++) - continue; - if (*dp) { - if ((result = !uprf (dp, "charset"))) - goto out; - dp += sizeof("charset") - 1; - while (isspace (*dp)) - dp++; - if (*dp++ != '=') - goto invalid; - while (isspace (*dp)) - dp++; - if (*dp == '"') { - if ((bp = strchr(++dp, '"'))) - *bp = '\0'; - } else { - for (bp = dp; *bp; bp++) - if (!istoken (*bp)) { - *bp = '\0'; - break; - } - } - } else { - /* Default character set */ - dp = "US-ASCII"; - } - /* Check the character set */ - result = !check_charset (dp, strlen (dp)); - } else { - if (!(result = (mh_strcasecmp (bp, "text") != 0))) { - *dp = c; - bp = dp; - passno = 2; - goto again; - } - } -out: - free (cp); - if (result) { - fclose (fp); - return result; - } - break; - } - - /* - * Check Content-Transfer-Encoding field - */ - if (!mh_strcasecmp (name, ENCODING_FIELD)) { - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); - cp = add (buf, cp); - } - for (bp = cp; isspace (*bp); bp++) - continue; - for (dp = bp; istoken (*dp); dp++) - continue; - *dp = '\0'; - result = (mh_strcasecmp (bp, "7bit") - && mh_strcasecmp (bp, "8bit") - && mh_strcasecmp (bp, "binary")); - - free (cp); - if (result) { - fclose (fp); - return result; - } - break; - } - - /* - * Just skip the rest of this header - * field and go to next one. - */ - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); - break; - - /* - * We've passed the message header, - * so message is just text. - */ - default: - fclose (fp); - return 0; - } - } -} diff --git a/uip/slocal.c b/uip/slocal.c index e6880fe..107117f 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -1,32 +1,25 @@ - /* - * slocal.c -- asynchronously filter and deliver new mail - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** slocal.c -- asynchronously filter and deliver new mail +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ /* - * Under sendmail, users should add the line - * - * "| /usr/local/nmh/lib/slocal" - * - * to their $HOME/.forward file. - * - */ - -/* Changed to use getutent() and friends. Assumes that when getutent() exists, - * a number of other things also exist. Please check. - * Ruud de Rooij Sun, 28 May 2000 17:28:55 +0200 - */ +** Under sendmail, users should add the line +** +** "| /usr/local/mmh/bin/slocal" +** +** to their $HOME/.forward file. +** +*/ + #include -#include #include #include #include -#include #include #include @@ -37,73 +30,48 @@ #ifdef INITGROUPS_HEADER #include INITGROUPS_HEADER #else -/* On AIX 4.1, initgroups() is defined and even documented (giving the parameter - types as char* and int), but doesn't have a prototype in any of the system - header files. AIX 4.3, SunOS 4.1.3, and ULTRIX 4.2A have the same - problem. */ +/* +** On AIX 4.1, initgroups() is defined and even documented (giving the +** parameter types as char* and int), but doesn't have a prototype in any +** of the system header files. AIX 4.3, SunOS 4.1.3, and ULTRIX 4.2A have +** the same problem. +*/ extern int initgroups(char*, int); #endif -/* This define is needed for Berkeley db v2 and above to - * make the header file expose the 'historical' ndbm APIs. - * We define it unconditionally because this is simple and - * harmless. - */ -#define DB_DBM_HSEARCH 1 -#ifdef NDBM_HEADER -#include NDBM_HEADER -#endif - -#include - -#ifndef HAVE_GETUTENT -# ifndef UTMP_FILE -# ifdef _PATH_UTMP -# define UTMP_FILE _PATH_UTMP -# else -# define UTMP_FILE "/etc/utmp" -# endif -# endif -#endif - static struct swit switches[] = { -#define ADDRSW 0 - { "addr address", 0 }, -#define USERSW 1 - { "user name", 0 }, -#define FILESW 2 - { "file file", 0 }, -#define SENDERSW 3 - { "sender address", 0 }, -#define MAILBOXSW 4 - { "mailbox file", 0 }, -#define HOMESW 5 - { "home directory", -4 }, -#define INFOSW 6 - { "info data", 0 }, -#define MAILSW 7 - { "maildelivery file", 0 }, -#define VERBSW 8 - { "verbose", 0 }, -#define NVERBSW 9 - { "noverbose", 0 }, -#define SUPPRESSDUP 10 - { "suppressdup", 0 }, -#define NSUPPRESSDUP 11 - { "nosuppressdup", 0 }, -#define DEBUGSW 12 - { "debug", 0 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - { NULL, 0 } +#define ADDRSW 0 + { "addr address", 0 }, +#define USERSW 1 + { "user name", 0 }, +#define FILESW 2 + { "file file", 0 }, +#define SENDERSW 3 + { "sender address", 0 }, +#define MAILBOXSW 4 + { "mailbox file", 0 }, +#define HOMESW 5 + { "home directory", -4 }, +#define INFOSW 6 + { "info data", 0 }, +#define MAILSW 7 + { "maildelivery file", 0 }, +#define VERBSW 8 + { "verbose", 0 }, +#define NVERBSW 9 + { "noverbose", 2 }, +#define DEBUGSW 10 + { "debug", 0 }, +#define VERSIONSW 11 + { "Version", 0 }, +#define HELPSW 12 + { "help", 0 }, + { NULL, 0 } }; -static int globbed = 0; /* have we built "vars" table yet? */ -static int parsed = 0; /* have we built header field table yet */ -static int utmped = 0; /* have we scanned umtp(x) file yet */ -static int suppressdup = 0; /* are we suppressing duplicate messages? */ + +static int globbed = 0; /* have we built "vars" table yet? */ +static int parsed = 0; /* have we built header field table yet */ static int verbose = 0; static int debug = 0; @@ -113,1502 +81,1255 @@ static char *user = NULL; static char *info = NULL; static char *file = NULL; static char *sender = NULL; -static char *envelope = NULL; /* envelope information ("From " line) */ +static char *envelope = NULL; /* envelope information ("From " line) */ static char *mbox = NULL; static char *home = NULL; -static struct passwd *pw; /* passwd file entry */ +static struct passwd *pw; /* passwd file entry */ -static char ddate[BUFSIZ]; /* record the delivery date */ +static char ddate[BUFSIZ]; /* record the delivery date */ struct tws *now; static jmp_buf myctx; /* flags for pair->p_flags */ -#define P_NIL 0x00 -#define P_ADR 0x01 /* field is address */ -#define P_HID 0x02 /* special (fake) field */ -#define P_CHK 0x04 +#define P_NIL 0x00 +#define P_ADR 0x01 /* field is address */ +#define P_HID 0x02 /* special (fake) field */ +#define P_CHK 0x04 struct pair { - char *p_name; - char *p_value; - char p_flags; + char *p_name; + char *p_value; + char p_flags; }; -#define NVEC 100 +#define NVEC 100 /* - * Lookup table for matching fields and patterns - * in messages. The rest of the table is added - * when the message is parsed. - */ +** Lookup table for matching fields and patterns +** in messages. The rest of the table is added +** when the message is parsed. +*/ static struct pair hdrs[NVEC + 1] = { - { "source", NULL, P_HID }, - { "addr", NULL, P_HID }, - { "Return-Path", NULL, P_ADR }, - { "Reply-To", NULL, P_ADR }, - { "From", NULL, P_ADR }, - { "Sender", NULL, P_ADR }, - { "To", NULL, P_ADR }, - { "cc", NULL, P_ADR }, - { "Resent-Reply-To", NULL, P_ADR }, - { "Resent-From", NULL, P_ADR }, - { "Resent-Sender", NULL, P_ADR }, - { "Resent-To", NULL, P_ADR }, - { "Resent-cc", NULL, P_ADR }, - { NULL, NULL, 0 } + { "source", NULL, P_HID }, + { "addr", NULL, P_HID }, + { "Return-Path", NULL, P_ADR }, + { "Reply-To", NULL, P_ADR }, + { "From", NULL, P_ADR }, + { "Sender", NULL, P_ADR }, + { "To", NULL, P_ADR }, + { "cc", NULL, P_ADR }, + { "Resent-Reply-To", NULL, P_ADR }, + { "Resent-From", NULL, P_ADR }, + { "Resent-Sender", NULL, P_ADR }, + { "Resent-To", NULL, P_ADR }, + { "Resent-Cc", NULL, P_ADR }, + { NULL, NULL, 0 } }; /* - * The list of builtin variables to expand in a string - * before it is executed by the "pipe" or "qpipe" action. - */ +** The list of builtin variables to expand in a string +** before it is executed by the "pipe" or "qpipe" action. +*/ static struct pair vars[] = { - { "sender", NULL, P_NIL }, - { "address", NULL, P_NIL }, - { "size", NULL, P_NIL }, - { "reply-to", NULL, P_CHK }, - { "info", NULL, P_NIL }, - { NULL, NULL, 0 } + { "sender", NULL, P_NIL }, + { "address", NULL, P_NIL }, + { "size", NULL, P_NIL }, + { "reply-to", NULL, P_CHK }, + { "info", NULL, P_NIL }, + { NULL, NULL, 0 } }; extern char **environ; /* - * static prototypes - */ -static int localmail (int, char *); -static int usr_delivery (int, char *, int); -static int split (char *, char **); -static int parse (int); -static void expand (char *, char *, int); -static void glob (int); -static struct pair *lookup (struct pair *, char *); -static int logged_in (void); -static int timely (char *, char *); -static int usr_file (int, char *, int); -static int usr_pipe (int, char *, char *, char **, int); -static int usr_folder (int, char *); -static RETSIGTYPE alrmser (int); -static void get_sender (char *, char **); -static int copy_message (int, char *, int); -static void verbose_printf (char *fmt, ...); -static void adorn (char *, char *, ...); -static void debug_printf (char *fmt, ...); -static int suppress_duplicates (int, char *); -static char *trim (char *); +** static prototypes +*/ +static int localmail(int, char *); +static int usr_delivery(int, char *, int); +static int split(char *, char **); +static int parse(int); +static void expand(char *, char *, int); +static void glob(int); +static struct pair *lookup(struct pair *, char *); +static int usr_file(int, char *); +static int usr_pipe(int, char *, char *, char **, int); +static int usr_folder(int, char *); +static void alrmser(int); +static void get_sender(char *, char **); +static int copy_message(int, char *, int); +static void verbose_printf(char *fmt, ...); +static void adorn(char *, char *, ...); +static void debug_printf(char *fmt, ...); +static char *trim(char *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int fd, status; - FILE *fp = stdin; - char *cp, *mdlvr = NULL, buf[BUFSIZ]; - char mailbox[BUFSIZ], tmpfil[BUFSIZ]; - char **argp, **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (*argv, '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - /* Parse arguments */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), - "%s [switches] [address info sender]", invo_name); - print_help (buf, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case ADDRSW: - if (!(addr = *argp++))/* allow -xyz arguments */ - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case INFOSW: - if (!(info = *argp++))/* allow -xyz arguments */ - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case USERSW: - if (!(user = *argp++))/* allow -xyz arguments */ - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case FILESW: - if (!(file = *argp++) || *file == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case SENDERSW: - if (!(sender = *argp++))/* allow -xyz arguments */ - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case MAILBOXSW: - if (!(mbox = *argp++) || *mbox == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case HOMESW: - if (!(home = *argp++) || *home == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case MAILSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (mdlvr) - adios (NULL, "only one maildelivery file at a time!"); - mdlvr = cp; - continue; - - case VERBSW: - verbose++; - continue; - case NVERBSW: - verbose = 0; - continue; - - case SUPPRESSDUP: - suppressdup++; - continue; - case NSUPPRESSDUP: - suppressdup = 0; - continue; - case DEBUGSW: - debug++; - continue; - } - } + int fd, status; + FILE *fp = stdin; + char *cp, *mdlvr = NULL, buf[BUFSIZ]; + char mailbox[BUFSIZ], tmpfil[BUFSIZ]; + char **argp, **arguments; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(*argv); + + arguments = getarguments(invo_name, argc, argv, 0); + argp = arguments; + + /* Parse arguments */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [switches] [address info sender]", invo_name); + print_help(buf, switches, 0); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case ADDRSW: + if (!(addr = *argp++)) { + /* allow -xyz arguments */ + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case INFOSW: + if (!(info = *argp++)) { + /* allow -xyz arguments */ + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case USERSW: + if (!(user = *argp++)) { + /* allow -xyz arguments */ + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case FILESW: + if (!(file = *argp++) || *file == '-') { + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case SENDERSW: + if (!(sender = *argp++)) { + /* allow -xyz arguments */ + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case MAILBOXSW: + if (!(mbox = *argp++) || *mbox == '-') { + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; + case HOMESW: + if (!(home = *argp++) || *home == '-') { + adios(NULL, "missing argument to %s", + argp[-2]); + } + continue; - switch (argp - (argv + 1)) { - case 1: - addr = cp; - break; + case MAILSW: + if (!(cp = *argp++) || *cp == '-') { + adios(NULL, "missing argument to %s", + argp[-2]); + } + if (mdlvr) { + adios(NULL, "only one maildelivery file at a time!"); + } + mdlvr = cp; + continue; + + case VERBSW: + verbose++; + continue; + case NVERBSW: + verbose = 0; + continue; + + case DEBUGSW: + debug++; + continue; + } + } - case 2: - info = cp; - break; + switch (argp - (argv + 1)) { + case 1: + addr = cp; + break; + case 2: + info = cp; + break; + case 3: + sender = cp; + break; + } + } - case 3: - sender = cp; - break; + if (!addr) { + addr = getusername(); + } + if (!user) { + user = (cp = strchr(addr, '.')) ? ++cp : addr; + } + if (!(pw = getpwnam(user))) { + adios(NULL, "no such local user as %s", user); } - } - - if (addr == NULL) - addr = getusername (); - if (user == NULL) - user = (cp = strchr(addr, '.')) ? ++cp : addr; - if ((pw = getpwnam (user)) == NULL) - adios (NULL, "no such local user as %s", user); - - if (chdir (pw->pw_dir) == -1) - chdir ("/"); - umask (0077); - - if (geteuid() == 0) { - setgid (pw->pw_gid); - initgroups (pw->pw_name, pw->pw_gid); - setuid (pw->pw_uid); - } - - if (info == NULL) - info = ""; - - setbuf (stdin, NULL); - - /* Record the delivery time */ - if ((now = dlocaltimenow ()) == NULL) - adios (NULL, "unable to ascertain local time"); - snprintf (ddate, sizeof(ddate), "Delivery-Date: %s\n", dtimenow (0)); - - /* - * Copy the message to a temporary file - */ - if (file) { - int tempfd; - - /* getting message from file */ - if ((tempfd = open (file, O_RDONLY)) == -1) - adios (file, "unable to open"); - if (debug) - debug_printf ("retrieving message from file \"%s\"\n", file); - if ((fd = copy_message (tempfd, tmpfil, 1)) == -1) - adios (NULL, "unable to create temporary file"); - close (tempfd); - } else { - /* getting message from stdin */ - if (debug) - debug_printf ("retrieving message from stdin\n"); - if ((fd = copy_message (fileno (stdin), tmpfil, 1)) == -1) - adios (NULL, "unable to create temporary file"); - } - - if (debug) - debug_printf ("temporary file=\"%s\"\n", tmpfil); - - /* Delete the temp file now or a copy of every single message passed through - slocal will be left in the /tmp directory until deleted manually! This - unlink() used to be under an 'else' of the 'if (debug)' above, but since - some people like to always run slocal with -debug and log the results, - the /tmp directory would get choked over time. Of course, now that we - always delete the temp file, the "temporary file=" message above is - somewhat pointless -- someone watching debug output wouldn't have a - chance to 'tail -f' or 'ln' the temp file before it's unlinked. The best - thing would be to delay this unlink() until later if debug == 1, but I'll - leave that for someone who cares about the temp-file-accessing - functionality (they'll have to watch out for cases where we adios()). */ - unlink (tmpfil); - - if (!(fp = fdopen (fd, "r+"))) - adios (NULL, "unable to access temporary file"); - - /* - * If no sender given, extract it - * from envelope information. */ - if (sender == NULL) - get_sender (envelope, &sender); - - if (mbox == NULL) { - snprintf (mailbox, sizeof(mailbox), "%s/%s", - mmdfldir[0] ? mmdfldir : pw->pw_dir, - mmdflfil[0] ? mmdflfil : pw->pw_name); - mbox = mailbox; - } - if (home == NULL) - home = pw->pw_dir; - - if (debug) { - debug_printf ("addr=\"%s\"\n", trim(addr)); - debug_printf ("user=\"%s\"\n", trim(user)); - debug_printf ("info=\"%s\"\n", trim(info)); - debug_printf ("sender=\"%s\"\n", trim(sender)); - debug_printf ("envelope=\"%s\"\n", envelope ? trim(envelope) : ""); - debug_printf ("mbox=\"%s\"\n", trim(mbox)); - debug_printf ("home=\"%s\"\n", trim(home)); - debug_printf ("ddate=\"%s\"\n", trim(ddate)); - debug_printf ("now=%02d:%02d\n\n", now->tw_hour, now->tw_min); - } - - /* deliver the message */ - status = localmail (fd, mdlvr); - - done (status != -1 ? RCV_MOK : RCV_MBX); - return 1; -} + if (chdir(pw->pw_dir) == -1) { + chdir("/"); + } + umask(0077); -/* - * Main routine for delivering message. - */ + if (geteuid() == 0) { + setgid(pw->pw_gid); + initgroups(pw->pw_name, pw->pw_gid); + setuid(pw->pw_uid); + } -static int -localmail (int fd, char *mdlvr) -{ - /* check if this message is a duplicate */ - if (suppressdup && - suppress_duplicates(fd, mdlvr ? mdlvr : ".maildelivery") == DONE) - return 0; + if (!info) { + info = ""; + } - /* delivery according to personal Maildelivery file */ - if (usr_delivery (fd, mdlvr ? mdlvr : ".maildelivery", 0) != -1) - return 0; + setbuf(stdin, NULL); - /* delivery according to global Maildelivery file */ - if (usr_delivery (fd, maildelivery, 1) != -1) - return 0; + /* Record the delivery time */ + if (!(now = dlocaltimenow())) { + adios(NULL, "unable to ascertain local time"); + } + snprintf(ddate, sizeof(ddate), "Delivery-Date: %s\n", dtimenow()); - if (verbose) - verbose_printf ("(delivering to standard mail spool)\n"); - - /* last resort - deliver to standard mail spool */ -#ifdef SLOCAL_MBOX - return usr_file (fd, mbox, MBOX_FORMAT); -#else - return usr_file (fd, mbox, MMDF_FORMAT); -#endif -} + /* + ** Copy the message to a temporary file + */ + if (file) { + int tempfd; + /* getting message from file */ + if ((tempfd = open(file, O_RDONLY)) == -1) { + adios(file, "unable to open"); + } + if (debug) { + debug_printf("retrieving message from file \"%s\"\n", + file); + } + if ((fd = copy_message(tempfd, tmpfil, 1)) == -1) { + adios(NULL, "unable to create temporary file"); + } + close(tempfd); + } else { + /* getting message from stdin */ + if (debug) { + debug_printf("retrieving message from stdin\n"); + } + if ((fd = copy_message(fileno(stdin), tmpfil, 1)) == -1) { + adios(NULL, "unable to create temporary file"); + } + } -#define matches(a,b) (stringdex (b, a) >= 0) + if (debug) { + debug_printf("temporary file=\"%s\"\n", tmpfil); + } -/* - * Parse the delivery file, and process incoming message. - */ + /* + ** Delete the temp file now or a copy of every single message + ** passed through slocal will be left in the /tmp directory until + ** deleted manually! This unlink() used to be under an 'else' + ** of the 'if (debug)' above, but since some people like to + ** always run slocal with -debug and log the results, the /tmp + ** directory would get choked over time. Of course, now that + ** we always delete the temp file, the "temporary file=" message + ** above is somewhat pointless -- someone watching debug output + ** wouldn't have a chance to 'tail -f' or 'ln' the temp file + ** before it's unlinked. The best thing would be to delay this + ** unlink() until later if debug == 1, but I'll leave that for + ** someone who cares about the temp-file-accessing functionality + ** (they'll have to watch out for cases where we adios()). + */ + unlink(tmpfil); + + if (!(fp = fdopen(fd, "r+"))) { + adios(NULL, "unable to access temporary file"); + } -static int -usr_delivery (int fd, char *delivery, int su) -{ - int i, accept, status=1, won, vecp, next; - char *field, *pattern, *action, *result, *string; - char buffer[BUFSIZ], tmpbuf[BUFSIZ]; - char *cp, *vec[NVEC]; - struct stat st; - struct pair *p; - FILE *fp; - - /* open the delivery file */ - if ((fp = fopen (delivery, "r")) == NULL) - return -1; + /* If no sender given, extract it from envelope information. */ + if (!sender) { + get_sender(envelope, &sender); + } + if (!mbox) { + snprintf(mailbox, sizeof(mailbox), "%s/%s", + mailspool, pw->pw_name); + mbox = mailbox; + } + if (!home) { + home = pw->pw_dir; + } - /* check if delivery file has bad ownership or permissions */ - if (fstat (fileno (fp), &st) == -1 - || (st.st_uid != 0 && (su || st.st_uid != pw->pw_uid)) - || st.st_mode & (S_IWGRP|S_IWOTH)) { - if (verbose) { - verbose_printf ("WARNING: %s has bad ownership/modes (su=%d,uid=%d,owner=%d,mode=0%o)\n", - delivery, su, (int) pw->pw_uid, (int) st.st_uid, (int) st.st_mode); + if (debug) { + debug_printf("addr=\"%s\"\n", trim(addr)); + debug_printf("user=\"%s\"\n", trim(user)); + debug_printf("info=\"%s\"\n", trim(info)); + debug_printf("sender=\"%s\"\n", trim(sender)); + debug_printf("envelope=\"%s\"\n", + envelope ? trim(envelope) : ""); + debug_printf("mbox=\"%s\"\n", trim(mbox)); + debug_printf("home=\"%s\"\n", trim(home)); + debug_printf("ddate=\"%s\"\n", trim(ddate)); + debug_printf("now=%02d:%02d\n\n", now->tw_hour, now->tw_min); } - return -1; - } - won = 0; - next = 1; + /* deliver the message */ + status = localmail(fd, mdlvr); - /* read and process delivery file */ - while (fgets (buffer, sizeof(buffer), fp)) { - /* skip comments and empty lines */ - if (*buffer == '#' || *buffer == '\n') - continue; + done(status != -1 ? RCV_MOK : RCV_MBX); + return 1; +} - /* zap trailing newline */ - if ((cp = strchr(buffer, '\n'))) - *cp = 0; - /* split buffer into fields */ - vecp = split (buffer, vec); +/* +** Main routine for delivering message. +*/ +static int +localmail(int fd, char *mdlvr) +{ + char buf[BUFSIZ]; - /* check for too few fields */ - if (vecp < 5) { - if (debug) - debug_printf ("WARNING: entry with only %d fields, skipping.\n", vecp); - continue; + /* delivery according to personal Maildelivery file */ + if (usr_delivery(fd, mdlvr ? mdlvr : ".maildelivery", 0) != -1) { + return 0; } - - if (debug) { - for (i = 0; vec[i]; i++) - debug_printf ("vec[%d]: \"%s\"\n", i, trim(vec[i])); + /* delivery according to global Maildelivery file */ + snprintf(buf, sizeof buf, "%s/%s", mhetcdir, "maildelivery"); + if (usr_delivery(fd, buf, 1) != -1) { + return 0; + } + if (verbose) { + verbose_printf("(delivering to standard mail spool)\n"); } + /* last resort - deliver to standard mail spool */ + return usr_file(fd, mbox); +} - field = vec[0]; - pattern = vec[1]; - action = vec[2]; - result = vec[3]; - string = vec[4]; - - /* find out how to perform the action */ - switch (result[0]) { - case 'N': - case 'n': - /* - * If previous condition failed, don't - * do this - else fall through - */ - if (!next) - continue; /* else fall */ - - case '?': - /* - * If already delivered, skip this action. Else - * consider delivered if action is successful. - */ - if (won) - continue; /* else fall */ - - case 'A': - case 'a': - /* - * Take action, and consider delivered if - * action is successful. - */ - accept = 1; - break; - case 'R': - case 'r': - default: - /* - * Take action, but don't consider delivered, even - * if action is successful - */ - accept = 0; - break; - } +#define matches(a,b) (stringdex(b, a) >= 0) - if (vecp > 5) { - if (!mh_strcasecmp (vec[5], "select")) { - if (logged_in () != -1) - continue; - if (vecp > 7 && timely (vec[6], vec[7]) == -1) - continue; - } +/* +** Parse the delivery file, and process incoming message. +*/ +static int +usr_delivery(int fd, char *delivery, int su) +{ + int i, accept, status=1, won, vecp, next; + char *field, *pattern, *action, *result, *string; + char buffer[BUFSIZ], tmpbuf[BUFSIZ]; + char *cp, *vec[NVEC]; + struct stat st; + struct pair *p; + FILE *fp; + + /* open the delivery file */ + if (!(fp = fopen(delivery, "r"))) { + return -1; + } + /* check if delivery file has bad ownership or permissions */ + if (fstat(fileno(fp), &st) == -1 || + (st.st_uid != 0 && (su || st.st_uid != pw->pw_uid)) || + st.st_mode & (S_IWGRP|S_IWOTH)) { + if (verbose) { + verbose_printf("WARNING: %s has bad ownership/modes (su=%d,uid=%d,owner=%d,mode=0%o)\n", delivery, su, (int) pw->pw_uid, (int) st.st_uid, (int) st.st_mode); + } + return -1; } - /* check if the field matches */ - switch (*field) { - case '*': - /* always matches */ - break; + won = 0; + next = 1; - case 'd': - /* - * "default" matches only if the message hasn't - * been delivered yet. - */ - if (!mh_strcasecmp (field, "default")) { - if (won) + /* read and process delivery file */ + while (fgets(buffer, sizeof(buffer), fp)) { + /* skip comments and empty lines */ + if (*buffer == '#' || *buffer == '\n') { continue; - break; - } /* else fall */ - - default: - /* parse message and build lookup table */ - if (!parsed && parse (fd) == -1) { - fclose (fp); - return -1; } - /* - * find header field in lookup table, and - * see if the pattern matches. - */ - if ((p = lookup (hdrs, field)) && (p->p_value != NULL) - && matches (p->p_value, pattern)) { - next = 1; - } else { - next = 0; - continue; + /* zap trailing newline */ + if ((cp = strchr(buffer, '\n'))) { + *cp = '\0'; } - break; - } + /* split buffer into fields */ + vecp = split(buffer, vec); - /* find out the action to perform */ - switch (*action) { - case 'q': - /* deliver to quoted pipe */ - if (mh_strcasecmp (action, "qpipe")) - continue; /* else fall */ - case '^': - expand (tmpbuf, string, fd); - if (split (tmpbuf, vec) < 1) - continue; - status = usr_pipe (fd, tmpbuf, vec[0], vec, 0); - break; + /* check for too few fields */ + if (vecp < 5) { + if (debug) + debug_printf("WARNING: entry with only %d fields, skipping.\n", vecp); + continue; + } - case 'p': - /* deliver to pipe */ - if (mh_strcasecmp (action, "pipe")) - continue; /* else fall */ - case '|': - vec[2] = "sh"; - vec[3] = "-c"; - expand (tmpbuf, string, fd); - vec[4] = tmpbuf; - vec[5] = NULL; - status = usr_pipe (fd, tmpbuf, "/bin/sh", vec + 2, 0); - break; + if (debug) { + for (i = 0; vec[i]; i++) { + debug_printf("vec[%d]: \"%s\"\n", + i, trim(vec[i])); + } + } + + field = vec[0]; + pattern = vec[1]; + action = vec[2]; + result = vec[3]; + string = vec[4]; + + /* find out how to perform the action */ + switch (result[0]) { + case 'N': + case 'n': + /* + ** If previous condition failed, don't + ** do this - else fall through + */ + if (!next) { + continue; + } + /* fall */ + + case '?': + /* + ** If already delivered, skip this action. + ** Else consider delivered if action is + ** successful. + */ + if (won) { + continue; + } + /* fall */ + + case 'A': + case 'a': + /* + ** Take action, and consider delivered if + ** action is successful. + */ + accept = 1; + break; - case 'f': - /* mbox format */ - if (!mh_strcasecmp (action, "file")) { - status = usr_file (fd, string, MBOX_FORMAT); - break; + case 'R': + case 'r': + default: + /* + ** Take action, but don't consider delivered, + ** even if action is successful + */ + accept = 0; + break; } - /* deliver to nmh folder */ - else if (mh_strcasecmp (action, "folder")) - continue; /* else fall */ - case '+': - status = usr_folder (fd, string); - break; - case 'm': - /* mmdf format */ - if (!mh_strcasecmp (action, "mmdf")) { - status = usr_file (fd, string, MMDF_FORMAT); - break; + /* check if the field matches */ + switch (*field) { + case '*': + /* always matches */ + break; + + case 'd': + /* + ** "default" matches only if the message hasn't + ** been delivered yet. + */ + if (mh_strcasecmp(field, "default")==0) { + if (won) { + continue; + } + break; + } + /* fall */ + default: + /* parse message and build lookup table */ + if (!parsed && parse(fd) == -1) { + fclose(fp); + return -1; + } + /* + ** find header field in lookup table, and + ** see if the pattern matches. + */ + if ((p = lookup(hdrs, field)) && p->p_value && + matches(p->p_value, pattern)) { + next = 1; + } else { + next = 0; + continue; + } + break; } - /* mbox format */ - else if (mh_strcasecmp (action, "mbox")) - continue; /* else fall */ - case '>': - /* mbox format */ - status = usr_file (fd, string, MBOX_FORMAT); - break; + /* find out the action to perform */ + switch (*action) { + case 'q': + /* deliver to quoted pipe */ + if (mh_strcasecmp(action, "qpipe")) { + continue; + } + /* fall */ + case '^': + expand(tmpbuf, string, fd); + if (split(tmpbuf, vec) < 1) { + continue; + } + status = usr_pipe(fd, tmpbuf, vec[0], vec, 0); + break; - case 'd': - /* ignore message */ - if (mh_strcasecmp (action, "destroy")) - continue; - status = 0; - break; - } + case 'p': + /* deliver to pipe */ + if (mh_strcasecmp(action, "pipe")) { + continue; + } + /* fall */ + case '|': + vec[2] = "sh"; + vec[3] = "-c"; + expand(tmpbuf, string, fd); + vec[4] = tmpbuf; + vec[5] = NULL; + status = usr_pipe(fd, tmpbuf, "/bin/sh", vec+2, 0); + break; - if (status) next = 0; /* action failed, mark for 'N' result */ + case 'f': + if (mh_strcasecmp(action, "file")==0) { + /* mbox format */ + status = usr_file(fd, string); + break; + } + if (mh_strcasecmp(action, "folder")!=0) { + continue; + } + /* fall */ + case '+': + /* deliver to nmh folder */ + status = usr_folder(fd, string); + break; - if (accept && status == 0) - won++; - } + case 'm': + /* mbox format */ + if (mh_strcasecmp(action, "mbox")!=0) { + continue; + } + /* fall */ + case '>': + /* mbox format */ + status = usr_file(fd, string); + break; - fclose (fp); - return (won ? 0 : -1); -} + case 'd': + /* ignore message */ + if (mh_strcasecmp(action, "destroy")!=0) { + continue; + } + status = 0; + break; + } + + if (status) { + next = 0; /* action failed, mark for 'N' result */ + } else if (accept) { + won++; + } + } + fclose(fp); + return (won ? 0 : -1); +} -#define QUOTE '\\' /* - * Split buffer into fields (delimited by whitespace or - * comma's). Return the number of fields found. - */ - +** Split buffer into fields (delimited by whitespace or +** comma's). Return the number of fields found. +*/ static int -split (char *cp, char **vec) +split(char *cp, char **vec) { - int i; - unsigned char *s; + int i; + unsigned char *s; - s = cp; + s = cp; - /* split into a maximum of NVEC fields */ - for (i = 0; i <= NVEC;) { - vec[i] = NULL; + /* split into a maximum of NVEC fields */ + for (i = 0; i <= NVEC;) { + vec[i] = NULL; - /* zap any whitespace and comma's */ - while (isspace (*s) || *s == ',') - *s++ = 0; - - /* end of buffer, time to leave */ - if (*s == 0) - break; - - /* get double quote text as a single field */ - if (*s == '"') { - for (vec[i++] = ++s; *s && *s != '"'; s++) { - /* - * Check for escaped double quote. We need - * to shift the string to remove slash. - */ - if (*s == QUOTE) { - if (*++s == '"') - strcpy (s - 1, s); - s--; + /* zap any whitespace and comma's */ + while (isspace(*s) || *s == ',') { + *s++ = '\0'; + } + /* end of buffer, time to leave */ + if (!*s) { + break; + } + /* get double quote text as a single field */ + if (*s == '"') { + for (vec[i++] = ++s; *s && *s != '"'; s++) { + /* + ** Check for escaped double quote. We need + ** to shift the string to remove slash. + */ + if (*s == '\\') { + if (*++s == '"') { + strcpy(s - 1, s); + } + s--; + } + } + if (*s == '"') { + /* zap trailing double quote */ + *s++ = '\0'; + } + continue; } - } - if (*s == '"') /* zap trailing double quote */ - *s++ = 0; - continue; - } - if (*s == QUOTE && *++s != '"') - s--; - vec[i++] = s++; + if (*s == '\\' && *++s != '"') { + s--; + } + vec[i++] = s++; - /* move forward to next field delimiter */ - while (*s && !isspace (*s) && *s != ',') - s++; - } - vec[i] = NULL; + /* move forward to next field delimiter */ + while (*s && !isspace(*s) && *s != ',') { + s++; + } + } + vec[i] = NULL; - return i; + return i; } /* - * Parse the headers of a message, and build the - * lookup table for matching fields and patterns. - */ - +** Parse the headers of a message, and build the +** lookup table for matching fields and patterns. +*/ static int -parse (int fd) +parse(int fd) { - int i, state; - int fd1; - char *cp, *dp, *lp; - char name[NAMESZ], field[BUFSIZ]; - struct pair *p, *q; - FILE *in; - - if (parsed++) - return 0; + int i, state; + int fd1; + char *cp, *dp, *lp; + char name[NAMESZ], field[BUFSIZ]; + struct pair *p, *q; + FILE *in; + + if (parsed++) { + return 0; + } - /* get a new FILE pointer to message */ - if ((fd1 = dup (fd)) == -1) - return -1; - if ((in = fdopen (fd1, "r")) == NULL) { - close (fd1); - return -1; - } - rewind (in); - - /* add special entries to lookup table */ - if ((p = lookup (hdrs, "source"))) - p->p_value = getcpy (sender); - if ((p = lookup (hdrs, "addr"))) - p->p_value = getcpy (addr); - - /* - * Scan the headers of the message and build - * a lookup table. - */ - for (i = 0, state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), in)) { - case FLD: - case FLDEOF: - case FLDPLUS: - lp = add (field, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), in); - lp = add (field, lp); - } - for (p = hdrs; p->p_name; p++) { - if (!mh_strcasecmp (p->p_name, name)) { - if (!(p->p_flags & P_HID)) { - if ((cp = p->p_value)) { - if (p->p_flags & P_ADR) { - dp = cp + strlen (cp) - 1; - if (*dp == '\n') - *dp = 0; - cp = add (",\n\t", cp); - } else { - cp = add ("\t", cp); + /* get a new FILE pointer to message */ + if ((fd1 = dup(fd)) == -1) { + return -1; + } + if (!(in = fdopen(fd1, "r"))) { + close(fd1); + return -1; + } + rewind(in); + + /* add special entries to lookup table */ + if ((p = lookup(hdrs, "source"))) { + p->p_value = getcpy(sender); + } + if ((p = lookup(hdrs, "addr"))) { + p->p_value = getcpy(addr); + } + + /* + ** Scan the headers of the message and build a lookup table. + */ + for (i = 0, state = FLD;;) { + switch (state = m_getfld(state, name, field, sizeof(field), + in)) { + case FLD: + case FLDEOF: + case FLDPLUS: + lp = getcpy(field); + while (state == FLDPLUS) { + state = m_getfld(state, name, field, + sizeof(field), in); + lp = add(field, lp); + } + for (p = hdrs; p->p_name; p++) { + if (mh_strcasecmp(p->p_name, name)!=0) { + if (!(p->p_flags & P_HID)) { + if ((cp = p->p_value)) { + if (p->p_flags & P_ADR) { + dp = cp + strlen(cp) - 1; + if (*dp == '\n') { + *dp = '\0'; + } + cp = add(",\n\t", cp); + } else { + cp = add("\t", cp); + } + } + p->p_value = add(lp, cp); + } + free(lp); + break; } - } - p->p_value = add (lp, cp); } - free (lp); + if (!p->p_name && i < NVEC) { + p->p_name = getcpy(name); + p->p_value = lp; + p->p_flags = P_NIL; + p++, i++; + p->p_name = NULL; + } + if (state != FLDEOF) { + continue; + } break; - } - } - if (p->p_name == NULL && i < NVEC) { - p->p_name = getcpy (name); - p->p_value = lp; - p->p_flags = P_NIL; - p++, i++; - p->p_name = NULL; - } - if (state != FLDEOF) - continue; - break; - case BODY: - case BODYEOF: - case FILEEOF: - break; + case BODY: + case BODYEOF: + case FILEEOF: + break; - case LENERR: - case FMTERR: - advise (NULL, "format error in message"); + case LENERR: + case FMTERR: + advise(NULL, "format error in message"); + break; + + default: + advise(NULL, "internal error in m_getfld"); + fclose(in); + return -1; + } break; + } + fclose(in); - default: - advise (NULL, "internal error in m_getfld"); - fclose (in); - return -1; + if ((p = lookup(vars, "reply-to"))) { + if (!(q = lookup(hdrs, "reply-to")) || !q->p_value) { + q = lookup(hdrs, "from"); + } + p->p_value = getcpy(q ? q->p_value : ""); + p->p_flags &= ~P_CHK; + if (debug) { + debug_printf("vars[%d]: name=\"%s\" value=\"%s\"\n", + p - vars, p->p_name, trim(p->p_value)); + } + } + if (debug) { + for (p = hdrs; p->p_name; p++) { + debug_printf("hdrs[%d]: name=\"%s\" value=\"%s\"\n", + p - hdrs, p->p_name, + p->p_value ? trim(p->p_value) : ""); + } } - break; - } - fclose (in); - - if ((p = lookup (vars, "reply-to"))) { - if ((q = lookup (hdrs, "reply-to")) == NULL || q->p_value == NULL) - q = lookup (hdrs, "from"); - p->p_value = getcpy (q ? q->p_value : ""); - p->p_flags &= ~P_CHK; - if (debug) - debug_printf ("vars[%d]: name=\"%s\" value=\"%s\"\n", - p - vars, p->p_name, trim(p->p_value)); - } - if (debug) { - for (p = hdrs; p->p_name; p++) - debug_printf ("hdrs[%d]: name=\"%s\" value=\"%s\"\n", - p - hdrs, p->p_name, p->p_value ? trim(p->p_value) : ""); - } - - return 0; + return 0; } -#define LPAREN '(' -#define RPAREN ')' - /* - * Expand any builtin variables such as $(sender), - * $(address), etc., in a string. - */ - +** Expand any builtin variables such as $(sender), +** $(address), etc., in a string. +*/ static void -expand (char *s1, char *s2, int fd) +expand(char *s1, char *s2, int fd) { - char c, *cp; - struct pair *p; + char c, *cp; + struct pair *p; - if (!globbed) - glob (fd); - - while ((c = *s2++)) { - if (c != '$' || *s2 != LPAREN) { - *s1++ = c; - } else { - for (cp = ++s2; *s2 && *s2 != RPAREN; s2++) - continue; - if (*s2 != RPAREN) { - s2 = --cp; - continue; - } - *s2++ = 0; - if ((p = lookup (vars, cp))) { - if (!parsed && (p->p_flags & P_CHK)) - parse (fd); - - strcpy (s1, p->p_value); - s1 += strlen (s1); - } + if (!globbed) { + glob(fd); } - } - *s1 = 0; + while ((c = *s2++)) { + if (c != '$' || *s2 != '(') { + *s1++ = c; + } else { + for (cp = ++s2; *s2 && *s2 != ')'; s2++) { + continue; + } + if (*s2 != ')') { + s2 = --cp; + continue; + } + *s2++ = '\0'; + if ((p = lookup(vars, cp))) { + if (!parsed && (p->p_flags & P_CHK)) { + parse(fd); + } + strcpy(s1, p->p_value); + s1 += strlen(s1); + } + } + } + *s1 = '\0'; } /* - * Fill in the information missing from the "vars" - * table, which is necessary to expand any builtin - * variables in the string for a "pipe" or "qpipe" - * action. - */ - +** Fill in the information missing from the "vars" +** table, which is necessary to expand any builtin +** variables in the string for a "pipe" or "qpipe" +** action. +*/ static void -glob (int fd) +glob(int fd) { - char buffer[BUFSIZ]; - struct stat st; - struct pair *p; - - if (globbed++) - return; - - if ((p = lookup (vars, "sender"))) - p->p_value = getcpy (sender); - if ((p = lookup (vars, "address"))) - p->p_value = getcpy (addr); - if ((p = lookup (vars, "size"))) { - snprintf (buffer, sizeof(buffer), "%d", - fstat (fd, &st) != -1 ? (int) st.st_size : 0); - p->p_value = getcpy (buffer); - } - if ((p = lookup (vars, "info"))) - p->p_value = getcpy (info); - - if (debug) { - for (p = vars; p->p_name; p++) - debug_printf ("vars[%d]: name=\"%s\" value=\"%s\"\n", - p - vars, p->p_name, trim(p->p_value)); - } + char buffer[BUFSIZ]; + struct stat st; + struct pair *p; + + if (globbed++) { + return; + } + if ((p = lookup(vars, "sender"))) { + p->p_value = getcpy(sender); + } + if ((p = lookup(vars, "address"))) { + p->p_value = getcpy(addr); + } + if ((p = lookup(vars, "size"))) { + snprintf(buffer, sizeof(buffer), "%d", + fstat(fd, &st) != -1 ? (int) st.st_size : 0); + p->p_value = getcpy(buffer); + } + if ((p = lookup(vars, "info"))) { + p->p_value = getcpy(info); + } + if (debug) { + for (p = vars; p->p_name; p++) { + debug_printf("vars[%d]: name=\"%s\" value=\"%s\"\n", + p - vars, p->p_name, trim(p->p_value)); + } + } } /* - * Find a matching name in a lookup table. If found, - * return the "pairs" entry, else return NULL. - */ - +** Find a matching name in a lookup table. If found, +** return the "pairs" entry, else return NULL. +*/ static struct pair * -lookup (struct pair *pairs, char *key) +lookup(struct pair *pairs, char *key) { - for (; pairs->p_name; pairs++) - if (!mh_strcasecmp (pairs->p_name, key)) - return pairs; - - return NULL; + for (; pairs->p_name; pairs++) { + if (!mh_strcasecmp(pairs->p_name, key)) { + return pairs; + } + } + return NULL; } /* - * Check utmp(x) file to see if user is currently - * logged in. - */ - -#ifdef HAVE_GETUTENT +** Deliver message by appending to a file, using rcvpack(1). +*/ static int -logged_in (void) +usr_file(int fd, char *mailbox) { - struct utmp * utp; - - if (utmped) - return utmped; - - setutent(); + char *vec[3]; - while ((utp = getutent()) != NULL) { - if ( -#ifdef HAVE_STRUCT_UTMP_UT_TYPE - utp->ut_type == USER_PROCESS - && -#endif - utp->ut_name[0] != 0 - && strncmp (user, utp->ut_name, sizeof(utp->ut_name)) == 0) { - if (debug) - continue; - endutent(); - return (utmped = DONE); - } - } - - endutent(); - return (utmped = NOTOK); -} -#else -static int -logged_in (void) -{ - struct utmp ut; - FILE *uf; - - if (utmped) - return utmped; - - if ((uf = fopen (UTMP_FILE, "r")) == NULL) - return NOTOK; - - while (fread ((char *) &ut, sizeof(ut), 1, uf) == 1) { - if (ut.ut_name[0] != 0 - && strncmp (user, ut.ut_name, sizeof(ut.ut_name)) == 0) { - if (debug) - continue; - fclose (uf); - return (utmped = DONE); + if (verbose) { + verbose_printf("delivering to file \"%s\" (mbox style)", + mailbox); } - } - - fclose (uf); - return (utmped = NOTOK); -} -#endif - -#define check(t,a,b) if (t < a || t > b) return -1 -#define cmpar(h1,m1,h2,m2) if (h1 < h2 || (h1 == h2 && m1 < m2)) return 0 - -static int -timely (char *t1, char *t2) -{ - int t1hours, t1mins, t2hours, t2mins; - - if (sscanf (t1, "%d:%d", &t1hours, &t1mins) != 2) - return -1; - check (t1hours, 0, 23); - check (t1mins, 0, 59); - - if (sscanf (t2, "%d:%d", &t2hours, &t2mins) != 2) - return -1; - check (t2hours, 0, 23); - check (t2mins, 0, 59); - - cmpar (now->tw_hour, now->tw_min, t1hours, t1mins); - cmpar (t2hours, t2mins, now->tw_hour, now->tw_min); + vec[0] = "rcvpack"; + vec[1] = mailbox; + vec[2] = NULL; - return -1; + return usr_pipe(fd, "rcvpack", "rcvpack", vec, 1); } /* - * Deliver message by appending to a file. - */ - +** Deliver message to a nmh folder, using rcvstore(1). +*/ static int -usr_file (int fd, char *mailbox, int mbx_style) +usr_folder(int fd, char *string) { - int md, mapping; - - if (verbose) - verbose_printf ("delivering to file \"%s\"", mailbox); - - if (mbx_style == MBOX_FORMAT) { - if (verbose) - verbose_printf (" (mbox style)"); - mapping = 0; - } else { - if (verbose) - verbose_printf (" (mmdf style)"); - mapping = 1; - } - - /* open and lock the file */ - if ((md = mbx_open (mailbox, mbx_style, pw->pw_uid, pw->pw_gid, m_gmprot())) == -1) { - if (verbose) - adorn ("", "unable to open:"); - return -1; - } + char folder[BUFSIZ], *vec[3]; - lseek (fd, (off_t) 0, SEEK_SET); + /* get folder name ready */ + if (*string == '+') { + strncpy(folder, string, sizeof(folder)); + }else { + snprintf(folder, sizeof(folder), "+%s", string); + } + if (verbose) { + verbose_printf("delivering to folder \"%s\"", folder + 1); + } + vec[0] = "rcvstore"; + vec[1] = folder; + vec[2] = NULL; - /* append message to file */ - if (mbx_copy (mailbox, mbx_style, md, fd, mapping, NULL, verbose) == -1) { - if (verbose) - adorn ("", "error writing to:"); - return -1; - } - - /* close and unlock file */ - if (mbx_close (mailbox, md) == NOTOK) { - if (verbose) - adorn ("", "error closing:"); - return -1; - } - - if (verbose) - verbose_printf (", success.\n"); - return 0; + return usr_pipe(fd, "rcvstore", "rcvstore", vec, 1); } - /* - * Deliver message to a nmh folder. - */ - +** Deliver message to a process. +*/ static int -usr_folder (int fd, char *string) +usr_pipe(int fd, char *cmd, char *pgm, char **vec, int suppress) { - int status; - char folder[BUFSIZ], *vec[3]; - - /* get folder name ready */ - if (*string == '+') - strncpy(folder, string, sizeof(folder)); - else - snprintf(folder, sizeof(folder), "+%s", string); - - if (verbose) - verbose_printf ("delivering to folder \"%s\"", folder + 1); - - vec[0] = "rcvstore"; - vec[1] = folder; - vec[2] = NULL; - - /* use rcvstore to put message in folder */ - status = usr_pipe (fd, "rcvstore", rcvstoreproc, vec, 1); - -#if 0 - /* - * Currently, verbose status messages are handled by usr_pipe(). - */ - if (verbose) { - if (status == 0) - verbose_printf (", success.\n"); - else - verbose_printf (", failed.\n"); - } -#endif + pid_t child_id; + int bytes, seconds, status, n; + struct stat st; + char *path; - return status; -} + if (verbose && !suppress) { + verbose_printf("delivering to pipe \"%s\"", cmd); + } + lseek(fd, (off_t) 0, SEEK_SET); -/* - * Deliver message to a process. - */ + switch ((child_id = fork())) { + case -1: + /* fork error */ + if (verbose) { + adorn("fork", "unable to"); + } + return -1; -static int -usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress) -{ - pid_t child_id; - int i, bytes, seconds, status; - struct stat st; - - if (verbose && !suppress) - verbose_printf ("delivering to pipe \"%s\"", cmd); - - lseek (fd, (off_t) 0, SEEK_SET); - - for (i = 0; (child_id = fork()) == -1 && i < 5; i++) - sleep (5); - - switch (child_id) { - case -1: - /* fork error */ - if (verbose) - adorn ("fork", "unable to"); - return -1; - - case 0: - /* child process */ - if (fd != 0) - dup2 (fd, 0); - freopen ("/dev/null", "w", stdout); - freopen ("/dev/null", "w", stderr); - if (fd != 3) - dup2 (fd, 3); - closefds (4); + case 0: + /* child process */ + if (fd != 0) { + dup2(fd, 0); + } + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + if (fd != 3) { + dup2(fd, 3); + } + for (n=4; npw_name); - m_putenv ("HOME", pw->pw_dir); - m_putenv ("SHELL", pw->pw_shell); - - execvp (pgm, vec); - _exit (-1); - - default: - /* parent process */ - if (!setjmp (myctx)) { - SIGNAL (SIGALRM, alrmser); - bytes = fstat (fd, &st) != -1 ? (int) st.st_size : 100; + /* put in own process group */ + setpgid((pid_t) 0, getpid()); + + path = getenv("PATH"); + *environ = NULL; + m_putenv("USER", pw->pw_name); + m_putenv("HOME", pw->pw_dir); + m_putenv("SHELL", pw->pw_shell); + m_putenv("PATH", path); + + execvp(pgm, vec); + _exit(-1); + + default: + /* parent process */ + if (setjmp(myctx)) { + /* + ** Ruthlessly kill the child and anything + ** else in its process group. + */ + kill(-child_id, SIGKILL); + if (verbose) + verbose_printf(", timed-out; terminated\n"); + return -1; + } + SIGNAL(SIGALRM, alrmser); + bytes = fstat(fd, &st) != -1 ? (int) st.st_size : 100; /* amount of time to wait depends on message size */ if (bytes <= 100) { - /* give at least 5 minutes */ - seconds = 300; + /* give at least 5 minutes */ + seconds = 300; } else if (bytes >= 90000) { - /* a half hour is long enough */ - seconds = 1800; + /* a half hour is long enough */ + seconds = 1800; } else { - seconds = (bytes / 60) + 300; + seconds = (bytes / 60) + 300; } - alarm ((unsigned int) seconds); - status = pidwait (child_id, 0); - alarm (0); + alarm((unsigned int) seconds); + status = pidwait(child_id, 0); + alarm(0); if (verbose) { - if (status == 0) - verbose_printf (", success.\n"); - else - if ((status & 0xff00) == 0xff00) - verbose_printf (", system error\n"); - else - pidstatus (status, stdout, ", failed"); + if (!status) { + verbose_printf(", success.\n"); + } else if ((status & 0xff00) == 0xff00) { + verbose_printf(", system error\n"); + } else { + pidstatus(status, stdout, ", failed"); + } } return (status == 0 ? 0 : -1); - } else { - /* - * Ruthlessly kill the child and anything - * else in its process group. - */ - KILLPG(child_id, SIGKILL); - if (verbose) - verbose_printf (", timed-out; terminated\n"); - return -1; - } - } + } } -static RETSIGTYPE -alrmser (int i) +static void +alrmser(int i) { -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGALRM, alrmser); -#endif - - longjmp (myctx, DONE); + longjmp(myctx, DONE); } /* - * Get the `sender' from the envelope - * information ("From " line). - */ - +** Get the `sender' from the envelope +** information ("From " line). +*/ static void -get_sender (char *envelope, char **sender) +get_sender(char *envelope, char **sender) { - int i; - unsigned char *cp; - unsigned char buffer[BUFSIZ]; - - if (envelope == NULL) { - *sender = getcpy (""); - return; - } - - i = strlen ("From "); - strncpy (buffer, envelope + i, sizeof(buffer)); - if ((cp = strchr(buffer, '\n'))) { - *cp = 0; - cp -= 24; - if (cp < buffer) - cp = buffer; - } else { - cp = buffer; - } - *cp = 0; - - for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (isspace (*cp)) - *cp = 0; - else - break; - *sender = getcpy (buffer); + int i; + unsigned char *cp; + unsigned char buffer[BUFSIZ]; + + if (!envelope) { + *sender = getcpy(""); + return; + } + + i = strlen("From "); + strncpy(buffer, envelope + i, sizeof(buffer)); + buffer[sizeof buffer -1] = '\0'; /* ensure termination */ + if ((cp = strchr(buffer, '\n'))) { + *cp = '\0'; + cp -= 24; + if (cp < buffer) { + cp = buffer; + } + } else { + cp = buffer; + } + *cp = '\0'; + + for (cp = buffer + strlen(buffer) - 1; cp >= buffer; cp--) + if (isspace(*cp)) { + *cp = '\0'; + } else { + break; + } + *sender = getcpy(buffer); } /* - * Copy message into a temporary file. - * While copying, it will do some header processing - * including the extraction of the envelope information. - */ - +** Copy message into a temporary file. +** While copying, it will do some header processing +** including the extraction of the envelope information. +*/ static int -copy_message (int qd, char *tmpfil, int fold) +copy_message(int qd, char *tmpfil, int fold) { - int i, first = 1, fd1, fd2; - char buffer[BUFSIZ]; - FILE *qfp, *ffp; - char *tfile = NULL; - - tfile = m_mktemp2(NULL, invo_name, &fd1, NULL); - if (tfile == NULL) return -1; - fchmod(fd1, 0600); - strncpy (tmpfil, tfile, BUFSIZ); - - if (!fold) { - while ((i = read (qd, buffer, sizeof(buffer))) > 0) - if (write (fd1, buffer, i) != i) { + int i, first = 1, fd1, fd2; + char buffer[BUFSIZ]; + FILE *qfp, *ffp; + char *tfile = NULL; + + tfile = m_mktemp2("/tmp/", invo_name, &fd1, NULL); + if (tfile == NULL) return -1; + fchmod(fd1, 0600); + strncpy(tmpfil, tfile, BUFSIZ); + + if (!fold) { + while ((i = read(qd, buffer, sizeof(buffer))) > 0) { + if (write(fd1, buffer, i) != i) { you_lose: - close (fd1); - unlink (tmpfil); - return -1; - } - if (i == -1) - goto you_lose; - lseek (fd1, (off_t) 0, SEEK_SET); - return fd1; - } + close(fd1); + unlink(tmpfil); + return -1; + } + } + if (i == -1) { + goto you_lose; + } + lseek(fd1, (off_t) 0, SEEK_SET); + return fd1; + } - /* dup the fd for incoming message */ - if ((fd2 = dup (qd)) == -1) { - close (fd1); - return -1; - } + /* dup the fd for incoming message */ + if ((fd2 = dup(qd)) == -1) { + close(fd1); + return -1; + } - /* now create a FILE pointer for it */ - if ((qfp = fdopen (fd2, "r")) == NULL) { - close (fd1); - close (fd2); - return -1; - } + /* now create a FILE pointer for it */ + if (!(qfp = fdopen(fd2, "r"))) { + close(fd1); + close(fd2); + return -1; + } - /* dup the fd for temporary file */ - if ((fd2 = dup (fd1)) == -1) { - close (fd1); - fclose (qfp); - return -1; - } + /* dup the fd for temporary file */ + if ((fd2 = dup(fd1)) == -1) { + close(fd1); + fclose(qfp); + return -1; + } - /* now create a FILE pointer for it */ - if ((ffp = fdopen (fd2, "r+")) == NULL) { - close (fd1); - close (fd2); - fclose (qfp); - return -1; - } - - /* - * copy message into temporary file - * and massage the headers. Save - * a copy of the "From " line for later. - */ - i = strlen ("From "); - while (fgets (buffer, sizeof(buffer), qfp)) { - if (first) { - first = 0; - if (!strncmp (buffer, "From ", i)) { -#ifdef RPATHS - char *fp, *cp, *hp, *ep; -#endif - /* get copy of envelope information ("From " line) */ - envelope = getcpy (buffer); - -#if 0 - /* First go ahead and put "From " line in message */ - fputs (buffer, ffp); - if (ferror (ffp)) - goto fputs_error; -#endif + /* now create a FILE pointer for it */ + if (!(ffp = fdopen(fd2, "r+"))) { + close(fd1); + close(fd2); + fclose(qfp); + return -1; + } -#ifdef RPATHS - /* - * Now create a "Return-Path:" line - * from the "From " line. - */ - hp = cp = strchr(fp = envelope + i, ' '); - while ((hp = strchr(++hp, 'r'))) - if (uprf (hp, "remote from")) { - hp = strrchr(hp, ' '); - break; - } - if (hp) { - /* return path for UUCP style addressing */ - ep = strchr(++hp, '\n'); - snprintf (buffer, sizeof(buffer), "Return-Path: %.*s!%.*s\n", - (int)(ep - hp), hp, (int)(cp - fp), fp); - } else { - /* return path for standard domain addressing */ - snprintf (buffer, sizeof(buffer), "Return-Path: %.*s\n", - (int)(cp - fp), fp); + /* + ** copy message into temporary file + ** and massage the headers. Save + ** a copy of the "From " line for later. + */ + i = strlen("From "); + while (fgets(buffer, sizeof(buffer), qfp)) { + if (first) { + first = 0; + if (strncmp(buffer, "From ", i)==0) { + /* + ** get copy of envelope information + ** ("From " line) + */ + envelope = getcpy(buffer); + + /* Put the delivery date in message */ + fputs(ddate, ffp); + if (ferror(ffp)) { + goto fputs_error; + } + continue; + } } - /* Add Return-Path header to message */ - fputs (buffer, ffp); - if (ferror (ffp)) - goto fputs_error; -#endif - /* Put the delivery date in message */ - fputs (ddate, ffp); - if (ferror (ffp)) - goto fputs_error; - - continue; - } + fputs(buffer, ffp); + if (ferror(ffp)) { + goto fputs_error; + } } - fputs (buffer, ffp); - if (ferror (ffp)) - goto fputs_error; - } - - fclose (ffp); - if (ferror (qfp)) { - close (fd1); - fclose (qfp); - return -1; - } - fclose (qfp); - lseek (fd1, (off_t) 0, SEEK_SET); - return fd1; - + fclose(ffp); + if (ferror(qfp)) { + close(fd1); + fclose(qfp); + return -1; + } + fclose(qfp); + lseek(fd1, (off_t) 0, SEEK_SET); + return fd1; fputs_error: - close (fd1); - fclose (ffp); - fclose (qfp); - return -1; + close(fd1); + fclose(ffp); + fclose(qfp); + return -1; } /* - * Trim strings for pretty printing of debugging output - */ - +** Trim strings for pretty printing of debugging output +*/ static char * -trim (char *cp) +trim(char *cp) { - char buffer[BUFSIZ*4]; - unsigned char *bp, *sp; + char buffer[BUFSIZ*4]; + unsigned char *bp, *sp; - if (cp == NULL) - return NULL; - - /* copy string into temp buffer */ - strncpy (buffer, cp, sizeof(buffer)); - bp = buffer; - - /* skip over leading whitespace */ - while (isspace(*bp)) - bp++; - - /* start at the end and zap trailing whitespace */ - for (sp = bp + strlen(bp) - 1; sp >= bp; sp--) { - if (isspace(*sp)) - *sp = 0; - else - break; - } - - /* replace remaining whitespace with spaces */ - for (sp = bp; *sp; sp++) - if (isspace(*sp)) - *sp = ' '; - - /* now return a copy */ - return getcpy(bp); -} - -/* - * Function for printing `verbose' messages. - */ + if (!cp) { + return NULL; + } -static void -verbose_printf (char *fmt, ...) -{ - va_list ap; + /* copy string into temp buffer */ + strncpy(buffer, cp, sizeof(buffer)); + bp = buffer; - va_start(ap, fmt); - vfprintf (stdout, fmt, ap); - va_end(ap); + /* skip over leading whitespace */ + while (isspace(*bp)) { + bp++; + } + /* start at the end and zap trailing whitespace */ + for (sp = bp + strlen(bp) - 1; sp >= bp; sp--) { + if (isspace(*sp)) { + *sp = '\0'; + } else { + break; + } + } - fflush (stdout); /* now flush output */ + /* replace remaining whitespace with spaces */ + for (sp = bp; *sp; sp++) { + if (isspace(*sp)) { + *sp = ' '; + } + } + return getcpy(bp); } - /* - * Function for printing `verbose' delivery - * error messages. - */ - +** Function for printing `verbose' messages. +*/ static void -adorn (char *what, char *fmt, ...) +verbose_printf(char *fmt, ...) { - va_list ap; - int eindex; - char *s; - - eindex = errno; /* save the errno */ - fprintf (stdout, ", "); - - va_start(ap, fmt); - vfprintf (stdout, fmt, ap); - va_end(ap); - - if (what) { - if (*what) - fprintf (stdout, " %s: ", what); - if ((s = strerror (eindex))) - fprintf (stdout, "%s", s); - else - fprintf (stdout, "Error %d", eindex); - } - - fputc ('\n', stdout); - fflush (stdout); + va_list ap; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); + fflush(stdout); } /* - * Function for printing `debug' messages. - */ - +** Function for printing `verbose' delivery +** error messages. +*/ static void -debug_printf (char *fmt, ...) +adorn(char *what, char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vfprintf (stderr, fmt, ap); - va_end(ap); -} + va_list ap; + int eindex; + char *s; + eindex = errno; /* save the errno */ + fprintf(stdout, ", "); -/* - * Check ndbm/db file(s) to see if the Message-Id of this - * message matches the Message-Id of a previous message, - * so we can discard it. If it doesn't match, we add the - * Message-Id of this message to the ndbm/db file. - */ -static int -suppress_duplicates (int fd, char *file) -{ - int fd1, lockfd, state, result; - char *cp, buf[BUFSIZ], name[NAMESZ]; - datum key, value; - DBM *db; - FILE *in; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); - if ((fd1 = dup (fd)) == -1) - return -1; - if (!(in = fdopen (fd1, "r"))) { - close (fd1); - return -1; - } - rewind (in); - - for (state = FLD;;) { - state = m_getfld (state, name, buf, sizeof(buf), in); - switch (state) { - case FLD: - case FLDPLUS: - case FLDEOF: - /* Search for the message ID */ - if (mh_strcasecmp (name, "Message-ID")) { - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), in); - continue; - } - - cp = add (buf, NULL); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); - cp = add (buf, cp); - } - key.dptr = trimcpy (cp); - key.dsize = strlen (key.dptr) + 1; - free (cp); - cp = key.dptr; - - if (!(db = dbm_open (file, O_RDWR | O_CREAT, 0600))) { - advise (file, "unable to perform dbm_open on"); - free (cp); - fclose (in); - return -1; - } - /* - * Since it is difficult to portable lock a ndbm file, - * we will open and lock the Maildelivery file instead. - * This will fail if your Maildelivery file doesn't - * exist. - */ - if ((lockfd = lkopen(file, O_RDWR, 0)) == -1) { - advise (file, "unable to perform file locking on"); - free (cp); - fclose (in); - return -1; + if (what) { + if (*what) { + fprintf(stdout, " %s: ", what); } - value = dbm_fetch (db, key); - if (value.dptr) { - if (verbose) - verbose_printf ("Message-ID: %s\n already received on %s", - cp, value.dptr); - result = DONE; + if ((s = strerror(eindex))) { + fprintf(stdout, "%s", s); } else { - value.dptr = ddate + sizeof("Delivery-Date:"); - value.dsize = strlen(value.dptr) + 1; - if (dbm_store (db, key, value, DBM_INSERT)) - advise (file, "possibly corrupt file"); - result = 0; + fprintf(stdout, "Error %d", eindex); } + } - dbm_close (db); - lkclose(lockfd, file); - free (cp); - fclose (in); - return result; - break; - - case BODY: - case BODYEOF: - case FILEEOF: - break; + fputc('\n', stdout); + fflush(stdout); +} - case LENERR: - case FMTERR: - default: - break; - } - break; - } +/* +** Function for printing `debug' messages. +*/ +static void +debug_printf(char *fmt, ...) +{ + va_list ap; - fclose (in); - return 0; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); } diff --git a/uip/sortm.c b/uip/sortm.c index cfad3d3..ed09181 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -1,589 +1,584 @@ - /* - * sortm.c -- sort messages in a folder by date/time - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** sortm.c -- sort messages in a folder by date/time +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include #include static struct swit switches[] = { -#define DATESW 0 - { "datefield field", 0 }, -#define TEXTSW 1 - { "textfield field", 0 }, -#define NSUBJSW 2 - { "notextfield", 0 }, -#define SUBJSW 3 - { "subject", -3 }, /* backward-compatibility */ -#define LIMSW 4 - { "limit days", 0 }, -#define NLIMSW 5 - { "nolimit", 0 }, -#define VERBSW 6 - { "verbose", 0 }, -#define NVERBSW 7 - { "noverbose", 0 }, -#define VERSIONSW 8 - { "version", 0 }, -#define HELPSW 9 - { "help", 0 }, - { NULL, 0 } +#define DATESW 0 + { "datefield field", 0 }, +#define TEXTSW 1 + { "textfield field", 0 }, +#define NSUBJSW 2 + { "notextfield", 2 }, +#define LIMSW 3 + { "limit days", 0 }, +#define NLIMSW 4 + { "nolimit", 2 }, +#define VERBSW 5 + { "verbose", 0 }, +#define NVERBSW 6 + { "noverbose", 2 }, +#define VERSIONSW 7 + { "Version", 0 }, +#define HELPSW 8 + { "help", 0 }, + { NULL, 0 } }; struct smsg { - int s_msg; - time_t s_clock; - char *s_subj; + int s_msg; + time_t s_clock; + char *s_subj; }; static struct smsg *smsgs; int nmsgs; -char *subjsort = (char *) 0; /* sort on subject if != 0 */ -unsigned long datelimit = 0; -int submajor = 0; /* if true, sort on subject-major */ +char *subjsort = NULL; /* sort on subject if != 0 */ +time_t datelimit = 0; +int submajor = 0; /* if true, sort on subject-major */ int verbose; /* This keeps compiler happy on calls to qsort */ typedef int (*qsort_comp) (const void *, const void *); /* - * static prototypes - */ -static int read_hdrs (struct msgs *, char *); -static int get_fields (char *, int, struct smsg *); -static int dsort (struct smsg **, struct smsg **); -static int subsort (struct smsg **, struct smsg **); -static int txtsort (struct smsg **, struct smsg **); -static void rename_chain (struct msgs *, struct smsg **, int, int); -static void rename_msgs (struct msgs *, struct smsg **); +** static prototypes +*/ +static int read_hdrs(struct msgs *, char *); +static int get_fields(char *, int, struct smsg *); +static int dsort(struct smsg **, struct smsg **); +static int subsort(struct smsg **, struct smsg **); +static int txtsort(struct smsg **, struct smsg **); +static void rename_chain(struct msgs *, struct smsg **, int, int); +static void rename_msgs(struct msgs *, struct smsg **); int -main (int argc, char **argv) +main(int argc, char **argv) { - int i, msgnum; - unsigned char *cp; - char *maildir, *datesw = NULL; - char *folder = NULL, buf[BUFSIZ], **argp; - char **arguments; - struct msgs_array msgs = { 0, 0, NULL }; - struct msgs *mp; - struct smsg **dlist; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Parse arguments - */ - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", - invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DATESW: - if (datesw) - adios (NULL, "only one date field at a time"); - if (!(datesw = *argp++) || *datesw == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case TEXTSW: - if (subjsort) - adios (NULL, "only one text field at a time"); - if (!(subjsort = *argp++) || *subjsort == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case SUBJSW: - subjsort = "subject"; - continue; - case NSUBJSW: - subjsort = (char *)0; - continue; - - case LIMSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - while (*cp == '0') - cp++; /* skip any leading zeros */ - if (!*cp) { /* hit end of string */ - submajor++; /* sort subject-major */ - continue; + int i, msgnum; + unsigned char *cp; + char *maildir, *datesw = NULL; + char *folder = NULL, buf[BUFSIZ], **argp; + char **arguments; + struct msgs_array msgs = { 0, 0, NULL }; + struct msgs *mp; + struct smsg **dlist; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Parse arguments + */ + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case DATESW: + if (datesw) + adios(NULL, "only one date field at a time"); + if (!(datesw = *argp++) || *datesw == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case TEXTSW: + if (subjsort) + adios(NULL, "only one text field at a time"); + if (!(subjsort = *argp++) || *subjsort == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case NSUBJSW: + subjsort = NULL; + continue; + + case LIMSW: + if (!(cp = *argp++) || *cp == '-') + adios(NULL, "missing argument to %s", argp[-2]); + while (*cp == '0') + cp++; /* skip any leading zeros */ + if (!*cp) { /* hit end of string */ + submajor++; /* sort subject-major */ + continue; + } + if (!isdigit(*cp) || !(datelimit = atoi(cp))) + adios(NULL, "impossible limit %s", cp); + datelimit *= 60*60*24; + continue; + case NLIMSW: + submajor = 0; /* use date-major, but */ + datelimit = 0; /* use no limit */ + continue; + + case VERBSW: + verbose++; + continue; + case NVERBSW: + verbose = 0; + continue; + } } - if (!isdigit(*cp) || !(datelimit = atoi(cp))) - adios (NULL, "impossible limit %s", cp); - datelimit *= 60*60*24; - continue; - case NLIMSW: - submajor = 0; /* use date-major, but */ - datelimit = 0; /* use no limit */ - continue; - - case VERBSW: - verbose++; - continue; - case NVERBSW: - verbose = 0; - continue; - } + if (*cp == '+' || *cp == '@') { + if (folder) + adios(NULL, "only one folder at a time!"); + else + folder = getcpy(expandfol(cp)); + } else + app_msgarg(&msgs, cp); } - if (*cp == '+' || *cp == '@') { - if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); - } else - app_msgarg(&msgs, cp); - } - - if (!context_find ("path")) - free (path ("./", TFOLDER)); - if (!msgs.size) - app_msgarg(&msgs, "all"); - if (!datesw) - datesw = "date"; - if (!folder) - folder = getfolder (1); - maildir = m_maildir (folder); - - if (chdir (maildir) == NOTOK) - adios (maildir, "unable to change directory to"); - - /* read folder and create message structure */ - if (!(mp = folder_read (folder))) - adios (NULL, "unable to read folder %s", folder); - - /* check for empty folder */ - if (mp->nummsg == 0) - adios (NULL, "no messages in %s", folder); - - /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgs.size; msgnum++) - if (!m_convert (mp, msgs.msgs[msgnum])) - done (1); - seq_setprev (mp); /* set the previous sequence */ - - if ((nmsgs = read_hdrs (mp, datesw)) <= 0) - adios (NULL, "no messages to sort"); - - /* - * sort a list of pointers to our "messages to be sorted". - */ - dlist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*dlist)); - for (i = 0; i < nmsgs; i++) - dlist[i] = &smsgs[i]; - dlist[nmsgs] = 0; - - if (verbose) { /* announce what we're doing */ - if (subjsort) - printf ("sorting by %s-major %s-minor\n", - submajor ? subjsort : datesw, - submajor ? datesw : subjsort); - else - printf ("sorting by datefield %s\n", datesw); - } - - /* first sort by date, or by subject-major, date-minor */ - qsort ((char *) dlist, nmsgs, sizeof(*dlist), - (qsort_comp) (submajor && subjsort ? txtsort : dsort)); - - /* - * if we're sorting on subject, we need another list - * in subject order, then a merge pass to collate the - * two sorts. - */ - if (!submajor && subjsort) { /* already date sorted */ - struct smsg **slist, **flist; - register struct smsg ***il, **fp, **dp; - - slist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*slist)); - memcpy((char *)slist, (char *)dlist, (nmsgs+1)*sizeof(*slist)); - qsort((char *)slist, nmsgs, sizeof(*slist), (qsort_comp) subsort); + + if (!msgs.size) + app_msgarg(&msgs, seq_all); + if (!datesw) + datesw = "date"; + if (!folder) + folder = getcurfol(); + maildir = toabsdir(folder); + + if (chdir(maildir) == NOTOK) + adios(maildir, "unable to change directory to"); + + /* read folder and create message structure */ + if (!(mp = folder_read(folder))) + adios(NULL, "unable to read folder %s", folder); + + /* check for empty folder */ + if (mp->nummsg == 0) + adios(NULL, "no messages in %s", folder); + + /* parse all the message ranges/sequences and set SELECTED */ + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert(mp, msgs.msgs[msgnum])) + done(1); + seq_setprev(mp); /* set the previous sequence */ + + if ((nmsgs = read_hdrs(mp, datesw)) <= 0) + adios(NULL, "no messages to sort"); /* - * make an inversion list so we can quickly find - * the collection of messages with the same subj - * given a message number. - */ - il = (struct smsg ***) calloc (mp->hghsel+1, sizeof(*il)); - if (! il) - adios (NULL, "couldn't allocate msg list"); + ** sort a list of pointers to our "messages to be sorted". + */ + dlist = (struct smsg **) mh_xmalloc((nmsgs+1) * sizeof(*dlist)); for (i = 0; i < nmsgs; i++) - il[slist[i]->s_msg] = &slist[i]; + dlist[i] = &smsgs[i]; + dlist[nmsgs] = 0; + + if (verbose) { /* announce what we're doing */ + if (subjsort) + printf("sorting by %s-major %s-minor\n", + submajor ? subjsort : datesw, + submajor ? datesw : subjsort); + else + printf("sorting by datefield %s\n", datesw); + } + + /* first sort by date, or by subject-major, date-minor */ + qsort((char *) dlist, nmsgs, sizeof(*dlist), + (qsort_comp) (submajor && subjsort ? txtsort : dsort)); + /* - * make up the final list, chronological but with - * all the same subjects grouped together. - */ - flist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*flist)); - fp = flist; - for (dp = dlist; *dp;) { - register struct smsg **s = il[(*dp++)->s_msg]; - - /* see if we already did this guy */ - if (! s) - continue; - - *fp++ = *s++; - /* - * take the next message(s) if there is one, - * its subject isn't null and its subject - * is the same as this one and it's not too - * far away in time. - */ - while (*s && (*s)->s_subj[0] && - strcmp((*s)->s_subj, s[-1]->s_subj) == 0 && - (datelimit == 0 || - (*s)->s_clock - s[-1]->s_clock <= datelimit)) { - il[(*s)->s_msg] = 0; - *fp++ = *s++; - } + ** if we're sorting on subject, we need another list + ** in subject order, then a merge pass to collate the + ** two sorts. + */ + if (!submajor && subjsort) { /* already date sorted */ + struct smsg **slist, **flist; + register struct smsg ***il, **fp, **dp; + + slist = (struct smsg **) + mh_xmalloc((nmsgs+1) * sizeof(*slist)); + memcpy((char *)slist, (char *)dlist, (nmsgs+1)*sizeof(*slist)); + qsort((char *)slist, nmsgs, sizeof(*slist), + (qsort_comp) subsort); + + /* + ** make an inversion list so we can quickly find + ** the collection of messages with the same subj + ** given a message number. + */ + il = (struct smsg ***) calloc(mp->hghsel+1, sizeof(*il)); + if (! il) + adios(NULL, "couldn't allocate msg list"); + for (i = 0; i < nmsgs; i++) + il[slist[i]->s_msg] = &slist[i]; + /* + ** make up the final list, chronological but with + ** all the same subjects grouped together. + */ + flist = (struct smsg **) + mh_xmalloc((nmsgs+1) * sizeof(*flist)); + fp = flist; + for (dp = dlist; *dp;) { + register struct smsg **s = il[(*dp++)->s_msg]; + + /* see if we already did this guy */ + if (! s) + continue; + + *fp++ = *s++; + /* + ** take the next message(s) if there is one, + ** its subject isn't null and its subject + ** is the same as this one and it's not too + ** far away in time. + */ + while (*s && (*s)->s_subj[0] && strcmp((*s)->s_subj, s[-1]->s_subj) == 0 && (datelimit == 0 || (*s)->s_clock - s[-1]->s_clock <= datelimit)) { + il[(*s)->s_msg] = 0; + *fp++ = *s++; + } + } + *fp = 0; + free(slist); + free(dlist); + dlist = flist; } - *fp = 0; - free (slist); - free (dlist); - dlist = flist; - } - - /* - * At this point, dlist is a sorted array of pointers to smsg structures, - * each of which contains a message number. - */ - - rename_msgs (mp, dlist); - - context_replace (pfolder, folder); /* update current folder */ - seq_save (mp); /* synchronize message sequences */ - context_save (); /* save the context file */ - folder_free (mp); /* free folder/message structure */ - done (0); - return 1; + + /* + ** At this point, dlist is a sorted array of pointers to smsg + ** structures, each of which contains a message number. + */ + + rename_msgs(mp, dlist); + + context_replace(curfolder, folder); /* update current folder */ + seq_save(mp); /* synchronize message sequences */ + context_save(); /* save the context file */ + folder_free(mp); /* free folder/message structure */ + done(0); + return 1; } static int -read_hdrs (struct msgs *mp, char *datesw) +read_hdrs(struct msgs *mp, char *datesw) { - int msgnum; - struct tws tb; - register struct smsg *s; - - twscopy (&tb, dlocaltimenow ()); - - smsgs = (struct smsg *) - calloc ((size_t) (mp->hghsel - mp->lowsel + 2), - sizeof(*smsgs)); - if (smsgs == NULL) - adios (NULL, "unable to allocate sort storage"); - - s = smsgs; - for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { - if (is_selected(mp, msgnum)) { - if (get_fields (datesw, msgnum, s)) { - s->s_msg = msgnum; - s++; - } + int msgnum; + struct tws tb; + register struct smsg *s; + + twscopy(&tb, dlocaltimenow()); + + smsgs = (struct smsg *) calloc((size_t) (mp->hghsel - mp->lowsel + 2), + sizeof(*smsgs)); + if (smsgs == NULL) + adios(NULL, "unable to allocate sort storage"); + + s = smsgs; + for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { + if (is_selected(mp, msgnum)) { + if (get_fields(datesw, msgnum, s)) { + s->s_msg = msgnum; + s++; + } + } } - } - s->s_msg = 0; - return(s - smsgs); + s->s_msg = 0; + return(s - smsgs); } /* - * Parse the message and get the data or subject field, - * if needed. - */ +** Parse the message and get the data or subject field, +** if needed. +*/ static int -get_fields (char *datesw, int msg, struct smsg *smsg) +get_fields(char *datesw, int msg, struct smsg *smsg) { - register int state; - int compnum; - char *msgnam, buf[BUFSIZ], nam[NAMESZ]; - register struct tws *tw; - register char *datecomp = NULL, *subjcomp = NULL; - register FILE *in; - - if ((in = fopen (msgnam = m_name (msg), "r")) == NULL) { - admonish (msgnam, "unable to read message"); - return (0); - } - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, nam, buf, sizeof(buf), in)) { - case FLD: - case FLDEOF: - case FLDPLUS: - compnum++; - if (!mh_strcasecmp (nam, datesw)) { - datecomp = add (buf, datecomp); - while (state == FLDPLUS) { - state = m_getfld (state, nam, buf, sizeof(buf), in); - datecomp = add (buf, datecomp); - } - if (!subjsort || subjcomp) - break; - } else if (subjsort && !mh_strcasecmp (nam, subjsort)) { - subjcomp = add (buf, subjcomp); - while (state == FLDPLUS) { - state = m_getfld (state, nam, buf, sizeof(buf), in); - subjcomp = add (buf, subjcomp); - } - if (datecomp) - break; - } else { - /* just flush this guy */ - while (state == FLDPLUS) - state = m_getfld (state, nam, buf, sizeof(buf), in); - } - continue; - - case BODY: - case BODYEOF: - case FILEEOF: - break; - - case LENERR: - case FMTERR: - if (state == LENERR || state == FMTERR) - admonish (NULL, "format error in message %d (header #%d)", - msg, compnum); - if (datecomp) - free (datecomp); - if (subjcomp) - free (subjcomp); - fclose (in); - return (0); - - default: - adios (NULL, "internal error -- you lose"); + register int state; + int compnum; + char *msgnam, buf[BUFSIZ], nam[NAMESZ]; + register struct tws *tw; + register char *datecomp = NULL, *subjcomp = NULL; + register FILE *in; + + if ((in = fopen(msgnam = m_name(msg), "r")) == NULL) { + admonish(msgnam, "unable to read message"); + return (0); } - break; - } - - /* - * If no date component, then use the modification - * time of the file as its date - */ - if (!datecomp || (tw = dparsetime (datecomp)) == NULL) { - struct stat st; - - admonish (NULL, "can't parse %s field in message %d", datesw, msg); - fstat (fileno (in), &st); - smsg->s_clock = st.st_mtime; - } else { - smsg->s_clock = dmktime (tw); - } - - if (subjsort) { - if (subjcomp) { - /* - * try to make the subject "canonical": delete - * leading "re:", everything but letters & smash - * letters to lower case. - */ - register char *cp, *cp2; - register unsigned char c; - - cp = subjcomp; - cp2 = subjcomp; - if (strcmp (subjsort, "subject") == 0) { - while ((c = *cp)) { - if (! isspace(c)) { - if(uprf(cp, "re:")) - cp += 2; - else - break; - } - cp++; + for (compnum = 1, state = FLD;;) { + switch (state = m_getfld(state, nam, buf, sizeof(buf), in)) { + case FLD: + case FLDEOF: + case FLDPLUS: + compnum++; + if (!mh_strcasecmp(nam, datesw)) { + datecomp = add(buf, datecomp); + while (state == FLDPLUS) { + state = m_getfld(state, nam, buf, + sizeof(buf), in); + datecomp = add(buf, datecomp); + } + if (!subjsort || subjcomp) + break; + } else if (subjsort && !mh_strcasecmp(nam, subjsort)) { + subjcomp = add(buf, subjcomp); + while (state == FLDPLUS) { + state = m_getfld(state, nam, buf, + sizeof(buf), in); + subjcomp = add(buf, subjcomp); + } + if (datecomp) + break; + } else { + /* just flush this guy */ + while (state == FLDPLUS) + state = m_getfld(state, nam, buf, + sizeof(buf), in); + } + continue; + + case BODY: + case BODYEOF: + case FILEEOF: + break; + + case LENERR: + case FMTERR: + if (state == LENERR || state == FMTERR) + admonish(NULL, "format error in message %d (header #%d)", msg, compnum); + if (datecomp) + free(datecomp); + if (subjcomp) + free(subjcomp); + fclose(in); + return (0); + + default: + adios(NULL, "internal error -- you lose"); } - } - - while ((c = *cp++)) { - if (isalnum(c)) - *cp2++ = isupper(c) ? tolower(c) : c; - } + break; + } - *cp2 = '\0'; + /* + ** If no date component, then use the modification + ** time of the file as its date + */ + if (!datecomp || (tw = dparsetime(datecomp)) == NULL) { + struct stat st; + + admonish(NULL, "can't parse %s field in message %d", + datesw, msg); + fstat(fileno(in), &st); + smsg->s_clock = st.st_mtime; + } else { + smsg->s_clock = dmktime(tw); } - else - subjcomp = ""; - smsg->s_subj = subjcomp; - } - fclose (in); - if (datecomp) - free (datecomp); + if (subjsort) { + if (subjcomp) { + /* + ** try to make the subject "canonical": delete + ** leading "re:", everything but letters & smash + ** letters to lower case. + */ + register char *cp, *cp2; + register unsigned char c; + + cp = subjcomp; + cp2 = subjcomp; + if (strcmp(subjsort, "subject") == 0) { + while ((c = *cp)) { + if (! isspace(c)) { + if(uprf(cp, "re:")) + cp += 2; + else + break; + } + cp++; + } + } + + while ((c = *cp++)) { + if (isalnum(c)) + *cp2++ = isupper(c) ? tolower(c) : c; + } + + *cp2 = '\0'; + } else + subjcomp = ""; + + smsg->s_subj = subjcomp; + } + fclose(in); + if (datecomp) + free(datecomp); - return (1); + return (1); } /* - * sort on dates. - */ +** sort on dates. +*/ static int -dsort (struct smsg **a, struct smsg **b) +dsort(struct smsg **a, struct smsg **b) { - if ((*a)->s_clock < (*b)->s_clock) - return (-1); - else if ((*a)->s_clock > (*b)->s_clock) - return (1); - else if ((*a)->s_msg < (*b)->s_msg) - return (-1); - else - return (1); + if ((*a)->s_clock < (*b)->s_clock) + return (-1); + else if ((*a)->s_clock > (*b)->s_clock) + return (1); + else if ((*a)->s_msg < (*b)->s_msg) + return (-1); + else + return (1); } /* - * sort on subjects. - */ +** sort on subjects. +*/ static int -subsort (struct smsg **a, struct smsg **b) +subsort(struct smsg **a, struct smsg **b) { - register int i; + register int i; - if ((i = strcmp ((*a)->s_subj, (*b)->s_subj))) - return (i); + if ((i = strcmp((*a)->s_subj, (*b)->s_subj))) + return (i); - return (dsort (a, b)); + return (dsort(a, b)); } static int -txtsort (struct smsg **a, struct smsg **b) +txtsort(struct smsg **a, struct smsg **b) { - register int i; + register int i; - if ((i = strcmp ((*a)->s_subj, (*b)->s_subj))) - return (i); - else if ((*a)->s_msg < (*b)->s_msg) - return (-1); - else - return (1); + if ((i = strcmp((*a)->s_subj, (*b)->s_subj))) + return (i); + else if ((*a)->s_msg < (*b)->s_msg) + return (-1); + else + return (1); } static void -rename_chain (struct msgs *mp, struct smsg **mlist, int msg, int endmsg) +rename_chain(struct msgs *mp, struct smsg **mlist, int msg, int endmsg) { - int nxt, old, new; - char *newname, oldname[BUFSIZ]; - char newbuf[MAXPATHLEN + 1]; - - for (;;) { - nxt = mlist[msg] - smsgs; /* mlist[msg] is a ptr into smsgs */ - mlist[msg] = (struct smsg *)0; - old = smsgs[nxt].s_msg; - new = smsgs[msg].s_msg; - strncpy (oldname, m_name (old), sizeof(oldname)); - newname = m_name (new); - if (verbose) - printf ("message %d becomes message %d\n", old, new); - - (void)snprintf(oldname, sizeof (oldname), "%s/%d", mp->foldpath, old); - (void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, new); - ext_hook("ref-hook", oldname, newbuf); - - if (rename (oldname, newname) == NOTOK) - adios (newname, "unable to rename %s to", oldname); - - copy_msg_flags (mp, new, old); - if (mp->curmsg == old) - seq_setcur (mp, new); - - if (nxt == endmsg) - break; - - msg = nxt; - } -/* if (nxt != endmsg); */ -/* rename_chain (mp, mlist, nxt, endmsg); */ + int nxt, old, new; + char *newname, oldname[BUFSIZ]; + char newbuf[MAXPATHLEN + 1]; + + for (;;) { + nxt = mlist[msg] - smsgs; /* mlist[msg] is a ptr into smsgs */ + mlist[msg] = (struct smsg *)0; + old = smsgs[nxt].s_msg; + new = smsgs[msg].s_msg; + strncpy(oldname, m_name(old), sizeof(oldname)); + newname = m_name(new); + if (verbose) + printf("message %d becomes message %d\n", old, new); + + snprintf(oldname, sizeof (oldname), "%s/%d", + mp->foldpath, old); + snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, new); + ext_hook("ref-hook", oldname, newbuf); + + if (rename(oldname, newname) == NOTOK) + adios(newname, "unable to rename %s to", oldname); + + copy_msg_flags(mp, new, old); + if (mp->curmsg == old) + seq_setcur(mp, new); + + if (nxt == endmsg) + break; + + msg = nxt; + } +/* if (nxt != endmsg); */ +/* rename_chain(mp, mlist, nxt, endmsg); */ } static void -rename_msgs (struct msgs *mp, struct smsg **mlist) +rename_msgs(struct msgs *mp, struct smsg **mlist) { - int i, j, old, new; - seqset_t tmpset; - char f1[BUFSIZ], tmpfil[BUFSIZ]; - char newbuf[MAXPATHLEN + 1]; - struct smsg *sp; - - strncpy (tmpfil, m_name (mp->hghmsg + 1), sizeof(tmpfil)); - - for (i = 0; i < nmsgs; i++) { - if (! (sp = mlist[i])) - continue; /* did this one */ - - j = sp - smsgs; - if (j == i) - continue; /* this one doesn't move */ - - /* - * the guy that was msg j is about to become msg i. - * rename 'j' to make a hole, then recursively rename - * guys to fill up the hole. - */ - old = smsgs[j].s_msg; - new = smsgs[i].s_msg; - strncpy (f1, m_name (old), sizeof(f1)); - - if (verbose) - printf ("renaming message chain from %d to %d\n", old, new); - - /* - * Run the external hook to refile the old message as the - * temporary message number that is off of the end of the - * messages in the folder. - */ - - (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, old); - (void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, mp->hghmsg + 1); - ext_hook("ref-hook", f1, newbuf); - - if (rename (f1, tmpfil) == NOTOK) - adios (tmpfil, "unable to rename %s to ", f1); - - get_msg_flags (mp, &tmpset, old); - - rename_chain (mp, mlist, j, i); - - /* - * Run the external hook to refile the temorary message number - * to the real place. - */ - - (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, new); - ext_hook("ref-hook", newbuf, f1); - - if (rename (tmpfil, m_name(new)) == NOTOK) - adios (m_name(new), "unable to rename %s to", tmpfil); - - set_msg_flags (mp, &tmpset, new); - mp->msgflags |= SEQMOD; - } + int i, j, old, new; + seqset_t tmpset; + char f1[BUFSIZ], tmpfil[BUFSIZ]; + char newbuf[MAXPATHLEN + 1]; + struct smsg *sp; + + strncpy(tmpfil, m_name(mp->hghmsg + 1), sizeof(tmpfil)); + + for (i = 0; i < nmsgs; i++) { + if (! (sp = mlist[i])) + continue; /* did this one */ + + j = sp - smsgs; + if (j == i) + continue; /* this one doesn't move */ + + /* + ** the guy that was msg j is about to become msg i. + ** rename 'j' to make a hole, then recursively rename + ** guys to fill up the hole. + */ + old = smsgs[j].s_msg; + new = smsgs[i].s_msg; + strncpy(f1, m_name(old), sizeof(f1)); + + if (verbose) + printf("renaming message chain from %d to %d\n", + old, new); + + /* + ** Run the external hook to refile the old message as the + ** temporary message number that is off of the end of the + ** messages in the folder. + */ + + snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, old); + snprintf(newbuf, sizeof (newbuf), "%s/%d", + mp->foldpath, mp->hghmsg + 1); + ext_hook("ref-hook", f1, newbuf); + + if (rename(f1, tmpfil) == NOTOK) + adios(tmpfil, "unable to rename %s to ", f1); + + get_msg_flags(mp, &tmpset, old); + + rename_chain(mp, mlist, j, i); + + /* + ** Run the external hook to refile the temorary message number + ** to the real place. + */ + + snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, new); + ext_hook("ref-hook", newbuf, f1); + + if (rename(tmpfil, m_name(new)) == NOTOK) + adios(m_name(new), "unable to rename %s to", tmpfil); + + set_msg_flags(mp, &tmpset, new); + mp->msgflags |= SEQMOD; + } } diff --git a/uip/spost.c b/uip/spost.c index c7582ba..9b2ffcb 100644 --- a/uip/spost.c +++ b/uip/spost.c @@ -1,14 +1,13 @@ - /* - * spost.c -- feed messages to sendmail - * - * This is a simpler, faster, replacement for "post" for use - * when "sendmail" is the transport system. - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** spost.c -- feed messages to sendmail +** +** This is a simpler, faster, replacement for "post" for use +** when "sendmail" is the transport system. +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include #include @@ -16,882 +15,633 @@ #include #include #include -#include #include -#define MAX_SM_FIELD 1476 /* < largest hdr field sendmail will accept */ -#define FCCS 10 /* max number of fccs allowed */ - -struct swit switches[] = { -#define FILTSW 0 - { "filter filterfile", 0 }, -#define NFILTSW 1 - { "nofilter", 0 }, -#define FRMTSW 2 - { "format", 0 }, -#define NFRMTSW 3 - { "noformat", 0 }, -#define REMVSW 4 - { "remove", 0 }, -#define NREMVSW 5 - { "noremove", 0 }, -#define VERBSW 6 - { "verbose", 0 }, -#define NVERBSW 7 - { "noverbose", 0 }, -#define WATCSW 8 - { "watch", 0 }, -#define NWATCSW 9 - { "nowatch", 0 }, -#define BACKSW 10 - { "backup", 0 }, -#define NBACKSW 11 - { "nobackup", 0 }, -#define ALIASW 12 - { "alias aliasfile", 0 }, -#define NALIASW 13 - { "noalias", 0 }, -#define WIDTHSW 14 - { "width columns", 0 }, -#define VERSIONSW 15 - { "version", 0 }, -#define HELPSW 16 - { "help", 0 }, -#define DEBUGSW 17 - { "debug", -5 }, -#define DISTSW 18 - { "dist", -4 }, /* interface from dist */ -#define CHKSW 19 - { "check", -5 }, /* interface from whom */ -#define NCHKSW 20 - { "nocheck", -7 }, /* interface from whom */ -#define WHOMSW 21 - { "whom", -4 }, /* interface from whom */ -#define PUSHSW 22 /* fork to sendmail then exit */ - { "push", -4 }, -#define NPUSHSW 23 /* exec sendmail */ - { "nopush", -6 }, -#define LIBSW 24 - { "library directory", -7 }, -#define ANNOSW 25 - { "idanno number", -6 }, - { NULL, 0 } +#define MAX_SM_FIELD 1476 /* < largest hdr field sendmail will accept */ + +static struct swit switches[] = { +#define VERBSW 0 + { "verbose", 0 }, +#define NVERBSW 1 + { "noverbose", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, +#define DEBUGSW 4 + { "debug", -5 }, +#define DISTSW 5 + { "dist", -4 }, /* interface from dist */ + { NULL, 0 } }; /* flags for headers->flags */ -#define HNOP 0x0000 /* just used to keep .set around */ -#define HBAD 0x0001 /* bad header - don't let it through */ -#define HADR 0x0002 /* header has an address field */ -#define HSUB 0x0004 /* Subject: header */ -#define HTRY 0x0008 /* try to send to addrs on header */ -#define HBCC 0x0010 /* don't output this header */ -#define HMNG 0x0020 /* mung this header */ -#define HNGR 0x0040 /* no groups allowed in this header */ -#define HFCC 0x0080 /* FCC: type header */ -#define HNIL 0x0100 /* okay for this header not to have addrs */ -#define HIGN 0x0200 /* ignore this header */ +#define HNOP 0x0000 /* just used to keep .set around */ +#define HBAD 0x0001 /* bad header - don't let it through */ +#define HADR 0x0002 /* header has an address field */ +#define HSUB 0x0004 /* Subject: header */ +#define HTRY 0x0008 /* try to send to addrs on header */ +#define HBCC 0x0010 /* don't output this header */ +#define HFCC 0x0020 /* FCC: type header */ +#define HIGN 0x0040 /* ignore this header */ /* flags for headers->set */ -#define MFRM 0x0001 /* we've seen a From: */ -#define MDAT 0x0002 /* we've seen a Date: */ -#define MRFM 0x0004 /* we've seen a Resent-From: */ -#define MVIS 0x0008 /* we've seen sighted addrs */ -#define MINV 0x0010 /* we've seen blind addrs */ -#define MRDT 0x0020 /* we've seen a Resent-Date: */ +#define MFRM 0x0001 /* we've seen a From: */ +#define MDAT 0x0002 /* we've seen a Date: */ +#define MRFM 0x0004 /* we've seen a Resent-From: */ +#define MVIS 0x0008 /* we've seen sighted addrs */ +#define MINV 0x0010 /* we've seen blind addrs */ +#define MRDT 0x0020 /* we've seen a Resent-Date: */ struct headers { - char *value; - unsigned int flags; - unsigned int set; + char *value; + unsigned int flags; + unsigned int set; }; - static struct headers NHeaders[] = { - { "Return-Path", HBAD, 0 }, - { "Received", HBAD, 0 }, - { "Reply-To", HADR|HNGR, 0 }, - { "From", HADR|HNGR, MFRM }, - { "Sender", HADR|HBAD, 0 }, - { "Date", HNOP, MDAT }, - { "Subject", HSUB, 0 }, - { "To", HADR|HTRY, MVIS }, - { "cc", HADR|HTRY, MVIS }, - { "Bcc", HADR|HTRY|HBCC|HNIL, MINV }, - { "Message-Id", HBAD, 0 }, - { "Fcc", HFCC, 0 }, - { NULL, 0, 0 } + { "Return-Path", HBAD, 0 }, + { "Received", HBAD, 0 }, + { "Reply-To", HADR, 0 }, + { "From", HADR, MFRM }, + { "Sender", HADR|HBAD, 0 }, + { "Date", HNOP, MDAT }, + { "Subject", HSUB, 0 }, + { "To", HADR|HTRY, MVIS }, + { "Cc", HADR|HTRY, MVIS }, + { "Bcc", HADR|HTRY|HBCC, MINV }, + { "Message-Id", HBAD, 0 }, + { "Fcc", HFCC, 0 }, + { "Envelope-From", HIGN, 0 }, + { NULL, 0, 0 } }; static struct headers RHeaders[] = { - { "Resent-Reply-To", HADR|HNGR, 0 }, - { "Resent-From", HADR|HNGR, MRFM }, - { "Resent-Sender", HADR|HBAD, 0 }, - { "Resent-Date", HNOP, MRDT }, - { "Resent-Subject", HSUB, 0 }, - { "Resent-To", HADR|HTRY, MVIS }, - { "Resent-cc", HADR|HTRY, MVIS }, - { "Resent-Bcc", HADR|HTRY|HBCC, MINV }, - { "Resent-Message-Id", HBAD, 0 }, - { "Resent-Fcc", HFCC, 0 }, - { "Reply-To", HADR, 0 }, - { "Fcc", HIGN, 0 }, - { NULL, 0, 0 } + { "Resent-Reply-To", HADR, 0 }, + { "Resent-From", HADR, MRFM }, + { "Resent-Sender", HADR|HBAD, 0 }, + { "Resent-Date", HNOP, MRDT }, + { "Resent-Subject", HSUB, 0 }, + { "Resent-To", HADR|HTRY, MVIS }, + { "Resent-Cc", HADR|HTRY, MVIS }, + { "Resent-Bcc", HADR|HTRY|HBCC, MINV }, + { "Resent-Message-Id", HBAD, 0 }, + { "Resent-Fcc", HFCC, 0 }, + { "Reply-To", HADR, 0 }, + { "Fcc", HIGN, 0 }, + { "Envelope-From", HIGN, 0 }, + { NULL, 0, 0 } }; -static short fccind = 0; /* index into fccfold[] */ - -static int badmsg = 0; /* message has bad semantics */ -static int verbose = 0; /* spell it out */ -static int debug = 0; /* debugging post */ -static int rmflg = 1; /* remove temporary file when done */ -static int watch = 0; /* watch the delivery process */ -static int backflg = 0; /* rename input file as *.bak when done */ -static int whomflg = 0; /* if just checking addresses */ -static int pushflg = 0; /* if going to fork to sendmail */ -static int aliasflg = -1; /* if going to process aliases */ -static int outputlinelen=72; +static int badmsg = 0; +static int verbose = 0; +static int debug = 0; +static int aliasflg = 0; /* if going to process aliases */ -static unsigned msgflags = 0; /* what we've seen */ +static unsigned msgflags = 0; /* what we've seen */ static enum { - normal, resent + normal, resent } msgstate = normal; -static char tmpfil[] = "/tmp/pstXXXXXX"; - -static char from[BUFSIZ]; /* my network address */ -static char signature[BUFSIZ]; /* my signature */ -static char *filter = NULL; /* the filter for BCC'ing */ -static char *subject = NULL; /* the subject field for BCC'ing */ -static char *fccfold[FCCS]; /* foldernames for FCC'ing */ - -static struct headers *hdrtab; /* table for the message we're doing */ -static FILE *out; /* output (temp) file */ - -extern char *sendmail; +static char *tmpfil; -/* - * external prototypes - */ -extern char *getfullname (void); -extern char *getusername (void); +static char *subject = NULL; /* the subject field for BCC'ing */ +static char fccs[BUFSIZ] = ""; +struct mailname *bccs = NULL; /* list of the bcc recipients */ -extern boolean draft_from_masquerading; /* defined in mts.c */ +static struct headers *hdrtab; /* table for the message we're doing */ +static FILE *out; /* output (temp) file */ /* - * static prototypes - */ -static void putfmt (char *, char *, FILE *); -static void start_headers (void); -static void finish_headers (FILE *); -static int get_header (char *, struct headers *); -static void putadr (char *, struct mailname *); -static int putone (char *, int, int); -static void insert_fcc (struct headers *, unsigned char *); -static void file (char *); -static void fcc (char *, char *); - -#if 0 -static void die (char *, char *, ...); -static void make_bcc_file (void); -#endif +** static prototypes +*/ +static void putfmt(char *, char *, FILE *); +static void finish_headers(FILE *); +static int get_header(char *, struct headers *); +static void putadr(char *, struct mailname *); +static int putone(char *, int, int); +static void process_fcc(char *); +static void fcc(char *, char *); +static void process_bccs(char *); int -main (int argc, char **argv) +main(int argc, char **argv) { - int state, i, pid, compnum; - char *cp, *msg = NULL, **argp, **arguments; - char *sargv[16], buf[BUFSIZ], name[NAMESZ]; - FILE *in; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - mts_init (invo_name); - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DEBUGSW: - debug++; - continue; - - case DISTSW: - msgstate = resent; - continue; - - case WHOMSW: - whomflg++; - continue; - - case FILTSW: - if (!(filter = *argp++) || *filter == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NFILTSW: - filter = NULL; - continue; - - case REMVSW: - rmflg++; - continue; - case NREMVSW: - rmflg = 0; - continue; - - case BACKSW: - backflg++; - continue; - case NBACKSW: - backflg = 0; - continue; - - case VERBSW: - verbose++; - continue; - case NVERBSW: - verbose = 0; - continue; - - case WATCSW: - watch++; - continue; - case NWATCSW: - watch = 0; - continue; - - case PUSHSW: - pushflg++; - continue; - case NPUSHSW: - pushflg = 0; - continue; - - case ALIASW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if (aliasflg < 0) - alias (AliasFile);/* load default aka's */ - aliasflg = 1; - if ((state = alias(cp)) != AK_OK) - adios (NULL, "aliasing error in file %s - %s", - cp, akerror(state) ); - continue; - case NALIASW: - aliasflg = 0; - continue; - - case WIDTHSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - outputlinelen = atoi (cp); - if (outputlinelen <= 10) - outputlinelen = 72; - continue; - - case LIBSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - /* create a minimal context */ - if (context_foil (cp) == -1) - done(1); - continue; - - case ANNOSW: - /* -idanno switch ignored */ - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - } + int state, compnum; + char *cp, *msg = NULL, **argp, **arguments; + char *sargv[16], buf[BUFSIZ], name[NAMESZ]; + FILE *in; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + context_read(); + + arguments = getarguments(invo_name, argc, argv, 0); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [switches] file", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case DEBUGSW: + debug++; + continue; + + case DISTSW: + msgstate = resent; + continue; + + case VERBSW: + verbose++; + continue; + case NVERBSW: + verbose = 0; + continue; + } + } + if (msg) + adios(NULL, "only one message at a time!"); + else + msg = cp; } - if (msg) - adios (NULL, "only one message at a time!"); - else - msg = cp; - } - - if (aliasflg < 0) - alias (AliasFile); /* load default aka's */ - - if (!msg) - adios (NULL, "usage: %s [switches] file", invo_name); - - if ((in = fopen (msg, "r")) == NULL) - adios (msg, "unable to open"); - - start_headers (); - if (debug) { - verbose++; - out = stdout; - } - else { -#ifdef HAVE_MKSTEMP - if ((out = fdopen( mkstemp (tmpfil), "w" )) == NULL ) - adios (tmpfil, "unable to create"); -#else - mktemp (tmpfil); - if ((out = fopen (tmpfil, "w")) == NULL) - adios (tmpfil, "unable to create"); - chmod (tmpfil, 0600); -#endif + + if (!msg) + adios(NULL, "usage: %s [switches] file", invo_name); + + if ((in = fopen(msg, "r")) == NULL) + adios(msg, "unable to open"); + + if (debug) { + verbose++; + out = stdout; + } else { + tmpfil = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out)); } - hdrtab = (msgstate == normal) ? NHeaders : RHeaders; - - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), in)) { - case FLD: - compnum++; - putfmt (name, buf, out); - continue; - - case FLDPLUS: - compnum++; - cp = add (buf, cp); - while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); - cp = add (buf, cp); + /* check for "Aliasfile:" profile entry */ + if ((cp = context_find("Aliasfile"))) { + char *dp, **ap; + + aliasflg = 1; + for (ap=brkstring(dp=getcpy(cp), " ", "\n"); ap && *ap; + ap++) { + if ((state = alias(etcpath(*ap))) != AK_OK) { + adios(NULL, "aliasing error in file %s: %s", + *ap, akerror(state)); + } } - putfmt (name, cp, out); - free (cp); - continue; - - case BODY: - finish_headers (out); - fprintf (out, "\n%s", buf); - if(whomflg == 0) - while (state == BODY) { - state = m_getfld (state, name, buf, sizeof(buf), in); - fputs (buf, out); - } - break; + } + - case FILEEOF: - finish_headers (out); + hdrtab = (msgstate == normal) ? NHeaders : RHeaders; + + for (compnum = 1, state = FLD;;) { + switch (state = m_getfld(state, name, buf, sizeof(buf), in)) { + case FLD: + compnum++; + putfmt(name, buf, out); + continue; + + case FLDPLUS: + compnum++; + cp = add(buf, cp); + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof(buf), in); + cp = add(buf, cp); + } + putfmt(name, cp, out); + free(cp); + continue; + + case BODY: + finish_headers(out); + fprintf(out, "\n%s", buf); + while (state == BODY) { + state = m_getfld(state, name, buf, + sizeof(buf), in); + fputs(buf, out); + } + break; + + case FILEEOF: + finish_headers(out); + break; + + case LENERR: + case FMTERR: + adios(NULL, "message format error in component #%d", + compnum); + + default: + adios(NULL, "getfld() returned %d", state); + } break; + } + fclose(in); - case LENERR: - case FMTERR: - adios (NULL, "message format error in component #%d", - compnum); + if (debug) { + /* stop here */ + done(0); + } - default: - adios (NULL, "getfld() returned %d", state); + fclose(out); + + /* process Fcc */ + if (*fccs) { + fcc(tmpfil, fccs); } - break; - } - - fclose (in); - if (backflg && !whomflg) { - strncpy (buf, m_backup (msg), sizeof(buf)); - if (rename (msg, buf) == NOTOK) - advise (buf, "unable to rename %s to", msg); - } - - if (debug) { - done (0); - } - else - fclose (out); - - file (tmpfil); - - /* - * re-open the temp file, unlink it and exec sendmail, giving it - * the msg temp file as std in. - */ - if ( freopen( tmpfil, "r", stdin) == NULL) - adios (tmpfil, "can't reopen for sendmail"); - if (rmflg) - unlink (tmpfil); - - argp = sargv; - *argp++ = "send-mail"; - *argp++ = "-m"; /* send to me too */ - *argp++ = "-t"; /* read msg for recipients */ - *argp++ = "-i"; /* don't stop on "." */ - if (whomflg) - *argp++ = "-bv"; - if (watch || verbose) - *argp++ = "-v"; - *argp = NULL; - - if (pushflg && !(watch || verbose)) { - /* fork to a child to run sendmail */ - for (i=0; (pid = vfork()) == NOTOK && i < 5; i++) - sleep(5); - switch (pid) { - case NOTOK: - fprintf (verbose ? stdout : stderr, "%s: can't fork to %s\n", - invo_name, sendmail); - exit(-1); - case OK: - /* we're the child .. */ - break; - default: - exit(0); + + if (bccs) { + process_bccs(tmpfil); + if (!(msgflags & MVIS)) { + /* only Bcc rcpts: we're finished here */ + unlink(tmpfil); + exit(0); + } } - } - execv ( sendmail, sargv); - adios ( sendmail, "can't exec"); - return 0; /* dead code to satisfy the compiler */ + + /* + ** re-open the temp file, unlink it and exec sendmail, giving it + ** the msg temp file as std in. + */ + if (!freopen(tmpfil, "r", stdin)) { + adios(tmpfil, "can't reopen for sendmail"); + } + unlink(tmpfil); + + argp = sargv; + *argp++ = "send-mail"; + *argp++ = "-m"; /* send to me too */ + *argp++ = "-t"; /* read msg for recipients */ + *argp++ = "-i"; /* don't stop on "." */ + if (verbose) { + *argp++ = "-v"; + } + *argp = NULL; + execv(sendmail, sargv); + adios(sendmail, "can't exec"); + return -1; } + /* DRAFT GENERATION */ static void -putfmt (char *name, char *str, FILE *out) +putfmt(char *name, char *str, FILE *out) { - int i; - char *cp, *pp; - struct headers *hdr; - - while (*str == ' ' || *str == '\t') - str++; - - if ((i = get_header (name, hdrtab)) == NOTOK) { - fprintf (out, "%s: %s", name, str); - return; - } - - hdr = &hdrtab[i]; - if (hdr->flags & HIGN) - return; - if (hdr->flags & HBAD) { - advise (NULL, "illegal header line -- %s:", name); - badmsg++; - return; - } - msgflags |= hdr->set; - - if (hdr->flags & HSUB) - subject = subject ? add (str, add ("\t", subject)) : getcpy (str); - - if (hdr->flags & HFCC) { - if ((cp = strrchr(str, '\n'))) - *cp = 0; - for (cp = pp = str; (cp = strchr(pp, ',')); pp = cp) { - *cp++ = 0; - insert_fcc (hdr, pp); + int i; + char *cp; + struct headers *hdr; + + /* remove leading whitespace */ + while (*str==' ' || *str=='\t') { + str++; } - insert_fcc (hdr, pp); - return; - } - -#ifdef notdef - if (hdr->flags & HBCC) { - insert_bcc(str); - return; - } -#endif /* notdef */ - - if (*str != '\n' && *str != '\0') { - if (aliasflg && hdr->flags & HTRY) { - /* this header contains address(es) that we have to do - * alias expansion on. Because of the saved state in - * getname we have to put all the addresses into a list. - * We then let putadr munch on that list, possibly - * expanding aliases. - */ - register struct mailname *f = 0; - register struct mailname *mp = 0; - - while ((cp = getname(str))) { - mp = getm( cp, NULL, 0, AD_HOST, NULL); - if (f == 0) { - f = mp; - mp->m_next = mp; - } else { - mp->m_next = f->m_next; - f->m_next = mp; - f = mp; + + if ((i = get_header(name, hdrtab)) == NOTOK) { + /* no header we would care for */ + if (mh_strcasecmp(name, attach_hdr)!=0 && + mh_strcasecmp(name, sign_hdr)!=0 && + mh_strcasecmp(name, enc_hdr)!=0) { + /* push it through */ + fprintf(out, "%s: %s", name, str); } - } - f = mp->m_next; mp->m_next = 0; - putadr( name, f ); - } else { - /* The author(s) of spost decided that alias substitution wasn't - necessary for the non-HTRY headers. Unfortunately, one of those - headers is "From:", and having alias substitution work on that is - extremely useful for someone with a lot of POP3 email accounts or - aliases. post supports aliasing of "From:"... - - Since "From:"-processing is incompletely implemented in this - unsupported and undocumented spost backend, I'm not going to take - the time to implement my new draft-From:-based email address - masquerading. If I do ever implement it here, I'd almost - certainly want to implement "From:" line alias processing as - well. -- Dan Harkless */ - fprintf (out, "%s: %s", name, str ); + return; } - } -} - - -static void -start_headers (void) -{ - char *cp; - char sigbuf[BUFSIZ]; + /* it's one of the interesting headers */ + hdr = &hdrtab[i]; - strncpy(from, getusername(), sizeof(from)); + if (hdr->flags & HIGN || strcmp(str, "\n")==0) { + return; + } - if ((cp = getfullname ()) && *cp) { - strncpy (sigbuf, cp, sizeof(sigbuf)); - snprintf (signature, sizeof(signature), "%s <%s>", sigbuf, from); - } - else - snprintf (signature, sizeof(signature), "%s", from); -} + if (hdr->flags & HBAD) { + advise(NULL, "illegal header line -- %s:", name); + badmsg++; + return; + } + msgflags |= hdr->set; -static void -finish_headers (FILE *out) -{ - switch (msgstate) { - case normal: - if (!(msgflags & MDAT)) - fprintf (out, "Date: %s\n", dtimenow (0)); - - if (msgflags & MFRM) { - /* There was already a From: in the draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Sender: %s\n", from); - } - else - fprintf (out, "From: %s\n", signature); - -#ifdef notdef - if (!(msgflags & MVIS)) - fprintf (out, "Bcc: Blind Distribution List: ;\n"); -#endif /* notdef */ - break; - - case resent: - if (!(msgflags & MRDT)) - fprintf (out, "Resent-Date: %s\n", dtimenow(0)); - if (msgflags & MRFM) { - /* There was already a Resent-From: in draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Resent-Sender: %s\n", from); - } - else - /* Construct a Resent-From: header. */ - fprintf (out, "Resent-From: %s\n", signature); -#ifdef notdef - if (!(msgflags & MVIS)) - fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n"); -#endif /* notdef */ - break; - } - - if (badmsg) - adios (NULL, "re-format message and try again"); -} + if (hdr->flags & HFCC) { + process_fcc(str); + return; + } + if (hdr->flags & HBCC) { + struct mailname *mp = NULL; -static int -get_header (char *header, struct headers *table) -{ - struct headers *h; + /* Create list of Bcc addrs. */ + while ((cp = getname(str))) { + mp = getm(cp, NULL, 0, AD_HOST, NULL); + mp->m_next = bccs; /* push */ + bccs = mp; + } + return; + } - for (h = table; h->value; h++) - if (!mh_strcasecmp (header, h->value)) - return (h - table); + if (aliasflg && hdr->flags & HTRY) { + /* + ** This header contains address(es) that we have to do + ** alias expansion on. Because of the saved state in + ** getname we have to put all the addresses into a list. + **/ + struct mailname *f = NULL; + struct mailname *mp = NULL; + + while ((cp = getname(str))) { + mp = getm(cp, NULL, 0, AD_HOST, NULL); + if (!f) { + f = mp; + mp->m_next = mp; + } else { + mp->m_next = f->m_next; + f->m_next = mp; + f = mp; + } + } + f = mp->m_next; + mp->m_next = NULL; + /* Now munch on the list, possibly expanding aliases */ + putadr(name, f); + return; + } - return NOTOK; + /* + ** The author(s) of spost decided that alias substitution wasn't + ** necessary for the non-HTRY headers. Unfortunately, one of + ** those headers is "From:", and having alias substitution work on + ** that is extremely useful for someone with a lot of POP3 email + ** accounts or aliases. post supports aliasing of "From:"... + ** + ** Since "From:"-processing is incompletely implemented in this + ** unsupported and undocumented spost backend, I'm not going + ** to take the time to implement my new draft-From:-based email + ** address masquerading. If I do ever implement it here, I'd almost + ** certainly want to implement "From:" line alias processing as well. + ** -- Dan Harkless + */ + /* + ** Although there is no masquerading anymore in mmh, we might want + ** to have aliasing of From: addresses. Think about it. + ** -- meillo@marmaro.de 2012-02 + */ + + if (hdr->flags & HSUB) { + subject = getcpy(str); + } + fprintf(out, "%s: %s", name, str); } /* - * output the address list for header "name". The address list - * is a linked list of mailname structs. "nl" points to the head - * of the list. Alias substitution should be done on nl. - */ +** Add yet missing headers. +*/ static void -putadr (char *name, struct mailname *nl) +finish_headers(FILE *out) { - register struct mailname *mp, *mp2; - register int linepos; - register char *cp; - int namelen; - - fprintf (out, "%s: ", name); - namelen = strlen(name) + 2; - linepos = namelen; - - for (mp = nl; mp; ) { - if (linepos > MAX_SM_FIELD) { - fprintf (out, "\n%s: ", name); - linepos = namelen; + char *cp; + char from[BUFSIZ]; /* my network address */ + char signature[BUFSIZ]; /* my signature */ + char *resentstr = (msgstate == resent) ? "Resent-" : ""; + + if (!(msgflags & MDAT)) { + fprintf(out, "%sDate: %s\n", resentstr, dtimenow()); } - if (mp->m_nohost) { - /* a local name - see if it's an alias */ - cp = akvalue(mp->m_mbox); - if (cp == mp->m_mbox) - /* wasn't an alias - use what the user typed */ - linepos = putone( mp->m_text, linepos, namelen ); - else - /* an alias - expand it */ - while ((cp = getname(cp))) { - if (linepos > MAX_SM_FIELD) { - fprintf (out, "\n%s: ", name); - linepos = namelen; - } - mp2 = getm( cp, NULL, 0, AD_HOST, NULL); - if (akvisible()) { - mp2->m_pers = getcpy(mp->m_mbox); - linepos = putone( adrformat(mp2), linepos, namelen ); - } else { - linepos = putone( mp2->m_text, linepos, namelen ); - } - mnfree( mp2 ); - } + + strncpy(from, getusername(), sizeof(from)); + if ((cp = getfullname()) && *cp) { + snprintf(signature, sizeof(signature), "%s <%s>", cp, from); } else { - /* not a local name - use what the user typed */ - linepos = putone( mp->m_text, linepos, namelen ); + snprintf(signature, sizeof(signature), "%s", from); + } + if (!(msgflags & MFRM)) { + fprintf(out, "%sFrom: %s\n", resentstr, signature); + } else { + /* In case the From: header contains multiple addresses. */ + fprintf(out, "%sSender: %s\n", resentstr, from); + } + if (!(msgflags & MVIS)) { + fprintf(out, "%sBcc: Blind Distribution List: ;\n", resentstr); + } + if (badmsg) { + unlink(tmpfil); + adios(NULL, "re-format message and try again"); } - mp2 = mp; - mp = mp->m_next; - mnfree( mp2 ); - } - putc( '\n', out ); } + +/* +** Return index of the requested header in the table, or NOTOK if missing. +*/ static int -putone (char *adr, int pos, int indent) +get_header(char *header, struct headers *table) { - register int len; - static int linepos; - - len = strlen( adr ); - if (pos == indent) - linepos = pos; - else if ( linepos+len > outputlinelen ) { - fprintf ( out, ",\n%*s", indent, ""); - linepos = indent; - pos += indent + 2; - } - else { - fputs( ", ", out ); - linepos += 2; - pos += 2; - } - fputs( adr, out ); - - linepos += len; - return (pos+len); + struct headers *h; + + for (h=table; h->value; h++) { + if (mh_strcasecmp(header, h->value)==0) { + return (h - table); + } + } + + return NOTOK; } +/* +** output the address list for header "name". The address list +** is a linked list of mailname structs. "nl" points to the head +** of the list. Alias substitution should be done on nl. +*/ static void -insert_fcc (struct headers *hdr, unsigned char *pp) +putadr(char *name, struct mailname *nl) { - unsigned char *cp; - - for (cp = pp; isspace (*cp); cp++) - continue; - for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--) - continue; - if (pp >= cp) - *++pp = 0; - if (*cp == 0) - return; - - if (fccind >= FCCS) - adios (NULL, "too many %ss", hdr->value); - fccfold[fccind++] = getcpy (cp); + struct mailname *mp, *mp2; + int linepos; + char *cp; + int namelen; + + fprintf(out, "%s: ", name); + namelen = strlen(name) + 2; + linepos = namelen; + + for (mp = nl; mp; ) { + if (linepos > MAX_SM_FIELD) { + fprintf(out, "\n%s: ", name); + linepos = namelen; + } + if (mp->m_nohost) { + /* a local name - see if it's an alias */ + cp = akvalue(mp->m_mbox); + if (cp == mp->m_mbox) { + /* wasn't an alias - use what the user typed */ + linepos = putone(mp->m_text, linepos, namelen); + } else { + /* an alias - expand it */ + while ((cp = getname(cp))) { + if (linepos > MAX_SM_FIELD) { + fprintf(out, "\n%s: ", name); + linepos = namelen; + } + mp2 = getm(cp, NULL, 0, AD_HOST, NULL); + if (akvisible()) { + mp2->m_pers = getcpy(mp->m_mbox); + linepos = putone(adrformat(mp2), linepos, namelen); + } else { + linepos = putone(mp2->m_text, + linepos, + namelen); + } + mnfree(mp2); + } + } + } else { + /* not a local name - use what the user typed */ + linepos = putone(mp->m_text, linepos, namelen); + } + mp2 = mp; + mp = mp->m_next; + mnfree(mp2); + } + putc('\n', out); } -#if 0 -/* BCC GENERATION */ - -static void -make_bcc_file (void) +static int +putone(char *adr, int pos, int indent) { - pid_t child_id; - int fd, i, status; - char *vec[6]; - FILE * in, *out; - -#ifdef HAVE_MKSTEMP - fd = mkstemp(bccfil); - if (fd == -1 || (out = fdopen(fd, "w")) == NULL) - adios (bccfil, "unable to create"); -#else - mktemp (bccfil); - if ((out = fopen (bccfil, "w")) == NULL) - adios (bccfil, "unable to create"); -#endif - chmod (bccfil, 0600); - - fprintf (out, "Date: %s\n", dtimenow (0)); - if (msgflags & MFRM) { - /* There was already a From: in the draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Sender: %s\n", from); - } - else - /* Construct a From: header. */ - fprintf (out, "From: %s\n", signature); - if (subject) - fprintf (out, "Subject: %s", subject); - fprintf (out, "BCC:\n\n------- Blind-Carbon-Copy\n\n"); - fflush (out); - - if (filter == NULL) { - if ((fd = open (tmpfil, O_RDONLY)) == NOTOK) - adios (NULL, "unable to re-open"); - cpydgst (fd, fileno (out), tmpfil, bccfil); - close (fd); - } - else { - vec[0] = r1bindex (mhlproc, '/'); - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - adios ("vfork", "unable to"); - - case OK: - dup2 (fileno (out), 1); - - i = 1; - vec[i++] = "-forward"; - vec[i++] = "-form"; - vec[i++] = filter; - vec[i++] = tmpfil; - vec[i] = NULL; - - execvp (mhlproc, vec); - adios (mhlproc, "unable to exec"); - - default: - if (status = pidwait(child_id, OK)) - admonish (NULL, "%s lost (status=0%o)", vec[0], status); - break; + register int len; + static int linepos; + + len = strlen(adr); + if (pos == indent) + linepos = pos; + else if (linepos+len > OUTPUTLINELEN) { + fprintf(out, ",\n%*s", indent, ""); + linepos = indent; + pos += indent + 2; + } else { + fputs(", ", out); + linepos += 2; + pos += 2; } - } + fputs(adr, out); - fseek (out, 0L, SEEK_END); - fprintf (out, "\n------- End of Blind-Carbon-Copy\n"); - fclose (out); + linepos += len; + return (pos+len); } -#endif /* if 0 */ -/* FCC INTERACTION */ static void -file (char *path) +process_fcc(char *str) { - int i; - - if (fccind == 0) - return; + char *cp, *pp; + int state = 0; - for (i = 0; i < fccind; i++) - if (whomflg) - printf ("Fcc: %s\n", fccfold[i]); - else - fcc (path, fccfold[i]); + if (strlen(str)+strlen(fccs) > sizeof fccs /2) { + adios(NULL, "Too much Fcc data"); + } + /* todo: better have three states: SEPARATOR, PLUS, WORD */ + for (cp=pp=str; *cp; cp++) { + switch (*cp) { + case ' ': + case '\t': + case '\n': + case ',': + if (state != 0) { + state = 0; + *cp = '\0'; + if (*pp=='+' || *pp=='@') { + strcat(fccs, " "); + } else { + strcat(fccs, " +"); + } + strcat(fccs, pp); + } + break; + default: + if (state == 0) { + state = 1; + pp = cp; + } + break; + } + } } static void -fcc (char *file, char *folder) +fcc(char *file, char *folders) { - pid_t child_id; - int i, status; - char fold[BUFSIZ]; - - if (verbose) - printf ("%sFcc: %s\n", msgstate == resent ? "Resent-" : "", folder); - fflush (stdout); - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - if (!verbose) - fprintf (stderr, " %sFcc %s: ", - msgstate == resent ? "Resent-" : "", folder); - fprintf (verbose ? stdout : stderr, "no forks, so not ok\n"); - break; - - case OK: - snprintf (fold, sizeof(fold), "%s%s", - *folder == '+' || *folder == '@' ? "" : "+", folder); - execlp (fileproc, r1bindex (fileproc, '/'), - "-link", "-file", file, fold, NULL); - _exit (-1); - - default: - if ((status = pidwait(child_id, OK))) { - if (!verbose) - fprintf (stderr, " %sFcc %s: ", - msgstate == resent ? "Resent-" : "", folder); - fprintf (verbose ? stdout : stderr, - " errored (0%o)\n", status); - } - } - - fflush (stdout); -} + int status; + char cmd[BUFSIZ]; + if (verbose) { + printf("%sFcc: %s\n", msgstate == resent ? "Resent-" : "", + folders); + fflush(stdout); + } + if (100+strlen(file)+strlen(folders) > sizeof cmd) { + adios(NULL, "Too much Fcc data"); + } + /* hack: read from /dev/null and refile(1) won't question us */ + snprintf(cmd, sizeof cmd, "m_next) { + bccdraft = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out)); + fprintf(out, "To: %s\n", mp->m_text); + fprintf(out, "Subject: [BCC] %s", subject ? subject : ""); + fprintf(out, "%s: %s\n", attach_hdr, origmsg); + fprintf(out, "------------\n"); + fclose(out); + + snprintf(buf, sizeof buf, "send %s", bccdraft); + if (system(buf) != 0) { + admonish(invo_name, "Problems to send Bcc to %s", + mp->m_text); + unlink(bccdraft); + } + } } -#endif diff --git a/uip/termsbr.c b/uip/termsbr.c index 740d021..fbf5f16 100644 --- a/uip/termsbr.c +++ b/uip/termsbr.c @@ -1,23 +1,14 @@ - /* - * termsbr.c -- termcap support - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** termsbr.c -- termcap support +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# else -# include -# endif -#endif +#include #ifdef HAVE_TERMCAP_H # include @@ -37,198 +28,68 @@ #endif #if BUFSIZ<2048 -# define TXTSIZ 2048 +# define TXTSIZ 2048 #else # define TXTSIZ BUFSIZ #endif -/* - * These variables are sometimes defined in, - * and needed by the termcap library. - */ -#ifdef HAVE_OSPEED -# ifdef MUST_DEFINE_OSPEED -extern short ospeed; -extern char PC; -# endif -#else -short ospeed; -char PC; -#endif - static long speedcode; -static int initLI = 0; static int initCO = 0; -static int HC = 0; /* are we on a hardcopy terminal? */ -static int LI = 40; /* number of lines */ -static int CO = 80; /* number of colums */ -static char *CL = NULL; /* termcap string to clear screen */ -static char *SE = NULL; /* termcap string to end standout mode */ -static char *SO = NULL; /* termcap string to begin standout mode */ - -static char termcap[TXTSIZ]; +static int CO = 80; /* number of colums */ static void read_termcap(void) { - char *bp, *cp; - char *term; + char *term; #ifndef TGETENT_ACCEPTS_NULL - char termbuf[TXTSIZ]; -#endif - -#ifdef HAVE_TERMIOS_H - struct termios tio; -#else -# ifdef HAVE_TERMIO_H - struct termio tio; -# else - struct sgttyb tio; -# endif + char termbuf[TXTSIZ]; #endif - static int inited = 0; + struct termios tio; + static int inited = 0; - if (inited++) - return; + if (inited++) + return; - if (!(term = getenv ("TERM"))) - return; + if (!(term = getenv("TERM"))) + return; /* - * If possible, we let tgetent allocate its own termcap buffer - */ +** If possible, we let tgetent allocate its own termcap buffer +*/ #ifdef TGETENT_ACCEPTS_NULL - if (tgetent (NULL, term) != TGETENT_SUCCESS) - return; + if (tgetent(NULL, term) != TGETENT_SUCCESS) + return; #else - if (tgetent (termbuf, term) != TGETENT_SUCCESS) - return; + if (tgetent(termbuf, term) != TGETENT_SUCCESS) + return; #endif -#ifdef HAVE_TERMIOS_H - speedcode = cfgetospeed(&tio); -#else -# ifdef HAVE_TERMIO_H - speedcode = ioctl(fileno(stdout), TCGETA, &tio) != NOTOK ? tio.c_cflag & CBAUD : 0; -# else - speedcode = ioctl(fileno(stdout), TIOCGETP, (char *) &tio) != NOTOK ? tio.sg_ospeed : 0; -# endif -#endif + speedcode = cfgetospeed(&tio); - HC = tgetflag ("hc"); - - if (!initCO && (CO = tgetnum ("co")) <= 0) - CO = 80; - if (!initLI && (LI = tgetnum ("li")) <= 0) - LI = 24; - - cp = termcap; - CL = tgetstr ("cl", &cp); - if ((bp = tgetstr ("pc", &cp))) - PC = *bp; - if (tgetnum ("sg") <= 0) { - SE = tgetstr ("se", &cp); - SO = tgetstr ("so", &cp); - } + if (!initCO && (CO = tgetnum("co")) <= 0) + CO = 80; } int -sc_width (void) +sc_width(void) { #ifdef TIOCGWINSZ - struct winsize win; - int width; - - if (ioctl (fileno (stderr), TIOCGWINSZ, &win) != NOTOK - && (width = win.ws_col) > 0) { - CO = width; - initCO++; - } else + struct winsize win; + int width; + + if (ioctl(fileno(stderr), TIOCGWINSZ, &win) != NOTOK + && (width = win.ws_col) > 0) { + CO = width; + initCO++; + } else #endif /* TIOCGWINSZ */ - read_termcap(); - - return CO; -} - - -int -sc_length (void) -{ -#ifdef TIOCGWINSZ - struct winsize win; - - if (ioctl (fileno (stderr), TIOCGWINSZ, &win) != NOTOK - && (LI = win.ws_row) > 0) - initLI++; - else -#endif /* TIOCGWINSZ */ - read_termcap(); - - return LI; -} + read_termcap(); - -static int -outc (int c) -{ - return putchar(c); -} - - -void -clear_screen (void) -{ - read_termcap (); - - if (CL && speedcode) - tputs (CL, LI, outc); - else { - printf ("\f"); - if (speedcode) - printf ("\200"); - } - - fflush (stdout); -} - - -/* - * print in standout mode - */ -int -SOprintf (char *fmt, ...) -{ - va_list ap; - - read_termcap (); - if (!(SO && SE)) - return NOTOK; - - tputs (SO, 1, outc); - - va_start(ap, fmt); - vprintf (fmt, ap); - va_end(ap); - - tputs (SE, 1, outc); - - return OK; + return CO; } - -/* - * Is this a hardcopy terminal? - */ - -int -sc_hardcopy(void) -{ - read_termcap(); - return HC; -} - diff --git a/uip/viamail.c b/uip/viamail.c deleted file mode 100644 index aea746d..0000000 --- a/uip/viamail.c +++ /dev/null @@ -1,252 +0,0 @@ - -/* - * viamail.c -- send multiple files in a MIME message - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -static struct swit switches[] = { -#define TOSW 0 - { "to mailpath", 0 }, -#define FROMSW 1 - { "from mailpath", 0 }, -#define SUBJECTSW 2 - { "subject subject", 0 }, -#define PARAMSW 3 - { "parameters arguments", 0 }, -#define DESCRIPTSW 4 - { "description text", 0 }, -#define COMMENTSW 5 - { "comment text", 0 }, -#define DELAYSW 6 - { "delay seconds", 0 }, -#define VERBSW 7 - { "verbose", 0 }, -#define NVERBSW 8 - { "noverbose", 0 }, -#define VERSIONSW 9 - { "version", 0 }, -#define HELPSW 10 - { "help", 0 }, -#define DEBUGSW 11 - { "debug", -5 }, - { NULL, 0 } -}; - -extern int debugsw; -extern int splitsw; -extern int verbsw; - -int ebcdicsw = 0; /* hack for linking purposes */ - -/* mhmisc.c */ -void set_endian (void); - -/* mhoutsbr.c */ -int writeBase64aux (FILE *, FILE *); - -/* - * static prototypes - */ -static int via_mail (char *, char *, char *, char *, char *, int, char *); - - -int -main (int argc, char **argv) -{ - int delay = 0; - char *f1 = NULL, *f2 = NULL, *f3 = NULL; - char *f4 = NULL, *f5 = NULL, *f7 = NULL; - char *cp, buf[BUFSIZ]; - char **argp, **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case TOSW: - if (!(f1 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case SUBJECTSW: - if (!(f2 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case PARAMSW: - if (!(f3 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case DESCRIPTSW: - if (!(f4 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case COMMENTSW: - if (!(f5 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case DELAYSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - - /* - * If there is an error, just reset the delay parameter - * to -1. We will set a default delay later. - */ - if (sscanf (cp, "%d", &delay) != 1) - delay = -1; - continue; - case FROMSW: - if (!(f7 = *argp++)) - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case VERBSW: - verbsw = 1; - continue; - case NVERBSW: - verbsw = 0; - continue; - - case DEBUGSW: - debugsw = 1; - continue; - } - } - } - - set_endian (); - - if (!f1) - adios (NULL, "missing -viamail \"mailpath\" switch"); - - via_mail (f1, f2, f3, f4, f5, delay, f7); - return 0; /* dead code to satisfy the compiler */ -} - - -/* - * VIAMAIL - */ - -static int -via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw, - char *cmntsw, int delay, char *fromsw) -{ - int status, vecp = 1; - char tmpfil[BUFSIZ]; - char *vec[MAXARGS]; - struct stat st; - FILE *fp; - char *tfile = NULL; - - umask (~m_gmprot ()); - - tfile = m_mktemp2(NULL, invo_name, NULL, &fp); - if (tfile == NULL) adios("viamail", "unable to create temporary file"); - chmod(tfile, 0600); - strncpy (tmpfil, tfile, sizeof(tmpfil)); - - if (!strchr(mailsw, '@')) - mailsw = concat (mailsw, "@", LocalName (), NULL); - fprintf (fp, "To: %s\n", mailsw); - - if (subjsw) - fprintf (fp, "Subject: %s\n", subjsw); - - if (fromsw) { - if (!strchr(fromsw, '@')) - fromsw = concat (fromsw, "@", LocalName (), NULL); - fprintf (fp, "From: %s\n", fromsw); - } - - fprintf (fp, "%s: %s\n", VRSN_FIELD, VRSN_VALUE); - fprintf (fp, "%s: application/octet-stream", TYPE_FIELD); - - if (parmsw) - fprintf (fp, "; %s", parmsw); - - if (cmntsw) - fprintf (fp, "\n\t(%s)", cmntsw); - - if (descsw) - fprintf (fp, "\n%s: %s", DESCR_FIELD, descsw); - - fprintf (fp, "\n%s: %s\n\n", ENCODING_FIELD, "base64"); - - if (fflush (fp)) - adios (tmpfil, "error writing to"); - - writeBase64aux (stdin, fp); - if (fflush (fp)) - adios (tmpfil, "error writing to"); - - if (fstat (fileno (fp), &st) == NOTOK) - adios ("failed", "fstat of %s", tmpfil); - - if (delay < 0) - splitsw = 10; - else - splitsw = delay; - - status = 0; - vec[0] = r1bindex (postproc, '/'); - if (verbsw) - vec[vecp++] = "-verbose"; - - switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0, 0)) { - case DONE: - case NOTOK: - status++; - break; - case OK: - break; - } - - fclose (fp); - if (unlink (tmpfil) == -1) - advise (NULL, "unable to remove temp file %s", tmpfil); - done (status); - return 1; -} diff --git a/uip/vmh.c b/uip/vmh.c deleted file mode 100644 index 908df85..0000000 --- a/uip/vmh.c +++ /dev/null @@ -1,1515 +0,0 @@ - -/* - * vmh.c -- visual front-end to nmh - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - -#if 0 -#if defined(SYS5) && !defined(TERMINFO) -/* - * Define TERMINFO if you have it. - * You get it automatically if you're running SYS5, and you don't get - * it if you're not. (If you're not SYS5, you probably have termcap.) - * We distinguish TERMINFO from SYS5 because in this file SYS5 really - * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo - * is quite a separate issue. - */ -#define TERMINFO 1 -#endif -#endif - -/* - * TODO: - * 1) Pass signals to client during execution - * 2) Figure out a way for the user to say how big the Scan/Display - * windows should be. - * 3) If curses ever gets fixed, then XYZ code can be removed - */ - -#include - -#ifdef ncr -# define _SYS_REG_H /* NCR redefines "ERR" in */ -#endif - -#undef OK /* tricky */ - -/* removed for right now */ -#if 0 -#ifdef TERMINFO -# include /* variables describing terminal capabilities */ -#endif /* TERMINFO */ -#endif - -#include -#include -#include -#include - -#ifndef sigmask -# define sigmask(s) (1 << ((s) - 1)) -#endif /* not sigmask */ - -#ifdef ridge -# undef SIGTSTP -#endif /* ridge */ - -#ifdef HAVE_WRITEV -# include -#else -struct iovec { - char *iov_base; - int iov_len; -}; -#endif - -#ifdef hpux -# include -# define TCGETATTR /* tcgetattr() */ -#endif - -#ifdef BSD44 -# define USE_OLD_TTY -# define _maxx maxx /* curses.h */ -# define _maxy maxy -# define _curx curx /* curses.h */ -# define _cury cury -void __cputchar __P((int)); -# undef _putchar -# define _putchar __cputchar -# include /* sgttyb */ -#endif - -#define ALARM ((unsigned int) 10) -#define PAUSE ((unsigned int) 2) - -#ifndef abs -# define abs(a) ((a) > 0 ? (a) : -(a)) -#endif - -#define SMALLMOVE 1 -#define LARGEMOVE 10 - -#define XYZ /* XXX */ - -static struct swit switches[] = { -#define PRMPTSW 0 - { "prompt string", 6 }, -#define PROGSW 1 - { "vmhproc program", 7 }, -#define NPROGSW 2 - { "novmhproc", 9 }, -#define VERSIONSW 3 - { "version", 0 }, -#define HELPSW 4 - { "help", 0 }, - { NULL, 0 } -}; - - /* PEERS */ -static int PEERpid = NOTOK; - -static jmp_buf PEERctx; - - /* WINDOWS */ -static char *myprompt = "(%s) "; - -static WINDOW *Scan; -static WINDOW *Status; -static WINDOW *Display; -static WINDOW *Command; - -#define NWIN 3 -static int numwins; -WINDOW *windows[NWIN + 1]; - - - /* LINES */ - -struct line { - int l_no; - char *l_buf; - struct line *l_prev; - struct line *l_next; -}; - -static struct line *lhead = NULL; -static struct line *ltop = NULL; -static struct line *ltail = NULL; - -static int did_less = 0; -static int smallmove = SMALLMOVE; -static int largemove = LARGEMOVE; - - - /* TTYS */ - -static int tty_ready = NOTOK; - -static int intrc; - -#ifndef SYS5 -# define ERASE sg.sg_erase -# define KILL sg.sg_kill -static struct sgttyb sg; - -#define EOFC tc.t_eofc -#define INTR tc.t_intrc -static struct tchars tc; -#else /* SYS5 */ -# define ERASE sg.c_cc[VERASE] -# define KILL sg.c_cc[VKILL] -# define EOFC sg.c_cc[VEOF] -# define INTR sg.c_cc[VINTR] -static struct termio sg; -#endif /* SYS5 */ - -#ifndef TIOCGLTC -# define WERASC ('W' & 037) -#else /* TIOCGLTC */ -# ifndef SVR4 -# define WERASC ltc.t_werasc -static struct ltchars ltc; -# else /* SVR4 */ -# define WERASC sg.c_cc[VWERASE] -# undef TIOCGLTC /* the define exists, but struct ltchars doesn't */ -# endif -#endif /* TIOCGLTC */ - - -#if !defined(SYS5) && !defined(BSD44) -int _putchar(); -#endif /* not SYS5 */ - -#ifdef SIGTSTP -char *tgoto(); -#endif /* SIGTSTP */ - - /* SIGNALS */ -static RETSIGTYPE ALRMser(int); -static RETSIGTYPE PIPEser(int); -static RETSIGTYPE SIGser(int); -#ifdef SIGTSTP -static RETSIGTYPE TSTPser(int); -#endif /* SIGTSTP */ - - - /* MISCELLANY */ - -/* - * static prototypes - */ -static void adorn (char *, char *, ...); - -static vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo(); -static TTYon(), TTYoff(), foreground(); -static int PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit(); -static int WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux(); - - -int -main (int argc, char **argv) -{ - int vecp = 1, nprog = 0; - char *cp, buffer[BUFSIZ]; - char **argp, **arguments, *vec[MAXARGS]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - while ((cp = *argp++)) - if (*cp == '-') - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - vec[vecp++] = --cp; - continue; - - case HELPSW: - snprintf (buffer, sizeof(buffer), "%s [switches for vmhproc]", - invo_name); - print_help (buffer, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case PRMPTSW: - if (!(myprompt = *argp++) || *myprompt == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PROGSW: - if (!(vmhproc = *argp++) || *vmhproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NPROGSW: - nprog++; - continue; - } - else - vec[vecp++] = cp; - - if (TTYinit (nprog) == NOTOK || WINinit (nprog) == NOTOK) { - vec[vecp] = NULL; - - vec[0] = r1bindex (vmhproc, '/'); - execvp (vmhproc, vec); - adios (vmhproc, "unable to exec"); - } - TTYoff (); - PEERinit (vecp, vec); - TTYon (); - - vmh (); - - return done (0); -} - - -static void -vmh (void) -{ - char buffer[BUFSIZ]; - - for (;;) { - pLOOP (RC_QRY, NULL); - - wmove (Command, 0, 0); - wprintw (Command, myprompt, invo_name); - wclrtoeol (Command); - wrefresh (Command); - - switch (WINgetstr (Command, buffer)) { - case NOTOK: - break; - - case OK: - done (0); /* NOTREACHED */ - - default: - if (*buffer) - pLOOP (RC_CMD, buffer); - break; - } - } -} - -/* PEERS */ - -static int -PEERinit (int vecp, char *vec[]) -{ - int pfd0[2], pfd1[2]; - char buf1[BUFSIZ], buf2[BUFSIZ]; - - if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK) - adios ("pipe", "unable to"); -#ifdef hpux - switch (PEERpid = fork ()) { - /* - * Calling vfork() and then another routine [like close()] before - * an exec() messes up the stack frame, causing crib death. - * Use fork() instead. - */ -#else /* not hpux */ - switch (PEERpid = vfork ()) { -#endif /* not hpux */ - case NOTOK: - adios ("vfork", "unable to");/* NOTREACHED */ - - case OK: - close (pfd0[0]); - close (pfd1[1]); - - vec[vecp++] = "-vmhread"; - snprintf (buf1, sizeof(buf1), "%d", pfd1[0]); - vec[vecp++] = buf1; - vec[vecp++] = "-vmhwrite"; - snprintf (buf2, sizeof(buf2), "%d", pfd0[1]); - vec[vecp++] = buf2; - vec[vecp] = NULL; - - SIGNAL (SIGINT, SIG_DFL); - SIGNAL (SIGQUIT, SIG_DFL); - - vec[0] = r1bindex (vmhproc, '/'); - execvp (vmhproc, vec); - perror (vmhproc); - _exit (-1); /* NOTREACHED */ - - default: - close (pfd0[1]); - close (pfd1[0]); - - rcinit (pfd0[0], pfd1[1]); - return pINI (); - } -} - - -static int -pINI (void) -{ - int len, buflen; - char *bp, buffer[BUFSIZ]; - struct record rcs; - register struct record *rc = &rcs; - register WINDOW **w; - - initrc (rc); - - /* Get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - snprintf (bp, buflen, "%d %d", RC_VRSN, numwins); - len = strlen (bp); - bp += len; - buflen -= len; - - for (w = windows; *w; w++) { - snprintf (bp, buflen, " %d", (*w)->_maxy); - len = strlen (bp); - bp += len; - buflen -= len; - } - - switch (str2rc (RC_INI, buffer, rc)) { - case RC_ACK: - return OK; - - case RC_ERR: - if (rc->rc_len) - adios (NULL, "%s", rc->rc_data); - else - adios (NULL, "pINI peer error"); - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pINI protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pLOOP (char *code, char *str) -{ - int i; - struct record rcs; - register struct record *rc = &rcs; - - initrc (rc); - - str2peer (code, str); - for (;;) - switch (peer2rc (rc)) { - case RC_TTY: - if (pTTY (rc) == NOTOK) - return NOTOK; - break; - - case RC_WIN: - if (sscanf (rc->rc_data, "%d", &i) != 1 - || i <= 0 - || i > numwins) { - fmt2peer (RC_ERR, "no such window \"%s\"", rc->rc_data); - return NOTOK; - } - if (pWIN (windows[i - 1]) == NOTOK) - return NOTOK; - break; - - case RC_EOF: - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pLOOP(%s) peer error", - code == RC_QRY ? "QRY" : "CMD"); - return NOTOK; - - case RC_FIN: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - rcdone (); - i = pidwait (PEERpid, OK); - PEERpid = NOTOK; - done (i); - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pLOOP(%s) protocol screw-up", - code == RC_QRY ? "QRY" : "CMD"); - } -} - - -static int -pTTY (struct record *r) -{ - SIGNAL_HANDLER hstat, istat, qstat, tstat; - struct record rcs; - register struct record *rc = &rcs; - - initrc (rc); - - TTYoff (); - - /* should be changed to block instead of ignore */ - hstat = SIGNAL (SIGHUP, SIG_IGN); - istat = SIGNAL (SIGINT, SIG_IGN); - qstat = SIGNAL (SIGQUIT, SIG_IGN); - tstat = SIGNAL (SIGTERM, SIG_IGN); - - rc2rc (RC_ACK, 0, NULL, rc); - - SIGNAL (SIGHUP, hstat); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - SIGNAL (SIGTERM, tstat); - - TTYon (); - - if (r->rc_len && strcmp (r->rc_data, "FAST") == 0) - goto no_refresh; - -#ifdef SIGTSTP - SIGNAL (SIGTSTP, SIG_IGN); -#endif - -#ifndef TERMINFO - if (SO) - tputs (SO, 0, _putchar); -#else /* TERMINFO */ - putp(enter_standout_mode); -#endif /* TERMINFO */ - fprintf (stdout, "Type any key to continue... "); - fflush (stdout); -#ifndef TERMINFO - if (SE) - tputs (SE, 0, _putchar); -#else /* TERMINFO */ - putp(exit_standout_mode); -#endif /* TERMINFO */ - getc (stdin); -#ifdef SIGTSTP - SIGNAL (SIGTSTP, TSTPser); -#endif /* SIGTSTP */ - - wrefresh (curscr); - -no_refresh: ; - switch (rc->rc_type) { - case RC_EOF: - rc2peer (RC_ACK, 0, NULL); - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pTTY peer error"); - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pTTY protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pWIN (WINDOW *w) -{ - int i; - - did_less = 0; - if ((i = pWINaux (w)) == OK && did_less) - WINless (w, 1); - - lreset (); - - return i; -} - - -static int -pWINaux (WINDOW *w) -{ - register int n; - int eol; - register char c, *bp; - struct record rcs; - register struct record *rc = &rcs; - - initrc (rc); - - werase (w); - wmove (w, 0, 0); -#ifdef XYZ - if (w == Status) - wstandout (w); -#endif /* XYZ */ - - for (eol = 0;;) - switch (rc2rc (RC_ACK, 0, NULL, rc)) { - case RC_DATA: - if (eol && WINputc (w, '\n') == ERR && WINless (w, 0)) - goto flush; - for (bp = rc->rc_data, n = rc->rc_len; n-- > 0; ) { - if ((c = *bp++) == '\n') - linsert (w); - if (WINputc (w, c) == ERR) - if (n == 0 && c == '\n') - eol++; - else - if (WINless (w, 0)) { -flush: ; - fmt2peer (RC_ERR, "flush window"); -#ifdef XYZ /* should NEVER happen... */ - if (w == Status) - wstandend (w); -#endif /* XYZ */ - wrefresh (w); - return NOTOK; - } - } - break; - - case RC_EOF: - rc2peer (RC_ACK, 0, NULL); -#ifdef XYZ - if (w == Status) - wstandend (w); -#endif /* XYZ */ - wrefresh (w); - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pWIN peer error"); - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pWIN protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pFIN (void) -{ - int status; - - if (PEERpid <= OK) - return OK; - - rc2peer (RC_FIN, 0, NULL); - rcdone (); - - switch (setjmp (PEERctx)) { - case OK: - SIGNAL (SIGALRM, ALRMser); - alarm (ALARM); - - status = pidwait (PEERpid, OK); - - alarm (0); - break; - - default: - kill (PEERpid, SIGKILL); - status = NOTOK; - break; - } - PEERpid = NOTOK; - - return status; -} - -/* WINDOWS */ - -static int -WINinit (int nprog) -{ - register int nlines, /* not "lines" because terminfo uses that */ - top, - bottom; - - foreground (); - if (initscr () == (WINDOW *) ERR) - if (nprog) - return NOTOK; - else - adios (NULL, "could not initialize terminal"); -#ifdef SIGTSTP - SIGNAL (SIGTSTP, SIG_DFL); -#endif /* SIGTSTP */ - sideground (); - -#ifndef TERMINFO - if (CM == NULL) -#else /* TERMINFO */ - if (cursor_address == NULL) /* assume mtr wanted "cm", not "CM" */ -#endif /* TERMINFO */ - if (nprog) - return NOTOK; - else - adios (NULL, - "sorry, your terminal isn't powerful enough to run %s", - invo_name); - -#ifndef TERMINFO - if (tgetflag ("xt") || tgetnum ("sg") > 0) - SO = SE = US = UE = NULL; -#else /* TERMINFO */ -/* - * If termcap mapped directly to terminfo, we'd use the following: - * if (teleray_glitch || magic_cookie_glitch > 0) - * enter_standout_mode = exit_standout_mode = - * enter_underline_mode = exit_underline_mode = NULL; - * But terminfo does the right thing so we don't have to resort to that. - */ -#endif /* TERMINFO */ - - if ((nlines = LINES - 1) < 11) - adios (NULL, "screen too small"); - if ((top = nlines / 3 + 1) > LINES / 4 + 2) - top--; - bottom = nlines - top - 2; - - numwins = 0; - Scan = windows[numwins++] = newwin (top, COLS, 0, 0); - Status = windows[numwins++] = newwin (1, COLS, top, 0); -#ifndef XYZ - wstandout (Status); -#endif /* XYZ */ - Display = windows[numwins++] = newwin (bottom, COLS, top + 1, 0); - Command = newwin (1, COLS - 1, top + 1 + bottom, 0); - windows[numwins] = NULL; - - largemove = Display->_maxy / 2 + 2; - return OK; -} - - -static int WINgetstr (WINDOW *w, char *buffer) -{ - register int c; - register char *bp; - - bp = buffer; - *bp = 0; - - for (;;) { - switch (c = toascii (wgetch (w))) { - case ERR: - adios (NULL, "wgetch lost"); - - case '\f': - wrefresh (curscr); - break; - - case '\r': - case '\n': - *bp = 0; - if (bp > buffer) { - leaveok (curscr, FALSE); - wmove (w, 0, w->_curx - (bp - buffer)); - wrefresh (w); - leaveok (curscr, TRUE); - } - return DONE; - - default: - if (c == intrc) { - wprintw (w, " "); - wstandout (w); - wprintw (w, "Interrupt"); - wstandend (w); - wrefresh (w); - *buffer = 0; - return NOTOK; - } - if (c == EOFC) { - if (bp <= buffer) - return OK; - break; - } - if (c == ERASE) { - if (bp <= buffer) - continue; - bp--, w->_curx--; - wclrtoeol (w); - break; - } - if (c == KILL) { - if (bp <= buffer) - continue; - w->_curx -= bp - buffer; - bp = buffer; - wclrtoeol (w); - break; - } - if (c == WERASC) { - if (bp <= buffer) - continue; - do { - bp--, w->_curx--; - } while (isspace (*bp) && bp > buffer); - - if (bp > buffer) { - do { - bp--, w->_curx--; - } while (!isspace (*bp) && bp > buffer); - if (isspace (*bp)) - bp++, w->_curx++; - } - wclrtoeol (w); - break; - } - - if (c >= ' ' && c < '\177') - waddch (w, *bp++ = c); - break; - } - - wrefresh (w); - } -} - - -static int -WINwritev (WINDOW *w, struct iovec *iov, int n) -{ - register int i; - - werase (w); - wmove (w, 0, 0); - for (i = 0; i < n; i++, iov++) - wprintw (w, "%*.*s", iov->iov_len, iov->iov_len, iov->iov_base); - wrefresh (w); - - sleep (PAUSE); - - return OK; -} - - -static struct { - char *h_msg; - int *h_val; -} hlpmsg[] = { - " forward backwards", NULL, - " ------- ---------", NULL, - "next screen SPACE", NULL, - "next %d line%s RETURN y", &smallmove, - "next %d line%s EOT u", &largemove, - "go g G", NULL, - "", NULL, - "refresh CTRL-L", NULL, - "quit q", NULL, - - NULL, NULL -}; - - -static int -WINless (WINDOW *w, int fin) -{ - register int c, i, n; - char *cp; - register struct line *lbottom; - int nfresh, nwait; - -#ifdef notdef - int nlatch; -#endif - - did_less++; - - cp = NULL; -#ifdef notdef - if (fin) - ltop = NULL; -#endif /* notdef */ - lbottom = NULL; - nfresh = 1; - nwait = 0; - wrefresh (w); - - for (;;) { - if (nfresh || nwait) { - nfresh = 0; -#ifdef notdef - nlatch = 1; - -once_only: ; -#endif /* notdef */ - werase (w); - wmove (w, 0, 0); - - if (ltop == NULL) - if (fin) { - lgo (ltail->l_no - w->_maxy + 1); - if (ltop == NULL) - ltop = lhead; - } - else - ltop = lbottom && lbottom->l_prev ? lbottom->l_prev - : lbottom; - - for (lbottom = ltop; lbottom; lbottom = lbottom->l_next) - if (waddstr (w, lbottom->l_buf) == ERR - || waddch (w, '\n') == ERR) - break; - if (lbottom == NULL) - if (fin) { -#ifdef notdef - if (nlatch && (ltail->l_no >= w->_maxy)) { - lgo (ltail->l_no - w->_maxy + 1); - nlatch = 0; - goto once_only; - } -#endif /* notdef */ - lbottom = ltail; - while (waddstr (w, "~\n") != ERR) - continue; - } - else { - wrefresh (w); - return 0; - } - - if (!nwait) - wrefresh (w); - } - - wmove (Command, 0, 0); - if (cp) { - wstandout (Command); - wprintw (Command, "%s", cp); - wstandend (Command); - cp = NULL; - } - else - wprintw (Command, fin ? "top:%d bot:%d end:%d" : "top:%d bot:%d", - ltop->l_no, lbottom->l_no, ltail->l_no); - wprintw (Command, ">> "); - wclrtoeol (Command); - wrefresh (Command); - - c = toascii (wgetch (Command)); - - werase (Command); - wrefresh (Command); - - if (nwait) { - nwait = 0; - wrefresh (w); - } - - n = 0; -again: ; - switch (c) { - case ' ': - ltop = lbottom->l_next; - nfresh++; - break; - - case '\r': - case '\n': - case 'e': - case 'j': - if (n) - smallmove = n; - if (ladvance (smallmove)) - nfresh++; - break; - - case 'y': - case 'k': - if (n) - smallmove = n; - if (lretreat (smallmove)) - nfresh++; - break; - - case 'd': - eof: ; - if (n) - largemove = n; - if (ladvance (largemove)) - nfresh++; - break; - - case 'u': - if (n) - largemove = n; - if (lretreat (largemove)) - nfresh++; - break; - - case 'g': - if (lgo (n ? n : 1)) - nfresh++; - break; - - case 'G': - if (lgo (n ? n : ltail->l_no - w->_maxy + 1)) - nfresh++; - break; - - case '\f': - case 'r': - wrefresh (curscr); - break; - - case 'h': - case '?': - werase (w); - wmove (w, 0, 0); - for (i = 0; hlpmsg[i].h_msg; i++) { - if (hlpmsg[i].h_val) - wprintw (w, hlpmsg[i].h_msg, *hlpmsg[i].h_val, - *hlpmsg[i].h_val != 1 ? "s" : ""); - else - waddstr (w, hlpmsg[i].h_msg); - waddch (w, '\n'); - } - wrefresh (w); - nwait++; - break; - - case 'q': - return 1; - - default: - if (c == EOFC) - goto eof; - - if (isdigit (c)) { - wmove (Command, 0, 0); - i = 0; - while (isdigit (c)) { - wprintw (Command, "%c", c); - wrefresh (Command); - i = i * 10 + c - '0'; - c = toascii (wgetch (Command)); - } - werase (Command); - wrefresh (Command); - - if (i > 0) { - n = i; - goto again; - } - cp = "bad number"; - } - else - cp = "not understood"; - break; - } - } -} - - -static int -WINputc (WINDOW *w, char c) -{ - register int x, y; - - switch (c) { - default: - if (!isascii (c)) { - if (WINputc (w, 'M') == ERR || WINputc (w, '-') == ERR) - return ERR; - c = toascii (c); - } - else - if (c < ' ' || c == '\177') { - if (WINputc (w, '^') == ERR) - return ERR; - c ^= 0100; - } - break; - - case '\t': - case '\n': - break; - } - - if (w != Scan) - return waddch (w, c); - - if ((x = w->_curx) < 0 || x >= w->_maxx - || (y = w->_cury) < 0 || y >= w->_maxy) - return DONE; - - switch (c) { - case '\t': - for (x = 8 - (x & 0x07); x > 0; x--) - if (WINputc (w, ' ') == ERR) - return ERR; - break; - - case '\n': - if (++y < w->_maxy) - waddch (w, c); - else - wclrtoeol (w); - break; - - default: - if (++x < w->_maxx) - waddch (w, c); - break; - } - - return DONE; -} - -/* LINES */ - -static void -lreset (void) -{ - register struct line *lp, *mp; - - for (lp = lhead; lp; lp = mp) { - mp = lp->l_next; - free (lp->l_buf); - free ((char *) lp); - } - lhead = ltop = ltail = NULL; -} - - -static void -linsert (WINDOW *w) -{ - register char *cp; - register struct line *lp; - - if ((lp = (struct line *) calloc ((size_t) 1, sizeof *lp)) == NULL) - adios (NULL, "unable to allocate line storage"); - - lp->l_no = (ltail ? ltail->l_no : 0) + 1; -#ifndef BSD44 - lp->l_buf = getcpy (w->_y[w->_cury]); -#else - lp->l_buf = getcpy (w->lines[w->_cury]->line); -#endif - for (cp = lp->l_buf + strlen (lp->l_buf) - 1; cp >= lp->l_buf; cp--) - if (isspace (*cp)) - *cp = 0; - else - break; - - if (lhead == NULL) - lhead = lp; - if (ltop == NULL) - ltop = lp; - if (ltail) - ltail->l_next = lp; - lp->l_prev = ltail; - ltail = lp; -} - - -static int -ladvance (int n) -{ - register int i; - register struct line *lp; - - for (i = 0, lp = ltop; i < n && lp; i++, lp = lp->l_next) - continue; - - if (ltop == lp) - return 0; - - ltop = lp; - return 1; -} - - -static int -lretreat (int n) -{ - register int i; - register struct line *lp; - - for (i = 0, lp = ltop; i < n && lp; i++, lp = lp->l_prev) - if (!lp->l_prev) - break; - - if (ltop == lp) - return 0; - - ltop = lp; - return 1; -} - - -static int -lgo (int n) -{ - register int i, j; - register struct line *lp; - - if ((i = n - (lp = lhead)->l_no) - > (j = abs (n - (ltop ? ltop : ltail)->l_no))) - i = j, lp = ltop ? ltop : ltail; - if (i > (j = abs (ltail->l_no - n))) - i = j, lp = ltail; - - if (n >= lp->l_no) { - for (; lp; lp = lp->l_next) - if (lp->l_no == n) - break; - } - else { - for (; lp; lp = lp->l_prev) - if (lp->l_no == n) - break; - if (!lp) - lp = lhead; - } - - if (ltop == lp) - return 0; - - ltop = lp; - return 1; -} - -/* TTYS */ - -static int -TTYinit (int nprog) -{ - if (!isatty (fileno (stdin)) || !isatty (fileno (stdout))) - if (nprog) - return NOTOK; - else - adios (NULL, "not a tty"); - - foreground (); -#ifndef SYS5 - if (ioctl (fileno (stdin), TIOCGETP, (char *) &sg) == NOTOK) - adios ("failed", "ioctl TIOCGETP"); - if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK) - adios ("failed", "ioctl TIOCGETC"); -#else -#ifdef TCGETATTR - if( tcgetattr( fileno(stdin), &sg) == NOTOK) - adios( "failed", "tcgetattr"); -#else /* SYS5 */ - if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK) - adios ("failed", "ioctl TCGETA"); -#endif -#endif -#ifdef TIOCGLTC - if (ioctl (fileno (stdin), TIOCGLTC, (char *) <c) == NOTOK) - adios ("failed", "ioctl TIOCGLTC"); -#endif /* TIOCGLTC */ - intrc = INTR; - sideground (); - - tty_ready = OK; - - SIGNAL (SIGPIPE, PIPEser); - - return OK; -} - - -static void -TTYon (void) -{ - if (tty_ready == DONE) - return; - - INTR = NOTOK; -#ifndef SYS5 - ioctl (fileno (stdin), TIOCSETC, (char *) &tc); -#else /* SYS5 */ - ioctl (fileno (stdin), TCSETA, &sg); -#endif /* SYS5 */ - - crmode (); - noecho (); - nonl (); - scrollok (curscr, FALSE); - - discard (stdin); - - tty_ready = DONE; - - SIGNAL (SIGHUP, SIGser); - SIGNAL (SIGINT, SIGser); - SIGNAL (SIGQUIT, SIGser); -#ifdef SIGTSTP - SIGNAL (SIGTSTP, TSTPser); -#endif /* SIGTSTP */ -} - - -static void -TTYoff (void) -{ - if (tty_ready == NOTOK) - return; - - INTR = intrc; -#ifndef SYS5 - ioctl (fileno (stdin), TIOCSETC, (char *) &tc); -#else /* SYS5 */ - ioctl (fileno (stdin), TCSETA, &sg); -#endif /* SYS5 */ - - leaveok (curscr, TRUE); - mvcur (0, COLS - 1, LINES - 1, 0); - endwin (); - if (tty_ready == DONE) { -#ifndef TERMINFO - if (CE) - tputs (CE, 0, _putchar); - else -#else /* TERMINFO */ - putp(clr_eol); -#endif /* TERMINFO */ - fprintf (stdout, "\r\n"); - } - fflush (stdout); - - tty_ready = NOTOK; - - SIGNAL (SIGHUP, SIG_DFL); - SIGNAL (SIGINT, SIG_DFL); - SIGNAL (SIGQUIT, SIG_DFL); -#ifdef SIGTSTP - SIGNAL (SIGTSTP, SIG_DFL); -#endif /* SIGTSTP */ -} - - -static void -foreground (void) -{ -#ifdef TIOCGPGRP - int pgrp, tpgrp; - SIGNAL_HANDLER tstat; - - if ((pgrp = getpgrp()) == NOTOK) - adios ("process group", "unable to determine"); - for (;;) { - if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK) - adios ("tty's process group", "unable to determine"); - if (pgrp == tpgrp) - break; - - tstat = SIGNAL (SIGTTIN, SIG_DFL); - kill (0, SIGTTIN); - SIGNAL (SIGTTIN, tstat); - } - - SIGNAL (SIGTTIN, SIG_IGN); - SIGNAL (SIGTTOU, SIG_IGN); - SIGNAL (SIGTSTP, SIG_IGN); -#endif /* TIOCGPGRP */ -} - - -void -sideground (void) -{ -#ifdef TIOCGPGRP - SIGNAL (SIGTTIN, SIG_DFL); - SIGNAL (SIGTTOU, SIG_DFL); - SIGNAL (SIGTSTP, SIG_DFL); -#endif /* TIOCGPGRP */ -} - -/* SIGNALS */ - - -static RETSIGTYPE -ALRMser (int sig) -{ - longjmp (PEERctx, DONE); -} - - -#ifdef BSD42 -/* ARGSUSED */ -#endif /* BSD42 */ - -static RETSIGTYPE -PIPEser (int sig) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (sig, SIG_IGN); -#endif - - adios (NULL, "lost peer"); -} - - -static RETSIGTYPE -SIGser (int sig) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (sig, SIG_IGN); -#endif - - done (1); -} - - -#ifdef SIGTSTP -static RETSIGTYPE -TSTPser (int sig) -{ -#ifndef TERMINFO - tputs (tgoto (CM, 0, LINES - 1), 0, _putchar); -#else /* TERMINFO */ - move(LINES - 1, 0); /* to lower left corner */ - clrtoeol(); /* clear bottom line */ - wrefresh(curscr); /* flush out everything */ -#endif /* TERMINFO */ - fflush (stdout); - - TTYoff (); -#ifdef BSD42 - sigsetmask (sigblock (0) & ~sigmask (SIGTSTP)); -#endif /* BSD42 */ - - kill (getpid (), sig); - -#ifdef BSD42 - sigblock (sigmask (SIGTSTP)); -#endif /* BSD42 */ - TTYon (); - - wrefresh (curscr); -} -#endif /* SIGTSTP */ - - -/* MISCELLANY */ - -int -done (int status) -{ - TTYoff (); - pFIN (); - - exit (status); - return 1; /* dead code to satisfy the compiler */ -} - - -static void -adorn (char *what, char *fmt, ...) -{ - va_list ap; - char *cp; - - cp = invo_name; - invo_name = NULL; - - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); - - invo_name = cp; -} - - -void -advertise (char *what, char *tail, char *fmt, va_list ap) -{ - int eindex = errno; - char buffer[BUFSIZ], err[BUFSIZ]; - struct iovec iob[20]; - register struct iovec *iov = iob; - - fflush (stdout); - fflush (stderr); - - if (invo_name) { - iov->iov_len = strlen (iov->iov_base = invo_name); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - - vsnprintf (buffer, sizeof(buffer), fmt, ap); - iov->iov_len = strlen (iov->iov_base = buffer); - iov++; - if (what) { - if (*what) { - iov->iov_len = strlen (iov->iov_base = " "); - iov++; - iov->iov_len = strlen (iov->iov_base = what); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - if (!(iov->iov_base = strerror (eindex))) { - snprintf (err, sizeof(err), "Error %d", eindex); - iov->iov_base = err; - } - iov->iov_len = strlen (iov->iov_base); - iov++; - } - if (tail && *tail) { - iov->iov_len = strlen (iov->iov_base = ", "); - iov++; - iov->iov_len = strlen (iov->iov_base = tail); - iov++; - } - iov->iov_len = strlen (iov->iov_base = "\n"); - iov++; - - if (tty_ready == DONE) - WINwritev (Display, iob, iov - iob); - else - writev (fileno (stderr), iob, iov - iob); -} - diff --git a/uip/vmhsbr.c b/uip/vmhsbr.c deleted file mode 100644 index eb6e037..0000000 --- a/uip/vmhsbr.c +++ /dev/null @@ -1,227 +0,0 @@ - -/* - * vmhsbr.c -- routines to help vmh along - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* - * TODO (for vrsn 2): - * INI: include width of windows - */ - -#include -#include -#include -#include - -static char *types[] = { - "OK", - "INI", "ACK", "ERR", "CMD", "QRY", "TTY", "WIN", "DATA", "EOF", "FIN", - "XXX", NULL -}; - -static FILE *fp = NULL; - -static int PEERrfd = NOTOK; -static int PEERwfd = NOTOK; - -/* - * static prototypes - */ -static int rclose (struct record *, char *, ...); - - -int -rcinit (int rfd, int wfd) -{ - char *cp, buffer[BUFSIZ]; - - PEERrfd = rfd; - PEERwfd = wfd; - - if ((cp = getenv ("MHVDEBUG")) && *cp) { - snprintf (buffer, sizeof(buffer), "%s.out", invo_name); - if ((fp = fopen (buffer, "w"))) { - fseek (fp, 0L, SEEK_END); - fprintf (fp, "%d: rcinit (%d, %d)\n", (int) getpid(), rfd, wfd); - fflush (fp); - } - } - - return OK; -} - - -int -rcdone (void) -{ - if (PEERrfd != NOTOK) - close (PEERrfd); - if (PEERwfd != NOTOK) - close (PEERwfd); - - if (fp) { - fclose (fp); - fp = NULL; - } - return OK; -} - - -int -rc2rc (char code, int len, char *data, struct record *rc) -{ - if (rc2peer (code, len, data) == NOTOK) - return NOTOK; - - return peer2rc (rc); -} - - -int -str2rc (char code, char *str, struct record *rc) -{ - return rc2rc (code, str ? strlen (str) : 0, str, rc); -} - - -int -peer2rc (struct record *rc) -{ - if (rc->rc_data) - free (rc->rc_data); - - if (read (PEERrfd, (char *) rc_head (rc), RHSIZE (rc)) != RHSIZE (rc)) - return rclose (rc, "read from peer lost(1)"); - if (rc->rc_len) { - rc->rc_data = mh_xmalloc ((unsigned) rc->rc_len + 1); - if (read (PEERrfd, rc->rc_data, rc->rc_len) != rc->rc_len) - return rclose (rc, "read from peer lost(2)"); - rc->rc_data[rc->rc_len] = 0; - } - else - rc->rc_data = NULL; - - if (fp) { - fseek (fp, 0L, SEEK_END); - fprintf (fp, "%d: <--- %s %d: \"%*.*s\"\n", (int) getpid(), - types[(unsigned char)rc->rc_type], rc->rc_len, - rc->rc_len, rc->rc_len, rc->rc_data); - fflush (fp); - } - - return rc->rc_type; -} - - -int -rc2peer (char code, int len, char *data) -{ - struct record rcs; - register struct record *rc = &rcs; - - rc->rc_type = code; - rc->rc_len = len; - - if (fp) { - fseek (fp, 0L, SEEK_END); - fprintf (fp, "%d: ---> %s %d: \"%*.*s\"\n", (int) getpid(), - types[(unsigned char)rc->rc_type], rc->rc_len, - rc->rc_len, rc->rc_len, data); - fflush (fp); - } - - if (write (PEERwfd, (char *) rc_head (rc), RHSIZE (rc)) != RHSIZE (rc)) - return rclose (rc, "write to peer lost(1)"); - - if (rc->rc_len) - if (write (PEERwfd, data, rc->rc_len) != rc->rc_len) - return rclose (rc, "write to peer lost(2)"); - - return OK; -} - - -int -str2peer (char code, char *str) -{ - return rc2peer (code, str ? strlen (str) : 0, str); -} - - -int -fmt2peer (char code, char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - return verr2peer (code, NULL, fmt, ap); - va_end(ap); -} - - -int -err2peer (char code, char *what, char *fmt, ...) -{ - int return_value; - va_list ap; - - va_start(ap, fmt); - return_value = verr2peer(code, what, fmt, ap); - va_end(ap); - return return_value; /* This routine returned garbage before 1999-07-15. */ -} - - -int -verr2peer (char code, char *what, char *fmt, va_list ap) -{ - int eindex = errno; - int len, buflen; - char *bp, *s, buffer[BUFSIZ * 2]; - - /* Get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - vsnprintf (bp, buflen, fmt, ap); - len = strlen (bp); - bp += len; - buflen -= len; - - if (what) { - if (*what) { - snprintf (bp, buflen, " %s: ", what); - len = strlen (bp); - bp += len; - buflen -= len; - } - if ((s = strerror (eindex))) - strncpy (bp, s, buflen); - else - snprintf (bp, buflen, "unknown error %d", eindex); - len = strlen (bp); - bp += len; - buflen -= len; - } - - return rc2peer (code, bp - buffer, buffer); -} - - -static int -rclose (struct record *rc, char *fmt, ...) -{ - va_list ap; - static char buffer[BUFSIZ * 2]; - - va_start(ap, fmt); - vsnprintf (buffer, sizeof(buffer), fmt, ap); - va_end(ap); - - rc->rc_len = strlen (rc->rc_data = getcpy (buffer)); - return (rc->rc_type = RC_XXX); -} diff --git a/uip/vmhtest.c b/uip/vmhtest.c deleted file mode 100644 index 572bad5..0000000 --- a/uip/vmhtest.c +++ /dev/null @@ -1,324 +0,0 @@ - -/* - * vmhtest.c -- test out vmh protocol - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include -#include - -static struct swit switches[] = { -#define READSW 0 - { "vmhread fd", 7 }, -#define WRITESW 1 - { "vmhwrite fd", 8 }, -#define VERSIONSW 2 - { "version", 0 }, -#define HELPSW 3 - { "help", 0 }, - { NULL, NULL } -}; - -#define NWIN 20 -static int numwins = 0; -static int windows[NWIN + 1]; - - -static int selcmds = 0; -#define selcmd() (selcmds++ % 2) - -static int selwins = 0; -#define selwin() (selwins++ % 2 ? 3 : 1) - - -int -main (int argc, char **argv) -{ - int fd1, fd2; - char *cp, buffer[BUFSIZ]; - char **argp, **arguments; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* foil search of user profile/context */ - if (context_foil (NULL) == -1) - done (1); - - arguments = getarguments (invo_name, argc, argv, 0); - argp = arguments; - - while ((cp = *argp++)) - if (*cp == '-') - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buffer, sizeof(buffer), "%s [switches]", invo_name); - print_help (buffer, switches, 0); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case READSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((fd1 = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - case WRITESW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - if ((fd2 = atoi (cp)) < 1) - adios (NULL, "bad argument %s %s", argp[-2], cp); - continue; - } - else - adios (NULL, "usage: %s [switches]", invo_name); - - rcinit (fd1, fd2); - pINI (); - pLOOP (); - - return done (0); -} - - -static int pINI () { - int i, - vrsn; - char *bp; - struct record rcs, - *rc = &rcs; - - initrc (rc); - - switch (peer2rc (rc)) { - case RC_INI: - bp = rc->rc_data; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &vrsn) != 1) { - bad_init: ; - fmt2peer (RC_ERR, "bad init \"%s\"", rc->rc_data); - done (1); - } - if (vrsn != RC_VRSN) { - fmt2peer (RC_ERR, "version %d unsupported", vrsn); - done (1); - } - - while (*bp && !isspace (*bp)) - bp++; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &numwins) != 1 || numwins <= 0) - goto bad_init; - if (numwins > NWIN) - numwins = NWIN; - - for (i = 1; i <= numwins; i++) { - while (*bp && !isspace (*bp)) - bp++; - while (isspace (*bp)) - bp++; - if (sscanf (bp, "%d", &windows[i]) != 1 || windows[i] <= 0) - goto bad_init; - } - rc2peer (RC_ACK, 0, NULL); - return OK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pINI protocol screw-up"); - done (1); /* NOTREACHED */ - } -} - - -static int pLOOP () { - struct record rcs, - *rc = &rcs; - - initrc (rc); - - for (;;) - switch (peer2rc (rc)) { - case RC_QRY: - pQRY (rc->rc_data); - break; - - case RC_CMD: - pCMD (rc->rc_data); - break; - - case RC_FIN: - done (0); - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pLOOP protocol screw-up"); - done (1); - } -} - - -static int pQRY (str) -char *str; -{ - rc2peer (RC_EOF, 0, NULL); - return OK; -} - - -static int pCMD (str) -char *str; -{ - if ((selcmd () ? pTTY (str) : pWIN (str)) == NOTOK) - return NOTOK; - rc2peer (RC_EOF, 0, NULL); - return OK; -} - - -static int pTTY (str) -char *str; -{ - struct record rcs, - *rc = &rcs; - - initrc (rc); - - switch (rc2rc (RC_TTY, 0, NULL, rc)) { - case RC_ACK: - break; - - case RC_ERR: - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pTTY protocol screw-up"); - done (1); - } - - system (str); - - switch (rc2rc (RC_EOF, 0, NULL, rc)) { - case RC_ACK: - return OK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data);/* NOTREACHED */ - - default: - fmt2peer (RC_ERR, "pTTY protocol screw-up"); - done (1); /* NOTREACHED */ - } -} - - -static int pWIN (str) -char *str; -{ - int i, - pid, - pd[2]; - char buffer[BUFSIZ]; - struct record rcs, - *rc = &rcs; - - initrc (rc); - - snprintf (buffer, sizeof(buffer), "%d", selwin ()); - switch (str2rc (RC_WIN, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - - if (pipe (pd) == NOTOK) { - fmt2peer (RC_ERR, "no pipes"); - return NOTOK; - } - - switch (pid = vfork ()) { - case NOTOK: - fmt2peer (RC_ERR, "no forks"); - return NOTOK; - - case OK: - close (0); - open ("/dev/null", O_RDONLY); - dup2 (pd[1], 1); - dup2 (pd[1], 2); - close (pd[0]); - close (pd[1]); - execlp ("/bin/sh", "sh", "-c", str, NULL); - write (2, "no shell\n", strlen ("no shell\n")); - _exit (1); - - default: - close (pd[1]); - while ((i = read (pd[0], buffer, sizeof buffer)) > 0) - switch (rc2rc (RC_DATA, i, buffer, rc)) { - case RC_ACK: - break; - - case RC_ERR: - close (pd[0]); - pidwait (pid, OK); - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - if (i == OK) - switch (rc2rc (RC_EOF, 0, NULL, rc)) { - case RC_ACK: - break; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - fmt2peer (RC_ERR, "pWIN protocol screw-up"); - done (1); - } - if (i == NOTOK) - fmt2peer (RC_ERR, "read from pipe lost"); - - close (pd[0]); - pidwait (pid, OK); - return (i != NOTOK ? OK : NOTOK); - } -} diff --git a/uip/whatnow.c b/uip/whatnow.c index d3fccfd..c60a11c 100644 --- a/uip/whatnow.c +++ b/uip/whatnow.c @@ -1,23 +1,663 @@ - /* - * whatnow.c -- the nmh `WhatNow' shell - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** whatnow.c -- the WhatNow shell +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include +#include +#include +#include +#include + +static struct swit switches[] = { +#define EDITRSW 0 + { "editor editor", 0 }, +#define PRMPTSW 1 + { "prompt string", 0 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 + { "help", 0 }, + { NULL, 0 } +}; + +/* +** Options at the "whatnow" prompt +*/ +static struct swit aleqs[] = { +#define EDITSW 0 + { "edit [editor [switches]]", 0 }, +#define LISTSW 1 + { "list", 0 }, +#define DISPSW 2 + { "display", 0 }, +#define WHOMSW 3 + { "whom", 0 }, +#define SENDSW 4 + { "send", 0 }, +#define REFILEOPT 5 + { "refile +folder", 0 }, +#define DELETESW 6 + { "delete", 0 }, +#define QUITSW 7 + { "quit", 0 }, +#define CDCMDSW 8 + { "cd [directory]", 0 }, +#define PWDCMDSW 9 + { "pwd", 0 }, +#define LSCMDSW 10 + { "ls", 0 }, +#define ALISTCMDSW 11 + { "alist", 0 }, +#define ATTACHCMDSW 12 + { "attach files", 0 }, +#define DETACHCMDSW 13 + { "detach numbers", 0 }, + { NULL, 0 } +}; -/* from whatnowsbr.c */ -int WhatNow (int, char **); +static char *myprompt = "\nWhat now? "; + +/* +** static prototypes +*/ +static int editfile(char **, char **, char *, int); +static int sendfile(char **, char *); +static int refile(char **, char *); +static int removefile(char *); +static void writelscmd(char *, int, char **); +static void writesomecmd(char *, int, char *, char *, char **); +static FILE* popen_in_dir(const char *, const char *, const char *); +static int system_in_dir(const char *, const char *); int -main (int argc, char **argv) +main(int argc, char **argv) +{ + int use = 0; + char *cp; + char *ed = NULL, *drft = NULL; + char buf[BUFSIZ], prompt[BUFSIZ]; + char **argp, **arguments; + struct stat st; + char cwd[MAXPATHLEN + 1]; /* current working directory */ + char file[MAXPATHLEN + 1]; /* file name buffer */ + char shell[MAXPATHLEN + 1]; /* shell response buffer */ + FILE *f; /* read pointer for bgnd proc */ + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + /* + ** Get the initial current working directory. + */ + + if (!getcwd(cwd, sizeof (cwd))) { + adios("getcwd", "could not get working directory"); + } + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [switches] [file]", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case EDITRSW: + if (!(ed = *argp++) || *ed == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + case PRMPTSW: + if (!(myprompt = *argp++) || *myprompt == '-') + adios(NULL, "missing argument to %s", + argp[-2]); + continue; + + } + } + if (drft) + adios(NULL, "only one draft at a time!"); + else + drft = cp; + } + + if ((!drft && !(drft = getenv("mhdraft"))) || !*drft) + drft = getcpy(m_draft(seq_cur)); + + if ((cp = getenv("mhuse")) && *cp) + use = atoi(cp); + + if (!ed && !(ed = getenv("mheditor"))) { + ed = ""; /* Don't initially edit the draft */ + } + + /* start editing the draft, unless editor is the empty string */ + if (*ed) { + if (editfile(&ed, NULL, drft, use) <0) { + if (!use) { + unlink(drft); + } + advise(NULL, "Try again."); + done(1); + } + } + + snprintf(prompt, sizeof(prompt), myprompt, invo_name); + for (;;) { + if (!(argp = getans(prompt, aleqs))) { + done(1); + } + switch (smatch(*argp, aleqs)) { + case DISPSW: + /* display the msg being replied to or distributed */ + if ((cp = getenv("mhaltmsg")) && *cp) { + snprintf(buf, sizeof buf, "%s '%s'", + listproc, cp); + system(buf); + } else { + advise(NULL, "no alternate message to display"); + } + break; + + case EDITSW: + /* Call an editor on the draft file */ + if (*++argp) + ed = *argp++; + editfile(&ed, argp, drft, NOUSE); + break; + + case LISTSW: + /* display the draft file */ + snprintf(buf, sizeof buf, "%s '%s'", listproc, drft); + system(buf); + break; + + case QUITSW: + /* quit */ + if (stat(drft, &st) != NOTOK) { + advise(NULL, "draft left on %s", drft); + } + done(1); + + case DELETESW: + /* Delete draft and exit */ + removefile(drft); + done(1); + + case SENDSW: + /* Send draft */ + sendfile(++argp, drft); + break; + + case REFILEOPT: + /* Refile the draft */ + if (refile(++argp, drft) == 0) { + done(0); + } + break; + + case CDCMDSW: + /* + ** Change the working directory for attachments + ** + ** Run the directory through the user's shell + ** so that we can take advantage of any syntax + ** that the user is accustomed to. Read back + ** the absolute path. + */ + + if (*(argp+1) == NULL) { + sprintf(buf, "$SHELL -c \"cd;pwd\""); + } else { + writesomecmd(buf, BUFSIZ, "cd", "pwd", argp); + } + if ((f = popen_in_dir(cwd, buf, "r"))) { + fgets(cwd, sizeof (cwd), f); + + if (strchr(cwd, '\n')) + *strchr(cwd, '\n') = '\0'; + + pclose(f); + } else { + advise("popen", "could not get directory"); + } + + break; + + case PWDCMDSW: + /* Print the working directory for attachments */ + printf("%s\n", cwd); + break; + + case LSCMDSW: + /* + ** List files in the current attachment working + ** directory + ** + ** Use the user's shell so that we can take + ** advantage of any syntax that the user is + ** accustomed to. + */ + writelscmd(buf, sizeof(buf), argp); + system_in_dir(cwd, buf); + break; + + case ALISTCMDSW: + /* + ** List attachments on current draft. + */ + snprintf(buf, sizeof buf, "anno -list -comp '%s' " + "-number '%s'", attach_hdr, drft); + if (system(buf) != 0) { + advise(NULL, "Could not list attachment headers."); + } + break; + + case ATTACHCMDSW: + /* + ** Attach files to current draft. + */ + + if (*(argp+1) == NULL) { + advise(NULL, "attach command requires file argument(s)."); + break; + } + + /* + ** Build a command line that causes the user's + ** shell to list the file name arguments. + ** This handles and wildcard expansion, tilde + ** expansion, etc. + */ + writelscmd(buf, sizeof(buf), argp); + + /* + ** Read back the response from the shell, + ** which contains a number of lines with one + ** file name per line. Remove off the newline. + ** Determine whether we have an absolute or + ** relative path name. Prepend the current + ** working directory to relative path names. + ** Add the attachment annotation to the draft. + */ + if ((f = popen_in_dir(cwd, buf, "r"))) { + char buf[BUFSIZ]; + + while (fgets(shell, sizeof(shell), f)) { + *(strchr(shell, '\n')) = '\0'; + + if (*shell == '/') + sprintf(file, "%s", shell); + else { + sprintf(file, "%s/%s", cwd, + shell); + } + snprintf(buf, sizeof buf, + "anno -nodate -append " + "-comp '%s' -text '%s'" + " '%s'", + attach_hdr, file, + drft); + if (system(buf) != 0) { + advise(NULL, "Could not add attachment header."); + } + } + + pclose(f); + } else { + advise("popen", "could not get file from shell"); + } + + break; + + case DETACHCMDSW: + /* + ** Detach files from current draft. + ** + ** Interpret the arguments as + ** attachment numbers. Decrement any remaining + ** argument number that is greater than the one + ** just processed after processing each one so + ** that the numbering stays correct. + */ + for (arguments=argp+1; *arguments; arguments++) { + char buf[BUFSIZ]; + int n; + + if (**arguments == '\0') { + continue; + } + + n = atoi(*arguments); + snprintf(buf, sizeof buf, "anno -delete " + "-comp '%s' -number '%d' " + "'%s'", + attach_hdr, n, drft); + if (system(buf) != 0) { + advise(NULL, "Could not delete attachment header."); + } + + for (argp=arguments+1; *argp; argp++) { + if (atoi(*argp) > n) { + if (atoi(*argp) == 1) { + *argp = ""; + } else { + sprintf(*argp, "%d", atoi(*argp) - 1); + } + } + } + } + break; + + case WHOMSW: + /* list recipients */ + snprintf(buf, sizeof buf, "%s '%s'", "whom", drft); + system(buf); + break; + + default: + /* Unknown command */ + advise(NULL, "say what?"); + break; + } + } + /*NOTREACHED*/ +} + + + +/* +** Build a command line of the form $SHELL -c "cd 'cwd'; cmd argp ... ; +** trailcmd". +*/ +static void +writesomecmd(char *buf, int bufsz, char *cmd, char *trailcmd, char **argp) +{ + char *cp; + /* + ** Note that we do not quote -- the argp from the user + ** is assumed to be quoted as they desire. (We can't treat + ** it as pure literal as that would prevent them using ~, + ** wildcards, etc.) The buffer produced by this function + ** should be given to popen_in_dir() or system_in_dir() so + ** that the current working directory is set correctly. + */ + int ln = snprintf(buf, bufsz, "$SHELL -c \"%s", cmd); + /* + ** NB that some snprintf() return -1 on overflow rather than the + ** new C99 mandated 'number of chars that would have been written' + */ + /* + ** length checks here and inside the loop allow for the + ** trailing ';', trailcmd, '"' and NUL + */ + int trailln = strlen(trailcmd) + 3; + if (ln < 0 || ln + trailln > bufsz) + adios(NULL, "arguments too long"); + + cp = buf + ln; + + while (*++argp) { + ln = strlen(*argp); + /* +1 for leading space */ + if (ln + trailln + 1 > bufsz - (cp-buf)) + adios(NULL, "arguments too long"); + *cp++ = ' '; + memcpy(cp, *argp, ln+1); + cp += ln; + } + if (*trailcmd) { + *cp++ = ';'; + strcpy(cp, trailcmd); + cp += trailln - 3; + } + *cp++ = '"'; + *cp = 0; +} + +/* +** Build a command line that causes the user's shell to list the file name +** arguments. This handles and wildcard expansion, tilde expansion, etc. +*/ +static void +writelscmd(char *buf, int bufsz, char **argp) +{ + writesomecmd(buf, bufsz, "ls", "", argp); +} + +/* +** Like system(), but run the command in directory dir. +** This assumes the program is single-threaded! +*/ +static int +system_in_dir(const char *dir, const char *cmd) { -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - return WhatNow (argc, argv); + char olddir[BUFSIZ]; + int r; + if (getcwd(olddir, sizeof(olddir)) == 0) + adios("getcwd", "could not get working directory"); + if (chdir(dir) != 0) + adios("chdir", "could not change working directory"); + r = system(cmd); + if (chdir(olddir) != 0) + adios("chdir", "could not change working directory"); + return r; +} + +/* ditto for popen() */ +static FILE* +popen_in_dir(const char *dir, const char *cmd, const char *type) +{ + char olddir[BUFSIZ]; + FILE *f; + if (getcwd(olddir, sizeof(olddir)) == 0) + adios("getcwd", "could not get working directory"); + if (chdir(dir) != 0) + adios("chdir", "could not change working directory"); + f = popen(cmd, type); + if (chdir(olddir) != 0) + adios("chdir", "could not change working directory"); + return f; +} + + +/* +** EDIT +*/ + +static char *edsave = NULL; /* the editor we used previously */ + + +static int +editfile(char **ed, char **arg, char *file, int use) +{ + int pid, status, vecp; + char *cp, *vec[MAXARGS]; + + if (!*ed || !**ed) { + /* We have no explicit editor. */ + if (edsave) { + /* Use the previous editor ... */ + *ed = edsave; + if (!(cp = mhbasename(*ed))) + cp = *ed; + + /* but prefer one specified via "editor-next" */ + cp = concat(cp, "-next", NULL); + if ((cp = context_find(cp))) + *ed = cp; + } else { + /* set initial editor */ + *ed = defaulteditor; + } + } + + context_save(); + fflush(stdout); + + switch (pid = fork()) { + case NOTOK: + advise("fork", "unable to"); + status = NOTOK; + break; + + case OK: + vecp = 0; + vec[vecp++] = mhbasename(*ed); + if (arg) + while (*arg) + vec[vecp++] = *arg++; + vec[vecp++] = file; + vec[vecp] = NULL; + + execvp(*ed, vec); + fprintf(stderr, "%s: unable to exec ", invo_name); + perror(*ed); + _exit(-1); + + default: + if ((status = pidwait(pid, NOTOK))) { + if ((status & 0xff00) == 0xff00) { + /* cmd not found or pidwait() failed */ + status = -1; + break; + } + if (status & 0x00ff) { + /* terminated by signal */ + advise(NULL, "%s terminated by signal %d", + *ed, status & 0x7f); + } else { + /* failure exit */ + advise(NULL, "%s exited with return code %d", + *ed, (status & 0xff00) >> 8); + } + status = -1; + break; + } + } + + /* remember which editor we used */ + edsave = getcpy(*ed); + + *ed = NULL; + + return status; +} + + +/* +** SEND +*/ + +static int +sendfile(char **arg, char *file) +{ + pid_t child_id; + int vecp; + char *vec[MAXARGS]; + + context_save(); /* save the context file */ + fflush(stdout); + + switch (child_id = fork()) { + case NOTOK: + advise(NULL, "unable to fork, so sending directly..."); + /* fall */ + case OK: + vecp = 0; + vec[vecp++] = "send"; + if (arg) + while (*arg) + vec[vecp++] = *arg++; + vec[vecp++] = file; + vec[vecp] = NULL; + + execvp("send", vec); + fprintf(stderr, "%s: unable to exec ", invo_name); + perror("send"); + _exit(-1); + + default: + if (pidwait(child_id, OK) == 0) + done(0); + return 1; + } +} + + +/* +** refile msg into another folder +*/ +static int +refile(char **arg, char *file) +{ + pid_t pid; + register int vecp; + char *vec[MAXARGS]; + + vecp = 0; + vec[vecp++] = "refile"; + vec[vecp++] = "-nolink"; /* override bad .mh_profile defaults */ + vec[vecp++] = "-file"; + vec[vecp++] = file; + + while (arg && *arg) { + vec[vecp++] = *arg++; + } + vec[vecp] = NULL; + + context_save(); /* save the context file */ + fflush(stdout); + + switch (pid = fork()) { + case -1: + advise("fork", "unable to"); + return -1; + + case 0: + execvp(*vec, vec); + fprintf(stderr, "%s: unable to exec ", invo_name); + perror(*vec); + _exit(-1); + + default: + return (pidwait(pid, -1)); + } +} + + +/* +** Remove the draft file +*/ + +static int +removefile(char *drft) +{ + if (unlink(drft) == NOTOK) + adios(drft, "unable to unlink"); + + return OK; } diff --git a/uip/whatnowproc.c b/uip/whatnowproc.c index 6bf4b36..e20df68 100644 --- a/uip/whatnowproc.c +++ b/uip/whatnowproc.c @@ -1,121 +1,102 @@ - /* - * whatnowproc.c -- exec the "whatnowproc" - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** whatnowproc.c -- exec the "whatnowproc" +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include /* - * This routine is used by comp, repl, forw, and dist to exec - * the "whatnowproc". It first sets up all the environment - * variables that the "whatnowproc" will need to check, and - * then execs the command. As an optimization, if the - * "whatnowproc" is the nmh command "whatnow" (typical case), - * it will call this routine directly without exec'ing it. - */ - -/* from whatnowsbr.c */ -int WhatNow (int, char **); - - +** This routine is used by comp, repl, forw, and dist to exec +** the "whatnowproc". It first sets up all the environment +** variables that the "whatnowproc" will need to check, and +** then execs the command. +*/ int -what_now (char *ed, int nedit, int use, char *file, char *altmsg, int dist, - struct msgs *mp, char *text, int inplace, char *cwd) +what_now(char *ed, int use, char *file, char *altmsg, int dist, + struct msgs *mp, char *text, char *cwd) { - int found, k, msgnum, vecp; - int len, buflen; - register char *bp; - char buffer[BUFSIZ], *vec[MAXARGS]; - - vecp = 0; - vec[vecp++] = r1bindex (whatnowproc, '/'); - vec[vecp] = NULL; - - m_putenv ("mhdraft", file); - if (mp) - m_putenv ("mhfolder", mp->foldpath); - else - unputenv ("mhfolder"); - if (altmsg) { - if (mp == NULL || *altmsg == '/' || cwd == NULL) - m_putenv ("mhaltmsg", altmsg); - else { - snprintf (buffer, sizeof(buffer), "%s/%s", mp->foldpath, altmsg); - m_putenv ("mhaltmsg", buffer); - } - } else { - unputenv ("mhaltmsg"); - } - if ((bp = getenv ("mhaltmsg")))/* XXX */ - m_putenv ("editalt", bp); - snprintf (buffer, sizeof(buffer), "%d", dist); - m_putenv ("mhdist", buffer); - if (nedit) { - unputenv ("mheditor"); - } else { - m_putenv ("mheditor", ed ? ed : (ed = context_find ("editor")) - ? ed : defaulteditor); - } - snprintf (buffer, sizeof(buffer), "%d", use); - m_putenv ("mhuse", buffer); - - unputenv ("mhmessages"); - unputenv ("mhannotate"); - unputenv ("mhinplace"); - - if (text && mp && !is_readonly(mp)) { - found = 0; - bp = buffer; - buflen = sizeof(buffer); - for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { - if (is_selected(mp, msgnum)) { - snprintf (bp, buflen, "%s%s", found ? " " : "", m_name (msgnum)); - len = strlen (bp); - bp += len; - buflen -= len; - for (k = msgnum + 1; k <= mp->hghmsg && is_selected(mp, k); k++) - continue; - if (--k > msgnum) { - snprintf (bp, buflen, "-%s", m_name (k)); - len = strlen (bp); - bp += len; - buflen -= len; + int found, k, msgnum, vecp; + int len, buflen; + register char *bp; + char buffer[BUFSIZ], *vec[MAXARGS]; + + vecp = 0; + vec[vecp++] = mhbasename(whatnowproc); + vec[vecp] = NULL; + + m_putenv("mhdraft", file); + if (mp) + m_putenv("mhfolder", mp->foldpath); + else + unputenv("mhfolder"); + if (altmsg) { + if (mp == NULL || *altmsg == '/' || cwd == NULL) + m_putenv("mhaltmsg", altmsg); + else { + snprintf(buffer, sizeof(buffer), "%s/%s", + mp->foldpath, altmsg); + m_putenv("mhaltmsg", buffer); } - msgnum = k + 1; - found++; - } + } else { + unputenv("mhaltmsg"); } - if (found) { - m_putenv ("mhmessages", buffer); - m_putenv ("mhannotate", text); - snprintf (buffer, sizeof(buffer), "%d", inplace); - m_putenv ("mhinplace", buffer); + snprintf(buffer, sizeof(buffer), "%d", dist); + m_putenv("mhdist", buffer); + if (!ed) { + m_putenv("mheditor", defaulteditor); + } else if (*ed) { + m_putenv("mheditor", ed); + } else { + unputenv("mheditor"); + } + snprintf(buffer, sizeof(buffer), "%d", use); + m_putenv("mhuse", buffer); + + unputenv("mhmessages"); + unputenv("mhannotate"); + + if (text && mp && !is_readonly(mp)) { + found = 0; + bp = buffer; + buflen = sizeof(buffer); + for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { + if (is_selected(mp, msgnum)) { + snprintf(bp, buflen, "%s%s", found ? " " : "", + m_name(msgnum)); + len = strlen(bp); + bp += len; + buflen -= len; + for (k = msgnum + 1; k <= mp->hghmsg && is_selected(mp, k); k++) + continue; + if (--k > msgnum) { + snprintf(bp, buflen, "-%s", m_name(k)); + len = strlen(bp); + bp += len; + buflen -= len; + } + msgnum = k + 1; + found++; + } + } + if (found) { + m_putenv("mhmessages", buffer); + m_putenv("mhannotate", text); + } } - } - - context_save (); /* save the context file */ - fflush (stdout); - if (cwd) - chdir (cwd); + context_save(); /* save the context file */ + fflush(stdout); - /* - * If the "whatnowproc" is the nmh command "whatnow", - * we run it internally, rather than exec'ing it. - */ - if (strcmp (vec[0], "whatnow") == 0) { - WhatNow (vecp, vec); - done (0); - } + if (cwd) + chdir(cwd); - execvp (whatnowproc, vec); - fprintf (stderr, "unable to exec "); - perror (whatnowproc); + execvp(whatnowproc, vec); + fprintf(stderr, "unable to exec "); + perror(whatnowproc); - return 0; + return 0; } diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c deleted file mode 100644 index 6541b42..0000000 --- a/uip/whatnowsbr.c +++ /dev/null @@ -1,1402 +0,0 @@ - -/* - * whatnowsbr.c -- the WhatNow shell - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - * - * Several options have been added to ease the inclusion of attachments - * using the header field name mechanism added to anno and send. The - * -attach option is used to specify the header field name for attachments. - * - * Several commands have been added at the whatnow prompt: - * - * cd [ directory ] This option works just like the shell's - * cd command and lets the user change the - * directory from which attachments are - * taken so that long path names are not - * needed with every file. - * - * ls [ ls-options ] This option works just like the normal - * ls command and exists to allow the user - * to verify file names in the directory. - * - * pwd This option works just like the normal - * pwd command and exists to allow the user - * to verify the directory. - * - * attach files This option attaches the named files to - * the draft. - * - * alist [-ln] This option lists the attachments on the - * draft. -l gets long listings, -n gets - * numbered listings. - * - * detach files This option removes attachments from the - * detach -n numbers draft. This can be done by file name or - * by attachment number. - */ - -#include -#include -#include -#include -#include - -static struct swit whatnowswitches[] = { -#define DFOLDSW 0 - { "draftfolder +folder", 0 }, -#define DMSGSW 1 - { "draftmessage msg", 0 }, -#define NDFLDSW 2 - { "nodraftfolder", 0 }, -#define EDITRSW 3 - { "editor editor", 0 }, -#define NEDITSW 4 - { "noedit", 0 }, -#define PRMPTSW 5 - { "prompt string", 4 }, -#define VERSIONSW 6 - { "version", 0 }, -#define HELPSW 7 - { "help", 0 }, -#define ATTACHSW 8 - { "attach header-field-name", 0 }, - { NULL, 0 } -}; - -/* - * Options at the "whatnow" prompt - */ -static struct swit aleqs[] = { -#define EDITSW 0 - { "edit [ ]", 0 }, -#define REFILEOPT 1 - { "refile [] +folder", 0 }, -#define BUILDMIMESW 2 - { "mime []", 0 }, -#define DISPSW 3 - { "display []", 0 }, -#define LISTSW 4 - { "list []", 0 }, -#define SENDSW 5 - { "send []", 0 }, -#define PUSHSW 6 - { "push []", 0 }, -#define WHOMSW 7 - { "whom []", 0 }, -#define QUITSW 8 - { "quit [-delete]", 0 }, -#define DELETESW 9 - { "delete", 0 }, -#define CDCMDSW 10 - { "cd [directory]", 0 }, -#define PWDCMDSW 11 - { "pwd", 0 }, -#define LSCMDSW 12 - { "ls", 0 }, -#define ATTACHCMDSW 13 - { "attach", 0 }, -#define DETACHCMDSW 14 - { "detach [-n]", 2 }, -#define ALISTCMDSW 15 - { "alist [-ln] ", 2 }, - { NULL, 0 } -}; - -static char *myprompt = "\nWhat now? "; - -/* - * static prototypes - */ -static int editfile (char **, char **, char *, int, struct msgs *, - char *, char *, int); -static int sendfile (char **, char *, int); -static void sendit (char *, char **, char *, int); -static int buildfile (char **, char *); -static int check_draft (char *); -static int whomfile (char **, char *); -static int removefile (char *); -static void writelscmd(char *, int, char **); -static void writesomecmd(char *buf, int bufsz, char *cmd, char *trailcmd, char **argp); -static FILE* popen_in_dir(const char *dir, const char *cmd, const char *type); -static int system_in_dir(const char *dir, const char *cmd); - - -#ifdef HAVE_LSTAT -static int copyf (char *, char *); -#endif - - -int -WhatNow (int argc, char **argv) -{ - int isdf = 0, nedit = 0, use = 0; - char *cp, *dfolder = NULL, *dmsg = NULL; - char *ed = NULL, *drft = NULL, *msgnam = NULL; - char buf[BUFSIZ], prompt[BUFSIZ]; - char **argp, **arguments; - struct stat st; - char *attach = (char *)0; /* attachment header field name */ - char cwd[MAXPATHLEN + 1]; /* current working directory */ - char file[MAXPATHLEN + 1]; /* file name buffer */ - char shell[MAXPATHLEN + 1]; /* shell response buffer */ - FILE *f; /* read pointer for bgnd proc */ - char *l; /* set on -l to alist command */ - int n; /* set on -n to alist command */ - - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - /* - * Get the initial current working directory. - */ - - if (getcwd(cwd, sizeof (cwd)) == (char *)0) { - adios("getcwd", "could not get working directory"); - } - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, whatnowswitches)) { - case AMBIGSW: - ambigsw (cp, whatnowswitches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name); - print_help (buf, whatnowswitches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - - case EDITRSW: - if (!(ed = *argp++) || *ed == '-') - adios (NULL, "missing argument to %s", argp[-2]); - nedit = 0; - continue; - case NEDITSW: - nedit++; - continue; - - case PRMPTSW: - if (!(myprompt = *argp++) || *myprompt == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case ATTACHSW: - if (attach != (char *)0) - adios(NULL, "only one attachment header field name at a time!"); - if (!(attach = *argp++) || *attach == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - } - } - if (drft) - adios (NULL, "only one draft at a time!"); - else - drft = cp; - } - - if ((drft == NULL && (drft = getenv ("mhdraft")) == NULL) || *drft == 0) - drft = getcpy (m_draft (dfolder, dmsg, 1, &isdf)); - - msgnam = (cp = getenv ("mhaltmsg")) && *cp ? getcpy (cp) : NULL; - - if ((cp = getenv ("mhuse")) && *cp) - use = atoi (cp); - - if (ed == NULL && ((ed = getenv ("mheditor")) == NULL || *ed == 0)) { - ed = NULL; - nedit++; - } - - /* start editing the draft, unless -noedit was given */ - if (!nedit && editfile (&ed, NULL, drft, use, NULL, msgnam, NULL, 1) < 0) - done (1); - - snprintf (prompt, sizeof(prompt), myprompt, invo_name); - for (;;) { - if (!(argp = getans (prompt, aleqs))) { - unlink (LINK); - done (1); - } - switch (smatch (*argp, aleqs)) { - case DISPSW: - /* display the message being replied to, or distributed */ - if (msgnam) - showfile (++argp, msgnam); - else - advise (NULL, "no alternate message to display"); - break; - - case BUILDMIMESW: - /* Translate MIME composition file */ - buildfile (++argp, drft); - break; - - case EDITSW: - /* Call an editor on the draft file */ - if (*++argp) - ed = *argp++; - if (editfile (&ed, argp, drft, NOUSE, NULL, msgnam, NULL, 1) == NOTOK) - done (1); - break; - - case LISTSW: - /* display the draft file */ - showfile (++argp, drft); - break; - - case WHOMSW: - /* Check to whom the draft would be sent */ - whomfile (++argp, drft); - break; - - case QUITSW: - /* Quit, and possibly delete the draft */ - if (*++argp && (*argp[0] == 'd' || - ((*argp)[0] == '-' && (*argp)[1] == 'd'))) { - removefile (drft); - } else { - if (stat (drft, &st) != NOTOK) - advise (NULL, "draft left on %s", drft); - } - done (1); - - case DELETESW: - /* Delete draft and exit */ - removefile (drft); - done (1); - - case PUSHSW: - /* Send draft in background */ - if (sendfile (++argp, drft, 1)) - done (1); - break; - - case SENDSW: - /* Send draft */ - sendfile (++argp, drft, 0); - break; - - case REFILEOPT: - /* Refile the draft */ - if (refile (++argp, drft) == 0) - done (0); - break; - - case CDCMDSW: - /* Change the working directory for attachments - * - * Run the directory through the user's shell so that - * we can take advantage of any syntax that the user - * is accustomed to. Read back the absolute path. - */ - - if (*(argp+1) == (char *)0) { - (void)sprintf(buf, "$SHELL -c \"cd;pwd\""); - } - else { - writesomecmd(buf, BUFSIZ, "cd", "pwd", argp); - } - if ((f = popen_in_dir(cwd, buf, "r")) != (FILE *)0) { - fgets(cwd, sizeof (cwd), f); - - if (strchr(cwd, '\n') != (char *)0) - *strchr(cwd, '\n') = '\0'; - - pclose(f); - } - else { - advise("popen", "could not get directory"); - } - - break; - - case PWDCMDSW: - /* Print the working directory for attachments */ - printf("%s\n", cwd); - break; - - case LSCMDSW: - /* List files in the current attachment working directory - * - * Use the user's shell so that we can take advantage of any - * syntax that the user is accustomed to. - */ - writelscmd(buf, sizeof(buf), argp); - (void)system_in_dir(cwd, buf); - break; - - case ALISTCMDSW: - /* - * List attachments on current draft. Options are: - * - * -l long listing (full path names) - * -n numbers listing - */ - - if (attach == (char *)0) { - advise((char *)0, "can't list because no header field name was given."); - break; - } - - l = (char *)0; - n = 0; - - while (*++argp != (char *)0) { - if (strcmp(*argp, "-l") == 0) - l = "/"; - - else if (strcmp(*argp, "-n") == 0) - n = 1; - - else if (strcmp(*argp, "-ln") == 0 || strcmp(*argp, "-nl") == 0) { - l = "/"; - n = 1; - } - - else { - n = -1; - break; - } - } - - if (n == -1) - advise((char *)0, "usage is alist [-ln]."); - - else - annolist(drft, attach, l, n); - - break; - - case ATTACHCMDSW: - /* - * Attach files to current draft. - */ - - if (attach == (char *)0) { - advise((char *)0, "can't attach because no header field name was given."); - break; - } - - if (*(argp+1) == (char *)0) { - advise((char *)0, "attach command requires file argument(s)."); - break; - } - - /* - * Build a command line that causes the user's shell to list the file name - * arguments. This handles and wildcard expansion, tilde expansion, etc. - */ - writelscmd(buf, sizeof(buf), argp); - - /* - * Read back the response from the shell, which contains a number of lines - * with one file name per line. Remove off the newline. Determine whether - * we have an absolute or relative path name. Prepend the current working - * directory to relative path names. Add the attachment annotation to the - * draft. - */ - - if ((f = popen_in_dir(cwd, buf, "r")) != (FILE *)0) { - while (fgets(shell, sizeof (shell), f) != (char *)0) { - *(strchr(shell, '\n')) = '\0'; - - if (*shell == '/') - (void)annotate(drft, attach, shell, 1, 0, -2, 1); - else { - (void)sprintf(file, "%s/%s", cwd, shell); - (void)annotate(drft, attach, file, 1, 0, -2, 1); - } - } - - pclose(f); - } - else { - advise("popen", "could not get file from shell"); - } - - break; - - case DETACHCMDSW: - /* - * Detach files from current draft. - */ - - if (attach == (char *)0) { - advise((char *)0, "can't detach because no header field name was given."); - break; - } - - /* - * Scan the arguments for a -n. Mixed file names and numbers aren't allowed, - * so this catches a -n anywhere in the argument list. - */ - - for (n = 0, arguments = argp + 1; *arguments != (char *)0; arguments++) { - if (strcmp(*arguments, "-n") == 0) { - n = 1; - break; - } - } - - /* - * A -n was found so interpret the arguments as attachment numbers. - * Decrement any remaining argument number that is greater than the one - * just processed after processing each one so that the numbering stays - * correct. - */ - - if (n == 1) { - for (arguments = argp + 1; *arguments != (char *)0; arguments++) { - if (strcmp(*arguments, "-n") == 0) - continue; - - if (**arguments != '\0') { - n = atoi(*arguments); - (void)annotate(drft, attach, (char *)0, 1, 0, n, 1); - - for (argp = arguments + 1; *argp != (char *)0; argp++) { - if (atoi(*argp) > n) { - if (atoi(*argp) == 1) - *argp = ""; - else - (void)sprintf(*argp, "%d", atoi(*argp) - 1); - } - } - } - } - } - - /* - * The arguments are interpreted as file names. Run them through the - * user's shell for wildcard expansion and other goodies. Do this from - * the current working directory if the argument is not an absolute path - * name (does not begin with a /). - * - * We feed all the file names to the shell at once, otherwise you can't - * provide a file name with a space in it. - */ - writelscmd(buf, sizeof(buf), argp); - if ((f = popen_in_dir(cwd, buf, "r")) != (FILE *)0) { - while (fgets(shell, sizeof (shell), f) != (char *)0) { - *(strchr(shell, '\n')) = '\0'; - (void)annotate(drft, attach, shell, 1, 0, 0, 1); - } - pclose(f); - } else { - advise("popen", "could not get file from shell"); - } - - break; - - default: - /* Unknown command */ - advise (NULL, "say what?"); - break; - } - } - /*NOTREACHED*/ -} - - - -/* Build a command line of the form $SHELL -c "cd 'cwd'; cmd argp ... ; trailcmd". */ -static void -writesomecmd(char *buf, int bufsz, char *cmd, char *trailcmd, char **argp) -{ - char *cp; - /* Note that we do not quote -- the argp from the user - * is assumed to be quoted as they desire. (We can't treat - * it as pure literal as that would prevent them using ~, - * wildcards, etc.) The buffer produced by this function - * should be given to popen_in_dir() or system_in_dir() so - * that the current working directory is set correctly. - */ - int ln = snprintf(buf, bufsz, "$SHELL -c \"%s", cmd); - /* NB that some snprintf() return -1 on overflow rather than the - * new C99 mandated 'number of chars that would have been written' - */ - /* length checks here and inside the loop allow for the - * trailing ';', trailcmd, '"' and NUL - */ - int trailln = strlen(trailcmd) + 3; - if (ln < 0 || ln + trailln > bufsz) - adios((char *)0, "arguments too long"); - - cp = buf + ln; - - while (*++argp != (char *)0) { - ln = strlen(*argp); - /* +1 for leading space */ - if (ln + trailln + 1 > bufsz - (cp-buf)) - adios((char *)0, "arguments too long"); - *cp++ = ' '; - memcpy(cp, *argp, ln+1); - cp += ln; - } - if (*trailcmd) { - *cp++ = ';'; - strcpy(cp, trailcmd); - cp += trailln - 3; - } - *cp++ = '"'; - *cp = 0; -} - -/* - * Build a command line that causes the user's shell to list the file name - * arguments. This handles and wildcard expansion, tilde expansion, etc. - */ -static void -writelscmd(char *buf, int bufsz, char **argp) -{ - writesomecmd(buf, bufsz, "ls", "", argp); -} - -/* Like system(), but run the command in directory dir. - * This assumes the program is single-threaded! - */ -static int -system_in_dir(const char *dir, const char *cmd) -{ - char olddir[BUFSIZ]; - int r; - if (getcwd(olddir, sizeof(olddir)) == 0) - adios("getcwd", "could not get working directory"); - if (chdir(dir) != 0) - adios("chdir", "could not change working directory"); - r = system(cmd); - if (chdir(olddir) != 0) - adios("chdir", "could not change working directory"); - return r; -} - -/* ditto for popen() */ -static FILE* -popen_in_dir(const char *dir, const char *cmd, const char *type) -{ - char olddir[BUFSIZ]; - FILE *f; - if (getcwd(olddir, sizeof(olddir)) == 0) - adios("getcwd", "could not get working directory"); - if (chdir(dir) != 0) - adios("chdir", "could not change working directory"); - f = popen(cmd, type); - if (chdir(olddir) != 0) - adios("chdir", "could not change working directory"); - return f; -} - - -/* - * EDIT - */ - -static int reedit = 0; /* have we been here before? */ -static char *edsave = NULL; /* the editor we used previously */ - - -static int -editfile (char **ed, char **arg, char *file, int use, struct msgs *mp, - char *altmsg, char *cwd, int save_editor) -{ - int pid, status, vecp; - char altpath[BUFSIZ], linkpath[BUFSIZ]; - char *cp, *vec[MAXARGS]; - struct stat st; - -#ifdef HAVE_LSTAT - int slinked = 0; -#if 0 - int oumask; /* PJS: for setting permissions on symlinks. */ -#endif -#endif /* HAVE_LSTAT */ - - /* Was there a previous edit session? */ - if (reedit) { - if (!*ed) { /* no explicit editor */ - *ed = edsave; /* so use the previous one */ - if ((cp = r1bindex (*ed, '/')) == NULL) - cp = *ed; - - /* unless we've specified it via "editor-next" */ - cp = concat (cp, "-next", NULL); - if ((cp = context_find (cp)) != NULL) - *ed = cp; - } - } else { - /* set initial editor */ - if (*ed == NULL && (*ed = context_find ("editor")) == NULL) - *ed = defaulteditor; - } - - if (altmsg) { - if (mp == NULL || *altmsg == '/' || cwd == NULL) - strncpy (altpath, altmsg, sizeof(altpath)); - else - snprintf (altpath, sizeof(altpath), "%s/%s", mp->foldpath, altmsg); - if (cwd == NULL) - strncpy (linkpath, LINK, sizeof(linkpath)); - else - snprintf (linkpath, sizeof(linkpath), "%s/%s", cwd, LINK); - } - - if (altmsg) { - unlink (linkpath); -#ifdef HAVE_LSTAT - if (link (altpath, linkpath) == NOTOK) { -#if 0 - /* I don't think permission on symlinks matters /JLR */ - oumask = umask(0044); /* PJS: else symlinks are world 'r' */ -#endif - symlink (altpath, linkpath); -#if 0 - umask(oumask); /* PJS: else symlinks are world 'r' */ -#endif - slinked = 1; - } else { - slinked = 0; - } -#else /* not HAVE_LSTAT */ - link (altpath, linkpath); -#endif /* not HAVE_LSTAT */ - } - - context_save (); /* save the context file */ - fflush (stdout); - - switch (pid = vfork ()) { - case NOTOK: - advise ("fork", "unable to"); - status = NOTOK; - break; - - case OK: - if (cwd) - chdir (cwd); - if (altmsg) { - if (mp) - m_putenv ("mhfolder", mp->foldpath); - m_putenv ("editalt", altpath); - } - - vecp = 0; - vec[vecp++] = r1bindex (*ed, '/'); - if (arg) - while (*arg) - vec[vecp++] = *arg++; - vec[vecp++] = file; - vec[vecp] = NULL; - - execvp (*ed, vec); - fprintf (stderr, "unable to exec "); - perror (*ed); - _exit (-1); - - default: - if ((status = pidwait (pid, NOTOK))) { -#ifdef ATTVIBUG - if ((cp = r1bindex (*ed, '/')) - && strcmp (cp, "vi") == 0 - && (status & 0x00ff) == 0) - status = 0; - else { -#endif - if (((status & 0xff00) != 0xff00) - && (!reedit || (status & 0x00ff))) { - if (!use && (status & 0xff00) && - (rename (file, cp = m_backup (file)) != NOTOK)) { - advise (NULL, "problems with edit--draft left in %s", cp); - } else { - advise (NULL, "problems with edit--%s preserved", file); - } - } - status = -2; /* maybe "reedit ? -2 : -1"? */ - break; -#ifdef ATTVIBUG - } -#endif - } - - reedit++; -#ifdef HAVE_LSTAT - if (altmsg - && mp - && !is_readonly(mp) - && (slinked - ? lstat (linkpath, &st) != NOTOK - && S_ISREG(st.st_mode) - && copyf (linkpath, altpath) == NOTOK - : stat (linkpath, &st) != NOTOK - && st.st_nlink == 1 - && (unlink (altpath) == NOTOK - || link (linkpath, altpath) == NOTOK))) - advise (linkpath, "unable to update %s from", altmsg); -#else /* HAVE_LSTAT */ - if (altmsg - && mp - && !is_readonly(mp) - && stat (linkpath, &st) != NOTOK - && st.st_nlink == 1 - && (unlink (altpath) == NOTOK - || link (linkpath, altpath) == NOTOK)) - advise (linkpath, "unable to update %s from", altmsg); -#endif /* HAVE_LSTAT */ - } - - /* normally, we remember which editor we used */ - if (save_editor) - edsave = getcpy (*ed); - - *ed = NULL; - if (altmsg) - unlink (linkpath); - - return status; -} - - -#ifdef HAVE_LSTAT -static int -copyf (char *ifile, char *ofile) -{ - int i, in, out; - char buffer[BUFSIZ]; - - if ((in = open (ifile, O_RDONLY)) == NOTOK) - return NOTOK; - if ((out = open (ofile, O_WRONLY | O_TRUNC)) == NOTOK) { - admonish (ofile, "unable to open and truncate"); - close (in); - return NOTOK; - } - - while ((i = read (in, buffer, sizeof(buffer))) > OK) - if (write (out, buffer, i) != i) { - advise (ofile, "may have damaged"); - i = NOTOK; - break; - } - - close (in); - close (out); - return i; -} -#endif /* HAVE_LSTAT */ - - -/* - * SEND - */ - -static int -sendfile (char **arg, char *file, int pushsw) -{ - pid_t child_id; - int i, vecp; - char *cp, *sp, *vec[MAXARGS]; - - /* Translate MIME composition file, if necessary */ - if ((cp = context_find ("automimeproc")) - && (!strcmp (cp, "1")) - && !getenv ("NOMHNPROC") - && check_draft (file) - && (buildfile (NULL, file) == NOTOK)) - return 0; - - /* For backwards compatibility */ - if ((cp = context_find ("automhnproc")) - && !getenv ("NOMHNPROC") - && check_draft (file) - && (i = editfile (&cp, NULL, file, NOUSE, NULL, NULL, NULL, 0))) - return 0; - - /* - * If the sendproc is the nmh command `send', then we call - * those routines directly rather than exec'ing the command. - */ - if (strcmp (sp = r1bindex (sendproc, '/'), "send") == 0) { - cp = invo_name; - sendit (invo_name = sp, arg, file, pushsw); - invo_name = cp; - return 1; - } - - context_save (); /* save the context file */ - fflush (stdout); - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { - case NOTOK: - advise (NULL, "unable to fork, so sending directly..."); - case OK: - vecp = 0; - vec[vecp++] = invo_name; - if (pushsw) - vec[vecp++] = "-push"; - if (arg) - while (*arg) - vec[vecp++] = *arg++; - vec[vecp++] = file; - vec[vecp] = NULL; - - execvp (sendproc, vec); - fprintf (stderr, "unable to exec "); - perror (sendproc); - _exit (-1); - - default: - if (pidwait(child_id, OK) == 0) - done (0); - return 1; - } -} - - -/* - * Translate MIME composition file (call buildmimeproc) - */ - -static int -buildfile (char **argp, char *file) -{ - int i; - char **args, *ed; - - ed = buildmimeproc; - - /* allocate space for arguments */ - i = 0; - if (argp) { - while (argp[i]) - i++; - } - args = (char **) mh_xmalloc((i + 2) * sizeof(char *)); - - /* - * For backward compatibility, we need to add -build - * if we are using mhn as buildmimeproc - */ - i = 0; - if (strcmp (r1bindex (ed, '/'), "mhn") == 0) - args[i++] = "-build"; - - /* copy any other arguments */ - while (argp && *argp) - args[i++] = *argp++; - args[i] = NULL; - - i = editfile (&ed, args, file, NOUSE, NULL, NULL, NULL, 0); - free (args); - - return (i ? NOTOK : OK); -} - - -/* - * Check if draft is a mhbuild composition file - */ - -static int -check_draft (char *msgnam) -{ - int state; - char buf[BUFSIZ], name[NAMESZ]; - FILE *fp; - - if ((fp = fopen (msgnam, "r")) == NULL) - return 0; - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { - case FLD: - case FLDPLUS: - case FLDEOF: - /* - * If draft already contains any of the - * Content-XXX fields, then assume it already - * been converted. - */ - if (uprf (name, XXX_FIELD_PRF)) { - fclose (fp); - return 0; - } - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); - break; - - case BODY: - do { - char *bp; - - for (bp = buf; *bp; bp++) - if (*bp != ' ' && *bp != '\t' && *bp != '\n') { - fclose (fp); - return 1; - } - - state = m_getfld (state, name, buf, sizeof(buf), fp); - } while (state == BODY); - /* and fall... */ - - default: - fclose (fp); - return 0; - } -} - - -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else /* CYRUS_SASL */ -# define SASLminc(a) 0 -#endif /* CYRUS_SASL */ - -#ifndef TLS_SUPPORT -# define TLSminc(a) (a) -#else /* TLS_SUPPORT */ -# define TLSminc(a) 0 -#endif /* TLS_SUPPORT */ - -static struct swit sendswitches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define DEBUGSW 1 - { "debug", -5 }, -#define FILTSW 2 - { "filter filterfile", 0 }, -#define NFILTSW 3 - { "nofilter", 0 }, -#define FRMTSW 4 - { "format", 0 }, -#define NFRMTSW 5 - { "noformat", 0 }, -#define FORWSW 6 - { "forward", 0 }, -#define NFORWSW 7 - { "noforward", 0 }, -#define MIMESW 8 - { "mime", 0 }, -#define NMIMESW 9 - { "nomime", 0 }, -#define MSGDSW 10 - { "msgid", 0 }, -#define NMSGDSW 11 - { "nomsgid", 0 }, -#define SPSHSW 12 - { "push", 0 }, -#define NSPSHSW 13 - { "nopush", 0 }, -#define SPLITSW 14 - { "split seconds", 0 }, -#define UNIQSW 15 - { "unique", -6 }, -#define NUNIQSW 16 - { "nounique", -8 }, -#define VERBSW 17 - { "verbose", 0 }, -#define NVERBSW 18 - { "noverbose", 0 }, -#define WATCSW 19 - { "watch", 0 }, -#define NWATCSW 20 - { "nowatch", 0 }, -#define WIDTHSW 21 - { "width columns", 0 }, -#define SVERSIONSW 22 - { "version", 0 }, -#define SHELPSW 23 - { "help", 0 }, -#define BITSTUFFSW 24 - { "dashstuffing", -12 }, -#define NBITSTUFFSW 25 - { "nodashstuffing", -14 }, -#define MAILSW 26 - { "mail", -4 }, -#define SAMLSW 27 - { "saml", -4 }, -#define SSNDSW 28 - { "send", -4 }, -#define SOMLSW 29 - { "soml", -4 }, -#define CLIESW 30 - { "client host", -6 }, -#define SERVSW 31 - { "server host", 6 }, -#define SNOOPSW 32 - { "snoop", -5 }, -#define SDRFSW 33 - { "draftfolder +folder", -6 }, -#define SDRMSW 34 - { "draftmessage msg", -6 }, -#define SNDRFSW 35 - { "nodraftfolder", -3 }, -#define SASLSW 36 - { "sasl", SASLminc(-4) }, -#define SASLMECHSW 37 - { "saslmech", SASLminc(-5) }, -#define USERSW 38 - { "user", SASLminc(-4) }, -#define SNDATTACHSW 39 - { "attach file", 6 }, -#define SNDATTACHFORMAT 40 - { "attachformat", 7 }, -#define PORTSW 41 - { "port server-port-name/number", 4 }, -#define TLSSW 42 - { "tls", TLSminc(-3) }, - { NULL, 0 } -}; - - -extern int debugsw; /* from sendsbr.c */ -extern int forwsw; -extern int inplace; -extern int pushsw; -extern int splitsw; -extern int unique; -extern int verbsw; - -extern char *altmsg; /* .. */ -extern char *annotext; -extern char *distfile; - - -static void -sendit (char *sp, char **arg, char *file, int pushed) -{ - int vecp, n = 1; - char *cp, buf[BUFSIZ], **argp; - char **arguments, *vec[MAXARGS]; - struct stat st; - char *attach = (char *)0; /* attachment header field name */ - int attachformat = 0; /* mhbuild format specifier for - attachments */ - -#ifndef lint - int distsw = 0; -#endif -#ifdef UCI - FILE *fp; -#endif - - /* - * Make sure these are defined. In particular, we need - * vec[1] to be NULL, in case "arg" is NULL below. It - * doesn't matter what is the value of vec[0], but we - * set it to NULL, to help catch "off-by-one" errors. - */ - vec[0] = NULL; - vec[1] = NULL; - - /* - * Temporarily copy arg to vec, since the brkstring() call in - * getarguments() will wipe it out before it is merged in. - * Also, we skip the first element of vec, since getarguments() - * skips it. Then we count the number of arguments - * copied. The value of "n" will be one greater than - * this in order to simulate the standard argc/argv. - */ - if (arg) { - char **bp; - - copyip (arg, vec+1, MAXARGS-1); - bp = vec+1; - while (*bp++) - n++; - } - - /* - * Merge any arguments from command line (now in vec) - * and arguments from profile. - */ - arguments = getarguments (sp, n, vec, 1); - argp = arguments; - - debugsw = 0; - forwsw = 1; - inplace = 1; - unique = 0; - - altmsg = NULL; - annotext = NULL; - distfile = NULL; - - vecp = 1; /* we'll get the zero'th element later */ - vec[vecp++] = "-library"; - vec[vecp++] = getcpy (m_maildir ("")); - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, sendswitches)) { - case AMBIGSW: - ambigsw (cp, sendswitches); - return; - case UNKWNSW: - advise (NULL, "-%s unknown\n", cp); - return; - - case SHELPSW: - snprintf (buf, sizeof(buf), "%s [switches]", sp); - print_help (buf, sendswitches, 1); - return; - case SVERSIONSW: - print_version (invo_name); - return; - - case SPSHSW: - pushed++; - continue; - case NSPSHSW: - pushed = 0; - continue; - - case SPLITSW: - if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) { - advise (NULL, "missing argument to %s", argp[-2]); - return; - } - continue; - - case UNIQSW: - unique++; - continue; - case NUNIQSW: - unique = 0; - continue; - case FORWSW: - forwsw++; - continue; - case NFORWSW: - forwsw = 0; - continue; - - case VERBSW: - verbsw++; - vec[vecp++] = --cp; - continue; - case NVERBSW: - verbsw = 0; - vec[vecp++] = --cp; - continue; - - case DEBUGSW: - debugsw++; /* fall */ - case NFILTSW: - case FRMTSW: - case NFRMTSW: - case BITSTUFFSW: - case NBITSTUFFSW: - case MIMESW: - case NMIMESW: - case MSGDSW: - case NMSGDSW: - case WATCSW: - case NWATCSW: - case MAILSW: - case SAMLSW: - case SSNDSW: - case SOMLSW: - case SNOOPSW: - case SASLSW: - case TLSSW: - vec[vecp++] = --cp; - continue; - - case ALIASW: - case FILTSW: - case WIDTHSW: - case CLIESW: - case SERVSW: - case SASLMECHSW: - case USERSW: - case PORTSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') { - advise (NULL, "missing argument to %s", argp[-2]); - return; - } - vec[vecp++] = cp; - continue; - - case SDRFSW: - case SDRMSW: - if (!(cp = *argp++) || *cp == '-') { - advise (NULL, "missing argument to %s", argp[-2]); - return; - } - case SNDRFSW: - continue; - - case SNDATTACHSW: - if (!(attach = *argp++) || *attach == '-') { - advise (NULL, "missing argument to %s", argp[-2]); - return; - } - continue; - - case SNDATTACHFORMAT: - if (! *argp || **argp == '-') - adios (NULL, "missing argument to %s", argp[-1]); - else { - attachformat = atoi (*argp); - if (attachformat < 0 || - attachformat > ATTACHFORMATS - 1) { - advise (NULL, "unsupported attachformat %d", - attachformat); - continue; - } - } - ++argp; - continue; - } - } - advise (NULL, "usage: %s [switches]", sp); - return; - } - - /* allow Aliasfile: profile entry */ - if ((cp = context_find ("Aliasfile"))) { - char **ap, *dp; - - dp = getcpy (cp); - for (ap = brkstring (dp, " ", "\n"); ap && *ap; ap++) { - vec[vecp++] = "-alias"; - vec[vecp++] = *ap; - } - } - - if ((cp = getenv ("SIGNATURE")) == NULL || *cp == 0) - if ((cp = context_find ("signature")) && *cp) - m_putenv ("SIGNATURE", cp); -#ifdef UCI - else { - snprintf (buf, sizeof(buf), "%s/.signature", mypath); - if ((fp = fopen (buf, "r")) != NULL - && fgets (buf, sizeof(buf), fp) != NULL) { - fclose (fp); - if (cp = strchr (buf, '\n')) - *cp = 0; - m_putenv ("SIGNATURE", buf); - } - } -#endif /* UCI */ - - if ((annotext = getenv ("mhannotate")) == NULL || *annotext == 0) - annotext = NULL; - if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == 0) - altmsg = NULL; - if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != 0)) - inplace = atoi (cp); - - if ((cp = getenv ("mhdist")) - && *cp -#ifndef lint - && (distsw = atoi (cp)) -#endif /* not lint */ - && altmsg) { - vec[vecp++] = "-dist"; - distfile = getcpy (m_mktemp2(altmsg, invo_name, NULL, NULL)); - if (link (altmsg, distfile) == NOTOK) - adios (distfile, "unable to link %s to", altmsg); - } else { - distfile = NULL; - } - - if (altmsg == NULL || stat (altmsg, &st) == NOTOK) { - st.st_mtime = 0; - st.st_dev = 0; - st.st_ino = 0; - } - if ((pushsw = pushed)) - push (); - - vec[0] = r1bindex (postproc, '/'); - closefds (3); - - if (sendsbr (vec, vecp, file, &st, 1, attach, attachformat) == OK) - done (0); -} - -/* - * WHOM - */ - -static int -whomfile (char **arg, char *file) -{ - pid_t pid; - int vecp; - char *vec[MAXARGS]; - - context_save (); /* save the context file */ - fflush (stdout); - - switch (pid = vfork ()) { - case NOTOK: - advise ("fork", "unable to"); - return 1; - - case OK: - vecp = 0; - vec[vecp++] = r1bindex (whomproc, '/'); - vec[vecp++] = file; - if (arg) - while (*arg) - vec[vecp++] = *arg++; - vec[vecp] = NULL; - - execvp (whomproc, vec); - fprintf (stderr, "unable to exec "); - perror (whomproc); - _exit (-1); /* NOTREACHED */ - - default: - return (pidwait (pid, NOTOK) & 0377 ? 1 : 0); - } -} - - -/* - * Remove the draft file - */ - -static int -removefile (char *drft) -{ - if (unlink (drft) == NOTOK) - adios (drft, "unable to unlink"); - - return OK; -} diff --git a/uip/whom.c b/uip/whom.c index ddf99ef..8ffe8b8 100644 --- a/uip/whom.c +++ b/uip/whom.c @@ -1,217 +1,342 @@ - /* - * whom.c -- report to whom a message would be sent - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** whom.c -- list recipients of message +** +** This code is Copyright (c) 2012, by the authors of mmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#include -#include - -#ifndef CYRUS_SASL -# define SASLminc(a) (a) -#else /* CYRUS_SASL */ -# define SASLminc(a) 0 -#endif /* CYRUS_SASL */ - -#ifndef TLS_SUPPORT -# define TLSminc(a) (a) -#else /* TLS_SUPPORT */ -# define TLSminc(a) 0 -#endif /* TLS_SUPPORT */ +#include +#include +#include static struct swit switches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define CHKSW 1 - { "check", 0 }, -#define NOCHKSW 2 - { "nocheck", 0 }, -#define DRAFTSW 3 - { "draft", 0 }, -#define DFOLDSW 4 - { "draftfolder +folder", 6 }, -#define DMSGSW 5 - { "draftmessage msg", 6 }, -#define NDFLDSW 6 - { "nodraftfolder", 0 }, -#define VERSIONSW 7 - { "version", 0 }, -#define HELPSW 8 - { "help", 0 }, -#define CLIESW 9 - { "client host", -6 }, -#define SERVSW 10 - { "server host", -6 }, -#define SNOOPSW 11 - { "snoop", -5 }, -#define SASLSW 12 - { "sasl", SASLminc(4) }, -#define SASLMECHSW 13 - { "saslmech mechanism", SASLminc(-5) }, -#define USERSW 14 - { "user username", SASLminc(-4) }, -#define PORTSW 15 - { "port server port name/number", 4 }, -#define TLSSW 16 - { "tls", TLSminc(-3) }, - { NULL, 0 } +#define VERSIONSW 0 + { "Version", 0 }, +#define HELPSW 1 + { "help", 0 }, +#define TOCCSW 2 + { "tocc", 0 }, +#define NTOCCSW 3 + { "notocc", 2 }, +#define BCCSW 4 + { "bcc", 0 }, +#define NBCCSW 5 + { "nobcc", 2 }, +#define ALISW 6 + { "alias", 0 }, +#define NALISW 7 + { "noalias", 2 }, + { NULL, 0 } }; +#define NFILES 32 + +#define HRESENT (1<<1) +#define HTO (1<<2) +#define HCC (1<<3) +#define HBCC (1<<4) + +struct mailname head = {0}; +struct mailname *mp = &head; + +static char *cmd; + +static int resent = 0; /* consider normal or resent headers */ +static int toccsw = 1; /* list sighted recipients */ +static int bccsw = 1; /* list hidden recipients */ +static int alisw = 1; /* expand aliases on rcpt addrs */ + +static char *separator = "\t==BCC=="; + + +/* +** static prototypes +*/ +static int process(char *); +static void proc_hdr(char *, char *); +static int print(void); +static int printbcc(void); +static void printone(struct mailname *); + + int -main (int argc, char **argv) +main(int argc, char **argv) +{ + int filep=0, naddrs=0, n; + char *cp; + char buf[BUFSIZ], **argp; + char **arguments, *files[NFILES]; + FILE *in; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + + case UNKWNSW: + adios(NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [switches] file ...", + invo_name); + print_help(buf, switches, 1); + done(1); + case VERSIONSW: + print_version(invo_name); + done(1); + + case TOCCSW: + toccsw = 1; + continue; + case NTOCCSW: + toccsw = 0; + continue; + + case BCCSW: + bccsw = 1; + continue; + case NBCCSW: + bccsw = 0; + continue; + + case ALISW: + alisw = 1; + continue; + case NALISW: + alisw = 0; + continue; + } + } + if (filep > NFILES) { + adios(NULL, "too many files (more than %d)", + NFILES); + } else { + files[filep++] = cp; + } + } + files[filep] = NULL; + if (!filep) { + adios(NULL, "usage: %s [switches] file ...", invo_name); + } + if (!toccsw && !bccsw) { + adios(NULL, "give -tocc or -bcc or both to produce output"); + } + for (filep=0; files[filep]; filep++) { + process(files[filep]); + } + + cmd = add("ali -list", NULL); + if ((n=print()) && alisw) { + if (!(in = popen(cmd, "r"))) { + adios("popen", "unable to"); + } + while (fgets(buf, sizeof buf, in)) { + fputs(buf, stdout); + } + pclose(in); + } + free(cmd); + naddrs += n; + + cmd = add("ali -list", NULL); + if ((n=printbcc()) && alisw) { + if (!(in = popen(cmd, "r"))) { + adios("popen", "unable to"); + } + while (fgets(buf, sizeof buf, in)) { + fputs(buf, stdout); + } + pclose(in); + } + free(cmd); + naddrs += n; + return naddrs ? 0 : 1; +} + + +static int +process(char *file) +{ + int state, compnum; + char *cp; + char buf[BUFSIZ], name[NAMESZ]; + FILE *in; + + + if ((in = fopen(file, "r")) == NULL) { + adios(file, "unable to open"); + } + + for (compnum = 1, state = FLD;;) { + switch (state = m_getfld(state, name, buf, sizeof(buf), in)) { + case FLD: + compnum++; + proc_hdr(name, buf); + continue; + + case FLDPLUS: + compnum++; + cp = add(buf, cp); + while (state == FLDPLUS) { + state = m_getfld(state, name, buf, + sizeof(buf), in); + cp = add(buf, cp); + } + proc_hdr(name, cp); + free(cp); + continue; + + case BODY: + case FILEEOF: + break; + + case LENERR: + case FMTERR: + adios(NULL, "message format error in component #%d", + compnum); + + default: + adios(NULL, "getfld() returned %d", state); + } + break; + } + fclose(in); + return 0; +} + + +/* +** Check if the header contains addresses we're interested in. +** If so, extract the addresses and add them to the global list. +*/ +static void +proc_hdr(char *name, char *val) { - pid_t child_id; - int i, status, isdf = 0; - int distsw = 0, vecp = 0; - char *cp, *dfolder = NULL, *dmsg = NULL; - char *msg = NULL, **ap, **argp, backup[BUFSIZ]; - char buf[BUFSIZ], **arguments, *vec[MAXARGS]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - vec[vecp++] = invo_name; - vec[vecp++] = "-whom"; - vec[vecp++] = "-library"; - vec[vecp++] = getcpy (m_maildir ("")); - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case CHKSW: - case NOCHKSW: - case SNOOPSW: - case SASLSW: - vec[vecp++] = --cp; - continue; - - case DRAFTSW: - msg = draft; - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - - case ALIASW: - case CLIESW: - case SERVSW: - case USERSW: - case PORTSW: - case SASLMECHSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; - } - } - if (msg) - adios (NULL, "only one draft at a time!"); - else - vec[vecp++] = msg = cp; - } - - /* allow Aliasfile: profile entry */ - if ((cp = context_find ("Aliasfile"))) { - char *dp = NULL; - - for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++) { - vec[vecp++] = "-alias"; - vec[vecp++] = *ap; - } - } - - if (msg == NULL) { -#ifdef WHATNOW - if (dfolder || (cp = getenv ("mhdraft")) == NULL || *cp == '\0') -#endif /* WHATNOW */ - cp = getcpy (m_draft (dfolder, dmsg, 1, &isdf)); - msg = vec[vecp++] = cp; - } - if ((cp = getenv ("mhdist")) - && *cp - && (distsw = atoi (cp)) - && (cp = getenv ("mhaltmsg")) - && *cp) { - if (distout (msg, cp, backup) == NOTOK) - done (1); - vec[vecp++] = "-dist"; - distsw++; - } - vec[vecp] = NULL; - - closefds (3); - - if (distsw) { - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - } - - switch (distsw ? child_id : OK) { - case NOTOK: - advise (NULL, "unable to fork, so checking directly..."); - case OK: - execvp (postproc, vec); - fprintf (stderr, "unable to exec "); - perror (postproc); - _exit (-1); - - default: - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); - - status = pidwait(child_id, OK); - - unlink (msg); - if (rename (backup, msg) == NOTOK) - adios (msg, "unable to rename %s to", backup); - done (status); - } - - return 0; /* dead code to satisfy the compiler */ + char *cp; + int type = 0; + + while (*val==' ' || *val=='\t' || *val=='\n') { + val++; + } + if (strncasecmp(name, "resent-", 7)==0) { + resent = HRESENT; + } + if (mh_strcasecmp(name, "to")==0) { + type = HTO; + } else if (mh_strcasecmp(name, "cc")==0) { + type = HCC; + } else if (mh_strcasecmp(name, "bcc")==0) { + type = HBCC; + } else if (mh_strcasecmp(name, "resent-to")==0) { + type = (HRESENT | HTO); + } else if (mh_strcasecmp(name, "resent-cc")==0) { + type = (HRESENT | HCC); + } else if (mh_strcasecmp(name, "resent-bcc")==0) { + type = (HRESENT | HBCC); + } + /* ignore non-recpient headers */ + if (!type) { + return; + } + /* ignore recipient headers we are not interested in */ + if ((type&HTO || type&HCC) && !toccsw) { + return; + } + if ((type&HBCC) && !bccsw) { + return; + } + + while ((cp = getname(val))) { + if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) { + adios(NULL, "illegal address: %s", cp); + } + mp = mp->m_next; + if (mp->m_type == BADHOST) { + admonish(NULL, "bad address `%s'", mp->m_text); + continue; + } + mp->m_type = type; + } +} + + +/* +** Walk through the list of addresses and print the right ones. +*/ +static int +print(void) +{ + int naddrs = 0; + + for (mp=head.m_next; mp; mp=mp->m_next) { + /* skip unless both are resent or neither one is */ + if (resent != (mp->m_type&HRESENT)) { + continue; + } + if (mp->m_type & (HTO|HCC)) { + naddrs++; + printone(mp); + } + } + return naddrs; +} + +/* +** Walk through the list of addresses and print the right ones. +*/ +static int +printbcc(void) +{ + int naddrs = 0; + + for (mp=head.m_next; mp; mp=mp->m_next) { + /* skip unless both are resent or neither one is */ + if (resent != (mp->m_type&HRESENT)) { + continue; + } + if (mp->m_type & HBCC) { + if (!naddrs && toccsw) { + puts(separator); + } + naddrs++; + printone(mp); + } + } + return naddrs; +} + + +/* +** Print one single address in appropriate form. +*/ +static void +printone(struct mailname *mp) +{ + char buf[BUFSIZ]; + + if (mp->m_host) { + snprintf(buf, sizeof buf, " %s@%s", mp->m_mbox, mp->m_host); + } else { + snprintf(buf, sizeof buf, " %s", mp->m_mbox); + } + if (alisw) { + cmd = add(buf, cmd); + } else { + puts(buf+1); + } } diff --git a/uip/wmh.c b/uip/wmh.c deleted file mode 100644 index e5ff490..0000000 --- a/uip/wmh.c +++ /dev/null @@ -1,1389 +0,0 @@ - -/* - * wmh.c -- window front-end to nmh - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -/* - * TODO: - * Pass signals to client during execution - * - * Figure out a way for the user to say how big the Scan/Display - * windows should be, and where all the windows should be. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define ALARM ((unsigned int) 10) -#define PAUSE ((unsigned int) 2) - -#define SZ(a) (sizeof a / sizeof a[0]) - -static struct swit switches[] = { -#define PRMPTSW 0 - { "prompt string", 6 }, -#define PROGSW 1 - { "vmhproc program", 7 }, -#define NPROGSW 2 - { "novmhproc", 9 }, -#define VERSIONSW 3 - { "version", 0 }, -#define HELPSW 4 - { "help", 0 }, - { NULL, NULL } -}; - /* PEERS */ -static int PEERpid = NOTOK; - -static jmp_buf PEERctx; - - - /* WINDOWS */ -static int dfd = NOTOK; -static int twd = NOTOK; -static char *myprompt = "(%s) "; - -struct line { - int l_no; - char *l_buf; - struct line *l_prev; - struct line *l_next; -}; - -#define W_NULL 0x00 -#define W_CMND 0x01 -#define W_FAKE 0x02 -#define W_EBAR 0x04 - -typedef struct { - int w_fd; - int w_flags; - int w_wd; - struct wstate w_ws; - char *w_eb; - int w_ebloc; - int w_ebsize; - int w_cbase; - int w_height; - int w_cheight; - int w_width; - int w_cwidth; - struct line *w_head; - struct line *w_top; - struct line *w_bottom; - struct line *w_tail; - char w_buffer[BUFSIZ]; - int w_bufpos; -} WINDOW; - - -static WINDOW *Scan; -static WINDOW *Status; -static WINDOW *Display; -static WINDOW *Command; - -#define NWIN 4 -static int numwins; -WINDOW *windows[NWIN + 1]; - -WINDOW *WINnew (); - - -#ifdef HAVE_TERMIOS_H -static struct termios tio; -# define ERASE tio.c_cc[VERASE] -# define KILL tio.c_cc[VKILL] -# define INTR tio.c_cc[VINTR] -#else -# ifdef HAVE_TERMIO_H -static struct termio tio; -# define ERASE tio.c_cc[VERASE] -# define KILL tio.c_cc[VKILL] -# define INTR tio.c_cc[VINTR] -# else -static struct sgttyb tio; -static struct tchars tc; -# define ERASE tio.sg_erase -# define KILL tio.sg_kill -# define INTR tc.t_intrc -# define EOFC tc.t_eofc -# endif -#endif - -#define WERASC ltc.t_werasc -static struct ltchars ltc; - - -int ALRMser (), PIPEser (), SIGser (); -int ADJser (), REFser (); - -/* - * static prototypes - */ -static void adorn(char *, char *, ...); - - -int -main (int argc, char **argv) -{ - int vecp = 1, nprog = 0; - char *cp, buffer[BUFSIZ], **argp; - char **arguments, *vec[MAXARGS]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc,argv, 1); - argp = arguments; - - while ((cp = *argp++)) - if (*cp == '-') - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - vec[vecp++] = --cp; - continue; - - case HELPSW: - snprintf (buffer, sizeof(buffer), "%s [switches for vmhproc]", - invo_name); - print_help (buffer, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case PRMPTSW: - if (!(myprompt = *argp++) || *myprompt == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case PROGSW: - if (!(vmhproc = *argp++) || *vmhproc == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NPROGSW: - nprog++; - continue; - } - else - vec[vecp++] = cp; - - SIGinit (); - if (WINinit (nprog) == NOTOK) { - vec[vecp] = NULL; - - vec[0] = r1bindex (vmhproc, '/'); - execvp (vmhproc, vec); - adios (vmhproc, "unable to exec"); - } - PEERinit (vecp, vec); - - vmh (); - - return done (0); -} - - -static void -vmh (void) -{ - char buffer[BUFSIZ], prompt[BUFSIZ]; - - for (;;) { - pLOOP (RC_QRY, NULL); - - snprintf (prompt, sizeof(prompt), myprompt, invo_name); - - switch (WINgetstr (Command, prompt, buffer)) { - case NOTOK: - break; - - case OK: - done (0); /* NOTREACHED */ - - default: - if (*buffer) - pLOOP (RC_CMD, buffer); - break; - } - } -} - -/* PEERS */ - -static int -PEERinit (int vecp, char *vec[]) -{ - int pfd0[2], pfd1[2]; - char buf1[BUFSIZ], buf2[BUFSIZ]; - register WINDOW **w; - - SIGNAL (SIGPIPE, PIPEser); - - if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK) - adios ("pipe", "unable to"); - switch (PEERpid = vfork ()) { - case NOTOK: - adios ("vfork", "unable to");/* NOTREACHED */ - - case OK: - for (w = windows; *w; w++) - if ((*w)->w_fd != NOTOK) - close ((*w)->w_fd); - close (pfd0[0]); - close (pfd1[1]); - - vec[vecp++] = "-vmhread"; - snprintf (buf1, sizeof(buf1), "%d", pfd1[0]); - vec[vecp++] = buf1; - vec[vecp++] = "-vmhwrite"; - snprintf (buf2, sizeof(buf2), "%d", pfd0[1]); - vec[vecp++] = buf2; - vec[vecp] = NULL; - - SIGNAL (SIGINT, SIG_DFL); - SIGNAL (SIGQUIT, SIG_DFL); - SIGNAL (SIGTERM, SIG_DFL); - - vec[0] = r1bindex (vmhproc, '/'); - execvp (vmhproc, vec); - perror (vmhproc); - _exit (-1); /* NOTREACHED */ - - default: - close (pfd0[1]); - close (pfd1[0]); - - rcinit (pfd0[0], pfd1[1]); - return pINI (); - } -} - - -static int -pINI (void) -{ - int len, buflen; - char *bp, buffer[BUFSIZ]; - struct record rcs, *rc; - WINDOW **w; - - rc = &rcs; - initrc (rc); - - /* Get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer); - - snprintf (bp, buflen, "%d %d", RC_VRSN, numwins); - len = strlen (bp); - bp += len; - buflen -= len; - - for (w = windows; *w; w++) { - snprintf (bp, buflen, " %d", (*w)->w_height); - len = strlen (bp); - bp += len; - buflen -= len; - } - - switch (str2rc (RC_INI, buffer, rc)) { - case RC_ACK: - return OK; - - case RC_ERR: - if (rc->rc_len) - adios (NULL, "%s", rc->rc_data); - else - adios (NULL, "pINI peer error"); - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pINI protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pLOOP (char code, char *str) -{ - int i; - struct record rcs, *rc; - WINDOW *w; - - rc = &rcs; - initrc (rc); - - str2peer (code, str); - for (;;) - switch (peer2rc (rc)) { - case RC_TTY: - if (pTTY () == NOTOK) - return NOTOK; - break; - - case RC_WIN: - if (sscanf (rc->rc_data, "%d", &i) != 1 - || i <= 0 - || i > numwins) { - fmt2peer (RC_ERR, "no such window \"%s\"", rc->rc_data); - return NOTOK; - } - if ((w = windows[i - 1])->w_flags & W_CMND) { - fmt2peer (RC_ERR, "not a display window \"%s\"", rc->rc_data); - return NOTOK; - } - if (pWIN (w) == NOTOK) - return NOTOK; - break; - - case RC_EOF: - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pLOOP(%s) peer error", - code == RC_QRY ? "QRY" : "CMD"); - return NOTOK; - - case RC_FIN: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - rcdone (); - i = pidwait (PEERpid, OK); - PEERpid = NOTOK; - done (i); - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pLOOP(%s) protocol screw-up", - code == RC_QRY ? "QRY" : "CMD"); - } -} - - -static int -pTTY (void) -{ - SIGNAL_HANDLER hstat, istat, qstat, tstat; - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - if (ChangeWindowDepth (dfd, twd, 0) == NOTOK) - adios ("failed", "ChangeWindowDepth"); - - /* should block here instead of ignore */ - hstat = SIGNAL (SIGHUP, SIG_IGN); - istat = SIGNAL (SIGINT, SIG_IGN); - qstat = SIGNAL (SIGQUIT, SIG_IGN); - tstat = SIGNAL (SIGTERM, SIG_IGN); - - rc2rc (RC_ACK, 0, NULL, rc); - - SIGNAL (SIGHUP, hstat); - SIGNAL (SIGINT, istat); - SIGNAL (SIGQUIT, qstat); - SIGNAL (SIGTERM, tstat); - - switch (rc->rc_type) { - case RC_EOF: - rc2peer (RC_ACK, 0, NULL); - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pTTY peer error"); - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pTTY protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pWIN (WINDOW *w) -{ - int i; - - if ((i = pWINaux (w)) == OK) - WINless (w); - - return i; -} - - -static int -pWINaux (WINDOW *w) -{ - register int n; - register char *bp; - register struct line *lp, *mp; - struct record rcs, *rc; - - rc = &rcs; - initrc (rc); - - for (lp = w->w_head; lp; lp = mp) { - mp = lp->l_next; - free (lp->l_buf); - free ((char *) lp); - } - w->w_head = w->w_top = w->w_bottom = w->w_tail = NULL; - w->w_bufpos = 0; - - for (;;) - switch (rc2rc (RC_ACK, 0, NULL, rc)) { - case RC_DATA: - for (bp = rc->rc_data, n = rc->rc_len; n-- > 0; ) - WINputc (w, *bp++); - break; - - case RC_EOF: - rc2peer (RC_ACK, 0, NULL); - if (w->w_bufpos) - WINputc (w, '\n'); - return OK; - - case RC_ERR: - if (rc->rc_len) - adorn (NULL, "%s", rc->rc_data); - else - adorn (NULL, "pWIN peer error"); - return NOTOK; - - case RC_XXX: - adios (NULL, "%s", rc->rc_data); - - default: - adios (NULL, "pWIN protocol screw-up"); - } -/* NOTREACHED */ -} - - -static int -pFIN (void) -{ - int status; - - if (PEERpid <= OK) - return OK; - - rc2peer (RC_FIN, 0, NULL); - rcdone (); - - switch (setjmp (PEERctx)) { - case OK: - SIGNAL (SIGALRM, ALRMser); - alarm (ALARM); - - status = pidwait (PEERpid, OK); - - alarm (0); - break; - - default: - kill (PEERpid, SIGKILL); - status = NOTOK; - break; - } - PEERpid = NOTOK; - - return status; -} - -/* WINDOWS */ - -/* should dynamically determine all this stuff from gconfig... */ - -#define MyX 20 /* anchored hpos */ -#define MyY 40 /* .. vpos */ -#define MyW 800 /* .. width */ -#define MyH 500 /* .. height */ -#define MyS 30 /* .. height for Status, about one line */ - - -#define MySlop 45 /* slop */ - -#define EWIDTH 25 /* Width of vertical EBAR */ -#define ESLOP 5 /* .. slop */ - - -static intWINinit (nprog) { - short wx, wy, wh, sy; - struct gconfig gc; - - if (GetGraphicsConfig (fileno (stderr), &gc) == NOTOK) - if (nprog) - return NOTOK; - else - adios (NULL, "not a window"); - - if ((dfd = open ("/dev/ttyw0", O_RDWR)) == NOTOK) - adios ("/dev/ttyw0", "unable to open"); - - if ((twd = GetTopWindow (dfd)) == NOTOK) - adios ("failed", "GetTopWindow"); - - BlockRefreshAdjust (1); - - numwins = 0; - - wx = gc.w - (MyX + MyW + EWIDTH + ESLOP); - Scan = WINnew (wx, wy = MyY, MyW, wh = MyH * 2 / 3, "Scan", W_EBAR); - - wy += wh + MySlop; - Status = WINnew (wx, sy = wy, MyW, wh = MyS, "Status", W_FAKE); - - wy += wh + MySlop; - Display = WINnew (wx, wy, MyW, MyH, "Display", W_EBAR); - - Command = WINnew (wx, sy, MyW, MyS, invo_name, W_CMND); - - windows[numwins] = NULL; - - return OK; -} - - -WINDOW * -WINnew (short wx, short wy, short ww, short wh, char *name, int flags) -{ - register WINDOW *w; - - if ((w = (WINDOW *) calloc (1, sizeof *w)) == NULL) - adios (NULL, "unable to allocate window"); - - if ((w->w_flags = flags) & W_FAKE) { - w->w_fd = NOTOK; - w->w_height = 1; - - goto out; - } - - if (w->w_flags & W_EBAR) - ww += EWIDTH + ESLOP; - else - wx += EWIDTH + ESLOP; - - if ((w->w_fd = OpenWindow (wx, wy, ww, wh, name)) == NOTOK) - adios ("failed", "OpenWindow"); - if ((w->w_wd = GetTopWindow (dfd)) == NOTOK) - adios ("failed", "GetTopWindow"); - if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK) - adios ("failed", "GetWindowState"); - if (SetLineDisc (w->w_fd, TWSDISC) == NOTOK) - adios ("failed", "SetLineDisc"); - - SetBuf (w->w_fd, 1024); - SetAdjust (w->w_fd, numwins, ADJser); - SetRefresh (w->w_fd, numwins, REFser); - - SetAddressing (w->w_fd, VT_ABSOLUTE); - - if (w->w_flags & W_EBAR) { - w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH, - w->w_ws.height, VT_Gray50, 1, EB_VERTICAL, - EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX, - VT_White); - if (w->w_eb == NULL) - adios (NULL, "CreateElevatorBar failed"); - RefreshElevatorBar (w->w_eb); - } - - if ((w->w_cbase = CharacterBaseline (w->w_ws.font)) <= 0) - w->w_cbase = 14; - - if ((w->w_cheight = CharacterHeight (w->w_ws.font)) <= 0) - w->w_cheight = 20; - w->w_height = w->w_ws.height / w->w_cheight; - if (w->w_height < 1) - w->w_height = 1; - - /* 1 em */ - if ((w->w_cwidth = CharacterWidth (w->w_ws.font, 'm')) <= 0) - w->w_cwidth = 10; - w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0)) - / w->w_cwidth; - if (w->w_width < 1) - w->w_width = 1; - -out: ; - windows[numwins++] = w; - - return w; -} - - -static int -WINgetstr (WINDOW *w, char *prompt, char *buffer) -{ - register int c; - register char *bp, *ip; - char image[BUFSIZ]; - struct vtseq vts; - register struct vtseq *vt = &vts; - - if (w->w_eb != NULL) - adios (NULL, "internal error--elevator bar found"); - - if (w->w_head == NULL - && (w->w_head = (struct line *) calloc (1, sizeof *w->w_head)) - == NULL) - adios (NULL, "unable to allocate line storage"); - w->w_head->l_buf = image; - w->w_top = w->w_bottom = w->w_tail = w->w_head; - - if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK) - adios ("failed", "ChangeWindowDepth"); - - strncpy (image, prompt, sizeof(image)); - bp = ip = image + strlen (image); - - Redisplay (w, 0); - - for (;;) - switch (getvtseq (w->w_fd, vt)) { - case VT_HARDKEY: - DisplayStatus (w->w_fd, "no hardkeys, please"); - break; - - case VT_ASCII: - switch (c = toascii (vt->u.ascii)) { - case '\f': /* refresh? */ - break; - - case '\r': - case '\n': - strcpy (buffer, ip); - return DONE; - - default: - if (c == INTR) { - adorn (NULL, "Interrupt"); - return NOTOK; - } - - if (c == EOFC) { - if (bp <= ip) - return OK; - break; - } - - if (c == ERASE) { - if (bp <= ip) - continue; - bp--; - break; - } - - if (c == KILL) { - if (bp <= ip) - continue; - bp = ip; - break; - } - - if (c == WERASC) { - if (bp <= ip) - continue; - do { - bp--; - } while (isspace (*bp) && bp > ip); - if (bp > ip) { - do { - bp--; - } while (!isspace (*bp) && bp > buffer); - if (isspace (*bp)) - bp++; - } - break; - } - - if (c < ' ' || c >= '\177') - continue; - *bp++ = c; - break; - } - *bp = NULL; - Redisplay (w, 0); - break; - - case VT_MOUSE: - switch (vt->u.mouse.buttons - & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) { - case VT_MOUSE_LEFT: - DisplayStatus (w->w_fd, "use middle or right button"); - break; - -#define WPOP "WMH\0Advance\0Burst\0Exit\0EOF\0" - case VT_MOUSE_MIDDLE: - SetPosition (w->w_fd, vt->u.mouse.x, - vt->u.mouse.y); - switch (DisplayPopUp (w->w_fd, WPOP)) { - case 1: /* Advance */ - do_advance: ; - strcpy (buffer, "advance"); - return DONE; - - case 2: /* Burst */ - strcpy (buffer, "burst"); - return DONE; - - case 3: /* Exit */ - strcpy (buffer, "exit"); - return DONE; - - case 4: /* EOF */ - return OK; - - default: /* failed or none taken */ - break; - } - break; -#undef WPOP - - case VT_MOUSE_RIGHT: - goto do_advance; - } - break; - - case VT_EOF: - adios (NULL, "end-of-file on window");/* NOTREACHED */ - - default: - DisplayStatus (w->w_fd, "unknown VT sequence"); - break; - } -} - - -static int -WINputc (WINDOW *w, char c) -{ - register int i; - register char *cp; - register struct line *lp; - - switch (c) { - default: - if (!isascii (c)) { - if (WINputc (w, 'M') == NOTOK || WINputc (w, '-') == NOTOK) - return NOTOK; - c = toascii (c); - } - else - if (c < ' ' || c == '\177') { - if (WINputc (w, '^') == NOTOK) - return NOTOK; - c ^= 0100; - } - break; - - case '\t': - for (i = 8 - (w->w_bufpos & 0x07); i > 0; i--) - if (WINputc (w, ' ') == NOTOK) - return NOTOK; - return OK; - - case '\b': - if (w->w_bufpos > 0) - w->w_bufpos--; - return OK; - - case '\n': - break; - } - - if (c != '\n') { - w->w_buffer[w->w_bufpos++] = c; - return OK; - } - - w->w_buffer[w->w_bufpos] = NULL; - w->w_bufpos = 0; - - if ((lp = (struct line *) calloc (1, sizeof *lp)) == NULL) - adios (NULL, "unable to allocate line storage"); - - lp->l_no = (w->w_tail ? w->w_tail->l_no : 0) + 1; - lp->l_buf = getcpy (w->w_buffer); - for (cp = lp->l_buf + strlen (lp->l_buf) - 1; cp >= lp->l_buf; cp--) - if (isspace (*cp)) - *cp = NULL; - else - break; - - if (w->w_head == NULL) - w->w_head = lp; - if (w->w_top == NULL) - w->w_top = lp; - if (w->w_bottom == NULL) - w->w_bottom = lp; - if (w->w_tail) - w->w_tail->l_next = lp; - lp->l_prev = w->w_tail; - w->w_tail = lp; - - return DONE; -} - -#define PSLOP 2 - - -static char mylineno[5]; - -static bool cancel[] = { 1 }; -static struct choice mychoices[] = { LABEL, "cancel", VT_White }; - -static struct question myquestions[] = { - STRING, "Line", SZ (mylineno), (struct choice *) 0, - - TOGGLE, "", SZ (mychoices), mychoices -}; - -static struct menu mymenu = { "Goto", SZ (myquestions), myquestions }; - -static int *myanswers[] = { (int *) mylineno, (int *) cancel }; - - -static void -WINless (WINDOW *w) -{ - int clear, pos, forw, refresh; - struct vtseq vts; - register struct vtseq *vt = &vts; - - if (w->w_fd == NOTOK) { - if (w->w_head) - DisplayStatus (dfd, w->w_top->l_buf); - else - RemoveStatus (dfd); - - return; - } - - if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK) - adios ("failed", "ChangeWindowDepth"); - - Redisplay (w, 0); - - if (w->w_bottom == w->w_tail) - return; - - if (w->w_eb == NULL) - adios (NULL, "internal error--no elevator bar"); - - for (clear = refresh = 0, forw = 1;;) { - if (clear) { - RemoveStatus (w->w_fd); - clear = 0; - } - if (refresh) { - Redisplay (w, 0); - refresh = 0; - } - - switch (getvtseq (w->w_fd, vt)) { - case VT_HARDKEY: - case VT_ASCII: - DisplayStatus (w->w_fd, "use the mouse"); - clear++; - break; - - case VT_MOUSE: - switch (vt->u.mouse.buttons - & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) { - case VT_MOUSE_LEFT: - if ((pos = vt->u.mouse.x) < EWIDTH) { - pos = w->w_ebloc = DoElevatorBar (w->w_eb, pos, - vt->u.mouse.y); - refresh = WINgoto (w, ((pos * (w->w_tail->l_no - - w->w_head->l_no)) - / EB_MAX) + w->w_head->l_no); - } - break; - -#define WPOP "Paging\0Next\0Prev\0Left\0Right\0First\0Last\0Goto ...\0Exit\0" - case VT_MOUSE_MIDDLE: - SetPosition (w->w_fd, vt->u.mouse.x, - vt->u.mouse.y); - switch (DisplayPopUp (w->w_fd, WPOP)) { - case 1: /* Next */ - do_next_page: ; - if (w->w_bottom == w->w_tail) - forw = 0; - refresh = WINgoto (w, w->w_bottom->l_no + 1 - PSLOP); - break; - - case 2: /* Prev */ - do_prev_page: ; - if (w->w_top == w->w_head) - forw = 1; - refresh = WINgoto (w, w->w_top->l_no - - w->w_height + PSLOP); - break; - - case 3: /* Left */ - case 4: /* Right */ - DisplayStatus (w->w_fd, "not yet"); - clear++; - break; - - case 5: /* First */ - forw = 1; - refresh = WINgoto (w, w->w_head->l_no); - break; - - case 6: /* Last */ - forw = 0; - refresh = WINgoto (w, w->w_tail->l_no - - w->w_height + 1); - break; - - case 7: /* Goto ... */ - snprintf (mylineno, sizeof(mylineno), - "%d", w->w_top->l_no); - cancel[0] = 0; - if (PresentMenu (&mymenu, myanswers) - || cancel[0]) - break; - if (sscanf (mylineno, "%d", &pos) != 1) { - DisplayStatus (w->w_fd, "bad format"); - clear++; - break; - } - if (pos < w->w_head->l_no - || pos > w->w_tail->l_no) { - DisplayStatus (w->w_fd, "no such line"); - clear++; - break; - } - refresh = WINgoto (w, pos); - break; - - case 8: /* Exit */ - return; - - default: /* failed or none taken */ - break; - } - break; -#undef WPOP - - case VT_MOUSE_RIGHT: - if (forw) { - if (w->w_bottom == w->w_tail) - return; - else - goto do_next_page; - } - else - goto do_prev_page; - } - break; - - case VT_EOF: - adios (NULL, "end-of-file on window");/* NOTREACHED */ - - default: - DisplayStatus (w->w_fd, "unknown VT sequence"); - clear++; - break; - } - } -} - - -static int -WINgoto (WINDOW *w, int n) -{ - register int i, j; - register struct line *lp; - - if (n > (i = w->w_tail->l_no - w->w_height + 1)) - n = i; - if (n < w->w_head->l_no) - n = w->w_head->l_no; - - if ((i = n - (lp = w->w_head)->l_no) - > (j = abs (n - w->w_top->l_no))) - i = j, lp = w->w_top; - - if (i > (j = abs (w->w_tail->l_no - n))) - i = j, lp = w->w_tail; - - if (n >= lp->l_no) { - for (; lp; lp = lp->l_next) - if (lp->l_no == n) - break; - } - else { - for (; lp; lp = lp->l_prev) - if (lp->l_no == n) - break; - if (!lp) - lp = w->w_head; - } - - if (w->w_top == lp) - return 0; - - w->w_top = lp; - - return 1; -} - - -static int -ADJser (int id, short ww, short wh) -{ - register WINDOW *w; - - if (id < 0 || id >= numwins) - adios (NULL, "ADJser on bogus window (%d)", id); - w = windows[id]; - if (w->w_fd == NOTOK) - adios (NULL, "ADJser on closed window (%d)", id); - - w->w_ws.width = w->w_ws.tw = ww; - w->w_ws.height = w->w_ws.th = wh; - - if (w->w_eb) { - DeleteElevatorBar (w->w_eb); - w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH, - w->w_ws.height, VT_Gray50, 1, EB_VERTICAL, - EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX, - VT_White); - if (w->w_eb == NULL) - adios (NULL, "CreateElevatorBar failed"); - } - - Redisplay (w, 1); -} - - -static int -REFser (int id, short wx, short wy, short ww, short wh) -{ - short cx, cy, cw, ch; - register WINDOW *w; - - if (id < 0 || id >= numwins) - adios (NULL, "REFser on bogus window (%d)", id); - w = windows[id]; - if (w->w_fd == NOTOK) - adios (NULL, "REFser on closed window (%d)", id); - - - if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK) - adios ("failed", "GetWindowState"); - - GetPermanentClipping (w->w_fd, &cx, &cy, &cw, &ch); - SetPermanentClipping (w->w_fd, wx, wy, ww, wh); - Redisplay (w, 1); - SetPermanentClipping (w->w_fd, cx, cy, cw, ch); -} - - -static void -Redisplay (WINDOW *w, int doeb) -{ - register int y; - short sx; - register struct line *lp; - - if (w->w_fd == NOTOK) - return; - - sx = w->w_eb ? (EWIDTH + ESLOP) : 0; - w->w_height = w->w_ws.height / w->w_cheight; - if (w->w_height < 1) - w->w_height = 1; - - w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0)) - / w->w_cwidth; - if (w->w_width < 1) - w->w_width = 1; - - SetPosition (w->w_fd, sx, 0); - SetColor (w->w_fd, VT_White); - PaintRectangleInterior (w->w_fd, w->w_ws.width, w->w_ws.height); - - if (w->w_head) { - SetColor (w->w_fd, VT_Black); - for (lp = w->w_top, y = 0; - lp && y < w->w_height; - w->w_bottom = lp, lp = lp->l_next, y++) { - SetPosition (w->w_fd, sx, y * w->w_cheight + w->w_cbase); - PaintString (w->w_fd, VT_STREND, lp->l_buf); - } - } - - if (w->w_eb) { - if ((y = EB_LOC (w)) != w->w_ebloc) - MoveElevator (w->w_eb, w->w_ebloc = y); - if ((y = EB_SIZE (w)) != w->w_ebsize) - SizeElevator (w->w_eb, w->w_ebsize = y); - if (doeb) - RefreshElevatorBar (w->w_eb); - } - - Flush (w->w_fd); -} - - -static int -EB_SIZE (WINDOW *w) -{ - register int i; - - if (w->w_head == NULL) - return 0; - - if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0) - return EB_MAX; - - return (((w->w_bottom->l_no - w->w_top->l_no) * EB_MAX) / i); -} - - -static int -EB_LOC (WINDOW *w) -{ - register int i; - - if (w->w_head == NULL) - return 0; - - if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0) - return EB_MAX; - - return (((w->w_top->l_no - w->w_head->l_no) * EB_MAX) / i); -} - -/* SIGNALS */ - -static void -SIGinit (void) -{ - foreground (); - if (ioctl (fileno (stdin), TIOCGETP, (char *) &tio) == NOTOK) - adios ("failed", "ioctl TIOCGETP"); - if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK) - adios ("failed", "ioctl TIOCGETC"); - if (ioctl (fileno (stdin), TIOCGLTC, (char *) <c) == NOTOK) - adios ("failed", "ioctl TIOCGLTC"); - sideground (); - - SIGNAL (SIGHUP, SIGser); - SIGNAL (SIGINT, SIGser); - SIGNAL (SIGQUIT, SIGser); -} - - -static void -foreground (void) -{ -#ifdef TIOCGPGRP - int pgrp, tpgrp; - SIGNAL_HANDLER tstat; - - if ((pgrp = getpgrp (0)) == NOTOK) - adios ("process group", "unable to determine"); - for (;;) { - if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK) - adios ("tty's process group", "unable to determine"); - if (pgrp == tpgrp) - break; - - tstat = SIGNAL (SIGTTIN, SIG_DFL); - kill (0, SIGTTIN); - SIGNAL (SIGTTIN, tstat); - } - - SIGNAL (SIGTTIN, SIG_IGN); - SIGNAL (SIGTTOU, SIG_IGN); - SIGNAL (SIGTSTP, SIG_IGN); -#endif TIOCGPGRP -} - - -static void -sideground (void) -{ -#ifdef TIOCGPGRP - SIGNAL (SIGTTIN, SIG_DFL); - SIGNAL (SIGTTOU, SIG_DFL); - SIGNAL (SIGTSTP, SIG_DFL); -#endif TIOCGPGRP -} - - -static int -ALRMser (int sig) -{ - longjmp (PEERctx, DONE); -} - - -static int -PIPEser (int sig) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (sig, SIG_IGN); -#endif - - adios (NULL, "lost peer"); -} - - -static int -SIGser (int sig) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (sig, SIG_IGN); -#endif - - done (1); -} - - -int -done (int status) -{ - if (dfd != NOTOK) - RemoveStatus (dfd); - - pFIN (); - - exit (status); - return 1; /* dead code to satisfy the compiler */ -} - - -static void -adorn (char *what, char *fmt, ...) -{ - va_list ap - char *cp; - - cp = invo_name; - invo_name = NULL; - - va_start(ap, fmt); - advertise (what, NULL, fmt, ap); - va_end(ap); - - invo_name = cp; -} - - -void -advertise (char *what, char *tail, va_list ap) -{ - int eindex = errno; - char buffer[BUFSIZ], err[BUFSIZ]; - struct iovec iob[20]; - register struct iovec *iov = iob; - - fflush (stdout); - fflush (stderr); - - if (invo_name) { - iov->iov_len = strlen (iov->iov_base = invo_name); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - - vsnprintf (buffer, sizeof(buffer), fmt, ap); - iov->iov_len = strlen (iov->iov_base = buffer); - iov++; - if (what) { - if (*what) { - iov->iov_len = strlen (iov->iov_base = " "); - iov++; - iov->iov_len = strlen (iov->iov_base = what); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; - } - if (!(iov->iov_base = strerror (eindex))) { - snprintf (err, sizeof(err), "unknown error %d", eindex); - iov->iov_base = err; - } - iov->iov_len = strlen (iov->iov_base); - iov++; - } - if (tail && *tail) { - iov->iov_len = strlen (iov->iov_base = ", "); - iov++; - iov->iov_len = strlen (iov->iov_base = tail); - iov++; - } - iov->iov_len = strlen (iov->iov_base = "\n"); - iov++; - - if (dfd != NOTOK) - DisplayVector (iob, iov - iob); - else - writev (fileno (stderr), iob, iov - iob); -} - - -static void -DisplayVector (struct iovec *iov, int n) -{ - register int i; - register char *cp; - char buffer[BUFSIZ]; - - for (i = 0, cp = NULL; i < n; i++, iov++) { - snprintf (buffer, sizeof(buffer), "%*.*s", iov->iov_len, - iov->iov_len, iov->iov_base); - cp = add (buffer, cp); - } - - DisplayStatus (dfd, cp); - free (cp); - sleep (PAUSE); - RemoveStatus (dfd); -}