were incorporated directly into the user agents. .QE .P In nmh, the MSA is called \fIMessage Transfer Service\fP (MTS). This facility, implemented by the .Pn post command, establishes network connections and spoke SMTP to submit messages to be relayed to the outside world. When email transfer changed, this part needed to be changed as well. Encryption and authentication for network connections needed to be supported, hence TLS and SASL were introduced into nmh. This added complexity without improving the core functions. Furthermore, keeping up with recent developments in the field of mail transfer requires development power and specialists. In mmh, this whole facility was simply cut off .Ci f6aa95b724fd8c791164abe7ee5468bf5c34f226 .Ci fecd5d34f65597a4dfa16aeabea7d74b191532c3 .Ci 156d35f6425bea4c1ed3c4c79783dc613379c65b . Instead, mmh depends on an external MSA. All outgoing mail in mmh goes through the -- may be removed in the future. Mmh could pass the recipient addresses as command line arguments. This appears to be the better interface. .P To retrieve mail, the .Pn inc command in nmh acts as MRA. It establishes network connections and speaks POP3 to retrieve mail from remote servers. As with mail submission, the network connections required encryption and authentication, thus TLS and SASL were added to nmh. Support for message retrieval through IMAP will soon become necessary additions, too, and likewise for any other changes in mail transfer. But not in mmh because it has dropped the support for retrieving mail from remote locations .Ci ab7b48411962d26439f92f35ed084d3d6275459c . Instead, it depends on an external tool to cover this task. Mmh has two paths for messages to enter mmh's mail storage: -- \fIdma\fP, up to full-featured MTAs as for instance \fIPostfix\fP. MRAs are provided for example by \fIfetchmail\fP, \fIgetmail\fP, \fImpop\fP, and \fIfdm\fP. .H2 "Non-MUA Tools .P One goal of mmh is to remove the tools that do not significantly contribute to the MUA's job. Loosely related and rarely used tools distract from a lean appearance, and require maintenance work without adding much to the core task. By removing these tools, mmh became more streamlined and focused. .BU .Pn conflict was removed .Ci 8b235097cbd11d728c07b966cf131aa7133ce5a9 because it is a mail system maintenance tool and not MUA-related. It even checked .Fn /etc/passwd and .Fn /etc/group for consistency, which is completely unrelated to email. A tool like .Pn conflict is surely useful, but it should not be shipped with mmh. .BU .Pn rcvtty was removed .Ci 14767c94b3827be7c867196467ed7aea5f6f49b0 because its use case of writing to the user's terminal on reception of mail is obsolete. If users like to be informed of new mail, the shell's .Ev MAILPATH variable or graphical notifications are technically more appealing. Writing to terminals directly is hardly ever desired today. If, though, one prefers this approach, the standard tool .Pn write can be used in a way similar to: .VS scan -file - | write `id -un` VE .BU .Pn viamail was removed .Ci eda72d6a7a7c20ff123043fb7f19c509ea01f932 when the new attachment system was activated, because .Pn forw could then cover the task itself. The program .Pn sendfiles was rewritten as a shell script wrapper around .Pn forw . .Ci 0e82199cf3c991a173e0ac8aa776efdb3ded61e6 .BU .Pn msgchk was removed .Ci bb9360ead7eb7a3fedcce2eeedfc660014e41dbe , because it lost its use case when POP support was removed. A call to -- VE Yet, it distinguished between old and new mail, but these details can be retrieved with .Pn stat (1), too. A small shell script could be written to print the information in a similar way, if truly necessary. As mmh's .Pn inc only incorporates mail from the user's local maildrop, and thus no data transfers over slow networks are involved, there is hardly any need to check for new mail before incorporating it. .BU .Pn msh was removed .Ci 916690191222433a6923a4be54b0d8f6ac01bd02 because the tool was in conflict with the philosophy of MH. It provided an interactive shell to access the features of MH. -- Besides, the development of both programs needed to be in sync, to ensure that the programs behaved in a similar way, because they were used like a single tool. Different behavior would have surprised the user. .P Today, non-MIME messages are rather seen to be a special case of MIME messages, although it is the other way round. As .Pn mhshow already had been able to display non-MIME messages, it appeared natural to drop .Pn show in favor of using .Pn mhshow exclusively .Ci 4c1efddfd499300c7e74263e57d8aa137e84c853 . Removing .Pn show -- I have reduced the number of project-specific configure options from 15 to 3. .U3 "Mail Transfer Facilities .P With the removal of the mail transfer facilities (cf. Sec. .Cf mail-transfer-facilities ) five configure options vanished: .P The switches .Sw --with-tls and .Sw --with-cyrus-sasl had activated the support for transfer encryption and authentication. They are not needed anymore. .Ci fecd5d34f65597a4dfa16aeabea7d74b191532c3 .Ci 156d35f6425bea4c1ed3c4c79783dc613379c65b .P The configure switch -- the conditionally compiled code area for POP support was much larger. The code base had only changed slightly on toggling TLS or SASL support but it had changed much on toggling POP support. The changes in the code base could hardly be overviewed. By having POP support togglable, a second code base had been created, one that needed to be tested. This situation is basically similar for the conditional TLS and SASL code, but there the changes are minor and can yet be overviewed. Still, conditional compilation of a code base creates variations of the original program. More variations require more testing and maintenance work. .P Two other options had only specified default configuration values: .Sw --with-mts defined the default transport service .Ci f6aa95b724fd8c791164abe7ee5468bf5c34f226 . With .Sw --with-smtpservers default SMTP servers could be set .Ci 128545e06224233b7e91fc4c83f8830252fe16c9 . Both of them became irrelevant when the SMTP transport service was removed. In mmh, all messages are handed over to -- Thus, the command line .Cl "rm #13 #15 calls .Pn rm without arguments because the first hash character starts a comment that reaches until the end of the line. To delete the backup files, .Cl "rm ./#13 ./#15" needs to be used. Thus, using the hash as backup prefix may be seen as a precaution against backup loss. .P First, I removed the configure option but added the profile entry .Pe Backup-Prefix , which allowed to specify an arbitrary string as backup prefix .Ci 6c40d481d661d532dd527eaf34cebb6d3f8ed086 . This change did not remove the choice but moved it to a location where it suited better, in my eyes. .P Eventually however, the new trash folder concept (cf. Sec. .Cf trash-folder ) removed the need for the backup prefix completely. .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173 .Ci ca0b3e830b86700d9e5e31b1784de2bdcaf58fc5 -- as they are specified by POSIX since two decades. (The specifications for .Pn vi and .Pn more appeared in .[ posix 1987 .] and, .[ posix 1992 .] respectively.) As a first step, these two tools were hard-coded as defaults .Ci 5d43a99db70c12a673028c7758c20cbe3e13ef5f . Not changed were the .Pe editor and .Pe moreproc profile entries, which allowed the user to override the system defaults. Later, the concept was reworked again to respect the standard environment variables .Ev VISUAL and .Ev PAGER if they are set. Today, mmh determines the editor to use in the following order, taking the first available and non-empty item .Ci f85f4b7ae62e3d05a945dcd46ead51f0a2a89a9b : .LI 1 Environment variable .Ev MMHEDITOR .LI 2 Profile entry .Pe Editor .LI 3 Environment variable .Ev VISUAL .LI 4 Environment variable .Ev EDITOR .LI 5 Command .Pn vi . .LP The pager to use is determined in a similar order .Ci 0c4214ea2aec6497d0d67b436bbee9bc1d225f1e : .LI 1 Environment variable -- wolter unix incompat notes dbm .] complicated autoconf code was needed to detect them correctly. Furthermore, the configure switches .Sw --with-ndbm=ARG and .Sw --with-ndbmheader=ARG were added to help with difficult setups that would not be detected automatically or not correctly. .P By removing the suppress duplicates feature of .Pn slocal , the dependency on .I ndbm vanished and 120 lines of complex autoconf code could be saved .Ci ecd6d6a20cb7a1507e3a20d6c4cb3a1cf14c6bbf . The change removed functionality but that is considered minor to the improvement of dropping the dependency and the complex autoconf code. -- The .Sw --disable-mhe configure option had switched off these extensions. After removing the support for old versions of MH-E, only the .Sw -build switches of .Pn forw and .Pn repl are left to be MH-E extensions. They are now always built in because they add little code and complexity. In consequence, the .Sw --disable-mhe configure option was removed .Ci a7ce7b4a580d77b6c2c4d980812beb589aa4c643 . Dropping the option also removed a variant of the code base that would have needed to be tested. -- 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 `First.Last' sendmail aliases for all users. If this is the case, the GECOS field for each user should look like: ``First [Middle] Last '' .QE .P As mmh sends outgoing mail via the local MTA only, the best location to do such global rewrites is there. Besides, the MTA is conceptionally the right location because it does the reverse mapping for incoming mail (aliasing), too. Furthermore, masquerading set up there is readily available for all mail software on the system. Hence, mmailid masquerading was removed. .Ci 0836c8000ccb34b59410ef1c15b1b7feac70ce5f .P The -- .[ [ sill qmail handbook .], p. 141] and the similar .I "plussed user processing of Sendmail. .[ [ sendmail costales .], p. 476] The decision to remove this username_extension masquerading was motivated by the fact that .Pn spost had not supported it yet. Username extensions can be used in mmh, but less convenient. .\" XXX In the format file: %(getenv USERNAME_EXTENSION) .Ci 2abae0bfd0ad5bf898461e50aa4b466d641f23d9 .P The -- .Hd From header field as SMTP envelope sender. Sender addresses could be replaced completely. Mmh offers a kind of masquerading similar in effect, but with technical differences. As mmh does not transfer messages itself, the local MTA has final control over the sender's address. Any masquerading mmh introduces may be reverted by the MTA. In times of pedantic spam checking, an MTA will take care to use sensible envelope sender addresses to keep its own reputation up. Nonetheless, the MUA can set the .Hd From header field and thereby propose a sender address to the MTA. The MTA may then decide to take that one or generate the canonical sender address for use as envelope sender address. .Ci b14ea6073f77b4359aaf3fddd0e105989db9 .P In mmh, the MTA will always extract the recipient and sender from the -- A part of the switches vanished after functions were removed. This was the case for network mail transfer, for instance. Sometimes, however, the work flow was the other way: I looked through the .Mp mh-chart (7) man page to identify the tools with apparently too many switches. Then I considered the benefit of each switch by examining the tool's man page and source code, aided by literature research and testing. .U3 "Draft Folder Facility .P A change early in the project was the complete transition from the single draft message to the draft folder facility .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 (cf. Sec. .Cf draft-folder ). -- rose romine real work .] Since then, the facility was included, inactive by default. By making it permanently active and by related rework of the tools, the .Sw -[no]draftfolder , and .Sw -draftmessage switches could be removed from .Pn comp , .Pn repl , .Pn forw , .Pn dist , .Pn whatnow , and .Pn send .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 . The only flexibility lost with this change is having multiple draft folders within one profile. -- .U3 "In Place Editing .P .Pn anno had the switches .Sw -[no]inplace to either annotate the message in place and thus preserve hard links, or annotate a copy to replace the original message. The latter approach broke hard links. Following the assumption that linked messages should truly be the same message and annotating it should not break the link, the .Sw -[no]inplace switches were removed and the previous default .Sw -inplace was made the definitive behavior .Ci c8195849d2e366c569271abb0f5f60f4ebf0b4d0 . The .Sw -[no]inplace -- .QS If .Sw -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. .QE .LP The decision to drop the .Sw -inplace behavior was supported by the code complexity and the possible data loss it caused. .Sw -noinplace was chosen to be the definitive behavior. .Ci 68a686adeb39223a5e1ad35e4a24890ec053679d -- .Sw -form switches to supply a form file had .Sw -format switches as well to supply the contents of a form file as a string on the command line directly. In consequence, the following two lines equaled: .VS scan -form scan.mailx scan -format "`cat /path/to/scan.mailx`" VE The .Sw -format switches were dropped in favor for extending the .Sw -form switches .Ci f51956be123db66b00138f80464d06f030dbb88d . If their argument starts with an equal sign (`\fL=\fP'), then the rest of the argument is taken as a format string, -- .Sw -form and .Sw -format . Typing `\fL-fo\fP' is sufficient to specify form file or format string. .P The different meaning of .Sw -format for .Pn forw and .Pn repl was removed in mmh. .Pn forw was completely switched to MIME-type forwarding, thus removing the .Sw -[no]format .Ci 6e271608b7b9c23771523f88d23a4d3593010cf1 . For .Pn repl , the .Sw -[no]format switches were reworked to .Sw -[no]filter switches .Ci 67411b1f95d6ec987b4c732459e1ba8a8ac192c6 . The .Sw -format switches of .Pn send and .Pn post , which had a third meaning, were removed likewise .Ci f3cb7cde0e6f10451b6848678d95860d512224b9 . Eventually, the ambiguity of the .Sw -format -- .U3 "MIME Tools .P The MIME tools, which once were part of .Pn mhn (whatever that stood for), had several switches that added little practical value to the programs. The .Sw -[no]realsize switches of .Pn mhbuild and .Pn mhlist were removed .Ci 8d8f1c3abc586c005c904e52c4adbfe694d2201c . Real size calculations are done always now because nmh's .Mp mhbuild (1) man page states that ``This provides an accurate count at the expense of a small delay'' with the small delay not being noticeable on modern systems. .P The .Sw -[no]check switches were removed together with the support for .Hd Content-MD5 header fields [RFC\|1864] (cf. Sec. .Cf content-md5 ) .Ci 31dc797eb5178970d68962ca8939da3fd9a8efda . .P The .Sw -[no]ebcdicsafe and .Sw -[no]rfc934mode switches of .Pn mhbuild were removed because they are considered obsolete .Ci 01a3480928da485b4d6109d36d751dfa71799d58 .Ci 3363e2624dce0eb8164cf8b3f1ab385c8ff72e88 . .P Content caching of external MIME parts, activated with the .Sw -rcache and .Sw -wcache switches was completely removed .Ci d1fefd9f614e4dc3cda16da6c69133c1b2005269 . External MIME parts are rare today, having a caching facility for them appears to be unnecessary. .P In pre-MIME times, .Pn mhl had covered many tasks that are part of MIME handling today. Therefore, .Pn mhl could be simplified to a large extend, reducing the number of its switches from 21 to 6 .Ci 350ad6d3542a07639213cf2a4fe524e829c1e7b6 .Ci 0e46503be3c855bddaeae3843e1b659279c35d70 . .U3 "Header Printing .P .Pn folder 's data output is self-explaining enough that displaying the header line makes little sense. Hence, the .Sw -[no]header switch was removed and headers are never printed .Ci 601cc73d1fa05ce96faa728f036d6c51b91701c7 . .P In .Pn mhlist , the .Sw -[no]header switches were removed, as well .Ci b24f96523aaf60e44e04a3ffb1d22e69a13a602f . In this case, the headers are printed always because the output is not self-explaining. .P .Pn scan also had .Sw -[no]header switches. Printing this header had been sensible until the introduction of format strings made it impossible to display column headings. Only the folder name and the current date remained to be printed. As this information can be perfectly generated with .Pn folder and .Pn date , the switches were removed .Ci c477dc5d1d03fa6d9a8ab3dd3508c63cbddc044e . .P By removing all -- .U3 "Suppressing Edits or the Invocation of the WhatNow Shell .P The .Sw -noedit switch of .Pn comp , .Pn repl , .Pn forw , .Pn dist , and .Pn whatnow was removed and replaced by specifying .Sw -editor with an empty argument .Ci 75fca31a5b9d5c1a99c74ab14c94438d8852fba9 . (Specifying .Cl "-editor /bin/true is nearly the same. It differs only in setting the previous editor.) .P The more important change is the removal of the .Sw -nowhatnowproc switch .Ci ee4f43cf2ef0084ec698e4e87159a94c01940622 . This switch had once introduced an awkward behavior, as explained in nmh's man page for -- .U3 "Various .BU With the removal of MMDF maildrop format support, .Pn packf and .Pn rcvpack no longer needed their .Sw -mbox and .Sw -mmdf switches. The behavior of .Sw -mbox is the sole behavior now .Ci 3916ab66ad5d183705ac12357621ea8661afd3c0 . Further rework in both tools made the .Sw -file switch unnecessary .Ci ca1023716d4c2ab890696f3e41fa0d94267a940e . .BU Mmh's tools do no longer clear the screen (\c .Pn scan 's and .Pn mhl 's .Sw -[no]clear switches .Ci e57b17343dcb3ff373ef4dd089fbe778f0c7c270 .Ci 943765e7ac5693ae177fd8d2b5a2440e53ce816e ). Neither does .Pn mhl ring the bell (\c .Sw -[no]bell .Ci e11983f44e59d8de236affa5b0d0d3067c192e24 ) nor does it page the output itself (\c .Sw -length .Ci 5b9d883db0318ed2b84bb82dee880d7381f99188 ). Generally, the pager to use is no longer specified with the .Sw -[no]moreproc command line switches for .Pn mhl and .Pn show /\c .Pn mhshow .Ci 39e87a75b5c2d3572ec72e717720b44af291e88a . .BU In order to avoid prefix collisions among switch names, the .Sw -version switch was renamed to .Sw -Version (with capital `V') .Ci 32b2354dbaf4bf934936eb5b102a4a3d2fdd209a . Every program has the .Sw -version switch but its first three letters collided with the .Sw -verbose switch, present in many programs. The rename solved this problem once for all. Although this rename breaks a basic interface, having the .Sw -V abbreviation to display the version information, isn't all too bad. .BU .Sw -[no]preserve of .Pn refile was removed .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173 because what use was it anyway? Quoting nmh's man page -- [sic!] 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 .Sw -preserve switch, then .Pn refile will use the next available message number which is above the message number you wish to preserve. .QE .BU The removal of the .Sw -[no]reverse switches of .Pn scan .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173 is a bug fix. This is supported by the comments -- This system call will be eliminated when proper system sharing mechanisms are implemented. Users should not depend on the memory sharing semantics of vfork() as it will, in that case, be made synonymous to fork(2). .QE .LP Vixie supports the removal with the note that ``the last system on which fork was so slow that an mh user would notice it, was Eunice. that was 1987''. .[ nmh-workers vixie edginess .] I replaced all calls to .Fu vfork() with calls to .Fu fork() .Ci 40821f5c1316e9205a08375e7075909cc9968e7d . .P Related to the costs of -- is the probability of its success. In the eighties, on heavy loaded systems, calls to .Fu fork() were prone to failure. Hence, many of the .Fu fork() calls in the code were wrapped into loops to retry the .Fu fork() several times, to increase the chances to succeed eventually. On modern systems, a failing .Fu fork() call is unusual. Hence, in the rare case when .Fu fork() fails, mmh programs simply abort .Ci 5fbf37ee68e018998ada61eeab73e035b26834b6 . .U3 "Header Fields .BU The .Hd Encrypted header field was introduced by RFC\|822, but already marked as legacy in RFC\|2822. Today, OpenPGP provides the basis for standardized exchange of encrypted messages [RFC\|4880, RFC\|3156]. Hence, the support for .Hd Encrypted header fields is removed in mmh .Ci 064527f7b57ab050e5af13e15ad99aeeab125857 . .BU The native support for .Hd Face header fields has been removed, as well .Ci 8e5be81f784682822f5e868c1bf3c8624682bd23 . This feature is similar to the .Hd X-Face -- the transmission. The TCP includes a checksum field therefore. These two approaches in combinations render the .Hd Content-MD5 header field superfluous. Not a single one out of 4\|200 messages from two decades in the nmh-workers mailing list archive .[ nmh-workers mailing list archive website .] contains a .Hd Content-MD5 header field. Neither did any of the 60\|000 messages in my personal mail storage. Removing the support for this header field .Ci 31dc797eb5178970d68962ca8939da3fd9a8efda , removed the last place where MD5 computation was needed. Hence, the MD5 code could be removed as well. -- .P This type of maildrop format is conceptionally similar to the mbox format, but uses a different message delimiter (`\fL\\1\\1\\1\\1\fP', commonly written as `\fL^A^A^A^A\fP', instead of `\fLFrom\0\fP'). Mbox is the de-facto standard maildrop format on Unix, whereas the MMDF maildrop format is now forgotten. Mbox remains as the only packed mailbox format, supported in mmh. .P The simplifications within the code were moderate. Mainly, the reading and writing of MMDF mailbox files was removed. But also, switches of .Pn packf and .Pn rcvpack could be removed .Ci 3916ab66ad5d183705ac12357621ea8661afd3c0 . In the message parsing function .Fn sbr/m_getfld.c , knowledge of MMDF packed mail boxes was removed .Ci 684ec30d81e1223a282764452f4902ed4ad1c754 . Further code structure simplifications may be possible there, because only one single packed mailbox format is left to be supported. -- .Pn prompter had not been touched lately. Otherwise it's hardly explainable why it still offered the switches .Sw -erase .Ar chr and .Sw -kill .Ar chr to name the characters for command line editing. The times when this had been necessary are long time gone. Today these things work out-of-the-box, and if not, are configured with the standard tool .Pn stty . The switches are removed now .Ci 0bd9750710cdbab80cfb4036dd87af20afe1552f . .U3 "Hardcopy Terminal Support .P More of a funny anecdote is a check for being connected to a hardcopy terminal. It remained in the code until spring 2012, when I finally removed it .Ci b7764c4a6b71d37918a97594d866258f154017ca . .P The check only prevented a pager to be placed between the printing -- and parts of arbitrary type following. .P MH's MIME support is a direct implementation of the RFCs. The perception of the topic described in the RFCs is clearly visible in MH's implementation. As a result, MH had all the MIME features but no idea of attachments. But users do not need all the MIME features, they want convenient attachment handling. .U3 "Composing MIME Messages .P In order to improve the situation on the message composing side, Jon Steinhart had added an attachment system to nmh in 2002 .Ci 7480dbc14bc90f2d872d434205c0784704213252 . In the file .Fn docs/README-ATTACHMENTS , -- They allow attachments to be added, listed, and deleted. MIME messages are automatically created when drafts with attachments are sent. .QE .LP Unfortunately, the attachment system, like every new facilities in nmh, was inactive by default. .P During my time in Argentina, I tried to improve the attachment system. But, after long discussions my patch died as a proposal on the mailing list because of great opposition in the nmh community. .[ nmh-workers attachment proposal .] In January 2012, I extended the patch and applied it to mmh .Ci 8ff284ff9167eff8f5349481529332d59ed913b1 . In mmh, the attachment system is active by default. Instead of command line switches, the -- Drafts with attachment headers are converted to MIME automatically by .Pn send . The conversion to MIME is invisible to the user. The draft stored in the draft folder is always in source form with attachment headers. If the MIMEification fails (e.g. because the file to attach is not accessible) the original draft is not changed. .P The attachment system handles the forwarding of messages, too. If the attachment header value starts with a plus character (`\fL+\fP'), like in .Cl "Attach: +bob 30 42" , the given messages in the specified folder will be attached. This allowed to simplify .Pn forw .Ci f41f04cf4ceca7355232cf7413e59afafccc9550 . .P Closely related to attachments is non-ASCII text content, -- .U3 "MIME Type Guessing .P From the programmer's point of view, the use of .Pn mhbuild composition drafts had one notable advantage over attachment headers: The user provides the appropriate MIME types for files to include. The new attachment system needs to find out the correct MIME type itself. This is a difficult task. Determining the correct MIME type of content is partly mechanical, partly intelligent work. Forcing the user to find out the correct MIME type, forces him to do partly mechanical work. Letting the computer do the work can lead to bad choices for difficult content. For mmh, the latter option was chosen to spare the user the work .Ci 3baec236a39c5c89a9bda8dbd988d643a21decc6 . .P Determining the MIME type by the suffix of the file name is a dumb approach, yet it is simple to implement and provides good results for the common cases. If no MIME type can be determined, text content is sent as `text/plain', anything else under the generic fall-back type `application/octet-stream'. Mmh implements this approach in the .Pn print-mimetype script .Ci 4b5944268ea0da7bb30598a27857304758ea9b44 . .P A far better, though less portable, approach is the use of -- filename, built from message number, MIME part number, and MIME type. .P The .Sw -noauto mode had been the default in nmh because it was considered safe, in contrast to the .Sw -auto mode. In mmh, .Sw -auto is not dangerous anymore. Two changes were necessary: .LI 1 Any directory path is removed from the proposed filename. Thus, the files are always stored in the expected directory. .Ci 41b6eadbcecf63c9a66aa5e582011987494abefb .LI 2 Tar files are not extracted automatically any more. Thus, the rest of the file system will not be touched. .Ci 94c80042eae3383c812d9552089953f9846b1bb6 .P In mmh, the result of .Cl "mhstore -auto can be foreseen from the output of .Cl "mhlist -verbose" . Although the .Sw -noauto mode is considered to be more powerful, it is less convenient and .Sw -auto is safe now. Additionally, storing attachments under their original name is intuitive. Hence, .Sw -auto serves better as the default option .Ci 3410b680416c49a7617491af38bc1929855a331d . .P Files are stored into the directory given by the -- Appending a unique suffix to the filename is another bad option. For now, the behavior remains as it is. .P In mmh, only MIME parts of type message are special in .Pn mhstore 's .Sw -auto mode. Instead of storing message/rfc822 parts as files to disk, they are stored as messages into the current mail folder. The same applies to message/partial, although the parts are automatically reassembled beforehand. MIME parts of type message/external-body are not automatically retrieved anymore. Instead, information on how to retrieve them is output. Not supporting this rare case saved nearly one thousand lines of code .Ci 55e1d8c654ee0f7c45b9361ce34617983b454c32 . The MIME type `application/octet-stream; type=tar' is not special anymore. The automatically extracting of such MIME parts had been the dangerous part of the .Sw -auto mode .Ci 94c80042eae3383c812d9552089953f9846b1bb6 . -- Although .Pn mhshow was renamed to .Pn show in mmh, this section uses the name .Pn mhshow , in order to avoid confusion. .P In mmh, the basic idea is that .Pn mhshow should display a message in one single pager session. Therefore, .Pn mhshow invokes a pager session for all its output, whenever it prints to a terminal .Ci a4197ea6ffc5c1550e8b52d5a654bcaaaee04a4e . In consequence, .Pn mhl does no more invoke a pager .Ci 0e46503be3c855bddaeae3843e1b659279c35d70 . With .Pn mhshow -- is to format messages or parts of them. The only place in mmh, where a pager is invoked is .Pn mhshow . .P Only text content is displayed. Other kinds of attachments are ignored. Non-text content needs to be converted to text by appropriate .Pe mhshow-show-* profile entries before, if this is possible and wanted. A common example for this are PDF files. .P MIME parts are always displayed serially. The request to display the MIME type `multipart/parallel' in parallel is ignored. It is simply treated as `multipart/mixed' .Ci d0581ba306a7299113a346f9b4c46ce97bc4cef6 . This was already possible to requested with the, now removed, .Sw -serialonly switch of .Pn mhshow . As MIME parts are always processed exclusively, i.e. serially, the `\fL%e\fP' escape in .Pe mhshow-show-* profile entries became useless and was thus removed .Ci a20d405db09b7ccca74d3e8c57550883da49e1ae . For parallel display, the attachments need to be stored to disk first. .P To display text content in foreign charsets, they need to be converted to the native charset. Therefore, .Pe mhshow-charset-* profile entries were needed. In mmh, the conversion is performed automatically by piping the text through the .Pn iconv command, if necessary .Ci 2433122c20baccb10b70b49c04c6b0497b5b3b60 . Custom .Pe mhshow-show-* -- Though, the default setup of mmh displays message in foreign charsets correctly without the need to configure anything. .ig .P mhshow/mhstore: Removed support for retrieving message/external-body parts. These tools will not download the contents automatically anymore. Instead, they print the information needed to get the contents. If someone should really receive one of those rare message/external-body messages, he can do the job manually. We save nearly a thousand lines of code. That's worth it! (The profile entry `nmh-access-ftp' and sbr/ruserpass.c for reading ~/.netrc are gone now.) .Ci 55e1d8c654ee0f7c45b9361ce34617983b454c32 .. -- Nmh offers no direct support for digital signatures and message encryption. This functionality needed to be added through third-party software. In mmh, the functionality is included because it is a part of modern email and is likely wanted by users of mmh. A fresh mmh installation supports signing and encrypting out-of-the-box. Therefore, Neil Rickert's .Pn mhsign and .Pn mhpgp scripts .[ neil rickert mhsign mhpgp .] were included .Ci f45cdc98117a84f071759462c7ae212f4bc5ab2e .Ci 58cf09aa36e9f7f352a127158bbf1c5678bc6ed8 . The scripts fit well because they are lightweight and similar of style to the existing tools. Additionally, no licensing difficulties appeared as they are part of the public domain. .P .Pn mhsign handles the signing and encrypting part. It comprises about 250 lines of shell code and interfaces between .Pn gnupg and the MH system. It was meant to be invoked manually at the WhatNow prompt, but in mmh, .Pn send invokes .Pn mhsign automatically .Ci c7b5e1df086bcc37ff40163ee67571f076cf6683 . Special header fields were introduced to request this action. If a draft contains the -- In consequence, the command line switches .Sw -draftfolder and .Sw -draftmessage could be removed. More difficult but also more improving was updating the tools to the new concept. For nearly three decades, the tools needed to support two draft handling approaches. By fully switching to the draft folder, the tools could be simplified by dropping the awkward draft message handling code. .Sw -draft switches were removed because operating on a draft message is no longer special. It became indistinguishable to operating on any other message. .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 .P There is no more need to query the user for draft handling .Ci 2d48b455c303a807041c35e4248955f8bec59eeb . It is always possible to add another new draft. Refiling drafts is without difference to refiling other messages. -- .P Similar to the draft folder case, I dropped the old backup prefix approach in favor for replacing it by the better suiting trash folder system. Hence, .Pn rmm calls .Pn refile to move the to-be-removed message to the trash folder, .Fn +trash by default. To sweep it clean, the user can use .Cl "rmm -unlink +trash a" , where the .Sw -unlink switch causes the files to be unlinked. .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173 .Ci ca0b3e830b86700d9e5e31b1784de2bdcaf58fc5 .P Dropping the legacy approach and converting to the new approach -- Nmh's user base is small and old. Changing the interfaces causes inconvenience to long-term users of MH. It forces them to change their many years old MH configurations. I do understand this aspect, but by sticking to the old users, new users are kept from entering the world of MH. But the future lies in new users. In consequence, mmh invites new users by providing a convenient and modern setup, readily usable out-of-the-box. .P In mmh, all modern features are active by default and many previous approaches are removed or only accessible in a manual way. New default features include: .BU The attachment system (\c .Hd Attach ) .Ci 8ff284ff9167eff8f5349481529332d59ed913b1 . .BU The draft folder facility (\c .Fn +drafts ) .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 . .BU The unseen sequence (`u') .Ci c2360569e1d8d3678e294eb7c1354cb8bf7501c1 and the sequence negation prefix (`!') .Ci db74c2bd004b2dc9bf8086a6d8bf773ac051f3cc . .BU Quoting the original message in the reply .Ci 67411b1f95d6ec987b4c732459e1ba8a8ac192c6 . .BU Forwarding messages using MIME .Ci 6e271608b7b9c23771523f88d23a4d3593010cf1 . .LP An mmh setup with a profile that defines only the path to the -- The number of tabs corresponds to the nesting level \(en one tab, one level. Tab characters provide flexible visual appearance because developers can adjust their width as preferred. There is no more need to check for the correct mixture of tabs and spaces. Two simple rules ensure the integrity and flexibility of the visual appearance: .LI 1 Leading whitespace must consist of tabs only. .LI 2 All other whitespace should be spaces. .LP Although reformatting existing code should be avoided, I did it. I did not waste time arguing; I just reformatted the code. .Ci a485ed478abbd599d8c9aab48934e7a26733ecb1 .U3 "Comments .P Kernighan and Pike demand: ``Don't belabor the obvious''. .[ [ kernighan pike practice of programming .], p. 23] Following the advice, I removed unnecessary comments. For instance, I removed all comments in the following code excerpt .Ci 426543622b377fc5d091455cba685e114b6df674 : .VS context_replace(curfolder, folder); /* update current folder */ -- statements already, except for the NUL-termination, which became obvious from the context. .U3 "Names .P Regarding this topic, Kernighan and Pike suggest: ``Use active names for functions''. .[ [ kernighan pike practice of programming .], p. 4] One application of this rule was the rename of .Fu check_charset() to .Fu is_native_charset() .Ci 8d77b48284c58c135a6b2787e721597346ab056d . The same change additionally fixed a violation of ``Be accurate'', .[ [ -- It did not compare charset names but prefixes of them only. In case the native charset was `ISO-8859-1', then .VS check_charset("ISO-8859-11", strlen("ISO-8859-11")) VE had returned true although the upper halves of the code pages are different. .P More important than using active names is using descriptive names. .VS m_unknown(in); /* the MAGIC invocation... */ VE Renaming the obscure .Fu m_unknown() function was a delightful event, although it made the code less funny .Ci 611d68d19204d7cbf5bd585391249cb5bafca846 . .P Magic numbers are generally considered bad style. -- in .Fn uip/scansbr.c holds the number of the message to be created. As well it encodes program logic with negative numbers and zero. This led to obscure code. I clarified the code by introducing two variables that extracted the hidden information: .VS int incing = (outnum > 0); int ismbox = (outnum != 0); VE The readable names are thus used in conditions; the variable .CW outnum is used only to extract ordinary message numbers .Ci b8b075c77be7794f3ae9ff0e8cedb12b48fd139f . .P Through the clarity improvement of the change detours in the program logic of related code parts became apparent. The implementation was simplified. This possibility to improve had been invisible before .Ci aa60b0ab5e804f8befa890c0a6df0e3143ce0723 . .P The names just described were a first step, yet the situation -- .CW outnum : .VS #define SCN_MBOX (-1) #define SCN_FOLD 0 VE The two variables were updated thereafter as well: .VS int incing = (outnum != SCN_MBOX && outnum != SCN_FOLD); int scanfolder = (outnum == SCN_FOLD); VE Furthermore, .CW ismbox was replaced by .CW scanfolder because that matched better to the program logic. .Ci 7ffb36d28e517a6f3a10272056fc127592ab1c19 -- and the two pairs of flags, .Sw -[no]date and .Sw -[no]inplace . Then Jon Steinhart introduced his attachment system. In need for more advanced annotation handling, he extended .Pn anno . He added five more switches: .Sw -draft , .Sw -list , .Sw -delete , .Sw -append , and .Sw -number , the last one taking an argument .Ci 7480dbc14bc90f2d872d434205c0784704213252 . Later, .Sw -[no]preserve was added as well .Ci d9b1d57351d104d7ec1a5621f090657dcce8cb7f . Then, the Synopsis section of the man page .Mp anno (1) -- and .Sw -delete introduce operation modes. Historically, .Pn anno had only one operation mode: adding header fields. With the extension, two more modes were added: listing and deleting header fields. The structure of the code changes did not pay respect to this fundamental change. Neither the implementation nor the documentation did clearly declare the exclusive operation modes as such. Having identified the problem, I solved it by putting structure into .Pn anno and its documentation .Ci d54c8db8bdf01e8381890f7729bc0ef4a055ea11 . .P The difference is visible in both the code and the documentation. -- .P I clarified the path name conversion by complete rework. First of all, the terminology needed to be defined. A path name is either in the Unix domain, then it is called \fIdirectory path\fP or it is in the MH domain, then it is called \fIfolder path\fP. The two terms need to be used with strict distinction. Second, I exploited the concept of path type indicators. By requiring every path name to start with a distinct type identifier, the conversion between the types could be fully automated. This allows the tools to accept path names of any type from the user. Therefore, it was necessary to require relative directory paths to be prefixed with a dot character. In consequence, the dot character could no longer be an alias for the current message .Ci cff0e16925e7edbd25b8b9d6d4fbdf03e0e60c01 . Third, I created three new functions to replace the previous mess: .LI 1 -- Absolute directory paths are the most general representation of a path name. The result is a pointer to static memory. .P The new functions have names that indicate their use. Two of the functions convert relative to absolute path names of the same type. The third function converts any path name type to the most general one, the absolute directory path. All of the functions return pointers to static memory. The file .Fn sbr/path.c contains the implementation of the functions; .Fn sbr/m_maildir.c was removed. .Ci d39e2c447b0d163a5a63f480b23d06edb7a73aa0 .P Along with the path conversion rework, I also replaced .Fu getfolder(FDEF) with .Fu getdeffol() and .Fu getfolder(FCUR) with .Fu getcurfol() , which only wraps .Fu expandfol(""@"") for convenience. This code was moved from .Fn sbr/getfolder.c into .Fn sbr/path.c as well. .Ci d39e2c447b0d163a5a63f480b23d06edb7a73aa0 .P The related function .Fu etcpath() is now included in .Fn sbr/path.c , too .Ci b4c29794c12099556151d93a860ee51badae2e35 . Previously, it had been located in .Fn config/config.c . -- to use this profile by exporting an environment variable. With this approach, no special cases would have been introduced and no surprises would have been caused. By writing a wrapper program to provide a clean temporary profile, the concept could have been generalized orthogonally to the whole MH tool chest. .P In mmh, the wish to have .Pn mhmail as a replacement for .Pn mailx is considered obsolete. Mmh's .Pn mhmail does no longer cover this use-case .Ci d36e56e695fe1c482c7920644bfbb6386ac9edb0 . Currently, .Pn mhmail is in a transition state .Ci 32d4f9daaa70519be3072479232ff7be0500d009 . It may become a front-end to .Pn comp , -- into an ordinary MH tool. If, however, this idea does not convince, then .Pn mhmail will be removed. .P In the mmh tool chest, every program reads the profile. (\c .Pn slocal is not considered part of the mmh tool chest (cf. Sec. .Cf slocal ).) Mmh has no .Pn post program, but it has .Pn spost , which now does read the profile .Ci 3e017a7abbdf69bf0dff7a4073275961eda1ded8 . Following this change, .Pn send -- can and should be dropped. Kernighan and Pike advise: ``Use standard libraries''. .[ [ kernighan pike practice of programming .], p. 196] Actually, MH had followed this advice in history, but it had not adjusted to more recent changes in this field. The .Fu snprintf() function, for instance, was standardized with C99 and is available almost everywhere because of its high usefulness. Thus, the project's own implementation of .Fu snprintf() was dropped in March 2012 in favor for using the one of the standard library .Ci 0052f1024deb0a0a2fc2e5bacf93d45a5a9c9b32 . Such decisions limit the portability of mmh if systems do not support these standardized and widespread functions. -- Thus, I needed to learn about the history in retrospective. I have only read a lot of books about the (good) old times. This put me in a difficult position when working with old code. I need to freshly acquire knowledge about old code constructs and ancient programming styles, whereas older programmers know these things by heart from their own experience. Being aware of the situation, I rather let people with more historic experience do the transition from ancient code constructs to standardized ones. Lyndon Nerenberg covered large parts of this task for the nmh project. He converted project-specific functions to POSIX replacements, also removing the conditionals compilation of now standardized features. Ken Hornstein and David Levine had their part in this work, as well. Often, I only pulled the changes over from nmh into mmh. These changes include many commits, among them: .Ci 768b5edd9623b7238e12ec8dfc409b82a1ed9e2d .Ci 0052f1024deb0a0a2fc2e5bacf93d45a5a9c9b32 . .P Nevertheless, I worked on the task as well, tidying up the -- (``subroutines'') directory in the source tree and includes functions that mmh tools usually need. Among them are MH-specific functions for profile, context, sequence, and folder handling, but as well MH-independent functions, such as auxiliary string functions, portability interfaces and error-checking wrappers for critical functions of the standard library. .BU I have replaced the .Fu atooi() function with calls to .Fu strtoul() , setting the third parameter, the base, to eight. .Fu strtoul() is part of C89 and thus considered safe to use .Ci c490c51b3c0f8871b6953bd0c74551404f840a74 . .BU I did remove project-included fallback implementations of .Fu memmove() and .Fu strerror() .Ci b067ff5c465a5d243ce5a19e562085a9a1a97215 , although Peter Maydell had re-included them into nmh in 2008 to support SunOS 4. -- it returns a pointer to the terminating null-byte in the destination area. The code was adjusted to replace .Fu copy() with .Fu strcpy() , except within .Fu concat() , where .Fu copy() was more convenient. Therefore, the definition of .Fu copy() was moved into the source file of .Fu concat() and its visibility it limited to that .Ci 552fd7253e5ee9e554c5c7a8248a6322aa4363bb . .BU The function -- replacing .Fu r1bindex() with the more specific and better-named function .Fu basename() became desirable. Unfortunately, many of the 54 calls to .Fu r1bindex() depended on a special behavior, which differed from the POSIX specification for .Fu basename() . Hence, .Fu r1bindex() was kept but renamed to .Fu mhbasename() , setting the delimiter to the slash .Ci 240013872c392fe644bd4f79382d9f5314b4ea60 . For possible uses of .Fu r1bindex() with a different delimiter, the ANSI C function .Fu strrchr() provides the core functionality. .BU The .Fu ssequal() function \(en apparently for ``substring equal'' \(en was renamed to .Fu isprefix() , because this is what it actually checked .Ci c20b4fa14515c7ab388ce35411d89a7a92300711. Its source file had included both of the following comments, no joke. .in -\n(PIu -- * 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. */ VE .in +\n(PIu Eventually, the function was completely replaced with calls to .Fu strncmp() .Ci b0b1dd37ff515578cf7cba51625189eb34a196cb . -- .Fn profile . The path to the profile is no longer .Fn $HOME/.mh_profile but .Fn $HOME/.mmh/profile . (The alternative of having file .Fn $HOME/.mh_profile and a configuration directory .Fn $HOME/.mmh appeared to be inconsistent.) .P The approach chosen for mmh is consistent, simple, and familiar to Unix users. The main achievement of the change is the clear and sensible separation of the mail storage and the configuration. .Ci 7030d7edb099bff36ded7548bb5380f7acab4f9b .P As MH allows users to have multiple MH setups, -- This allows having a separate current folder in each terminal at the same time, for instance. In mmh, three environment variables replace the two of nmh. .Ev MMH overrides the default location of the mmh directory (\c .Fn .mmh ). .Ev MMHP and .Ev MMHC override the paths to the profile and context file, respectively. This approach allows the set of personal configuration files to be chosen independently of the profile, context, and mail storage. The new approach has no functional disadvantages, as every setup I can imagine can be implemented with both approaches, possibly even easier with the new one. .Ci 7030d7edb099bff36ded7548bb5380f7acab4f9b -- included the function .Fu annotate() . Each program that wanted to annotate messages, included the source file .Fn uip/annosbr.c and called .Fu annotate() . Because the function .Fu annotate() was used like the tool .Pn anno , it had seven parameters, reflecting the command line switches of the tool. When another pair of command line switches was added to .Pn anno , a rather ugly hack was implemented to avoid adding another parameter to the function .Ci d9b1d57351d104d7ec1a5621f090657dcce8cb7f . .P In mmh, the relevant code of -- No longer should readability or conceptional beauty be sacrificed. No longer should the Unix philosophy's ``one tool, one job'' guideline be violated. Therefore, mmh's .Pn comp no longer sends messages. .P In mmh, different jobs are divided among separate programs that invoke each other as needed. In consequence, .Pn comp invokes .Pn whatnow which thereafter invokes .Pn send .Ci 3df5ab3c116e6d4a2fb4bb5cc9dfc5f781825815 .Ci c73c00bfccd22ec77e9593f47462aeca4a8cd9c0 . The clear separation on the surface is maintained on the level below. Human users and other tools use the same interface \(en annotations, for example, are made by invoking .Pn anno , no matter if requested by programs or by human beings .Ci 469a4163c2a1a43731d412eaa5d9cae7d670c48b .Ci aed384169af5204b8002d06e7a22f89197963d2d .Ci 3caf9e298a8861729ca8b8a84f57022b6f3ea742 . The decrease of tools built from multiple source files and thus the decrease of .Fn uip/*sbr.c files confirm the improvement .Ci 9e6d91313f01c96b4058d6bf419a8ca9a207bc33 .ci 81744a46ac9f845d6c2b9908074d269275178d2e .Ci f0f858069d21111f0dbea510044593f89c9b0829 .Ci 0503a6e9be34f24858b55b555a5c948182b9f24b .Ci 27826f9353e0f0b04590b7d0f8f83e60462b90f0 .Ci d1da1f94ce62160aebb30df4063ccbc53768656b .Ci c42222869e318fff5dec395eca3e776db3075455 . This is also visible in the complexity of the build dependency graphs: -- In consequence, users need to activate modern features explicitly to be able to use them. The ancient style in which fresh nmh setups remain to appear causes difficulties for new users, as modern email features require additional configuration. The small but mature community around nmh, however, needs little change as they have had their convenient setups for decades. .H1 "mmh .P I started to work on my experimental version in October 2011, basing my work on nmh version \fInmh-1.3-dev\fP. At that time no more than three commits were made to nmh since the beginning of 2011, the latest one being .Ci a01a41d031c796b526329a4170eb23f0ac93b949 , committed on 2011-04-13. In December, when I announced my work in progress on the -- kernighan pike unix programming env .]]''. Citations of email messages and websites are distinguished by ``mail:'' and ``web:'' prefixes. All references are collected at the end of the document. The websites of the software projects mentioned are collected in a list in the appendix. .P This document describes practical programming work. The code of mmh is managed with the .Pn git version control system. All code changes were checked in. In the discussions, references to corresponding code changes are printed as ``\c .Ci 1a2b3c4 ''. The identifier is the seven-letter-prefix of the changeset hash value, which is considered unique.