docs/master

view discussion.roff @ 230:96778c1afc3e

More cleanups.
author markus schnalke <meillo@marmaro.de>
date Mon, 16 Jul 2012 00:37:31 +0200
parents a1468cf505fd
children 77c87c38bff4
line source
1 .H0 "Discussion
2 .P
3 This main chapter discusses the practical work accomplished in the
4 mmh project.
5 It is structured along the goals chosen for the project.
6 A selection of the work undertaken
7 is described.
8 .P
9 This discussion compares the present version of mmh with the state of
10 nmh at the time when the mmh project had started, i.e. fall 2011.
11 Recent changes in nmh are rarely part of the discussion.
12 .P
13 Whenever lines of code were counted, David A. Wheeler's \fIsloccount\fP
14 was used to measure the amount in a comparable way.
15 .P
16 For the reader's convenience, the structure of modern email systems
17 is depicted in the following figure.
18 It illustrates the path a message takes from sender to recipient.
20 .sp 1.5
21 .KS
22 .in 2c
23 .so input/mail-agents.pic
24 .KE
25 .sp 1.5
27 .LP
28 The ellipses denote mail agents, i.e. different jobs in email processing.
29 These are:
30 .IP "Mail User Agent (MUA)
31 The only program users directly interact with.
32 It includes functions to compose new mail, display received mail,
33 and to manage the mail storage.
34 It is called a \fImail client\fP as well.
35 .IP "Mail Submission Agent (MSA)
36 A special kind of Mail Transfer Agent, used to submit mail into the
37 mail transport system.
38 Often it is also called an MTA.
39 .IP "Mail Transfer Agent (MTA)
40 A node in the mail transport system.
41 It transfers incoming mail to a transport node nearer to the
42 final destination.
43 An MTA may be the final destination itself.
44 .IP "Mail Delivery Agent (MDA)
45 Delivers mail according to a set of rules.
46 Usually, the messages are stored to disk.
47 .IP "Mail Retrieval Agent (MRA)
48 Initiates the transfer of mail from a remote location to the local machine.
49 (The dashed arrow in the figure represents the pull request.)
50 .LP
51 The dashed boxes represent entities that usually reside on single machines.
52 The box on the lower left represents the sender's system.
53 The box on the upper left represents the first mail transfer node.
54 The box on the upper right represents the transfer node responsible
55 for the destination address.
56 The box on the lower right represents the recipient's system.
57 Often, the boxes above the dotted line are servers on the Internet.
58 Many mail clients, including nmh, include all of the components below
59 the dotted line.
60 This is not the case for mmh; it implements the MUA only.
67 .\" --------------------------------------------------------------
68 .H1 "Streamlining
70 .P
71 MH once provided a complete email system.
72 The community around nmh tries to keep nmh in similar shape.
73 In fundamental contrast, mmh shall be an MUA only.
74 I believe that the development of all-in-one mail systems is obsolete.
75 Today, email is too complex to be fully covered by a single project.
76 Such a project will not be able to excel in all aspects.
77 Instead, the aspects of email should be covered by multiple projects,
78 which then can be combined to form a complete system.
79 Excellent implementations for the various aspects of email already exist.
80 Just to name three examples: Postfix is a specialized MTA, Procmail
81 is a specialized MDA, and Fetchmail is a specialized MRA.
82 I believe that it is best to use such specialized tools instead of
83 providing the same function once more as a side component.
84 .P
85 Doing something well requires focusing on a small set of specific aspects.
86 Under the assumption that development which is focussed on a particular
87 area produces better results there, specialized projects will be superior
88 in their field of focus.
89 Hence, all-in-one mail system projects \(en no matter if monolithic
90 or modular \(en will never be the best choice in any of the fields.
91 Even in providing the most consistent all-in-one system, they are likely
92 to be beaten by projects that focus exclusively on the creation
93 of a homogeneous system by integrating existing mail components.
94 .P
95 Usually, the limiting resource in the community development of
96 free software is man power.
97 If the development effort is spread over a large development area,
98 it becomes more difficult to compete with the specialists in the
99 various fields.
100 The concrete situation for MH-based mail systems is even tougher,
101 given their small and aged community, concerning both developers and users.
102 .P
103 In consequence, I believe that the available development resources
104 should focus on the point where MH is most unique.
105 This is clearly the user interface \(en the MUA.
106 Peripheral parts should be removed to streamline mmh for the MUA task.
109 .H2 "Mail Transfer Facilities
110 .Id mail-transfer-facilities
111 .P
112 The removal of the mail transfer facilities, effectively dropping the
113 MSA and MRA, had been the first work task in the mmh project.
114 The desire for this change initiated the creation of the mmh project.
115 .P
116 Focusing on one mail agent role only, is motivated by Eric Allman's
117 experience with Sendmail.
118 He identified the limitation of Sendmail
119 to the MTA task as one reason for its success:
120 .[ [
121 costales sendmail
122 .], p. xviii]
123 .QS
124 Second, I limited myself to the routing function \(en
125 I wouldn't write user agents or delivery back-ends.
126 This was a departure of the dominant thought of the time,
127 in which routing logic, local delivery, and often the network code
128 were incorporated directly into the user agents.
129 .QE
130 .P
131 In nmh, the MSA is called \fIMessage Transfer Service\fP (MTS).
132 This facility, implemented by the
133 .Pn post
134 command, establishes network connections and spoke SMTP to submit
135 messages to be relayed to the outside world.
136 When email transfer changed, this part needed to be changed as well.
137 Encryption and authentication for network connections
138 needed to be supported, hence TLS and SASL were introduced into nmh.
139 This added complexity without improving the core functions.
140 Furthermore, keeping up with recent developments in the field of
141 mail transfer requires development power and specialists.
142 In mmh, this whole facility was simply cut off
143 .Ci f6aa95b724fd8c791164abe7ee5468bf5c34f226
144 .Ci fecd5d34f65597a4dfa16aeabea7d74b191532c3
145 .Ci 156d35f6425bea4c1ed3c4c79783dc613379c65b .
146 Instead, mmh depends on an external MSA.
147 All outgoing mail in mmh goes through the
148 .Pn sendmail
149 command, which almost any MSA provides.
150 If not, a wrapper program can be written.
151 It must read the message from the standard input, extract the
152 recipient addresses from the message header, and hand the message
153 over to the MSA.
154 For example, a wrapper script for qmail would be:
155 .VS
156 #!/bin/sh
157 exec qmail-inject # ignore command line arguments
158 VE
159 The requirement to parse the recipient addresses out of the message header
160 may be removed in the future.
161 Mmh could pass the recipient addresses as command line arguments.
162 This appears to be the better interface.
163 .P
164 To retrieve mail, the
165 .Pn inc
166 command in nmh acts as MRA.
167 It establishes network connections
168 and speaks POP3 to retrieve mail from remote servers.
169 As with mail submission, the network connections required encryption and
170 authentication, thus TLS and SASL were added to nmh.
171 Support for message retrieval through IMAP will soon become necessary
172 additions, too, and likewise for any other changes in mail transfer.
173 But not in mmh because it has dropped the support for retrieving mail
174 from remote locations
175 .Ci ab7b48411962d26439f92f35ed084d3d6275459c .
176 Instead, it depends on an external tool to cover this task.
177 Mmh has two paths for messages to enter mmh's mail storage:
178 (1) Mail can be incorporated with
179 .Pn inc
180 from the system maildrop, or (2) with
181 .Pn rcvstore
182 by reading them, one at a time, from the standard input.
183 .P
184 With the removal of the MSA and MRA, mmh converted from a complete
185 mail system to only an MUA.
186 Now, of course, mmh depends on third-party software.
187 An external MSA is required to transfer mail to the outside world;
188 an external MRA is required to retrieve mail from remote machines.
189 Excellent implementations of such software exist.
190 They likely are superior to the internal versions that were removed.
191 Additionally, the best suiting programs can be chosen freely.
192 .P
193 As it had already been possible to use an external MSA and MRA,
194 why should the internal version not be kept for convenience?
195 Transferred to a different area, the question,
196 whether there is sense in having a fall-back pager in all
197 the command line tools for the cases when
198 .Pn more
199 or
200 .Pn less
201 are not available, appears to be ridiculous.
202 Of course, MSAs and MRAs are more complex than text pagers
203 and not necessarily available but still the concept of orthogonal
204 design holds: ``Write programs that do one thing and do it well''.
205 .[
206 mcilroy unix phil
207 p. 53
208 .]
209 .[
210 mcilroy bstj foreword
211 .]
212 Here, this part of the Unix philosophy was applied not only
213 to the programs but to the project itself.
214 In other words:
215 Develop projects that focus on one thing and do it well.
216 Projects which have grown complex should be split, for the same
217 reasons that programs which have grown complex should be split.
218 If it is conceptionally more elegant to have the MSA and MRA as
219 separate projects then they should be separated.
220 In my opinion, this is the case.
221 The RFCs suggest this separation by clearly distinguishing the
222 different mail handling tasks [RFC\|821].
223 The small interfaces between the mail agents support the
224 separation as well.
225 .P
226 Once, email had been small and simple.
227 At that time,
228 .Pn /bin/mail
229 had covered everything there was to email and still was small and simple.
230 Later, the essential complexity of email increased.
231 (Essential complexity is the complexity defined by the problem itself
232 .[ [
233 brooks no silver bullet
234 .]].)
235 Consequently, email systems grew.
236 RFCs started to introduce the concept of mail agents to separate the
237 various roles because they became more extensive and because
238 new roles appeared.
239 As mail system implementations grew, parts of them were split off.
240 For instance, a POP server was included in the original MH;
241 it was removed in nmh.
242 Now is the time to go one step further and split off the MSA and MRA,
243 as well.
244 Not only does this decrease the code size of the project,
245 more importantly, it unburdens mmh of the whole field of
246 message transfer, with all its implications for the project.
247 There is no more need for concern with changes in network transfer.
248 This independence is gained by depending on external components
249 that cover the field.
250 .P
251 In general, functionality can be added in three different ways:
252 .LI 1
253 By implementing the function in the project itself.
254 .LI 2
255 By depending on a library that provides the function.
256 .LI 3
257 By depending on a program that provides the function.
258 .LP
259 While implementing the function in the project itself leads to the
260 largest increase in code size and requires the most maintenance
261 and development work,
262 it keeps the project's dependence on other software lowest.
263 Using libraries or external programs requires less maintenance work
264 but introduces dependencies on external projects.
265 Programs have the smallest interfaces and provide the best separation,
266 but possibly limit the information exchange.
267 External libraries are more strongly connected than external programs,
268 thus information can be exchanged in a more flexible manner.
269 Obviously, adding code to a project increases the maintenance work.
270 As implementing complex functions in the project itself adds
271 a lot of code, this should be avoided if possible.
272 Thus, the dependencies only change in their character,
273 not in their existence.
274 In mmh, library dependencies on
275 .Pn libsasl2
276 and
277 .Pn libcrypto /\c
278 .Pn libssl
279 were traded against program dependencies on an MSA and an MRA.
280 This also meant trading build-time dependencies against run-time
281 dependencies.
282 Besides providing stronger separation and greater flexibility,
283 program dependencies also allowed
284 over 6\|000 lines of code to be removed from mmh.
285 This made mmh's code base about 12\|% smaller.
286 Reducing the project's code size by such an amount without actually
287 losing functionality is a convincing argument.
288 Actually, as external MSAs and MRAs are likely superior to the
289 project's internal versions, the common user even gains functionality.
290 .P
291 Users of MH should not have problems setting up an external MSA and MRA.
292 Also, the popular MSAs and MRAs have large communities and a lot
293 of available documentation.
295 Choices for MSAs range from small forwarders such as \fIssmtp\fP and
296 \fInullmailer\fP, over mid-size MTAs including \fImasqmail\fP and
297 \fIdma\fP, up to full-featured MTAs as for instance \fIPostfix\fP.
298 MRAs are provided for example by \fIfetchmail\fP, \fIgetmail\fP,
299 \fImpop\fP, and \fIfdm\fP.
302 .H2 "Non-MUA Tools
303 .P
304 One goal of mmh is to remove the tools that do not significantly
305 contribute to the MUA's job.
306 Loosely related and rarely used tools distract from a lean appearance,
307 and require maintenance work without adding much to the core task.
308 By removing these tools, mmh became more streamlined and focused.
309 .BU
310 .Pn conflict
311 was removed
312 .Ci 8b235097cbd11d728c07b966cf131aa7133ce5a9
313 because it is a mail system maintenance tool and not MUA-related.
314 It even checked
315 .Fn /etc/passwd
316 and
317 .Fn /etc/group
318 for consistency, which is completely unrelated to email.
319 A tool like
320 .Pn conflict
321 is surely useful, but it should not be shipped with mmh.
322 .BU
323 .Pn rcvtty
324 was removed
325 .Ci 14767c94b3827be7c867196467ed7aea5f6f49b0
326 because its use case of writing to the user's terminal
327 on reception of mail is obsolete.
328 If users like to be informed of new mail, the shell's
329 .Ev MAILPATH
330 variable or graphical notifications are technically more appealing.
331 Writing to terminals directly is hardly ever desired today.
332 If, though, one prefers this approach, the standard tool
333 .Pn write
334 can be used in a way similar to:
335 .VS
336 scan -file - | write `id -un`
337 VE
338 .BU
339 .Pn viamail
340 was removed
341 .Ci eda72d6a7a7c20ff123043fb7f19c509ea01f932
342 when the new attachment system was activated, because
343 .Pn forw
344 could then cover the task itself.
345 The program
346 .Pn sendfiles
347 was rewritten as a shell script wrapper around
348 .Pn forw .
349 .Ci 0e82199cf3c991a173e0ac8aa776efdb3ded61e6
350 .BU
351 .Pn msgchk
352 was removed
353 .Ci bb9360ead7eb7a3fedcce2eeedfc660014e41dbe ,
354 because it lost its use case when POP support was removed.
355 A call to
356 .Pn msgchk
357 provided hardly more information than:
358 .VS
359 ls -l /var/mail/meillo
360 VE
361 Yet, it distinguished between old and new mail, but
362 these details can be retrieved with
363 .Pn stat (1),
364 too.
365 A small shell script could be written to print the information
366 in a similar way, if truly necessary.
367 As mmh's
368 .Pn inc
369 only incorporates mail from the user's local maildrop,
370 and thus no data transfers over slow networks are involved,
371 there is hardly any need to check for new mail before incorporating it.
372 .BU
373 .Pn msh
374 was removed
375 .Ci 916690191222433a6923a4be54b0d8f6ac01bd02
376 because the tool was in conflict with the philosophy of MH.
377 It provided an interactive shell to access the features of MH.
378 However, it was not just a shell tailored to the needs of mail handling,
379 but one large program that had several MH tools built in.
380 This conflicted with the major feature of MH of being a tool chest.
381 .Pn msh 's
382 main use case had been accessing Bulletin Boards, which have ceased to
383 be popular.
384 .P
385 Removing
386 .Pn msh
387 together with the truly archaic code relics
388 .Pn vmh
389 and
390 .Pn wmh
391 saved more than 7\|000 lines of C code \(en
392 about 15\|% of the project's original source code amount.
393 Having less code \(en with equal readability, of course \(en
394 for the same functionality is an advantage.
395 Less code means less bugs and less maintenance work.
396 As
397 .Pn rcvtty
398 and
399 .Pn msgchk
400 are assumed to be rarely used and can be implemented in different ways,
401 why should one keep them?
402 Removing them streamlined mmh.
403 .Pn viamail 's
404 use case is now partly obsolete and partly covered by
405 .Pn forw ,
406 hence there is no reason to still maintain it.
407 .Pn conflict
408 is not related to the mail client, and
409 .Pn msh
410 conflicts with the basic concept of MH.
411 These two tools might still be useful, but they should not be part of mmh.
412 .P
413 .Id slocal
414 Finally, there is
415 .Pn slocal ,
416 which is an MDA and thus not directly MUA-related.
417 It should be removed from mmh because including it conflicts with
418 the idea that mmh is an MUA only.
419 However,
420 .Pn slocal
421 provides rule-based processing of messages, like filing them into
422 different folders, which is otherwise not available in mmh.
423 Although
424 .Pn slocal
425 neither pulls in dependencies, nor does it include a separate
426 technical area (cf. Sec.
427 .Cf mail-transfer-facilities ),
428 it still accounts for about 1\|000 lines of code that need to be maintained.
429 As
430 .Pn slocal
431 is almost self-standing, it should be split off into a separate project.
432 This would cut the strong connection between the MUA mmh and the MDA
433 .Pn slocal .
434 For anyone not using MH,
435 .Pn slocal
436 would become yet another independent MDA, like
437 .I procmail .
438 Then
439 .Pn slocal
440 could be installed without a complete MH system.
441 Likewise, mmh users could decide to use
442 .I procmail
443 without having a second, unused MDA, i.e.
444 .Pn slocal ,
445 installed.
446 That appears to be conceptionally the best solution.
447 Yet,
448 .Pn slocal
449 is not split off.
450 I defer the decision over
451 .Pn slocal
452 out of a need for deeper investigation.
453 In the meanwhile, it remains part of mmh
454 as its continued existence is not significant;
455 .Pn slocal
456 is unrelated to the rest of the project.
460 .H2 "Displaying Messages
461 .Id mhshow
462 .P
463 Since the very beginning, already in the first concept paper,
464 .[
465 original memo rand mh shapiro gaines
466 .]
467 .Pn show
468 had been MH's message display program.
469 .Pn show
470 mapped message numbers and sequences to files and invoked
471 .Pn mhl
472 to have the files formatted.
473 With MIME, this approach was not sufficient anymore.
474 MIME messages can consist of multiple parts.
475 Some parts, like binary attachments or text content in foreign charsets,
476 are not directly displayable.
477 .Pn show 's
478 understanding of messages and
479 .Pn mhl 's
480 display capabilities could not cope with the task any longer.
481 .P
482 Instead of extending these tools, additional tools were written from
483 scratch and were added to the MH tool chest.
484 Doing so is encouraged by the tool chest approach.
485 Modular design is a great advantage for extending a system,
486 as new tools can be added without interfering with existing ones.
487 First, the new MIME features were added in form of the single program
488 .Pn mhn .
489 The command
490 .Cl "mhn -show 42
491 had then shown the message number
492 .Fn 42 ,
493 interpreting MIME.
494 With the 1.0 release of nmh in February 1999, Richard Coleman finished
495 the split of
496 .Pn mhn
497 into a set of specialized tools, which together covered the
498 multiple aspects of MIME.
499 One of them was
500 .Pn mhshow ,
501 which replaced
502 .Cl "mhn -show" .
503 It was capable of displaying MIME messages appropriately.
504 .P
505 From then on, two message display tools were part of nmh,
506 .Pn show
507 and
508 .Pn mhshow .
509 To ease the life of users,
510 .Pn show
511 was extended to automatically hand the job over to
512 .Pn mhshow
513 if displaying the message would be beyond
514 .Pn show 's
515 abilities.
516 In consequence, the user would simply invoke
517 .Pn show
518 (possibly through
519 .Pn next
520 or
521 .Pn prev )
522 and get the message printed with either
523 .Pn show
524 or
525 .Pn mhshow ,
526 whatever was more appropriate.
527 .P
528 Having two similar tools for basically the same task is redundancy.
529 Usually, users do not distinguish between
530 .Pn show
531 and
532 .Pn mhshow
533 in their daily mail reading.
534 Having two separate display programs was therefore unnecessary
535 from a user's point of view.
536 Besides, the development of both programs needed to be in sync,
537 to ensure that the programs behaved in a similar way,
538 because they were used like a single tool.
539 Different behavior would have surprised the user.
540 .P
541 Today, non-MIME messages are rather seen to be a special case of
542 MIME messages, although it is the other way round.
543 As
544 .Pn mhshow
545 already had been able to display non-MIME messages, it appeared natural
546 to drop
547 .Pn show
548 in favor of using
549 .Pn mhshow
550 exclusively
551 .Ci 4c1efddfd499300c7e74263e57d8aa137e84c853 .
552 Removing
553 .Pn show
554 is no loss in function, because
555 .Pn mhshow
556 covers it completely.
557 Yet, the old behavior of
558 .Pn show
559 can still be emulated with the simple command line:
560 .VS
561 mhl `mhpath c`
562 VE
563 .P
564 For convenience,
565 .Pn mhshow
566 was renamed to
567 .Pn show
568 after
569 .Pn show
570 was gone.
571 It is clear that such a rename may confuse future developers when
572 trying to understand the history.
573 Nevertheless, I consider the convenience on the user's side,
574 to outweigh the inconvenience for understanding the evolution
575 of the tools.
576 .P
577 To prepare for the transition,
578 .Pn mhshow
579 was reworked to behave more like
580 .Pn show
581 first (cf. Sec.
582 .Cf mhshow ).
583 Once the tools behaved more alike, the replacing appeared to be
584 even more natural.
585 Today, mmh's new
586 .Pn show
587 has become the one single message display program once again,
588 with the difference
589 that today it handles MIME messages as well as non-MIME messages.
590 The outcomes of the transition are one program less to maintain,
591 no second display program for users to deal with,
592 and less system complexity.
593 .P
594 Still, removing the old
595 .Pn show
596 hurts in one regard: It had been such a simple program.
597 Its lean elegance is missing from the new
598 .Pn show ,
599 but there is no alternative;
600 supporting MIME demands higher essential complexity.
604 .H2 "Configure Options
605 .P
606 Customization is a double-edged sword.
607 It allows better suiting setups, but not for free.
608 There is the cost of code complexity to be able to customize.
609 There is the cost of less tested setups, because there are
610 more possible setups and especially corner cases.
611 Steve Johnson confirms:
612 .[ [
613 eric raymond the art of unix programming
614 .], p. 233]
615 .QS
616 Unless it is done very carefully, the addition of an on/off
617 configuration option can lead to a need to double the amount of
618 testing. Since in practice one never does double the amount of testing,
619 the practical effect is to reduce the amount of testing that any
620 given configuration receives. Ten options leads to 1024 times as much
621 testing, and pretty soon you are talking real reliability problems.
622 .QE
623 .LP
624 Additionally, there is the cost of choice itself.
625 The code complexity directly affects the developers.
626 Less tested code affects both users and developers.
627 The problem of choice affects the users, for once by having to choose
628 but also by more complex interfaces that require more documentation.
629 Whenever options add few advantages but increase the complexity of the
630 system, they should be considered for removal.
631 I have reduced the number of project-specific configure options from
632 15 to 3.
634 .U3 "Mail Transfer Facilities
635 .P
636 With the removal of the mail transfer facilities (cf. Sec.
637 .Cf mail-transfer-facilities )
638 five configure options vanished:
639 .P
640 The switches
641 .Sw --with-tls
642 and
643 .Sw --with-cyrus-sasl
644 had activated the support for transfer encryption and authentication.
645 They are not needed anymore.
646 .Ci fecd5d34f65597a4dfa16aeabea7d74b191532c3
647 .Ci 156d35f6425bea4c1ed3c4c79783dc613379c65b
648 .P
649 The configure switch
650 .Sw --enable-pop
651 had activated the message retrieval facility.
652 Whereas the code area that had been conditionally compiled in
653 for TLS and SASL support was small,
654 the conditionally compiled code area for POP support was much larger.
655 The code base had only changed slightly on toggling TLS or SASL
656 support but it had changed much on toggling POP support.
657 The changes in the code base could hardly be overviewed.
658 By having POP support togglable, a second code base had been created,
659 one that needed to be tested.
660 This situation is basically similar for the conditional TLS and SASL
661 code, but there the changes are minor and can yet be overviewed.
662 Still, conditional compilation of a code base creates variations
663 of the original program.
664 More variations require more testing and maintenance work.
665 .P
666 Two other options had only specified default configuration values:
667 .Sw --with-mts
668 defined the default transport service
669 .Ci f6aa95b724fd8c791164abe7ee5468bf5c34f226 .
670 With
671 .Sw --with-smtpservers
672 default SMTP servers could be set
673 .Ci 128545e06224233b7e91fc4c83f8830252fe16c9 .
674 Both of them became irrelevant when the SMTP transport service was removed.
675 In mmh, all messages are handed over to
676 .Pn sendmail
677 for transportation.
680 .U3 "Backup Prefix
681 .P
682 The backup prefix is the string that was prepended to message
683 filenames to tag them as deleted.
684 By default it had been the comma character (`\fL,\fP').
685 In July 2000, Kimmo Suominen introduced
686 the configure option
687 .Sw --with-hash-backup
688 to change the default to the hash character `\f(CW#\fP'.
689 This choice was probably personal preference, but,
690 being related or not, words that start with the hash character
691 introduce a comment in the Unix shell.
692 Thus, the command line
693 .Cl "rm #13 #15
694 calls
695 .Pn rm
696 without arguments because the first hash character starts a comment
697 that reaches until the end of the line.
698 To delete the backup files,
699 .Cl "rm ./#13 ./#15"
700 needs to be used.
701 Thus, using the hash as backup prefix may be seen as a precaution
702 against backup loss.
703 .P
704 First, I removed the configure option but added the profile entry
705 .Pe Backup-Prefix ,
706 which allowed to specify an arbitrary string as backup prefix
707 .Ci 6c40d481d661d532dd527eaf34cebb6d3f8ed086 .
708 This change did not remove the choice but moved it to a location where
709 it suited better, in my eyes.
710 .P
711 Eventually however, the new trash folder concept
712 (cf. Sec.
713 .Cf trash-folder )
714 removed the need for the backup prefix completely.
715 .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173
716 .Ci ca0b3e830b86700d9e5e31b1784de2bdcaf58fc5
719 .U3 "Editor and Pager
720 .Id editor-pager
721 .P
722 The two configure options
723 .CW --with-editor=EDITOR
724 .CW --with-pager=PAGER
725 were used to specify the default editor and pager at configure time.
726 Doing so at configure time made sense in the eighties,
727 when the set of available editors and pagers varied much across
728 different systems.
729 Today, the situation is more homogeneous.
730 The programs
731 .Pn vi
732 and
733 .Pn more
734 can be expected to be available on every Unix system,
735 as they are specified by POSIX since two decades.
736 (The specifications for
737 .Pn vi
738 and
739 .Pn more
740 appeared in
741 .[
742 posix 1987
743 .]
744 and,
745 .[
746 posix 1992
747 .]
748 respectively.)
749 As a first step, these two tools were hard-coded as defaults
750 .Ci 5d43a99db70c12a673028c7758c20cbe3e13ef5f .
751 Not changed were the
752 .Pe editor
753 and
754 .Pe moreproc
755 profile entries, which allowed the user to override the system defaults.
756 Later, the concept was reworked again to respect the standard
757 environment variables
758 .Ev VISUAL
759 and
760 .Ev PAGER
761 if they are set.
762 Today, mmh determines the editor to use in the following order,
763 taking the first available and non-empty item
764 .Ci f85f4b7ae62e3d05a945dcd46ead51f0a2a89a9b :
765 .LI 1
766 Environment variable
767 .Ev MMHEDITOR
768 .LI 2
769 Profile entry
770 .Pe Editor
771 .LI 3
772 Environment variable
773 .Ev VISUAL
774 .LI 4
775 Environment variable
776 .Ev EDITOR
777 .LI 5
778 Command
779 .Pn vi .
780 .LP
781 The pager to use is determined in a similar order
782 .Ci 0c4214ea2aec6497d0d67b436bbee9bc1d225f1e :
783 .LI 1
784 Environment variable
785 .Ev MMHPAGER
786 .LI 2
787 Profile entry
788 .Pe Pager
789 (replaces
790 .Pe moreproc )
791 .LI 3
792 Environment variable
793 .Ev PAGER
794 .LI 4
795 Command
796 .Pn more .
797 .LP
798 By respecting the
799 .Ev VISUAL /\c
800 .Ev EDITOR
801 and
802 .Ev PAGER
803 environment variables,
804 the new behavior complies with the common style on Unix systems.
805 It is more uniform and clearer for users.
808 .U3 "ndbm
809 .P
810 .Pn slocal
811 used to depend on the database library
812 .I ndbm .
813 The database is used to store the
814 .Hd Message-ID
815 header field values of all messages delivered.
816 This enabled
817 .Pn slocal
818 to suppress delivering the same message to the same user twice.
819 This features was enabled by the
820 .Sw -suppressdup
821 switch.
822 .P
823 As a variety of versions of the database library exist,
824 .[
825 wolter unix incompat notes dbm
826 .]
827 complicated autoconf code was needed to detect them correctly.
828 Furthermore, the configure switches
829 .Sw --with-ndbm=ARG
830 and
831 .Sw --with-ndbmheader=ARG
832 were added to help with difficult setups that would
833 not be detected automatically or not correctly.
834 .P
835 By removing the suppress duplicates feature of
836 .Pn slocal ,
837 the dependency on
838 .I ndbm
839 vanished and 120 lines of complex autoconf code could be saved
840 .Ci ecd6d6a20cb7a1507e3a20d6c4cb3a1cf14c6bbf .
841 The change removed functionality but that is considered minor to the
842 improvement of dropping the dependency and the complex autoconf code.
845 .U3 "MH-E Support
846 .P
847 The configure option
848 .Sw --disable-mhe
849 was removed when the MH-E support was reworked.
850 MH-E is the Emacs front-end to MH.
851 It requires MH to provide minor additional functions.
852 The
853 .Sw --disable-mhe
854 configure option had switched off these extensions.
855 After removing the support for old versions of MH-E,
856 only the
857 .Sw -build
858 switches of
859 .Pn forw
860 and
861 .Pn repl
862 are left to be MH-E extensions.
863 They are now always built in because they add little code and complexity.
864 In consequence, the
865 .Sw --disable-mhe
866 configure option was removed
867 .Ci a7ce7b4a580d77b6c2c4d980812beb589aa4c643 .
868 Dropping the option also removed a variant of the code base
869 that would have needed to be tested.
870 This change was undertaken in January 2012 in nmh and
871 thereafter merged into mmh.
874 .U3 "Masquerading
875 .P
876 The configure option
877 .Sw --enable-masquerade
878 could take up to three arguments:
879 .Ar draft_from ,
880 .Ar mmailid ,
881 and
882 .Ar username_extension .
883 They activated different types of address masquerading.
884 All of them were implemented in the SMTP-speaking
885 .Pn post
886 command.
887 Address masquerading is an MTA's task and mmh does not cover
888 this field anymore.
889 Hence, true masquerading needs to be implemented in the external MTA.
890 .P
891 The
892 .I mmailid
893 masquerading type is the oldest one of the three and the only one
894 available in the original MH.
895 It provided a
896 .I username
897 to
898 .I fakeusername
899 mapping, based on the
900 .Fn passwd 's
901 GECOS field.
902 Nmh's man page
903 .Mp mh-tailor (5)
904 described the use case as being the following:
905 .QS
906 This is useful if you want the messages you send to always
907 appear to come from the name of an MTA alias rather than your
908 actual account name. For instance, many organizations set up
909 `First.Last' sendmail aliases for all users. If this is
910 the case, the GECOS field for each user should look like:
911 ``First [Middle] Last <First.Last>''
912 .QE
913 .P
914 As mmh sends outgoing mail via the local MTA only,
915 the best location to do such global rewrites is there.
916 Besides, the MTA is conceptionally the right location because it
917 does the reverse mapping for incoming mail (aliasing), too.
918 Furthermore, masquerading set up there is readily available for all
919 mail software on the system.
920 Hence, mmailid masquerading was removed.
921 .Ci 0836c8000ccb34b59410ef1c15b1b7feac70ce5f
922 .P
923 The
924 .I username_extension
925 masquerading type did not replace the username but would append a suffix,
926 specified by the
927 .Ev USERNAME_EXTENSION
928 environment variable, to it.
929 This provided support for the
930 .I user-extension
931 feature of qmail
932 .[ [
933 sill qmail handbook
934 .], p. 141]
935 and the similar
936 .I "plussed user
937 processing of Sendmail.
938 .[ [
939 sendmail costales
940 .], p. 476]
941 The decision to remove this username_extension masquerading
942 was motivated by the fact that
943 .Pn spost
944 had not supported it yet.
945 Username extensions can be used in mmh, but less convenient.
946 .\" XXX In the format file: %(getenv USERNAME_EXTENSION)
947 .Ci 2abae0bfd0ad5bf898461e50aa4b466d641f23d9
948 .P
949 The
950 .I draft_from
951 masquerading type instructed
952 .Pn post
953 to use the value of the
954 .Hd From
955 header field as SMTP envelope sender.
956 Sender addresses could be replaced completely.
957 Mmh offers a kind of masquerading similar in effect, but
958 with technical differences.
959 As mmh does not transfer messages itself, the local MTA has final control
960 over the sender's address.
961 Any masquerading mmh introduces may be reverted by the MTA.
962 In times of pedantic spam checking, an MTA will take care to use
963 sensible envelope sender addresses to keep its own reputation up.
964 Nonetheless, the MUA can set the
965 .Hd From
966 header field and thereby propose a sender address to the MTA.
967 The MTA may then decide to take that one or generate the canonical sender
968 address for use as envelope sender address.
969 .Ci b14ea6073f77b4359aaf3fddd0e105989db9
970 .P
971 In mmh, the MTA will always extract the recipient and sender from the
972 message header (\c
973 .Pn sendmail 's
974 .Sw -t
975 switch).
976 The
977 .Hd From
978 header field of the draft may be set arbitrary by the user.
979 If it is missing, the canonical sender address will be generated by the MTA.
981 .U3 "Remaining Options
982 .P
983 Two configure options remain in mmh.
984 One is the locking method to use:
985 .Sw --with-locking=[dot|fcntl|flock|lockf] .
986 The idea of removing all methods except the portable
987 .I "dot locking
988 and having that one as the default is appealing, but this change
989 requires deeper technical investigation into the topic.
990 The other option,
991 .Sw --enable-debug ,
992 compiles the programs with debugging symbols.
993 This option is likely to stay.
998 .H2 "Command Line Switches
999 .P
1000 The command line switches of MH tools are similar in style to the
1001 switches in the X Window System.
1002 They consist of a single dash (`\fL-\fP') followed by a word.
1003 For example
1004 .Cl -truncate .
1005 To ease typing, the word can be abbreviated, given the remaining
1006 prefix is unambiguous.
1007 If no other switch starts with the letter `t', then any of
1008 .Cl "-truncate" ,
1009 .Cl "-trunc" ,
1010 .Cl "-tr" ,
1011 and
1012 .Cl "-t
1013 is equal.
1014 As a result, switches can neither be grouped (as in
1015 .Cl "ls -ltr" )
1016 nor can switch arguments be appended directly to the switch (as in
1017 .Cl "sendmail -q30m" ).
1018 Many switches have negating counter-parts, which start with `no'.
1019 For example
1020 .Cl "-notruncate
1021 inverts the
1022 .Cl "-truncate
1023 switch.
1024 They exist to override the effect of default switches in the profile.
1025 Every program in mmh has two generic switches:
1026 .Sw -help ,
1027 to print a short message on how to use the program, and
1028 .Sw -Version
1029 (with capital `V'), to tell what version of mmh the program belongs to.
1030 .P
1031 Switches change the behavior of programs.
1032 Programs that do one thing in one way require no switches.
1033 In most cases, doing something in exactly one way is too limiting.
1034 If one task should be accomplished in various ways,
1035 switches are a good approach to alter the behavior of a program.
1036 Changing the behavior of programs provides flexibility and customization
1037 to users, but at the same time it complicates the code,
1038 the documentation, and the usage of the program.
1039 Therefore, the number of switches should be kept small.
1040 A small set of well-chosen switches is best.
1041 Usually, the number of switches increases over time.
1042 Already in 1985, Rose and Romine have identified this as a major
1043 problem of MH:
1044 .[ [
1045 rose romine real work
1046 .], p. 12]
1047 .QS
1048 A complaint often heard about systems which undergo substantial development
1049 by many people over a number of years, is that more and more options are
1050 introduced which add little to the functionality but greatly increase the
1051 amount of information a user needs to know in order to get useful work done.
1052 This is usually referred to as creeping featurism.
1053 .QP
1054 Unfortunately MH, having undergone six years of off-and-on development by
1055 ten or so well-meaning programmers (the present authors included),
1056 suffers mightily from this.
1057 .QE
1058 .P
1059 Being reluctant to adding new switches (or \fIoptions\fP,
1060 as Rose and Romine call them) is one part of a counter-action,
1061 the other part is removing hardly used switches.
1062 Nmh's tools have lots of switches already implemented.
1063 Hence, cleaning up by removing some of them was the more important part
1064 of the counter-action.
1065 Removing existing functionality is always difficult because it
1066 breaks programs that use these functions.
1067 Also, for every obsolete feature, there'll always be someone who still
1068 uses it and thus opposes its removal.
1069 This puts the developer into the position,
1070 where sensible improvements to style are regarded as destructive acts.
1071 Yet, living with the featurism is far worse, in my eyes, because
1072 future needs will demand adding further features,
1073 worsening the situation more and more.
1074 Rose and Romine added in a footnote,
1075 ``[...]
1076 .Pn send
1077 will no doubt acquire an endless number of switches in the years to come''
1078 .[ [
1079 rose romine real work
1080 .], p. 12].
1081 Although clearly humorous, the comment points to the nature of the problem.
1082 Refusing to add any new switches would encounter the problem at its root,
1083 but this is not practical.
1084 New needs will require new switches and it would be unwise to block
1085 them strictly.
1086 Nevertheless, removing obsolete switches still is an effective approach
1087 to deal with the problem.
1088 Working on an experimental branch without an established user base,
1089 eased my work because I did not offend users when I removed existing
1090 functions.
1091 .P
1092 Rose and Romine counted 24 visible and 9 more hidden switches for
1093 .Pn send .
1094 In nmh, they increased up to 32 visible and 12 hidden ones.
1095 At the time of writing, no more than 4 visible switches and 1 hidden switch
1096 have remained in mmh's
1097 .Pn send .
1098 These numbers include the two generic switches,
1099 .Sw -help
1100 and
1101 .Sw -Version .
1102 .P
1103 Hidden switches are ones not documented.
1104 In mmh, 12 tools have hidden switches.
1105 9 of them are
1106 .Sw -debug
1107 switches, the other 6 provide special interfaces for internal use.
1108 .P
1109 The following figure displays the number of switches for each of the tools
1110 that is available in both nmh and mmh.
1111 The tools are sorted by the number of switches they had in nmh.
1112 Both visible and hidden switches were counted,
1113 but not the generic help and version switches.
1114 Whereas in the beginning of the project, the average tool had 11 switches,
1115 now it has no more than 5 \(en only half as many.
1116 If the `no' switches and similar inverse variant are folded onto
1117 their counter-parts, the average tool had 8 switches in pre-mmh times and
1118 has 4 now.
1119 The total number of functional switches in mmh dropped from 465
1120 to 233.
1122 .KS
1123 .in 1c
1124 .so input/switches.grap
1125 .KE
1127 .P
1128 A part of the switches vanished after functions were removed.
1129 This was the case for network mail transfer, for instance.
1130 Sometimes, however, the work flow was the other way:
1131 I looked through the
1132 .Mp mh-chart (7)
1133 man page to identify the tools with apparently too many switches.
1134 Then I considered the benefit of each switch by examining
1135 the tool's man page and source code, aided by literature research
1136 and testing.
1139 .U3 "Draft Folder Facility
1140 .P
1141 A change early in the project was the complete transition from
1142 the single draft message to the draft folder facility
1143 .Ci 337338b404931f06f0db2119c9e145e8ca5a9860
1144 (cf. Sec.
1145 .Cf draft-folder ).
1146 The draft folder facility was introduced in the mid-eighties, when
1147 Rose and Romine called it a ``relatively new feature''.
1148 .[
1149 rose romine real work
1150 .]
1151 Since then, the facility was included, inactive by default.
1152 By making it permanently active and by related rework of the tools, the
1153 .Sw -[no]draftfolder ,
1154 and
1155 .Sw -draftmessage
1156 switches could be removed from
1157 .Pn comp ,
1158 .Pn repl ,
1159 .Pn forw ,
1160 .Pn dist ,
1161 .Pn whatnow ,
1162 and
1163 .Pn send
1164 .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 .
1165 The only flexibility lost with this change is having multiple
1166 draft folders within one profile.
1167 I consider this a theoretical problem only.
1168 At the same time, the
1169 .Sw -draft
1170 switch of
1171 .Pn anno ,
1172 .Pn refile ,
1173 and
1174 .Pn send
1175 was removed.
1176 The special treatment of \fIthe\fP draft message became irrelevant after
1177 the rework of the draft system
1178 (cf. Sec.
1179 .Cf draft-folder ).
1182 .U3 "In Place Editing
1183 .P
1184 .Pn anno
1185 had the switches
1186 .Sw -[no]inplace
1187 to either annotate the message in place and thus preserve hard links,
1188 or annotate a copy to replace the original message.
1189 The latter approach broke hard links.
1190 Following the assumption that linked messages should truly be the
1191 same message and annotating it should not break the link, the
1192 .Sw -[no]inplace
1193 switches were removed and the previous default
1194 .Sw -inplace
1195 was made the definitive behavior
1196 .Ci c8195849d2e366c569271abb0f5f60f4ebf0b4d0 .
1197 The
1198 .Sw -[no]inplace
1199 switches of
1200 .Pn repl ,
1201 .Pn forw ,
1202 and
1203 .Pn dist
1204 could be removed, as well, as they were simply passed through to
1205 .Pn anno .
1206 .P
1207 .Pn burst
1208 also had
1209 .Sw -[no]inplace
1210 switches, but with a different meaning.
1211 With
1212 .Sw -inplace ,
1213 the digest had been replaced by the table of contents (i.e. the
1214 introduction text) and the burst messages were placed right
1215 after this message, renumbering all following messages.
1216 Also, any trailing text of the digest was lost, though,
1217 in practice, it usually consists of an end-of-digest marker only.
1218 Nonetheless, this behavior appeared less elegant than the
1219 .Sw -noinplace
1220 behavior, which already had been the default.
1221 Nmh's
1222 .Mp burst (1)
1223 man page reads:
1224 .QS
1225 If
1226 .Sw -noinplace
1227 is given, each digest is preserved, no table
1228 of contents is produced, and the messages contained within
1229 the digest are placed at the end of the folder. Other messages
1230 are not tampered with in any way.
1231 .QE
1232 .LP
1233 The decision to drop the
1234 .Sw -inplace
1235 behavior was supported by the code complexity and the possible data loss
1236 it caused.
1237 .Sw -noinplace
1238 was chosen to be the definitive behavior.
1239 .Ci 68a686adeb39223a5e1ad35e4a24890ec053679d
1242 .U3 "Forms and Format Strings
1243 .P
1244 Historically, the tools that had
1245 .Sw -form
1246 switches to supply a form file had
1247 .Sw -format
1248 switches as well to supply the contents of a form file as a string
1249 on the command line directly.
1250 In consequence, the following two lines equaled:
1251 .VS
1252 scan -form scan.mailx
1253 scan -format "`cat /path/to/scan.mailx`"
1254 VE
1255 The
1256 .Sw -format
1257 switches were dropped in favor for extending the
1258 .Sw -form
1259 switches
1260 .Ci f51956be123db66b00138f80464d06f030dbb88d .
1261 If their argument starts with an equal sign (`\fL=\fP'),
1262 then the rest of the argument is taken as a format string,
1263 otherwise the arguments is treated as the name of a format file.
1264 Thus, now the following two lines equal:
1265 .VS
1266 scan -form scan.mailx
1267 scan -form "=`cat /path/to/scan.mailx`"
1268 VE
1269 This rework removed the prefix collision between
1270 .Sw -form
1271 and
1272 .Sw -format .
1273 Typing `\fL-fo\fP' is sufficient to specify form file or format string.
1274 .P
1275 The different meaning of
1276 .Sw -format
1277 for
1278 .Pn forw
1279 and
1280 .Pn repl
1281 was removed in mmh.
1282 .Pn forw
1283 was completely switched to MIME-type forwarding, thus removing the
1284 .Sw -[no]format
1285 .Ci 6e271608b7b9c23771523f88d23a4d3593010cf1 .
1286 For
1287 .Pn repl ,
1288 the
1289 .Sw -[no]format
1290 switches were reworked to
1291 .Sw -[no]filter
1292 switches
1293 .Ci 67411b1f95d6ec987b4c732459e1ba8a8ac192c6 .
1294 The
1295 .Sw -format
1296 switches of
1297 .Pn send
1298 and
1299 .Pn post ,
1300 which had a third meaning, were removed likewise
1301 .Ci f3cb7cde0e6f10451b6848678d95860d512224b9 .
1302 Eventually, the ambiguity of the
1303 .Sw -format
1304 switches is resolved by not having such switches anymore in mmh.
1307 .U3 "MIME Tools
1308 .P
1309 The MIME tools, which once were part of
1310 .Pn mhn
1311 (whatever that stood for),
1312 had several switches that added little practical value to the programs.
1313 The
1314 .Sw -[no]realsize
1315 switches of
1316 .Pn mhbuild
1317 and
1318 .Pn mhlist
1319 were removed
1320 .Ci 8d8f1c3abc586c005c904e52c4adbfe694d2201c .
1321 Real size calculations are done always now because nmh's
1322 .Mp mhbuild (1)
1323 man page states that
1324 ``This provides an accurate count at the expense of a small delay''
1325 with the small delay not being noticeable on modern systems.
1326 .P
1327 The
1328 .Sw -[no]check
1329 switches were removed together with the support for
1330 .Hd Content-MD5
1331 header fields [RFC\|1864]
1332 (cf. Sec.
1333 .Cf content-md5 )
1334 .Ci 31dc797eb5178970d68962ca8939da3fd9a8efda .
1335 .P
1336 The
1337 .Sw -[no]ebcdicsafe
1338 and
1339 .Sw -[no]rfc934mode
1340 switches of
1341 .Pn mhbuild
1342 were removed because they are considered obsolete
1343 .Ci 01a3480928da485b4d6109d36d751dfa71799d58
1344 .Ci 3363e2624dce0eb8164cf8b3f1ab385c8ff72e88 .
1345 .P
1346 Content caching of external MIME parts, activated with the
1347 .Sw -rcache
1348 and
1349 .Sw -wcache
1350 switches was completely removed
1351 .Ci d1fefd9f614e4dc3cda16da6c69133c1b2005269 .
1352 External MIME parts are rare today, having a caching facility
1353 for them appears to be unnecessary.
1354 .P
1355 In pre-MIME times,
1356 .Pn mhl
1357 had covered many tasks that are part of MIME handling today.
1358 Therefore,
1359 .Pn mhl
1360 could be simplified to a large extend, reducing the number of its
1361 switches from 21 to 6
1362 .Ci 350ad6d3542a07639213cf2a4fe524e829c1e7b6
1363 .Ci 0e46503be3c855bddaeae3843e1b659279c35d70 .
1368 .U3 "Header Printing
1369 .P
1370 .Pn folder 's
1371 data output is self-explaining enough that
1372 displaying the header line makes little sense.
1373 Hence, the
1374 .Sw -[no]header
1375 switch was removed and headers are never printed
1376 .Ci 601cc73d1fa05ce96faa728f036d6c51b91701c7 .
1377 .P
1378 In
1379 .Pn mhlist ,
1380 the
1381 .Sw -[no]header
1382 switches were removed, as well
1383 .Ci b24f96523aaf60e44e04a3ffb1d22e69a13a602f .
1384 In this case, the headers are printed always because the output
1385 is not self-explaining.
1386 .P
1387 .Pn scan
1388 also had
1389 .Sw -[no]header
1390 switches.
1391 Printing this header had been sensible until the introduction of
1392 format strings made it impossible to display column headings.
1393 Only the folder name and the current date remained to be printed.
1394 As this information can be perfectly generated with
1395 .Pn folder
1396 and
1397 .Pn date ,
1398 the switches were removed
1399 .Ci c477dc5d1d03fa6d9a8ab3dd3508c63cbddc044e .
1400 .P
1401 By removing all
1402 .Sw -header
1403 switches, the collision with
1404 .Sw -help
1405 on the first two letters was resolved.
1406 Currently,
1407 .Sw -h
1408 evaluates to
1409 .Sw -help
1410 for all tools of mmh.
1413 .U3 "Suppressing Edits or the Invocation of the WhatNow Shell
1414 .P
1415 The
1416 .Sw -noedit
1417 switch of
1418 .Pn comp ,
1419 .Pn repl ,
1420 .Pn forw ,
1421 .Pn dist ,
1422 and
1423 .Pn whatnow
1424 was removed and replaced by specifying
1425 .Sw -editor
1426 with an empty argument
1427 .Ci 75fca31a5b9d5c1a99c74ab14c94438d8852fba9 .
1428 (Specifying
1429 .Cl "-editor /bin/true
1430 is nearly the same. It differs only in setting the previous editor.)
1431 .P
1432 The more important change is the removal of the
1433 .Sw -nowhatnowproc
1434 switch
1435 .Ci ee4f43cf2ef0084ec698e4e87159a94c01940622 .
1436 This switch had once introduced an awkward behavior,
1437 as explained in nmh's man page for
1438 .Mp comp (1):
1439 .QS
1440 The
1441 .Sw -editor
1442 .Ar editor
1443 switch indicates the editor to use for
1444 the initial edit. Upon exiting from the editor,
1445 .Pn comp
1446 will invoke the
1447 .Pn whatnow
1448 program. See
1449 .Mp whatnow (1)
1450 for a discussion of available options.
1451 The invocation of this program can be
1452 inhibited by using the
1453 .Sw -nowhatnowproc
1454 switch. (In truth of fact, it is the
1455 .Pn whatnow
1456 program which starts the initial edit.
1457 Hence,
1458 .Sw -nowhatnowproc
1459 will prevent any edit from occurring.)
1460 .QE
1461 .P
1462 Effectively, the
1463 .Sw -nowhatnowproc
1464 switch caused only only a draft message to be created.
1465 As
1466 .Cl "-whatnowproc /bin/true
1467 does the same, the
1468 .Sw -nowhatnowproc
1469 switch was removed for being redundant.
1473 .U3 "Various
1474 .BU
1475 With the removal of MMDF maildrop format support,
1476 .Pn packf
1477 and
1478 .Pn rcvpack
1479 no longer needed their
1480 .Sw -mbox
1481 and
1482 .Sw -mmdf
1483 switches.
1484 The behavior of
1485 .Sw -mbox
1486 is the sole behavior now
1487 .Ci 3916ab66ad5d183705ac12357621ea8661afd3c0 .
1488 Further rework in both tools made the
1489 .Sw -file
1490 switch unnecessary
1491 .Ci ca1023716d4c2ab890696f3e41fa0d94267a940e .
1493 .BU
1494 Mmh's tools do no longer clear the screen (\c
1495 .Pn scan 's
1496 and
1497 .Pn mhl 's
1498 .Sw -[no]clear
1499 switches
1500 .Ci e57b17343dcb3ff373ef4dd089fbe778f0c7c270
1501 .Ci 943765e7ac5693ae177fd8d2b5a2440e53ce816e ).
1502 Neither does
1503 .Pn mhl
1504 ring the bell (\c
1505 .Sw -[no]bell
1506 .Ci e11983f44e59d8de236affa5b0d0d3067c192e24 )
1507 nor does it page the output itself (\c
1508 .Sw -length
1509 .Ci 5b9d883db0318ed2b84bb82dee880d7381f99188 ).
1510 Generally, the pager to use is no longer specified with the
1511 .Sw -[no]moreproc
1512 command line switches for
1513 .Pn mhl
1514 and
1515 .Pn show /\c
1516 .Pn mhshow
1517 .Ci 39e87a75b5c2d3572ec72e717720b44af291e88a .
1519 .BU
1520 In order to avoid prefix collisions among switch names, the
1521 .Sw -version
1522 switch was renamed to
1523 .Sw -Version
1524 (with capital `V')
1525 .Ci 32b2354dbaf4bf934936eb5b102a4a3d2fdd209a .
1526 Every program has the
1527 .Sw -version
1528 switch but its first three letters collided with the
1529 .Sw -verbose
1530 switch, present in many programs.
1531 The rename solved this problem once for all.
1532 Although this rename breaks a basic interface, having the
1533 .Sw -V
1534 abbreviation to display the version information, isn't all too bad.
1536 .BU
1537 .Sw -[no]preserve
1538 of
1539 .Pn refile
1540 was removed
1541 .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173
1542 because what use was it anyway?
1543 Quoting nmh's man page
1544 .Mp refile (1):
1545 .QS
1546 Normally when a message is refiled, for each destination
1547 folder it is assigned the number which is one above the current
1548 highest message number in that folder. Use of the
1549 .Sw -preserv
1550 [sic!] switch will override this message renaming, and try
1551 to preserve the number of the message. If a conflict for a
1552 particular folder occurs when using the
1553 .Sw -preserve
1554 switch, then
1555 .Pn refile
1556 will use the next available message number which
1557 is above the message number you wish to preserve.
1558 .QE
1560 .BU
1561 The removal of the
1562 .Sw -[no]reverse
1563 switches of
1564 .Pn scan
1565 .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173
1566 is a bug fix.
1567 This is supported by the comments
1568 ``\-[no]reverse under #ifdef BERK (I really HATE this)''
1569 by Rose and
1570 ``Lists messages in reverse order with the `\-reverse' switch.
1571 This should be considered a bug'' by Romine in the changelogs.
1572 The question remains why neither Rose nor Romine have fixed this
1573 bug in the eighties when they wrote these comments.
1581 .\" --------------------------------------------------------------
1582 .H1 "Modernizing
1583 .P
1584 In the more than thirty years of MH's existence, its code base was
1585 increasingly extended.
1586 New features entered the project and became alternatives to the
1587 existing behavior.
1588 Relics from several decades have gathered in the code base
1589 but seldom obsolete features were dropped.
1590 This section describes the removing of old code
1591 and the modernizing of the default setup.
1592 It focuses on the functional aspect only;
1593 the non-functional aspects of code style are discussed in Sec.
1594 .Cf code-style .
1597 .H2 "Code Relics
1598 .P
1599 My position regarding the removal of obsolete code
1600 is much more revolutional than the nmh community appreciates.
1601 Working on an experimental version, I was able to quickly drop
1602 functionality that I considered ancient.
1603 The need for consensus with peers would have slowed this process down.
1604 Without the need to justify my decisions, I was able to rush forward.
1605 .P
1606 In December 2011, Paul Vixie motivated the nmh developers to just
1607 do the work:
1608 .[
1609 paul vixie edginess nmh-workers
1610 .]
1611 .QS
1612 let's stop walking on egg shells with this code base. there's no need to
1613 discuss whether to keep using vfork, just note in [sic!] passing, [...]
1614 we don't need a separate branch for removing vmh
1615 or ridding ourselves of #ifdef's or removing posix replacement functions
1616 or depending on pure ansi/posix ``libc''.
1617 .QP
1618 these things should each be a day or two of work and the ``main branch''
1619 should just be modern. [...]
1620 let's push forward, aggressively.
1621 .QE
1622 .LP
1623 I did so already in the months before.
1624 I pushed forward.
1625 I simply dropped the cruft.
1626 .P
1627 The decision to drop a feature was based on literature research and
1628 careful thinking, but whether having had contact with this particular
1629 feature within my own computer life served as a rule of thumb.
1630 I explained my reasons in the commit messages
1631 in the version control system.
1632 Hence, others can comprehend my view and argue for undoing the change
1633 if I have missed an important aspect.
1634 I was quick in dropping parts.
1635 I rather include falsely dropped parts again, than going at a slower pace.
1636 Mmh is experimental work; it requires tough decisions.
1639 .U3 "Process Forking
1640 .P
1641 Being a tool chest, MH creates many processes.
1642 In earlier times
1643 .Fu fork()
1644 had been an expensive system call, because the process's image needed
1645 to be completely duplicated at once.
1646 This expensive work was especially unnecessary in the commonly occurring
1647 case wherein the image is replaced by a call to
1648 .Fu exec()
1649 right after having forked the child process.
1650 The
1651 .Fu vfork()
1652 system call was invented to speed up this particular case.
1653 It completely omits the duplication of the image.
1654 On old systems this resulted in significant speed ups.
1655 Therefore MH used
1656 .Fu vfork()
1657 whenever possible.
1658 .P
1659 Modern memory management units support copy-on-write semantics, which make
1660 .Fu fork()
1661 almost as fast as
1662 .Fu vfork() .
1663 The man page of
1664 .Mp vfork (2)
1665 in FreeBSD 8.0 states:
1666 .QS
1667 This system call will be eliminated when proper system sharing mechanisms
1668 are implemented. Users should not depend on the memory sharing semantics
1669 of vfork() as it will, in that case, be made synonymous to fork(2).
1670 .QE
1671 .LP
1672 Vixie supports the removal with the note that ``the last
1673 system on which fork was so slow that an mh user would notice it, was
1674 Eunice. that was 1987''.
1675 .[
1676 nmh-workers vixie edginess
1677 .]
1678 I replaced all calls to
1679 .Fu vfork()
1680 with calls to
1681 .Fu fork()
1682 .Ci 40821f5c1316e9205a08375e7075909cc9968e7d .
1683 .P
1684 Related to the costs of
1685 .Fu fork()
1686 is the probability of its success.
1687 In the eighties, on heavy loaded systems, calls to
1688 .Fu fork()
1689 were prone to failure.
1690 Hence, many of the
1691 .Fu fork()
1692 calls in the code were wrapped into loops to retry the
1693 .Fu fork()
1694 several times, to increase the chances to succeed eventually.
1695 On modern systems, a failing
1696 .Fu fork()
1697 call is unusual.
1698 Hence, in the rare case when
1699 .Fu fork()
1700 fails, mmh programs simply abort
1701 .Ci 5fbf37ee68e018998ada61eeab73e035b26834b6 .
1704 .U3 "Header Fields
1705 .BU
1706 The
1707 .Hd Encrypted
1708 header field was introduced by RFC\|822,
1709 but already marked as legacy in RFC\|2822.
1710 Today, OpenPGP provides the basis for standardized exchange of encrypted
1711 messages [RFC\|4880, RFC\|3156].
1712 Hence, the support for
1713 .Hd Encrypted
1714 header fields is removed in mmh
1715 .Ci 064527f7b57ab050e5af13e15ad99aeeab125857 .
1716 .BU
1717 The native support for
1718 .Hd Face
1719 header fields has been removed, as well
1720 .Ci 8e5be81f784682822f5e868c1bf3c8624682bd23 .
1721 This feature is similar to the
1722 .Hd X-Face
1723 header field in its intent,
1724 but takes a different approach to store the image.
1725 Instead of encoding the image data directly into the header field,
1726 it contains the hostname and UDP port where the image
1727 date can be retrieved.
1728 There is even a third Face system,
1729 which is the successor of
1730 .Hd X-Face ,
1731 although it re-uses the
1732 .Hd Face
1733 header field name.
1734 It was invented in 2005 and supports colored PNG images.
1735 None of the Face systems described here is popular today.
1736 Hence, mmh has no direct support for them.
1737 .BU
1738 .Id content-md5
1739 The
1740 .Hd Content-MD5
1741 header field was introduced by RFC\|1864.
1742 It provides detection of data corruption during the transfer.
1743 But it can not ensure verbatim end-to-end delivery of the contents
1744 [RFC\|1864].
1745 The proper approach to verify content integrity in an
1746 end-to-end relationship is the use of digital signatures [RFC\|4880].
1747 On the other hand, transfer protocols should detect corruption during
1748 the transmission.
1749 The TCP includes a checksum field therefore.
1750 These two approaches in combinations render the
1751 .Hd Content-MD5
1752 header field superfluous.
1753 Not a single one out of 4\|200 messages from two decades
1754 in the nmh-workers mailing list archive
1755 .[
1756 nmh-workers mailing list archive website
1757 .]
1758 contains a
1759 .Hd Content-MD5
1760 header field.
1761 Neither did any of the 60\|000 messages in my personal mail storage.
1762 Removing the support for this header field
1763 .Ci 31dc797eb5178970d68962ca8939da3fd9a8efda ,
1764 removed the last place where MD5 computation was needed.
1765 Hence, the MD5 code could be removed as well.
1766 Over 500 lines of code vanished by this one change.
1769 .U3 "MMDF maildrop support
1770 .P
1771 This type of maildrop format is conceptionally similar to the mbox format,
1772 but uses a different message delimiter (`\fL\\1\\1\\1\\1\fP',
1773 commonly written as `\fL^A^A^A^A\fP', instead of `\fLFrom\0\fP').
1774 Mbox is the de-facto standard maildrop format on Unix,
1775 whereas the MMDF maildrop format is now forgotten.
1776 Mbox remains as the only packed mailbox format, supported in mmh.
1777 .P
1778 The simplifications within the code were moderate.
1779 Mainly, the reading and writing of MMDF mailbox files was removed.
1780 But also, switches of
1781 .Pn packf
1782 and
1783 .Pn rcvpack
1784 could be removed
1785 .Ci 3916ab66ad5d183705ac12357621ea8661afd3c0 .
1786 In the message parsing function
1787 .Fn sbr/m_getfld.c ,
1788 knowledge of MMDF packed mail boxes was removed
1789 .Ci 684ec30d81e1223a282764452f4902ed4ad1c754 .
1790 Further code structure simplifications may be possible there,
1791 because only one single packed mailbox format is left to be supported.
1792 I have not worked on them yet because
1793 .Fu m_getfld()
1794 is heavily optimized and thus dangerous to touch.
1795 The risk of damaging the intricate workings of the optimized code is
1796 too high.
1799 .U3 "Prompter's Control Keys
1800 .P
1801 The program
1802 .Pn prompter
1803 queries the user to fill in a message form.
1804 When used as
1805 .Cl "comp -editor prompter" ,
1806 the resulting behavior is similar to
1807 .Pn mailx .
1808 Apparently,
1809 .Pn prompter
1810 had not been touched lately.
1811 Otherwise it's hardly explainable why it
1812 still offered the switches
1813 .Sw -erase
1814 .Ar chr
1815 and
1816 .Sw -kill
1817 .Ar chr
1818 to name the characters for command line editing.
1819 The times when this had been necessary are long time gone.
1820 Today these things work out-of-the-box, and if not, are configured
1821 with the standard tool
1822 .Pn stty .
1823 The switches are removed now
1824 .Ci 0bd9750710cdbab80cfb4036dd87af20afe1552f .
1827 .U3 "Hardcopy Terminal Support
1828 .P
1829 More of a funny anecdote is a check for being connected to a
1830 hardcopy terminal.
1831 It remained in the code until spring 2012, when I finally removed it
1832 .Ci b7764c4a6b71d37918a97594d866258f154017ca .
1833 .P
1834 The check only prevented a pager to be placed between the printing
1835 program (\c
1836 .Pn mhl )
1837 and the terminal.
1838 In nmh, this could have been ensured statically with the
1839 .Sw -nomoreproc
1840 at the command line, too.
1841 In mmh, setting the profile entry
1842 .Pe Pager
1843 or the environment variable
1844 .Ev PAGER
1845 to
1846 .Pn cat
1847 is sufficient.
1852 .H2 "Attachments
1853 .P
1854 The mind model of email attachments is unrelated to MIME.
1855 Although the MIME RFCs [RFC\|2045\(en2049] define the technical
1856 requirements for having attachments, they do not mention the term.
1857 Instead of attachments, MIME talks about ``multi-part message bodies''
1858 [RFC\|2045], a more general concept.
1859 Multi-part messages are messages
1860 ``in which one or more different
1861 sets of data are combined in a single body''
1862 [RFC\|2046].
1863 MIME keeps its descriptions generic;
1864 it does not imply specific usage models.
1865 Today, one usage model is prevalent: attachments.
1866 The idea is having a main text document with files of arbitrary kind
1867 attached to it.
1868 In MIME terms, this is a multi-part message having a text part first
1869 and parts of arbitrary type following.
1870 .P
1871 MH's MIME support is a direct implementation of the RFCs.
1872 The perception of the topic described in the RFCs is clearly visible
1873 in MH's implementation.
1874 As a result,
1875 MH had all the MIME features but no idea of attachments.
1876 But users do not need all the MIME features,
1877 they want convenient attachment handling.
1880 .U3 "Composing MIME Messages
1881 .P
1882 In order to improve the situation on the message composing side,
1883 Jon Steinhart had added an attachment system to nmh in 2002
1884 .Ci 7480dbc14bc90f2d872d434205c0784704213252 .
1885 In the file
1886 .Fn docs/README-ATTACHMENTS ,
1887 he described his motivation to do so:
1888 .QS
1889 Although nmh contains the necessary functionality for MIME message
1890 handing [sic!], the interface to this functionality is pretty obtuse.
1891 There's no way that I'm ever going to convince my partner to write
1892 .Pn mhbuild
1893 composition files!
1894 .QE
1895 .LP
1896 With this change, the mind model of attachments entered nmh.
1897 In the same document:
1898 .QS
1899 These changes simplify the task of managing attachments on draft files.
1900 They allow attachments to be added, listed, and deleted.
1901 MIME messages are automatically created when drafts with attachments
1902 are sent.
1903 .QE
1904 .LP
1905 Unfortunately, the attachment system, like every new facilities in nmh,
1906 was inactive by default.
1907 .P
1908 During my time in Argentina, I tried to improve the attachment system.
1909 But, after long discussions my patch died as a proposal on the
1910 mailing list because of great opposition in the nmh community.
1911 .[
1912 nmh-workers attachment proposal
1913 .]
1914 In January 2012, I extended the patch and applied it to mmh
1915 .Ci 8ff284ff9167eff8f5349481529332d59ed913b1 .
1916 In mmh, the attachment system is active by default.
1917 Instead of command line switches, the
1918 .Pe Attachment-Header
1919 profile entry is used to specify
1920 the name of the attachment header field.
1921 It is pre-defined to
1922 .Hd Attach .
1923 .P
1924 To add an attachment to a draft, a header line needs to be added:
1925 .VS
1926 To: bob
1927 Subject: The file you wanted
1928 Attach: /path/to/the/file-bob-wanted
1929 --------
1930 Here it is.
1931 VE
1932 The header field can be added to the draft manually in the editor,
1933 or by using the `attach' command at the WhatNow prompt, or
1934 non-interactively with
1935 .Pn anno :
1936 .VS
1937 anno -append -nodate -component Attach -text /path/to/attachment
1938 VE
1939 Drafts with attachment headers are converted to MIME automatically by
1940 .Pn send .
1941 The conversion to MIME is invisible to the user.
1942 The draft stored in the draft folder is always in source form with
1943 attachment headers.
1944 If the MIMEification fails (e.g. because the file to attach
1945 is not accessible) the original draft is not changed.
1946 .P
1947 The attachment system handles the forwarding of messages, too.
1948 If the attachment header value starts with a plus character (`\fL+\fP'),
1949 like in
1950 .Cl "Attach: +bob 30 42" ,
1951 the given messages in the specified folder will be attached.
1952 This allowed to simplify
1953 .Pn forw
1954 .Ci f41f04cf4ceca7355232cf7413e59afafccc9550 .
1955 .P
1956 Closely related to attachments is non-ASCII text content,
1957 because it requires MIME as well.
1958 In nmh, the user needed to call `mime' at the WhatNow prompt
1959 to have the draft converted to MIME.
1960 This was necessary whenever the draft contained non-ASCII characters.
1961 If the user did not call `mime', a broken message would be sent.
1962 Therefore, the
1963 .Pe automimeproc
1964 profile entry could be specified to have the `mime' command invoked
1965 automatically each time.
1966 Unfortunately, this approach conflicted with the attachment system
1967 because the draft would already be in MIME format at the time
1968 when the attachment system wanted to MIMEify it.
1969 To use nmh's attachment system, `mime' must not be called at the
1970 WhatNow prompt and
1971 .Pe automimeproc
1972 must not be set in the profile.
1973 But then the case of non-ASCII text without attachment headers was
1974 not caught.
1975 All in all, the solution was complex and irritating.
1976 My patch from December 2010
1977 .[
1978 nmh-workers attachment proposal
1979 .]
1980 would have simplified the situation.
1981 .P
1982 Mmh's current solution is even more elaborate.
1983 Any necessary MIMEification is done automatically.
1984 There is no `mime' command at the WhatNow prompt anymore.
1985 The draft will be converted automatically to MIME when either an
1986 attachment header or non-ASCII text is present.
1987 Furthermore, the hash character (`\fL#\fP') is not special any more
1988 at line beginnings in the draft message.
1989 Users need not concern themselves with the whole topic at all.
1990 .P
1991 Although the new approach does not anymore support arbitrary MIME
1992 compositions directly, the full power of
1993 .Pn mhbuild
1994 can still be accessed.
1995 Given no attachment headers are included, users can create
1996 .Pn mhbuild
1997 composition drafts like in nmh.
1998 Then, at the WhatNow prompt, they can invoke
1999 .Cl "edit mhbuild
2000 to convert the draft to MIME.
2001 Because the resulting draft neither contains non-ASCII characters
2002 nor has it attachment headers, the attachment system will not touch it.
2003 .P
2004 The approach taken in mmh is tailored towards today's most common case:
2005 a text part, possibly with attachments.
2006 This case was simplified.
2009 .U3 "MIME Type Guessing
2010 .P
2011 From the programmer's point of view, the use of
2012 .Pn mhbuild
2013 composition drafts had one notable advantage over attachment headers:
2014 The user provides the appropriate MIME types for files to include.
2015 The new attachment system needs to find out the correct MIME type itself.
2016 This is a difficult task.
2017 Determining the correct MIME type of content is partly mechanical,
2018 partly intelligent work.
2019 Forcing the user to find out the correct MIME type,
2020 forces him to do partly mechanical work.
2021 Letting the computer do the work can lead to bad choices for difficult
2022 content.
2023 For mmh, the latter option was chosen to spare the user the work
2024 .Ci 3baec236a39c5c89a9bda8dbd988d643a21decc6 .
2025 .P
2026 Determining the MIME type by the suffix of the file name is a dumb
2027 approach, yet it is simple to implement and provides good results
2028 for the common cases.
2029 If no MIME type can be determined, text content is sent as `text/plain',
2030 anything else under the generic fall-back type `application/octet-stream'.
2031 Mmh implements this approach in the
2032 .Pn print-mimetype
2033 script
2034 .Ci 4b5944268ea0da7bb30598a27857304758ea9b44 .
2035 .P
2036 A far better, though less portable, approach is the use of
2037 .Pn file .
2038 This standard tool tries to determine the type of files.
2039 Unfortunately, its capabilities and accuracy varies from system to system.
2040 Additionally, its output was only intended for human beings,
2041 but not to be used by programs.
2042 Nevertheless, modern versions of GNU
2043 .Pn file ,
2044 which are prevalent on the popular GNU/Linux systems,
2045 provide MIME type output in machine-readable form.
2046 Although this solution is system-dependent,
2047 it solves the difficult problem well.
2048 On systems where GNU
2049 .Pn file ,
2050 version 5.04 or higher, is available it should be used.
2051 One needs to specify the following profile entry to do so:
2052 .VS
2053 Mime-Type-Query: file -b --mime
2054 VE
2055 .LP
2056 Other versions of
2057 .Pn file
2058 might possibly be usable with wrapper scripts that reformat the output.
2059 The diversity among
2060 .Pn file
2061 implementations is great; one needs to check the local variant.
2062 .P
2063 It is not possible in mmh to override the automatic MIME type guessing
2064 for a specific file.
2065 To do so, either the user would need to know in advance for which file
2066 the automatic guessing fails or the system would require interaction.
2067 I consider both cases impractical.
2068 The existing solution should be sufficient.
2069 If not, the user may always fall back to
2070 .Pn mhbuild
2071 composition drafts and bypass the attachment system.
2074 .U3 "Storing Attachments
2075 .P
2076 Extracting MIME parts of a message and storing them to disk is performed by
2077 .Pn mhstore .
2078 The program has two operation modes,
2079 .Sw -auto
2080 and
2081 .Sw -noauto .
2082 With the former one, each part is stored under the filename given in the
2083 MIME part's meta information, if available.
2084 This naming information is usually available for modern attachments.
2085 If no filename is available, this MIME part is stored as if
2086 .Sw -noauto
2087 would have been specified.
2088 In the
2089 .Sw -noauto
2090 mode, the parts are processed according to rules, defined by
2091 .Pe mhstore-store-*
2092 profile entries.
2093 These rules define generic filename templates for storing
2094 or commands to post-process the contents in arbitrary ways.
2095 If no matching rule is available the part is stored under a generic
2096 filename, built from message number, MIME part number, and MIME type.
2097 .P
2098 The
2099 .Sw -noauto
2100 mode had been the default in nmh because it was considered safe,
2101 in contrast to the
2102 .Sw -auto
2103 mode.
2104 In mmh,
2105 .Sw -auto
2106 is not dangerous anymore.
2107 Two changes were necessary:
2108 .LI 1
2109 Any directory path is removed from the proposed filename.
2110 Thus, the files are always stored in the expected directory.
2111 .Ci 41b6eadbcecf63c9a66aa5e582011987494abefb
2112 .LI 2
2113 Tar files are not extracted automatically any more.
2114 Thus, the rest of the file system will not be touched.
2115 .Ci 94c80042eae3383c812d9552089953f9846b1bb6
2116 .P
2117 In mmh, the result of
2118 .Cl "mhstore -auto
2119 can be foreseen from the output of
2120 .Cl "mhlist -verbose" .
2121 Although the
2122 .Sw -noauto
2123 mode is considered to be more powerful, it is less convenient and
2124 .Sw -auto
2125 is safe now.
2126 Additionally, storing attachments under their original name
2127 is intuitive.
2128 Hence,
2129 .Sw -auto
2130 serves better as the default option
2131 .Ci 3410b680416c49a7617491af38bc1929855a331d .
2132 .P
2133 Files are stored into the directory given by the
2134 .Pe Nmh-Storage
2135 profile entry, if set, or
2136 into the current working directory, otherwise.
2137 Storing to different directories is only possible with
2138 .Pe mhstore-store-*
2139 profile entries.
2140 .P
2141 Still existing files get overwritten silently in both modes.
2142 This can be considered a bug.
2143 Yet, each other behavior has its draw-backs, too.
2144 Refusing to replace files requires adding a
2145 .Sw -force
2146 switch.
2147 Users will likely need to invoke
2148 .Pn mhstore
2149 a second time with
2150 .Sw -force .
2151 Eventually, only the user can decide in the specific case.
2152 This requires interaction, which I like to avoid if possible.
2153 Appending a unique suffix to the filename is another bad option.
2154 For now, the behavior remains as it is.
2155 .P
2156 In mmh, only MIME parts of type message are special in
2157 .Pn mhstore 's
2158 .Sw -auto
2159 mode.
2160 Instead of storing message/rfc822 parts as files to disk,
2161 they are stored as messages into the current mail folder.
2162 The same applies to message/partial, although the parts are
2163 automatically reassembled beforehand.
2164 MIME parts of type message/external-body are not automatically retrieved
2165 anymore.
2166 Instead, information on how to retrieve them is output.
2167 Not supporting this rare case saved nearly one thousand lines of code
2168 .Ci 55e1d8c654ee0f7c45b9361ce34617983b454c32 .
2169 The MIME type `application/octet-stream; type=tar' is not special anymore.
2170 The automatically extracting of such MIME parts had been the
2171 dangerous part of the
2172 .Sw -auto
2173 mode
2174 .Ci 94c80042eae3383c812d9552089953f9846b1bb6 .
2178 .U3 "Showing MIME Messages
2179 .Id showing-mime-msgs
2180 .P
2181 The program
2182 .Pn mhshow
2183 was written to display MIME messages.
2184 It implemented the conceptional view of the MIME RFCs.
2185 Nmh's
2186 .Pn mhshow
2187 handles each MIME part independently, presenting them separately
2188 to the user.
2189 This does not match today's understanding of email attachments,
2190 where displaying a message is seen to be a single, integrated operation.
2191 Today, email messages are expected to consist of a main text part
2192 plus possibly attachments.
2193 They are no more seen to be arbitrary MIME hierarchies with
2194 information on how to display the individual parts.
2195 I adjusted
2196 .Pn mhshow 's
2197 behavior to the modern view on the topic.
2198 .P
2199 One should note that this section completely ignores the original
2200 .Pn show
2201 program, because it was not capable to display MIME messages
2202 and is no longer part of mmh
2203 (cf. Sec.
2204 .Cf mhshow ).
2205 Although
2206 .Pn mhshow
2207 was renamed to
2208 .Pn show
2209 in mmh, this section uses the name
2210 .Pn mhshow ,
2211 in order to avoid confusion.
2212 .P
2213 In mmh, the basic idea is that
2214 .Pn mhshow
2215 should display a message in one single pager session.
2216 Therefore,
2217 .Pn mhshow
2218 invokes a pager session for all its output,
2219 whenever it prints to a terminal
2220 .Ci a4197ea6ffc5c1550e8b52d5a654bcaaaee04a4e .
2221 In consequence,
2222 .Pn mhl
2223 does no more invoke a pager
2224 .Ci 0e46503be3c855bddaeae3843e1b659279c35d70 .
2225 With
2226 .Pn mhshow
2227 replacing the original
2228 .Pn show ,
2229 the output of
2230 .Pn mhl
2231 no longer goes to the terminal directly, but through
2232 .Pn mhshow .
2233 Hence,
2234 .Pn mhl
2235 does not need to invoke a pager.
2236 The one and only job of
2237 .Pn mhl
2238 is to format messages or parts of them.
2239 The only place in mmh, where a pager is invoked is
2240 .Pn mhshow .
2241 .P
2242 Only text content is displayed.
2243 Other kinds of attachments are ignored.
2244 Non-text content needs to be converted to text by appropriate
2245 .Pe mhshow-show-*
2246 profile entries before, if this is possible and wanted.
2247 A common example for this are PDF files.
2248 .P
2249 MIME parts are always displayed serially.
2250 The request to display the MIME type `multipart/parallel' in parallel
2251 is ignored.
2252 It is simply treated as `multipart/mixed'
2253 .Ci d0581ba306a7299113a346f9b4c46ce97bc4cef6 .
2254 This was already possible to requested with the, now removed,
2255 .Sw -serialonly
2256 switch of
2257 .Pn mhshow .
2258 As MIME parts are always processed exclusively, i.e. serially,
2259 the `\fL%e\fP' escape in
2260 .Pe mhshow-show-*
2261 profile entries became useless and was thus removed
2262 .Ci a20d405db09b7ccca74d3e8c57550883da49e1ae .
2263 For parallel display, the attachments need to be stored to disk first.
2264 .P
2265 To display text content in foreign charsets, they need to be converted
2266 to the native charset.
2267 Therefore,
2268 .Pe mhshow-charset-*
2269 profile entries were needed.
2270 In mmh, the conversion is performed automatically by piping the
2271 text through the
2272 .Pn iconv
2273 command, if necessary
2274 .Ci 2433122c20baccb10b70b49c04c6b0497b5b3b60 .
2275 Custom
2276 .Pe mhshow-show-*
2277 rules for textual content might need a
2278 .Cl "iconv -f %c %f |
2279 prefix to have the text converted to the native charset.
2280 .P
2281 Although the conversion of foreign charsets to the native one
2282 has improved, it is not consistent enough.
2283 Further work needs to be done and
2284 the basic concepts in this field need to be re-thought.
2285 Though, the default setup of mmh displays message in foreign charsets
2286 correctly without the need to configure anything.
2289 .ig
2291 .P
2292 mhshow/mhstore: Removed support for retrieving message/external-body parts.
2293 These tools will not download the contents automatically anymore. Instead,
2294 they print the information needed to get the contents. If someone should
2295 really receive one of those rare message/external-body messages, he can
2296 do the job manually. We save nearly a thousand lines of code. That's worth
2297 it!
2298 (The profile entry `nmh-access-ftp' and sbr/ruserpass.c for reading
2299 ~/.netrc are gone now.)
2300 .Ci 55e1d8c654ee0f7c45b9361ce34617983b454c32
2302 ..
2306 .H2 "Signing and Encrypting
2307 .P
2308 Nmh offers no direct support for digital signatures and message encryption.
2309 This functionality needed to be added through third-party software.
2310 In mmh, the functionality is included because it
2311 is a part of modern email and is likely wanted by users of mmh.
2312 A fresh mmh installation supports signing and encrypting
2313 out-of-the-box.
2314 Therefore, Neil Rickert's
2315 .Pn mhsign
2316 and
2317 .Pn mhpgp
2318 scripts
2319 .[
2320 neil rickert mhsign mhpgp
2321 .]
2322 were included
2323 .Ci f45cdc98117a84f071759462c7ae212f4bc5ab2e
2324 .Ci 58cf09aa36e9f7f352a127158bbf1c5678bc6ed8 .
2325 The scripts fit well because they are lightweight and
2326 similar of style to the existing tools.
2327 Additionally, no licensing difficulties appeared
2328 as they are part of the public domain.
2329 .P
2330 .Pn mhsign
2331 handles the signing and encrypting part.
2332 It comprises about 250 lines of shell code and interfaces between
2333 .Pn gnupg
2334 and the MH system.
2335 It was meant to be invoked manually at the WhatNow prompt, but in mmh,
2336 .Pn send
2337 invokes
2338 .Pn mhsign
2339 automatically
2340 .Ci c7b5e1df086bcc37ff40163ee67571f076cf6683 .
2341 Special header fields were introduced to request this action.
2342 If a draft contains the
2343 .Hd Sign
2344 header field,
2345 .Pn send
2346 will initiate the signing.
2347 The signing key is either chosen automatically or it is specified by the
2348 .Pe Pgpkey
2349 profile entry.
2350 .Pn send
2351 always create signatures using the PGP/MIME standard [RFC\|4880],
2352 but by invoking
2353 .Pn mhsign
2354 manually, old-style non-MIME signatures can be created as well.
2355 To encrypt an outgoing message, the draft needs to contain an
2356 .Hd Enc
2357 header field.
2358 Public keys of all recipients are searched for in the gnupg keyring and
2359 in a file called
2360 .Fn pgpkeys ,
2361 which contains exceptions and overrides.
2362 Unless public keys are found for all recipients,
2363 .Pn mhsign
2364 will refuse to encrypt it.
2365 Currently, messages with hidden (BCC) recipients can not be encrypted.
2366 This work is pending because it requires a structurally more complex
2367 approach.
2368 .P
2369 .Pn mhpgp
2370 is the companion to
2371 .Pn mhsign .
2372 It verifies signatures and decrypts messages.
2373 Encrypted messages can be either temporarily decrypted and displayed
2374 or permanently decrypted and stored into the current folder.
2375 Currently,
2376 .Pn mhpgp
2377 needs to be invoked manually.
2378 The integration into
2379 .Pn show
2380 and
2381 .Pn mhstore
2382 to verify signatures and decrypt messages as needed
2383 is planned but not yet realized.
2384 .P
2385 Both scripts were written for nmh.
2386 Hence they needed to be adjust
2387 according to the differences between nmh and mmh.
2388 For instance, they use the backup prefix no longer.
2389 Furthermore, compatibility support for old PGP features was dropped.
2390 .P
2391 The integrated message signing and encrypting support is one of the
2392 most recent features in mmh.
2393 It has not had the time to mature.
2394 User feedback and personal experience need to be accumulated to
2395 direct the further development of the facility.
2396 Already it seems to be worthwhile to consider adding
2397 .Sw -[no]sign
2398 and
2399 .Sw -[no]enc
2400 switches to
2401 .Pn send ,
2402 to be able to override the corresponding header fields.
2403 A profile entry:
2404 .VS
2405 send: -sign
2406 VE
2407 would then activate signing for all outgoing messages.
2408 With the present approach, a
2409 .Hd Send
2410 header component needs to be added to each draft template
2411 to achieve the same result.
2412 Adding the switches would ease the work greatly and keep the
2413 template files clean.
2418 .H2 "Draft and Trash Folder
2419 .P
2421 .U3 "Draft Folder
2422 .Id draft-folder
2423 .P
2424 In the beginning, MH had the concept of a draft message.
2425 This was a file named
2426 .Fn draft
2427 in the MH directory, which was treated special.
2428 On composing a message, this draft file was used.
2429 When starting to compose another message before the former one was sent,
2430 the user had to decide among:
2431 .LI 1
2432 Using the old draft to finish and send it before starting with a new one.
2433 .LI 2
2434 Discarding the old draft and replacing it with a new one.
2435 .LI 3
2436 Preserving the old draft by refiling it to a folder.
2437 .LP
2438 Working on multiple drafts was only possible in alternation.
2439 For that, the current draft needed to be refiled to a folder and
2440 another one re-used for editing.
2441 Working on multiple drafts at the same time was impossible.
2442 The usual approach of switching to a different MH context did not
2443 help anything.
2444 .P
2445 The draft folder facility exists to
2446 allow true parallel editing of drafts, in a straight forward way.
2447 It was introduced by Marshall T. Rose, already in 1984.
2448 Similar to other new features, the draft folder was inactive by default.
2449 Even in nmh, the highly useful draft folder was not available
2450 out-of-the-box.
2451 At least, Richard Coleman added the man page
2452 .Mp mh-draft (5)
2453 to better document the feature.
2454 .P
2455 Not using the draft folder facility has the single advantage of having
2456 the draft file at a static location.
2457 This is simple in simple cases but the concept does not scale for more
2458 complex cases.
2459 The concept of the draft message is too limited for the problem
2460 it tries to solve.
2461 Therefore the draft folder was introduced.
2462 It is the more powerful and more natural concept.
2463 The draft folder is a folder like any other folder in MH.
2464 Its messages can be listed like any other messages.
2465 A draft message is no longer a special case.
2466 Tools do not need special switches to work on the draft message.
2467 Hence corner cases were removed.
2468 .P
2469 The trivial part of the work was activating the draft folder with a
2470 default name.
2471 I chose the name
2472 .Fn +drafts ,
2473 for obvious reasons.
2474 In consequence, the command line switches
2475 .Sw -draftfolder
2476 and
2477 .Sw -draftmessage
2478 could be removed.
2479 More difficult but also more improving was updating the tools to the
2480 new concept.
2481 For nearly three decades, the tools needed to support two draft handling
2482 approaches.
2483 By fully switching to the draft folder, the tools could be
2484 simplified by dropping the awkward draft message handling code.
2485 .Sw -draft
2486 switches were removed because operating on a draft message is no longer
2487 special.
2488 It became indistinguishable to operating on any other message.
2489 .Ci 337338b404931f06f0db2119c9e145e8ca5a9860
2490 .P
2491 There is no more need to query the user for draft handling
2492 .Ci 2d48b455c303a807041c35e4248955f8bec59eeb .
2493 It is always possible to add another new draft.
2494 Refiling drafts is without difference to refiling other messages.
2495 All of these special cases are gone.
2496 Yet, one draft-related switch remained.
2497 .Pn comp
2498 still has
2499 .Sw -[no]use
2500 for switching between two modes:
2501 .LI 1
2502 Modifying an existing draft, with
2503 .Sw -use .
2504 .LI 2
2505 Composing a new draft, possibly taking some existing message as template,
2506 with
2507 .Sw -nouse ,
2508 the default.
2509 .LP
2510 In either case, the behavior of
2511 .Pn comp
2512 is deterministic.
2513 .P
2514 .Pn send
2515 now operates on the current message in the draft folder by default.
2516 As message and folder can both be overridden by specifying them on
2517 the command line, it is possible to send any message in the mail storage
2518 by simply specifying its number and folder.
2519 In contrast to the other tools,
2520 .Pn send
2521 takes the draft folder as its default folder.
2522 .P
2523 Dropping the draft message concept in favor for the draft folder concept,
2524 replaced special cases with regular cases.
2525 This simplified the source code of the tools, as well as the concepts.
2526 In mmh, draft management does not break with the MH concepts
2527 but applies them.
2528 .Cl "scan +drafts" ,
2529 for instance, is a truly natural request.
2530 .P
2531 Most of the work was already performed by Rose in the eighties.
2532 The original improvement of mmh is dropping the old draft message approach
2533 and thus simplifying the tools, the documentation,
2534 and the system as a whole.
2535 Although my part in the draft handling improvement was small,
2536 it was important.
2539 .U3 "Trash Folder
2540 .Id trash-folder
2541 .P
2542 Similar to the situation for drafts is the situation for removed messages.
2543 Historically, a message was ``deleted'' by prepending a specific
2544 \fIbackup prefix\fP, usually the comma character,
2545 to the file name.
2546 The specific file would then be ignored by MH because only files with
2547 names consisting of digits only are treated as messages.
2548 Although files remained in the file system,
2549 the messages were no longer visible in MH.
2550 To truly delete them, a maintenance job was needed.
2551 Usually a cron job was installed to delete them after a grace time.
2552 For instance:
2553 .VS
2554 find $HOME/Mail -type f -name ',*' -ctime +7 -delete
2555 VE
2556 In such a setup, the original message could be restored
2557 within the grace time interval by stripping the
2558 backup prefix from the file name \(en usually but not always.
2559 If the last message of a folder with six messages (\fL1-6\fP) was removed,
2560 message
2561 .Fn 6 ,
2562 became file
2563 .Fn ,6 .
2564 If then a new message entered the same folder, it would be named with
2565 the number one above the highest existing message number.
2566 In this case the message would be named
2567 .Fn 6 ,
2568 reusing the number.
2569 If this new message would be removed as well,
2570 then the backup of the former message becomes overwritten.
2571 Hence, the ability to restore removed messages did not only depend on
2572 the sweeping cron job but also on the removing of further messages.
2573 It is undesirable to have such obscure and complex mechanisms.
2574 The user should be given a small set of clear assertions, such as
2575 ``Removed files are restorable within a seven-day grace time.''
2576 With the addition ``... unless a message with the same name in the
2577 same folder is removed before.'' the statement becomes complex.
2578 A user will hardly be able to keep track of all removals to know
2579 if the assertion still holds true for a specific file.
2580 In practice, the real mechanism is unclear to the user.
2581 .P
2582 Furthermore, the backup files were scattered within the whole mail storage.
2583 This complicated managing them.
2584 It was possible with the help of
2585 .Pn find ,
2586 but everything is more convenient
2587 if the deleted messages are collected in one place.
2588 .P
2589 The profile entry
2590 .Pe rmmproc
2591 (previously named
2592 .Pe Delete-Prog )
2593 was introduced very early to improve the situation.
2594 It could be set to any command, which would be executed to remove
2595 the specified messages.
2596 This had overridden the default action, described above.
2597 Refiling the to-be-removed files to a trash folder was the usual example.
2598 Nmh's man page
2599 .Mp rmm (1)
2600 proposes to set the
2601 .Pe rmmproc
2602 to
2603 .Cl "refile +d
2604 to move messages to the trash folder
2605 .Fn +d
2606 instead of renaming them with the backup prefix.
2607 The man page additionally proposes the expunge command
2608 .Cl "rm `mhpath +d all`
2609 to empty the trash folder.
2610 .P
2611 Removing messages in such a way has advantages:
2612 .LI 1
2613 The mail storage is prevented from being cluttered with removed messages
2614 because they are all collected in one place.
2615 Existing and removed messages are thus separated more strictly.
2616 .LI 2
2617 No backup files are silently overwritten.
2618 .LI 3
2619 Most important, however, removed messages are kept in the MH domain.
2620 Messages in the trash folder can be listed like those in any other folder.
2621 Deleted messages can be displayed like any other messages.
2622 .Pn refile
2623 can restore deleted messages.
2624 All operations on deleted files are still covered by the MH tools.
2625 The trash folder is just like any other folder in the mail storage.
2626 .P
2627 Similar to the draft folder case, I dropped the old backup prefix approach
2628 in favor for replacing it by the better suiting trash folder system.
2629 Hence,
2630 .Pn rmm
2631 calls
2632 .Pn refile
2633 to move the to-be-removed message to the trash folder,
2634 .Fn +trash
2635 by default.
2636 To sweep it clean, the user can use
2637 .Cl "rmm -unlink +trash a" ,
2638 where the
2639 .Sw -unlink
2640 switch causes the files to be unlinked.
2641 .Ci 8edc5aaf86f9f77124664f6801bc6c6cdf258173
2642 .Ci ca0b3e830b86700d9e5e31b1784de2bdcaf58fc5
2643 .P
2644 Dropping the legacy approach and converting to the new approach
2645 completely, simplified the code base.
2646 The relationship between
2647 .Pn rmm
2648 and
2649 .Pn refile
2650 was inverted.
2651 In mmh,
2652 .Pn rmm
2653 invokes
2654 .Pn refile .
2655 That used to be the other way round.
2656 Yet, the relationship is simpler now.
2657 Loops, like described in nmh's man page for
2658 .Mp refile (1),
2659 can no longer occur:
2660 .QS
2661 Since
2662 .Pn refile
2663 uses your
2664 .Pe rmmproc
2665 to delete the message, the
2666 .Pe rmmproc
2667 must NOT call
2668 .Pn refile
2669 without specifying
2670 .Sw -normmproc
2671 or you will create an infinite loop.
2672 .QE
2673 .LP
2674 .Pn rmm
2675 either unlinks a message with
2676 .Fu unlink()
2677 or invokes
2678 .Pn refile
2679 to move it to the trash folder.
2680 .Pn refile
2681 does not invoke any tools.
2682 .P
2683 By generalizing the message removal in the way that it became covered
2684 by the MH concepts made the whole system more powerful.
2690 .H2 "Modern Defaults
2691 .P
2692 Nmh has a bunch of convenience-improving features inactive by default,
2693 although one can expect every new user to want them active.
2694 The reason they are inactive by default is the wish to stay compatible
2695 with old versions.
2696 But what are old versions?
2697 Still, the highly useful draft folder facility has not been activated
2698 by default although it was introduced over twenty-five years ago.
2699 .[
2700 rose romine real work
2701 .]
2702 The community seems not to care.
2703 .P
2704 In nmh, new users are required to first build up
2705 a profile before they can access the modern features.
2706 Without an extensive profile, the setup is hardly usable
2707 for modern emailing.
2708 The point is not the customization of the setup,
2709 but the need to activate generally useful facilities.
2710 Yet, the real problem lies less in enabling the features,
2711 as this is straight forward as soon as one knows what he wants.
2712 The real problem is that new users need deep insight into the project
2713 to discover the available but inactive features.
2714 To give an example, I needed one year of using nmh
2715 before I became aware of the existence of the attachment system.
2716 One could argue that this fact disqualifies my reading of the
2717 documentation.
2718 If I would have installed nmh from source back then, I could agree.
2719 Yet, I had used a pre-packaged version and had expected that it would
2720 just work.
2721 Nevertheless, I had been convinced by the concepts of MH already
2722 and I am a software developer,
2723 still I required a lot of time to discover the cool features.
2724 How can we expect users to be even more advanced than me,
2725 just to enable them to use MH in a convenient and modern way?
2726 Unless they are strongly convinced of the concepts, they will fail.
2727 I have seen friends of me giving up disappointed
2728 before they truly used the system,
2729 although they had been motivated in the beginning.
2730 New users suffer hard enough to get used to the tool chest approach,
2731 we developers should spare them further inconveniences.
2732 .P
2733 Maintaining compatibility for its own sake is bad,
2734 because the code base will collect more and more compatibility code.
2735 Sticking to the compatibility code means remaining limited;
2736 whereas adjusting to the changes renders the compatibility unnecessary.
2737 Keeping unused alternatives in the code for longer than a short
2738 grace time is a bad choice as they likely
2739 gather bugs by not being constantly tested.
2740 Also, the increased code size and the greater number of conditions
2741 increase the maintenance costs.
2742 If any MH implementation would be the back-end of widespread
2743 email clients with large user bases, compatibility would be more
2744 important.
2745 Yet, it appears as if this is not the case.
2746 Hence, compatibility is hardly important for technical reasons.
2747 Its importance originates from personal reasons rather.
2748 Nmh's user base is small and old.
2749 Changing the interfaces causes inconvenience to long-term users of MH.
2750 It forces them to change their many years old MH configurations.
2751 I do understand this aspect, but by sticking to the old users,
2752 new users are kept from entering the world of MH.
2753 But the future lies in new users.
2754 In consequence, mmh invites new users by providing a convenient
2755 and modern setup, readily usable out-of-the-box.
2756 .P
2757 In mmh, all modern features are active by default and many previous
2758 approaches are removed or only accessible in a manual way.
2759 New default features include:
2760 .BU
2761 The attachment system (\c
2762 .Hd Attach )
2763 .Ci 8ff284ff9167eff8f5349481529332d59ed913b1 .
2764 .BU
2765 The draft folder facility (\c
2766 .Fn +drafts )
2767 .Ci 337338b404931f06f0db2119c9e145e8ca5a9860 .
2768 .BU
2769 The unseen sequence (`u')
2770 .Ci c2360569e1d8d3678e294eb7c1354cb8bf7501c1
2771 and the sequence negation prefix (`!')
2772 .Ci db74c2bd004b2dc9bf8086a6d8bf773ac051f3cc .
2773 .BU
2774 Quoting the original message in the reply
2775 .Ci 67411b1f95d6ec987b4c732459e1ba8a8ac192c6 .
2776 .BU
2777 Forwarding messages using MIME
2778 .Ci 6e271608b7b9c23771523f88d23a4d3593010cf1 .
2779 .LP
2780 An mmh setup with a profile that defines only the path to the
2781 mail storage, is already convenient to use.
2782 Again, Paul Vixie's supports the direction I took:
2783 ``the `main branch' should just be modern''.
2784 .[
2785 paul vixie edginess nmh-workers
2786 .]
2792 .\" --------------------------------------------------------------
2793 .H1 "Styling
2794 .P
2795 Kernighan and Pike have emphasized the importance of style in the
2796 preface of \fPThe Practice of Programming\fP:
2797 .[ [
2798 kernighan pike practice of programming
2799 .], p. x]
2800 .QS
2801 Chapter 1 discusses programming style.
2802 Good style is so important to good programming that we have chosen
2803 to cover it first.
2804 .QE
2805 This section covers changes in mmh that were guided by the desire
2806 to improve on style.
2807 Many of them follow the advice given in the quoted book.
2812 .H2 "Code Style
2813 .Id code-style
2814 .P
2815 .U3 "Indentation Style
2816 .P
2817 Indentation styles are the holy cow of programming.
2818 Kernighan and Pike write:
2819 .[ [
2820 kernighan pike practice of programming
2821 .], p. 10]
2822 .QS
2823 Programmers have always argued about the layout of programs,
2824 but the specific style is much less important than its consistent
2825 application.
2826 Pick one style, preferably ours, use it consistently, and don't waste
2827 time arguing.
2828 .QE
2829 .P
2830 I agree that the constant application is most important,
2831 but I believe that some styles have advantages over others.
2832 For instance the indentation with tab characters only.
2833 The number of tabs corresponds to the nesting level \(en
2834 one tab, one level.
2835 Tab characters provide flexible visual appearance because developers
2836 can adjust their width as preferred.
2837 There is no more need to check for the correct mixture of
2838 tabs and spaces.
2839 Two simple rules ensure the integrity and flexibility of the visual
2840 appearance:
2841 .LI 1
2842 Leading whitespace must consist of tabs only.
2843 .LI 2
2844 All other whitespace should be spaces.
2845 .LP
2846 Although reformatting existing code should be avoided, I did it.
2847 I did not waste time arguing; I just reformatted the code.
2848 .Ci a485ed478abbd599d8c9aab48934e7a26733ecb1
2850 .U3 "Comments
2851 .P
2852 Kernighan and Pike demand: ``Don't belabor the obvious''.
2853 .[ [
2854 kernighan pike practice of programming
2855 .], p. 23]
2856 Following the advice, I removed unnecessary comments.
2857 For instance, I removed all comments in the following code excerpt
2858 .Ci 426543622b377fc5d091455cba685e114b6df674 :
2859 .VS
2860 context_replace(curfolder, folder); /* update current folder */
2861 seq_setcur(mp, mp->lowsel); /* update current message */
2862 seq_save(mp); /* synchronize message sequences */
2863 folder_free(mp); /* free folder/message structure */
2864 context_save(); /* save the context file */
2866 [...]
2868 int c; /* current character */
2869 char *cp; /* miscellaneous character pointer */
2871 [...]
2873 /* NUL-terminate the field */
2874 *cp = '\0';
2875 VE
2876 .P
2877 The information in each of the comments was present in the code
2878 statements already, except for the NUL-termination, which became
2879 obvious from the context.
2882 .U3 "Names
2883 .P
2884 Regarding this topic, Kernighan and Pike suggest:
2885 ``Use active names for functions''.
2886 .[ [
2887 kernighan pike practice of programming
2888 .], p. 4]
2889 One application of this rule was the rename of
2890 .Fu check_charset()
2891 to
2892 .Fu is_native_charset()
2893 .Ci 8d77b48284c58c135a6b2787e721597346ab056d .
2894 The same change additionally fixed a violation of ``Be accurate'',
2895 .[ [
2896 kernighan pike practice of programming
2897 .], p. 4]
2898 as the code did not match the expectation the function suggested.
2899 It did not compare charset names but prefixes of them only.
2900 In case the native charset was `ISO-8859-1', then
2901 .VS
2902 check_charset("ISO-8859-11", strlen("ISO-8859-11"))
2903 VE
2904 had returned true although the upper halves of the code pages
2905 are different.
2906 .P
2907 More important than using active names is using descriptive names.
2908 .VS
2909 m_unknown(in); /* the MAGIC invocation... */
2910 VE
2911 Renaming the obscure
2912 .Fu m_unknown()
2913 function was a delightful event, although it made the code less funny
2914 .Ci 611d68d19204d7cbf5bd585391249cb5bafca846 .
2915 .P
2916 Magic numbers are generally considered bad style.
2917 Obviously, Kernighan and Pike agree:
2918 ``Give names to magic numbers''.
2919 .[ [
2920 kernighan pike practice of programming
2921 .], p. 19]
2922 .P
2923 The argument
2924 .CW outnum
2925 of the function
2926 .Fu scan()
2927 in
2928 .Fn uip/scansbr.c
2929 holds the number of the message to be created.
2930 As well it encodes program logic with negative numbers and zero.
2931 This led to obscure code.
2932 I clarified the code by introducing two variables that extracted
2933 the hidden information:
2934 .VS
2935 int incing = (outnum > 0);
2936 int ismbox = (outnum != 0);
2937 VE
2938 The readable names are thus used in conditions;
2939 the variable
2940 .CW outnum
2941 is used only to extract ordinary message numbers
2942 .Ci b8b075c77be7794f3ae9ff0e8cedb12b48fd139f .
2943 .P
2944 Through the clarity improvement of the change detours in the program
2945 logic of related code parts became apparent.
2946 The implementation was simplified.
2947 This possibility to improve had been invisible before
2948 .Ci aa60b0ab5e804f8befa890c0a6df0e3143ce0723 .
2949 .P
2950 The names just described were a first step, yet the situation
2951 was further improved by giving names to the magic values of
2952 .CW outnum :
2953 .VS
2954 #define SCN_MBOX (-1)
2955 #define SCN_FOLD 0
2956 VE
2957 The two variables were updated thereafter as well:
2958 .VS
2959 int incing = (outnum != SCN_MBOX && outnum != SCN_FOLD);
2960 int scanfolder = (outnum == SCN_FOLD);
2961 VE
2962 Furthermore,
2963 .CW ismbox
2964 was replaced by
2965 .CW scanfolder
2966 because that matched better to the program logic.
2967 .Ci 7ffb36d28e517a6f3a10272056fc127592ab1c19
2972 .H2 "Structural Rework
2973 .P
2974 Although the stylistic changes described already improve the
2975 readability of the source code, all of them were changes ``in the small''.
2976 Structural changes, in contrast, affect much larger code areas.
2977 They are more difficult to accomplish but lead to larger improvements,
2978 especially as they often influence the outer shape of the tools as well.
2979 .P
2980 At the end of their chapter on style,
2981 Kernighan and Pike ask: ``But why worry about style?''
2982 .[ [
2983 kernighan pike practice of programming
2984 .], p. 28].
2985 Following are two examples of structural rework that demonstrate
2986 why style is important in the first place.
2989 .U3 "Rework of \f(CWanno\fP
2990 .P
2991 Until 2002,
2992 .Pn anno
2993 had six functional command line switches:
2994 .Sw -component
2995 and
2996 .Sw -text ,
2997 each with an argument,
2998 and the two pairs of flags,
2999 .Sw -[no]date
3000 and
3001 .Sw -[no]inplace .
3002 Then Jon Steinhart introduced his attachment system.
3003 In need for more advanced annotation handling, he extended
3004 .Pn anno .
3005 He added five more switches:
3006 .Sw -draft ,
3007 .Sw -list ,
3008 .Sw -delete ,
3009 .Sw -append ,
3010 and
3011 .Sw -number ,
3012 the last one taking an argument
3013 .Ci 7480dbc14bc90f2d872d434205c0784704213252 .
3014 Later,
3015 .Sw -[no]preserve
3016 was added as well
3017 .Ci d9b1d57351d104d7ec1a5621f090657dcce8cb7f .
3018 Then, the Synopsis section of the man page
3019 .Mp anno (1)
3020 read:
3021 .VS
3022 anno [+folder] [msgs] [-component f(CIfieldfP] [-inplace | -noinplace]
3023 [-date | -nodate] [-draft] [-append] [-list] [-delete]
3024 [-number [f(CInumfP|fPallfP]] [-preserve | -nopreserve] [-version]
3025 [-help] [-text f(CIbodyfP]
3026 VE
3027 .LP
3028 The implementation followed the same structure.
3029 Problems became visible when
3030 .Cl "anno -list -number 42
3031 worked on the current message instead of on message number 42,
3032 and
3033 .Cl "anno -list -number l:5
3034 did not work on the last five messages but failed with the mysterious
3035 error message: ``anno: missing argument to -list''.
3036 Yet, the invocation matched the specification in the man page.
3037 There, the correct use of
3038 .Sw -number
3039 was defined as being
3040 .Cl "[-number [num|all]]
3041 and the textual description for the combination with
3042 .Sw -list
3043 read:
3044 .QS
3045 The
3046 .Sw -list
3047 option produces a listing of the field bodies for
3048 header fields with names matching the specified component,
3049 one per line. The listing is numbered, starting at 1, if the
3050 .Sw -number
3051 option is also used.
3052 .QE
3053 .LP
3054 The problem was manifold.
3055 Semantically, the argument to the
3056 .Sw -number
3057 switch is only necessary in combination with
3058 .Sw -delete ,
3059 but not with
3060 .Sw -list .
3061 The code, however, required a numeric argument in any case.
3062 If the argument was missing or non-numeric,
3063 .Pn anno
3064 aborted with an error message that additionally had an off-by-one error.
3065 It printed the name of the switch one before the concerned one.
3066 .P
3067 Trying to fix these problems on the surface would not have solved them.
3068 They originate from a discrepance between the
3069 structure of the problem and the structure implemented in the program.
3070 Such structural differences can only be solved by adjusting the
3071 structure of the implementation to the structure of the problem.
3072 .P
3073 Steinhart had added the new
3074 .Sw -list
3075 and
3076 .Sw -delete
3077 switches in a style similar to the other switches though
3078 they are of structural different type.
3079 Semantically,
3080 .Sw -list
3081 and
3082 .Sw -delete
3083 introduce operation modes.
3084 Historically,
3085 .Pn anno
3086 had only one operation mode: adding header fields.
3087 With the extension, two more modes were added:
3088 listing and deleting header fields.
3089 The structure of the code changes did not pay respect to this
3090 fundamental change.
3091 Neither the implementation nor the documentation did clearly
3092 declare the exclusive operation modes as such.
3093 Having identified the problem, I solved it by putting structure into
3094 .Pn anno
3095 and its documentation
3096 .Ci d54c8db8bdf01e8381890f7729bc0ef4a055ea11 .
3097 .P
3098 The difference is visible in both the code and the documentation.
3099 For instance in the following code excerpt:
3100 .VS
3101 int delete = -2; /* delete header element if set */
3102 int list = 0; /* list header elements if set */
3103 [...]
3104 case DELETESW: /* delete annotations */
3105 delete = 0;
3106 continue;
3107 case LISTSW: /* produce a listing */
3108 list = 1;
3109 continue;
3110 VE
3111 .LP
3112 which was replaced by:
3113 .VS
3114 static enum { MODE_ADD, MODE_DEL, MODE_LIST } mode = MODE_ADD;
3115 [...]
3116 case DELETESW: /* delete annotations */
3117 mode = MODE_DEL;
3118 continue;
3119 case LISTSW: /* produce a listing */
3120 mode = MODE_LIST;
3121 continue;
3122 VE
3123 .LP
3124 The replacement code does not only reflect the problem's structure better,
3125 it is easier to understand as well.
3126 The same applies to the documentation.
3127 The man page was completely reorganized to propagate the same structure.
3128 This is already visible in the Synopsis section:
3129 .VS
3130 anno [+folder] [msgs] [-component f(CIfieldfP] [-text fPbodyfP]
3131 [-append] [-date | -nodate] [-preserve | -nopreserve]
3132 [-Version] [-help]
3134 anno -delete [+folder] [msgs] [-component fPfieldfP] [-text
3135 fPbodyfP] [-number fPnum fP| fPall fP] [-preserve | -nopreserve]
3136 [-Version] [-help]
3138 anno -list [+folder] [msgs] [-component fPfieldfP] [-number]
3139 [-Version] [-help]
3140 VE
3144 .U3 "Path Conversion
3145 .P
3146 Four kinds of path names can appear in MH:
3147 .LI 1
3148 Absolute Unix directory paths, like
3149 .Fn /etc/passwd .
3150 .LI 2
3151 Relative Unix directory paths, like
3152 .Fn ./foo/bar .
3153 .LI 3
3154 Absolute MH folder paths, like
3155 .Fn +projects/mmh .
3156 .LI 4
3157 Relative MH folder paths, like
3158 .Fn @subfolder .
3159 .LP
3160 Relative MH folder paths, are hardly documented
3161 although they are useful for large mail storages.
3162 The current mail folder is specified as `\c
3163 .Fn @ ',
3164 just like the current directory is specified as `\c
3165 .Fn . '.
3166 .P
3167 To allow MH tools to understand all four notations,
3168 they need to be able to convert between them.
3169 In nmh, these path name conversion functions were located in the files
3170 .Fn sbr/path.c
3171 (``return a pathname'') and
3172 .Fn sbr/m_maildir.c
3173 (``get the path for the mail directory'').
3174 The seven functions in the two files were documented with no more
3175 than two comments, which described obvious information.
3176 The signatures of the four exported functions did not explain their
3177 semantics:
3178 .LI 1
3179 .CW "char *path(char *, int);
3180 .LI 2
3181 .CW "char *pluspath(char *);
3182 .LI 3
3183 .CW "char *m_mailpath(char *);
3184 .LI 4
3185 .CW "char *m_maildir(char *);
3186 .P
3187 My investigations provided the following descriptions:
3188 .LI 1
3189 The second parameter of
3190 .Fu path()
3191 defines the type as which the path given in the first parameter should
3192 be treated.
3193 Directory paths are converted to absolute directory paths.
3194 Folder paths are converted to absolute folder paths.
3195 Folder paths must not include a leading `\fL@\fP' character.
3196 Leading plus characters are preserved.
3197 The result is a pointer to newly allocated memory.
3198 .LI 2
3199 .Fu pluspath()
3200 is a convenience-wrapper to
3201 .Fu path() ,
3202 to convert folder paths only.
3203 This function can not be used for directory paths.
3204 An empty string parameter causes a buffer overflow.
3205 .LI 3
3206 .Fu m_mailpath()
3207 converts directory paths to absolute directory paths.
3208 The characters `\fL+\fP' or `\fL@\fP' at the beginning of the path name are
3209 treated literal, i.e. as the first character of a relative directory path.
3210 Hence, this function can not be used for folder paths.
3211 In any case, the result is an absolute directory path,
3212 returned as a pointer to newly allocated memory.
3213 .LI 4
3214 .Fu m_maildir()
3215 returns the parameter unchanged if it is an absolute directory path
3216 or begins with the entry `\fL.\fP' or `\fL..\fP'.
3217 All other strings are prepended with the current working directory.
3218 Hence, this function can not be used for folder paths.
3219 The result is either an absolute directory path or a relative
3220 directory path, starting with dot or dot-dot.
3221 In contrast to the other functions, the result is a pointer to
3222 static memory.
3223 .P
3224 The situation was obscure, irritating, error-prone, and non-orthogonal.
3225 Additionally, no clear terminology was used to name the different
3226 kinds of path names.
3227 Sometimes, the names were even misleading, much as the first argument of
3228 .Fu m_mailpath() ,
3229 which was named
3230 .CW folder ,
3231 although
3232 .Fu m_mailpath()
3233 could not be used with MH folder arguments.
3234 .P
3235 I clarified the path name conversion by complete rework.
3236 First of all, the terminology needed to be defined.
3237 A path name is either in the Unix domain, then it is called
3238 \fIdirectory path\fP or it is in the MH domain,
3239 then it is called \fIfolder path\fP.
3240 The two terms need to be used with strict distinction.
3241 Second, I exploited the concept of path type indicators.
3242 By requiring every path name to start with a distinct type identifier,
3243 the conversion between the types could be fully automated.
3244 This allows the tools to accept path names of any type from the user.
3245 Therefore, it was necessary to require relative directory paths to be
3246 prefixed with a dot character.
3247 In consequence, the dot character could no longer be an alias for the
3248 current message
3249 .Ci cff0e16925e7edbd25b8b9d6d4fbdf03e0e60c01 .
3250 Third, I created three new functions to replace the previous mess:
3251 .LI 1
3252 .Fu expandfol()
3253 converts folder paths to absolute folder paths.
3254 Directory paths are simply passed through.
3255 This function is to be used for folder paths only, thus the name.
3256 The result is a pointer to static memory.
3257 .LI 2
3258 .Fu expanddir()
3259 converts directory paths to absolute directory paths.
3260 Folder paths are treated as relative directory paths.
3261 This function is to be used for directory paths only, thus the name.
3262 The result is a pointer to static memory.
3263 .LI 3
3264 .Fu toabsdir()
3265 converts any type of path to an absolute directory path.
3266 This is the function of choice for path conversion.
3267 Absolute directory paths are the most general representation of a
3268 path name.
3269 The result is a pointer to static memory.
3270 .P
3271 The new functions have names that indicate their use.
3272 Two of the functions convert relative to absolute path names of the
3273 same type.
3274 The third function converts any path name type to the most general one,
3275 the absolute directory path.
3276 All of the functions return pointers to static memory.
3277 The file
3278 .Fn sbr/path.c
3279 contains the implementation of the functions;
3280 .Fn sbr/m_maildir.c
3281 was removed.
3282 .Ci d39e2c447b0d163a5a63f480b23d06edb7a73aa0
3283 .P
3284 Along with the path conversion rework, I also replaced
3285 .Fu getfolder(FDEF)
3286 with
3287 .Fu getdeffol()
3288 and
3289 .Fu getfolder(FCUR)
3290 with
3291 .Fu getcurfol() ,
3292 which only wraps
3293 .Fu expandfol(""@"")
3294 for convenience.
3295 This code was moved from
3296 .Fn sbr/getfolder.c
3297 into
3298 .Fn sbr/path.c
3299 as well.
3300 .Ci d39e2c447b0d163a5a63f480b23d06edb7a73aa0
3301 .P
3302 The related function
3303 .Fu etcpath()
3304 is now included in
3305 .Fn sbr/path.c ,
3306 too
3307 .Ci b4c29794c12099556151d93a860ee51badae2e35 .
3308 Previously, it had been located in
3309 .Fn config/config.c .
3310 .P
3311 Now,
3312 .Fn sbr/path.c
3313 contains all path handling code.
3314 Besides being less code, its readability is highly improved.
3315 The functions follow a common style and are well documented.
3320 .H2 "Profile Reading
3321 .P
3322 The MH profile contains the configuration of a user-specific MH setup.
3323 MH tools read the profile right after starting up
3324 because it contains the location of the user's mail storage
3325 and similar settings that influence the whole setup.
3326 Furthermore, the profile contains the default switches for the tools
3327 as well.
3328 The context file is read along with the profile.
3329 .P
3330 For historic reasons, some MH tools did not read the profile and context.
3331 Among them were
3332 .Pn post /\c
3333 .Pn spost ,
3334 .Pn mhmail ,
3335 and
3336 .Pn slocal .
3337 The reason why these tools ignored the profile were not clearly stated.
3338 During a discussion on the nmh-workers mailing list,
3339 David Levine posted an explanation, quoting John Romine:
3340 .[
3341 nmh-workers levine post profile
3342 .]
3344 .QS
3345 I asked John Romine and here's what he had to say, which
3346 agrees and provides an example that convinces me:
3347 .QS
3348 My take on this is that
3349 .Pn post
3350 should not be called by users directly, and it doesn't read the
3351 .Fn .mh_profile
3352 (only front-end UI programs read the profile).
3353 .QP
3354 For example, there can be contexts where
3355 .Pn post
3356 is called by a helper program (like `\c
3357 .Pn mhmail ')
3358 which may be run by a non-MH user.
3359 We don't want this to prompt the user to create an MH profile, etc.
3360 .QP
3361 My suggestion would be to have
3362 .Pn send
3363 pass a (hidden) `\c
3364 .Sw -fileproc
3365 .Ar proc '
3366 option to
3367 .Pn post
3368 if needed.
3369 You could also
3370 use an environment variable (I think
3371 .Pn send /\c
3372 .Pn whatnow
3373 do this).
3374 .QE
3375 .sp \n(PDu
3376 I think that's the way to go.
3377 My personal preference is to use a command line option,
3378 not an environment variable.
3379 .QE
3381 .P
3382 To solve the problem that
3383 .Pn post
3384 does not honor the
3385 .Pe fileproc
3386 profile entry,
3387 the community roughly agreed that a switch
3388 .Sw -fileproc
3389 should be added to
3390 .Pn post
3391 to be able to pass a different fileproc.
3392 I strongly disagree with this approach because it does not solve
3393 the problem; it only removes a single symptom.
3394 The actual problem is that
3395 .Pn post
3396 does not behave as expected,
3397 though all programs should behave as expected.
3398 Clear and general concepts are a precondition for this.
3399 Thus, there should be no separation into ``front-end UI programs''
3400 and ones that ``should not be called by users directly''.
3401 The real solution is having all MH tools read the profile.
3402 .P
3403 But the problem has a further aspect,
3404 which originates from
3405 .Pn mhmail
3406 mainly.
3407 .Pn mhmail
3408 was intended to be a replacement for
3409 .Pn mailx
3410 on systems with MH installations.
3411 In difference to
3412 .Pn mailx ,
3413 .Pn mhmail
3414 used MH's
3415 .Pn post
3416 to send the message.
3417 The idea was that using
3418 .Pn mhmail
3419 should not be influenced whether the user had
3420 MH set up for himself or not.
3421 Therefore
3422 .Pn mhmail
3423 had not read the profile.
3424 As
3425 .Pn mhmail
3426 used
3427 .Pn post ,
3428 .Pn post
3429 was not allowed to read the profile neither.
3430 This is the reason for the actual problem.
3431 Yet, this was not considered much of a problem because
3432 .Pn post
3433 was not intended to be used by users directly.
3434 To invoke
3435 .Pn post ,
3436 .Pn send
3437 was used an a front-end.
3438 .Pn send
3439 read the profile and passed all relevant values on the command line to
3440 .Pn post
3441 \(en an awkward solution.
3442 .P
3443 The important insight is that
3444 .Pn mhmail
3445 is a wolf in sheep's clothing.
3446 This alien tool broke the concepts because it was treated like
3447 a normal MH tool.
3448 Instead it should have been treated accordingly to its foreign style.
3449 .P
3450 The solution is not to prevent the tools from reading the profile but
3451 to instruct them to read a different profile.
3452 .Pn mhmail
3453 could have set up a well-defined profile and caused the following
3454 .Pn post
3455 to use this profile by exporting an environment variable.
3456 With this approach, no special cases would have been introduced
3457 and no surprises would have been caused.
3458 By writing a wrapper program to provide a clean temporary profile,
3459 the concept could have been generalized orthogonally to the whole
3460 MH tool chest.
3461 .P
3462 In mmh, the wish to have
3463 .Pn mhmail
3464 as a replacement for
3465 .Pn mailx
3466 is considered obsolete.
3467 Mmh's
3468 .Pn mhmail
3469 does no longer cover this use-case
3470 .Ci d36e56e695fe1c482c7920644bfbb6386ac9edb0 .
3471 Currently,
3472 .Pn mhmail
3473 is in a transition state
3474 .Ci 32d4f9daaa70519be3072479232ff7be0500d009 .
3475 It may become a front-end to
3476 .Pn comp ,
3477 which provides an alternative interface which can be more convenient
3478 in some cases.
3479 This would convert
3480 .Pn mhmail
3481 into an ordinary MH tool.
3482 If, however, this idea does not convince, then
3483 .Pn mhmail
3484 will be removed.
3485 .P
3486 In the mmh tool chest, every program reads the profile.
3487 (\c
3488 .Pn slocal
3489 is not considered part of the mmh tool chest (cf. Sec.
3490 .Cf slocal ).)
3491 Mmh has no
3492 .Pn post
3493 program, but it has
3494 .Pn spost ,
3495 which now does read the profile
3496 .Ci 3e017a7abbdf69bf0dff7a4073275961eda1ded8 .
3497 Following this change,
3498 .Pn send
3499 and
3500 .Pn spost
3501 can be considered for merging.
3502 Besides
3503 .Pn send ,
3504 .Pn spost
3505 is only invoked directly by the to-be-changed
3506 .Pn mhmail
3507 implementation and by
3508 .Pn rcvdist ,
3509 which requires rework anyway.
3511 .P
3512 Jeffrey Honig quoted Marshall T. Rose explaining the decision that
3513 .Pn post
3514 ignores the profile:
3515 .[
3516 nmh-workers honig post profile
3517 .]
3518 .QS
3519 when you run mh commands in a script, you want all the defaults to be
3520 what the man page says.
3521 when you run a command by hand, then you want your own defaults...
3522 .QE
3523 .LP
3524 The explanation neither matches the problem concerned exactly
3525 nor is the interpretation clear.
3526 If the described desire addresses the technical level,
3527 then it conflicts fundamentally with the Unix philosophy,
3528 precisely because the indistinquishability of human and script
3529 input is the main reason for the huge software leverage in Unix.
3530 If, however, the described desire addresses the user's view,
3531 then different technical solutions are more appropriate.
3532 The two cases can be regarded simply as two different MH setups.
3533 Hence, mapping the problem of different behavior between interactive and
3534 automated use on the concept of switching between different profiles,
3535 marks it already solved.
3539 .H2 "Standard Libraries
3540 .P
3541 MH is one decade older than the POSIX and ANSI C standards.
3542 Hence, MH included own implementations of functions
3543 that were neither standardized nor widely available, back then.
3544 Today, twenty years after POSIX and ANSI C were published,
3545 developers can expect that systems comply with these standards.
3546 In consequence, MH-specific replacements for standard functions
3547 can and should be dropped.
3548 Kernighan and Pike advise: ``Use standard libraries''.
3549 .[ [
3550 kernighan pike practice of programming
3551 .], p. 196]
3552 Actually, MH had followed this advice in history,
3553 but it had not adjusted to more recent changes in this field.
3554 The
3555 .Fu snprintf()
3556 function, for instance, was standardized with C99 and is available
3557 almost everywhere because of its high usefulness.
3558 Thus, the project's own implementation of
3559 .Fu snprintf()
3560 was dropped in March 2012 in favor for using the one of the
3561 standard library
3562 .Ci 0052f1024deb0a0a2fc2e5bacf93d45a5a9c9b32 .
3563 Such decisions limit the portability of mmh
3564 if systems do not support these standardized and widespread functions.
3565 This compromise is made because mmh focuses on the future.
3566 .P
3567 As I am still in my twenties, have no programming experience from
3568 past decades.
3569 I have not followed the evolution of C through time.
3570 I have not suffered from the the Unix wars.
3571 I have not longed for standardization.
3572 All my programming experience is from a time when ANSI C and POSIX
3573 were well established already.
3574 Thus, I needed to learn about the history in retrospective.
3575 I have only read a lot of books about the (good) old times.
3576 This put me in a difficult position when working with old code.
3577 I need to freshly acquire knowledge about old code constructs and ancient
3578 programming styles, whereas older programmers know these things by
3579 heart from their own experience.
3580 Being aware of the situation, I rather let people with more historic
3581 experience do the transition from ancient code constructs to
3582 standardized ones.
3583 Lyndon Nerenberg covered large parts of this task for the nmh project.
3584 He converted project-specific functions to POSIX replacements,
3585 also removing the conditionals compilation of now standardized features.
3586 Ken Hornstein and David Levine had their part in this work, as well.
3587 Often, I only pulled the changes over from nmh into mmh.
3588 These changes include many commits, among them:
3589 .Ci 768b5edd9623b7238e12ec8dfc409b82a1ed9e2d
3590 .Ci 0052f1024deb0a0a2fc2e5bacf93d45a5a9c9b32 .
3591 .P
3592 Nevertheless, I worked on the task as well, tidying up the
3593 \fIMH standard library\fP,
3594 .Fn libmh.a .
3595 It is located in the
3596 .Fn sbr
3597 (``subroutines'') directory in the source tree and
3598 includes functions that mmh tools usually need.
3599 Among them are MH-specific functions for profile, context, sequence,
3600 and folder handling, but as well
3601 MH-independent functions, such as auxiliary string functions,
3602 portability interfaces and error-checking wrappers for critical
3603 functions of the standard library.
3604 .BU
3605 I have replaced the
3606 .Fu atooi()
3607 function with calls to
3608 .Fu strtoul() ,
3609 setting the third parameter, the base, to eight.
3610 .Fu strtoul()
3611 is part of C89 and thus considered safe to use
3612 .Ci c490c51b3c0f8871b6953bd0c74551404f840a74 .
3613 .BU
3614 I did remove project-included fallback implementations of
3615 .Fu memmove()
3616 and
3617 .Fu strerror()
3618 .Ci b067ff5c465a5d243ce5a19e562085a9a1a97215 ,
3619 although Peter Maydell had re-included them into nmh in 2008
3620 to support SunOS 4.
3621 Nevertheless, these functions are part of ANSI C.
3622 Systems that do not even provide full ANSI C support should not
3623 put a load on mmh.
3624 .BU
3625 The
3626 .Fu copy()
3627 function copies the string in parameter one to the location in
3628 parameter two.
3629 In contrast to
3630 .Fu strcpy() ,
3631 it returns a pointer to the terminating null-byte in the destination area.
3632 The code was adjusted to replace
3633 .Fu copy()
3634 with
3635 .Fu strcpy() ,
3636 except within
3637 .Fu concat() ,
3638 where
3639 .Fu copy()
3640 was more convenient.
3641 Therefore, the definition of
3642 .Fu copy()
3643 was moved into the source file of
3644 .Fu concat()
3645 and its visibility it limited to that
3646 .Ci 552fd7253e5ee9e554c5c7a8248a6322aa4363bb .
3647 .BU
3648 The function
3649 .Fu r1bindex()
3650 had been a generalized version of
3651 .Fu basename()
3652 with minor differences.
3653 As all calls to
3654 .Fu r1bindex()
3655 had the slash (`\fL/\fP') as delimiter anyway,
3656 replacing
3657 .Fu r1bindex()
3658 with the more specific and better-named function
3659 .Fu basename()
3660 became desirable.
3661 Unfortunately, many of the 54 calls to
3662 .Fu r1bindex()
3663 depended on a special behavior,
3664 which differed from the POSIX specification for
3665 .Fu basename() .
3666 Hence,
3667 .Fu r1bindex()
3668 was kept but renamed to
3669 .Fu mhbasename() ,
3670 setting the delimiter to the slash
3671 .Ci 240013872c392fe644bd4f79382d9f5314b4ea60 .
3672 For possible uses of
3673 .Fu r1bindex()
3674 with a different delimiter,
3675 the ANSI C function
3676 .Fu strrchr()
3677 provides the core functionality.
3678 .BU
3679 The
3680 .Fu ssequal()
3681 function \(en apparently for ``substring equal'' \(en
3682 was renamed to
3683 .Fu isprefix() ,
3684 because this is what it actually checked
3685 .Ci c20b4fa14515c7ab388ce35411d89a7a92300711.
3686 Its source file had included both of the following comments, no joke.
3687 .in -\n(PIu
3688 .VS
3689 /*
3690 * THIS CODE DOES NOT WORK AS ADVERTISED.
3691 * It is actually checking if s1 is a PREFIX of s2.
3692 * All calls to this function need to be checked to see
3693 * if that needs to be changed. Prefix checking is cheaper, so
3694 * should be kept if it's sufficient.
3695 */
3697 /*
3698 * Check if s1 is a substring of s2.
3699 * If yes, then return 1, else return 0.
3700 */
3701 VE
3702 .in +\n(PIu
3703 Eventually, the function was completely replaced with calls to
3704 .Fu strncmp()
3705 .Ci b0b1dd37ff515578cf7cba51625189eb34a196cb .
3711 .H2 "User Data Locations
3712 .P
3713 In nmh, a personal setup consists of the MH profile and the MH directory.
3714 The profile is a file named
3715 .Fn \&.mh_profile
3716 in the user's home directory.
3717 It contains the static configuration.
3718 It also contains the location of the MH directory in the profile entry
3719 .Pe Path .
3720 The MH directory contains the mail storage and is the first
3721 place to search for form files, scan formats, and similar
3722 configuration files.
3723 The location of the MH directory can be chosen freely by the user.
3724 The usual name is a directory named
3725 .Fn Mail
3726 in the user's home directory.
3727 .P
3728 The way MH data is split between profile and MH directory is a legacy.
3729 It is only sensible in a situation where the profile is the only
3730 configuration file.
3731 Why else should the mail storage and the configuration files be intermixed?
3732 They are of different kind:
3733 One kind is the data to be operated on and the other kind is
3734 the configuration to change how tools operate.
3735 Splitting the configuration between the profile and the MH directory
3736 is inappropriate, as well.
3737 I improved the situation by breaking compatibility.
3738 .P
3739 In mmh, personal data is grouped by type.
3740 This results in two distinct parts:
3741 the mail storage and the configuration.
3742 The mail storage directory still contains all the messages,
3743 but, in exception of public sequences files, nothing else.
3744 In difference to nmh, the auxiliary configuration files are no longer
3745 located there.
3746 Therefore, the directory is no longer called the user's \fIMH directory\fP
3747 but the user's \fImail storage\fP.
3748 Its location is still user-chosen, with the default name
3749 .Fn Mail
3750 in the user's home directory.
3751 The configuration is grouped together in the hidden directory
3752 .Fn \&.mmh
3753 in the user's home directory.
3754 This \fImmh directory\fP contains the context file, personal forms,
3755 scan formats, and the like, but also the user's profile, now named
3756 .Fn profile .
3757 The path to the profile is no longer
3758 .Fn $HOME/.mh_profile
3759 but
3760 .Fn $HOME/.mmh/profile .
3761 (The alternative of having file
3762 .Fn $HOME/.mh_profile
3763 and a configuration directory
3764 .Fn $HOME/.mmh
3765 appeared to be inconsistent.)
3766 .P
3767 The approach chosen for mmh is consistent, simple, and familiar to
3768 Unix users.
3769 The main achievement of the change is the clear and sensible separation
3770 of the mail storage and the configuration.
3771 .Ci 7030d7edb099bff36ded7548bb5380f7acab4f9b
3772 .P
3773 As MH allows users to have multiple MH setups,
3774 it is necessary to switch the profile.
3775 The profile is the single entry point to access the rest of a
3776 personal MH setup.
3777 In nmh, the environment variable
3778 .Ev MH
3779 is used to specify a different profile.
3780 To operate in the same MH setup with a separate context, the
3781 .Ev MHCONTEXT
3782 environment variable is used.
3783 This allows having a separate current folder in each terminal at
3784 the same time, for instance.
3785 In mmh, three environment variables replace the two of nmh.
3786 .Ev MMH
3787 overrides the default location of the mmh directory (\c
3788 .Fn .mmh ).
3789 .Ev MMHP
3790 and
3791 .Ev MMHC
3792 override the paths to the profile and context file, respectively.
3793 This approach allows the set of personal configuration files to be chosen
3794 independently of the profile, context, and mail storage.
3795 The new approach has no functional disadvantages,
3796 as every setup I can imagine can be implemented with both approaches,
3797 possibly even easier with the new one.
3798 .Ci 7030d7edb099bff36ded7548bb5380f7acab4f9b
3804 .H2 "Modularization
3805 .Id modularization
3806 .P
3807 The source code of the mmh tools is located in the
3808 .Fn uip
3809 (``user interface programs'') directory.
3810 Each tool has a source file with the name of the command.
3811 For example,
3812 .Pn rmm
3813 is built from
3814 .Fn uip/rmm.c .
3815 Some source files are used for multiple programs.
3816 For example
3817 .Fn uip/scansbr.c
3818 is used for both
3819 .Pn scan
3820 and
3821 .Pn inc .
3822 In nmh, 49 tools were built from 76 source files.
3823 This is a ratio of 1.6 source files per program.
3824 32 programs depended on multiple source files;
3825 17 programs depended on one source file only.
3826 In mmh, 39 tools are built from 51 source files.
3827 This is a ratio of 1.3 source files per program.
3828 18 programs depend on multiple source files;
3829 21 programs depend on one source file only.
3830 (These numbers and the ones in the following text ignore the MH library
3831 as well as shell scripts and multiple names for the same program.)
3832 .P
3833 Splitting the source code of a large program into multiple files can
3834 increase the readability of its source code,
3835 but most of the mmh tools are small and straight-forward programs.
3836 In exception of the MIME handling tools (i.e.
3837 .Pn mhbuild ,
3838 .Pn mhstore ,
3839 .Pn show ,
3840 etc.),
3841 .Pn pick
3842 is the only tool with more than one thousand lines of source code.
3843 Splitting programs with less than one thousand lines of code into
3844 multiple source files leads seldom to better readability.
3845 For such tools, splitting still makes sense
3846 when parts of the code are reused in other programs
3847 and the reused code fragment is (1) not general enough
3848 for including it in the MH library
3849 or (2) has dependencies on a library that only few programs need.
3850 .Fn uip/packsbr.c ,
3851 for instance, provides the core program logic for the
3852 .Pn packf
3853 and
3854 .Pn rcvpack
3855 programs.
3856 .Fn uip/packf.c
3857 and
3858 .Fn uip/rcvpack.c
3859 mainly wrap the core function appropriately.
3860 No other tools use the folder packing functions.
3861 As another example,
3862 .Fn uip/termsbr.c
3863 accesses terminal properties, which requires linking with the
3864 \fItermcap\fP or a \fIcurses\fP library.
3865 If
3866 .Fn uip/termsbr.c
3867 is included in the MH library, then every program needs to be linked
3868 with termcap or curses, although only few of the programs use
3869 the library.
3870 .P
3871 The task of MIME handling is complex enough that splitting its code
3872 into multiple source files improves the readability.
3873 The program
3874 .Pn mhstore ,
3875 for instance, is compiled out of seven source files with 2\|500
3876 lines of code in summary.
3877 The main code file
3878 .Fn uip/mhstore.c
3879 consists of 800 lines; the other 1\|700 lines are code reused in
3880 other MIME handling tools.
3881 It seems to be worthwhile to bundle the generic MIME handling code into
3882 a MH-MIME library, as a companion to the MH standard library.
3883 This is left to be done.
3884 .P
3885 The work already accomplished focussed on the non-MIME tools.
3886 The amount of code compiled into each program was reduced.
3887 This eases the understanding of the code base.
3888 In nmh,
3889 .Pn comp
3890 was built from six source files:
3891 .Fn comp.c ,
3892 .Fn whatnowproc.c ,
3893 .Fn whatnowsbr.c ,
3894 .Fn sendsbr.c ,
3895 .Fn annosbr.c ,
3896 and
3897 .Fn distsbr.c .
3898 In mmh, it builds from only two:
3899 .Fn comp.c
3900 and
3901 .Fn whatnowproc.c .
3902 In nmh's
3903 .Pn comp ,
3904 the core function of
3905 .Pn whatnow ,
3906 .Pn send ,
3907 and
3908 .Pn anno
3909 were all compiled into
3910 .Pn comp .
3911 This saved the need to execute these programs with
3912 the expensive system calls
3913 .Fu fork()
3914 and
3915 .Fu exec() .
3916 Whereas this approach improved the time performance,
3917 it interwove the source code.
3918 Core functionalities were not encapsulated into programs but into
3919 function, which were then wrapped by programs.
3920 For example,
3921 .Fn uip/annosbr.c
3922 included the function
3923 .Fu annotate() .
3924 Each program that wanted to annotate messages, included the source file
3925 .Fn uip/annosbr.c
3926 and called
3927 .Fu annotate() .
3928 Because the function
3929 .Fu annotate()
3930 was used like the tool
3931 .Pn anno ,
3932 it had seven parameters, reflecting the command line switches of the tool.
3933 When another pair of command line switches was added to
3934 .Pn anno ,
3935 a rather ugly hack was implemented to avoid adding another parameter
3936 to the function
3937 .Ci d9b1d57351d104d7ec1a5621f090657dcce8cb7f .
3938 .P
3939 In mmh, the relevant code of
3940 .Pn comp
3941 comprises the two files
3942 .Fn uip/comp.c
3943 and
3944 .Fn uip/whatnowproc.c ,
3945 together 210 lines of code,
3946 whereas in nmh,
3947 .Pn comp
3948 comprises six files with 2\|450 lines.
3949 Not all of the code in these six files is actually used by
3950 .Pn comp ,
3951 but the reader needed to read it all to know which parts are relevant.
3952 Understanding nmh's
3953 .Pn comp ,
3954 required understanding the inner workings of
3955 .Fn uip/annosbr.c
3956 first.
3957 To be sure to fully understand a program, its whole source code needs
3958 to be examined.
3959 Not doing so is a leap of faith, assuming that the developers
3960 have avoided obscure programming techniques.
3961 Here, it should be recalled that information passed in obscure ways
3962 through the program's source base, due to the aforementioned hack
3963 to save an additional parameter in nmh's
3964 .Pn anno .
3965 .P
3966 In mmh, understanding
3967 .Pn comp
3968 requires to read only 210 lines of code to read, whereas the amount
3969 is ten times more for nmh's
3970 .Pn comp .
3971 .P
3972 By separating the tools on the program-level,
3973 the boundaries are clearly visible, as the interfaces are calls to
3974 .Fu exec()
3975 rather than arbitrary function calls.
3976 Additionally, this kind of separation is more strict because
3977 it is technically enforced by the operating system;
3978 it can not be simply bypassed with global variables.
3979 Good separation simplifies the understanding of program code
3980 because the area influenced by any particular statement is small.
3981 As I have read a lot in nmh's code base during the last two years,
3982 I have learned about the easy and the difficult parts.
3983 In my observation, the understanding of code is enormously eased
3984 if the influenced area is small and clearly bounded.
3985 .P
3986 Yet, the real problem is another:
3987 Nmh violates the golden ``one tool, one job'' rule of the Unix philosophy.
3988 Understanding
3989 .Pn comp
3990 requires understanding
3991 .Fn uip/annosbr.c
3992 and
3993 .Fn uip/sendsbr.c
3994 because
3995 .Pn comp
3996 annotates and sends messages.
3997 In nmh, there surely exist the tools
3998 .Pn anno
3999 and
4000 .Pn send ,
4001 which cover these jobs,
4002 but
4003 .Pn comp
4004 and
4005 .Pn repl
4006 and
4007 .Pn forw
4008 and
4009 .Pn dist
4010 and
4011 .Pn whatnow
4012 and
4013 .Pn viamail
4014 \(en they all (!) \(en
4015 have the same annotating and sending functions included, once more.
4016 As a result,
4017 .Pn comp
4018 sends messages without using
4019 .Pn send .
4020 The situation is the same as if
4021 .Pn grep
4022 would page its output without using
4023 .Pn more
4024 just because both programs are part of the same code base.
4025 .P
4026 The clear separation on the surface of nmh
4027 \(en the tool chest approach \(en
4028 is violated on the level below.
4029 This violation is for the sake of time performance.
4030 Decades ago, sacrificing readability and conceptional beauty
4031 for speed might have been necessary to prevent MH from being
4032 unusably slow, but today this is not the case anymore.
4033 No longer should speed improvements that became unnecessary be kept.
4034 No longer should readability or conceptional beauty be sacrificed.
4035 No longer should the Unix philosophy's ``one tool, one job''
4036 guideline be violated.
4037 Therefore, mmh's
4038 .Pn comp
4039 no longer sends messages.
4040 .P
4041 In mmh, different jobs are divided among separate programs that
4042 invoke each other as needed.
4043 In consequence,
4044 .Pn comp
4045 invokes
4046 .Pn whatnow
4047 which thereafter invokes
4048 .Pn send
4049 .Ci 3df5ab3c116e6d4a2fb4bb5cc9dfc5f781825815
4050 .Ci c73c00bfccd22ec77e9593f47462aeca4a8cd9c0 .
4051 The clear separation on the surface is maintained on the level below.
4052 Human users and other tools use the same interface \(en
4053 annotations, for example, are made by invoking
4054 .Pn anno ,
4055 no matter if requested by programs or by human beings
4056 .Ci 469a4163c2a1a43731d412eaa5d9cae7d670c48b
4057 .Ci aed384169af5204b8002d06e7a22f89197963d2d
4058 .Ci 3caf9e298a8861729ca8b8a84f57022b6f3ea742 .
4059 The decrease of tools built from multiple source files and thus
4060 the decrease of
4061 .Fn uip/*sbr.c
4062 files confirm the improvement
4063 .Ci 9e6d91313f01c96b4058d6bf419a8ca9a207bc33
4064 .ci 81744a46ac9f845d6c2b9908074d269275178d2e
4065 .Ci f0f858069d21111f0dbea510044593f89c9b0829
4066 .Ci 0503a6e9be34f24858b55b555a5c948182b9f24b
4067 .Ci 27826f9353e0f0b04590b7d0f8f83e60462b90f0
4068 .Ci d1da1f94ce62160aebb30df4063ccbc53768656b
4069 .Ci c42222869e318fff5dec395eca3e776db3075455 .
4070 This is also visible in the complexity of the build dependency graphs:
4072 .sp
4073 Nmh:
4074 .BP input/deps-nmh.eps .5i
4075 .EP
4076 .sp
4077 Mmh:
4078 .BP input/deps-mmh.eps .8i
4079 .EP
4081 The figures display all program to source file relationships where
4082 programs (ellipses) are built from multiple source files (rectangles).
4083 The primary source file of each program is omited from the graph.