docs/master

view discussion.roff @ 224:b0e83cfde2bf

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