docs/master

view discussion.roff @ 225:d83ab437e3a6

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