docs/master

view discussion.roff @ 227:157c92fc1597

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