Use forward-line rather than goto-line.
[bpt/emacs.git] / lisp / mail / feedmail.el
CommitLineData
0bb37c1a
KH
1;;; feedmail.el --- assist other email packages to massage outgoing messages
2;;; This file is in the public domain.
3
e8af40ee
PJ
4;; This file is part of GNU Emacs.
5
edd69520 6;; Author: Bill Carpenter <bill@carpenter.ORG>
29a69d04
DL
7;; Version: 8
8;; Keywords: email, queue, mail, sendmail, message, spray, smtp, draft
9;; X-URL: <URL:http://www.carpenter.org/feedmail/feedmail.html>
10
0bb37c1a
KH
11;;; Commentary:
12
13;; A replacement for parts of Emacs' sendmail.el (specifically,
14;; it's what handles your outgoing mail after you hit C-c C-c in mail
15;; mode). See below for a list of additional features, including the
16;; ability to queue messages for later sending. If you are using
17;; fakemail as a subprocess, you can switch to feedmail and eliminate
18;; the use of fakemail. feedmail works with recent versions of
19;; Emacs (mostly, but not exclusively, tested against 19.34 on
20;; Win95; some testing on 20.x) and XEmacs (tested with 20.4 and
21;; later betas). It probably no longer works with Emacs 18,
22;; though I haven't tried that in a long time. Sorry, no manual yet
23;; in this release. Look for one with the next release.
bd1cd4c2
KH
24
25;; As far as I'm concerned, anyone can do anything they want with
26;; this specific piece of code. No warranty or promise of support is
27;; offered. This code is hereby released into the public domain.
28
bd1cd4c2
KH
29;; Thanks: My thanks to the many people who have sent me suggestions
30;; and fixes over time, as well as those who have tested many beta
31;; iterations. Some are cited in comments in code fragments below,
32;; but that doesn't correlate well with the list of folks who have
33;; actually helped me along the way.
34
bd1cd4c2
KH
35;; If you use feedmail, I invite you to send me some email about it.
36;; I appreciate feedback about problems you find or suggestions for
37;; improvements or added features (even though I can't predict when
38;; I'll incorporate changes). It's also OK with me if you send me a
39;; note along the lines of "I use feedmail and find it useful" or "I
40;; tried feedmail and didn't find it useful, so I stopped using it".
41;;
42;; It is most useful, when sending a bug report, if you tell me what
0bb37c1a 43;; version of Emacs you are using, what version of feedmail you are
bd1cd4c2
KH
44;; using, and what versions of other email-related elisp packages you
45;; are using. If in doubt about any of that, send the bug report
46;; anyhow.
0bb37c1a 47;;
bd1cd4c2
KH
48;; =====
49;; A NOTE TO THOSE WHO WOULD CHANGE THIS CODE... Since it is PD,
50;; you're within your rights to do whatever you want. If you do
51;; publish a new version with your changes in it, please (1) insert
52;; lisp comments describing the changes, (2) insert lisp comments
53;; that clearly delimit where your changes are, (3) email me a copy
54;; (I can't always consistently follow the relevant usenet groups),
55;; and (4) use a version number that is based on the version you're
56;; changing along with something that indicates you changed it. For
57;; example,
58;;
59;; (defconst feedmail-patch-level "123")
60;; (defconst feedmail-patch-level "123-XYZ-mods")
61;;
62;; The point of the last item, of course, is to try to minimize
63;; confusion. Odds are good that if your idea makes sense to me that
64;; it will show up in some future version of feedmail, though it's
65;; hard to say when releases will tumble out.
66;; =====
67;;
68;; This file requires the mail-utils library.
69;;
70;; This file requires the smtpmail library if you use
71;; feedmail-buffer-to-smtpmail.
72;;
73;; This file requires the custom library. Unfortunately, there are
74;; two incompatible versions of the custom library. If you don't have
75;; custom or you have the old version, this file will still load and
76;; work properly. If you don't know what custom is all about and want
77;; to edit your user option elisp variables the old fashioned way,
78;; just imagine that all the "defcustom" stuff you see below is really
79;; "defvar", and ignore everthing else. For info about custom, see
80;; <URL:http://www.dina.kvl.dk/~abraham/custom/>.
81;;
82;; This code does in elisp a superset of the stuff that used to be done
83;; by the separate program "fakemail" for processing outbound email.
84;; In other words, it takes over after you hit "C-c C-c" in mail mode.
85;; By appropriate setting of options, you can still use "fakemail",
86;; or you can even revert to sendmail (which is not too popular
87;; locally). See the variables at the top of the elisp for how to
88;; achieve these effects (there are more features than in this bullet
89;; list, so trolling through the variable and function doc strings may
90;; be worth your while):
91;;
92;; --- you can park outgoing messages into a disk-based queue and
93;; stimulate sending them all later (handy for laptop users);
94;; there is also a queue for draft messages
95;;
96;; --- you can get one last look at the prepped outbound message and
97;; be prompted for confirmation
98;;
37aa9115 99;; --- removes Bcc:/Resent-Bcc: headers after getting address info
bd1cd4c2
KH
100;;
101;; --- does smart filling of address headers
102;;
37aa9115 103;; --- calls a routine to process Fcc: lines and removes them
bd1cd4c2
KH
104;;
105;; --- empty headers are removed
106;;
37aa9115 107;; --- can force From: or Sender: line
bd1cd4c2 108;;
37aa9115 109;; --- can generate a Message-Id: line
bd1cd4c2 110;;
37aa9115 111;; --- can generate a Date: line; the date can be the time the
bd1cd4c2
KH
112;; message was written or the time it is being sent
113;;
114;; --- strips comments from address info (both "()" and "<>" are
115;; handled via a call to mail-strip-quoted-names); the
116;; comments are stripped in the simplified address list given
117;; to a subprocess, not in the headers in the mail itself
118;; (they are left unchanged, modulo smart filling)
119;;
120;; --- error info is pumped into a normal buffer instead of the
121;; minibuffer
122;;
123;; --- just before the optional prompt for confirmation, lets you
124;; run a hook on the prepped message and simplified address
125;; list
126;;
127;; --- you can specify something other than /bin/mail for the
128;; subprocess
129;;
37aa9115 130;; --- you can generate/modify an X-Mailer: message header
bd1cd4c2
KH
131;;
132;; After a long list of options below, you will find the function
133;; feedmail-send-it. Hers's the best way to use the stuff in this
134;; file:
135;;
136;; Save this file as feedmail.el somewhere on your elisp
137;; loadpath; byte-compile it. Put the following lines somewhere in
138;; your ~/.emacs stuff:
139;;
140;; (setq send-mail-function 'feedmail-send-it)
141;; (autoload 'feedmail-send-it "feedmail")
142;;
143;; If you plan to use the queue stuff, also use this:
144;;
145;; (setq feedmail-enable-queue t)
146;; (autoload 'feedmail-run-the-queue "feedmail")
147;; (autoload 'feedmail-run-the-queue-no-prompts "feedmail")
148;; (setq auto-mode-alist (cons '("\\.fqm$" . mail-mode) auto-mode-alist))
149;;
0bb37c1a 150;; If you are using the desktop.el library to restore your sessions, you might
bd1cd4c2
KH
151;; like to add the suffix ".fqm" to the list of non-saved things via the variable
152;; desktop-files-not-to-save.
153;;
154;; If you are planning to call feedmail-queue-reminder from your .emacs or
155;; something similar, you might need this:
156;;
157;; (autoload 'feedmail-queue-reminder "feedmail")
158;;
159;; If you ever use rmail-resend and queue messages, you should do this:
160;;
161;; (setq feedmail-queue-alternative-mail-header-separator "")
162;;
163;; If you want to automatically spell-check messages, but not when sending
164;; them from the queue, you could do something like this:
165;;
166;; (autoload 'feedmail-mail-send-hook-splitter "feedmail")
167;; (add-hook 'mail-send-hook 'feedmail-mail-send-hook-splitter)
168;; (add-hook 'feedmail-mail-send-hook 'ispell-message)
169;;
170;; If you are using message-mode to compose and send mail, feedmail will
171;; probably work fine with that (someone else tested it and told me it worked).
172;; Follow the directions above, but make these adjustments instead:
173;;
174;; (setq message-send-mail-function 'feedmail-send-it)
175;; (add-hook 'message-mail-send-hook 'feedmail-mail-send-hook-splitter)
176;;
177;; I think the LCD is no longer being updated, but if it were, this
178;; would be a proper LCD record. There is an old version of
179;; feedmail.el in the LCD archive. It works but is missing a lot of
180;; features.
181;;
182;; LCD record:
183;; feedmail|Bill Carpenter|bill@bubblegum.net,bill@carpenter.ORG|Outbound mail queue handling|98-06-15|8|feedmail.el
184;;
185;; Change log:
186;; original, 31 March 1991
187;; patchlevel 1, 5 April 1991
188;; patchlevel 2, 24 May 1991
189;; 5-may-92 jwz Conditionalized calling expand-mail-aliases, since that
0bb37c1a 190;; function doesn't exist in Lucid Emacs or when using
bd1cd4c2
KH
191;; mail-abbrevs.el.
192;; patchlevel 3, 3 October 1996
193;; added queue stuff; still works in v18
194;; patchlevel 4, issued by someone else
195;; patchlevel 5, issued by someone else
196;; patchlevel 6, not issued as far as I know
197;; patchlevel 7, 20 May 1997
0bb37c1a 198;; abandon futile support of Emacs 18 (sorry if that hurts you)
37aa9115
KH
199;; provide a Date: header by default
200;; provide a default for generating Message-Id: header contents
bd1cd4c2
KH
201;; and use it by default (slightly changed API)
202;; return value from feedmail-run-the-queue
203;; new wrapper function feedmail-run-the-queue-no-prompts
37aa9115
KH
204;; user-mail-address as default for From:
205;; properly deal with Resent-{To,Cc,Bcc}
206;; Bcc and Resent-* now included in smart filling
bd1cd4c2
KH
207;; limited support for a "drafts" directory
208;; user-configurable default message action
209;; allow timeout for confirmation prompt (where available)
37aa9115 210;; move Fcc handling to as late as possible to get max
bd1cd4c2
KH
211;; header munging in the saved file
212;; work around sendmail.el's prompts when working from queue
213;; more reliably detect voluntary user bailouts
214;; offer to save modified buffers visiting queue files
215;; offer to delete old file copies of messages being queued
216;; offer to delete queue files when sending immediately
217;; queue filename convention preserves queue order
218;; default queue and draft directory names that work on VMS
219;; deduced address list now really a list, not a string (API change)
220;; no more address buffer
221;; when sending immediately, brief reminder of queue/draft counts
222;; copy trace of smtpmail stuff to feedmail error buffer on no-go
223;; more granularity on when to confirm sending
224;; pause a bit for errors while running queue
225;; try to clean up some pesky auto-save files from the
226;; queue/draft directories
227;; feedmail-force-expand-mail-aliases in case you can't figure
228;; any other way
229;; cleanup some of my sloppiness about case-fold-search (a strange
230;; variable)
0bb37c1a 231;; best effort following coding conventions from Emacs
bd1cd4c2
KH
232;; elisp manual appendix
233;; "customize" (see custom.el)
234;; when user selects "immediate send", clear action prompt since
235;; hooks may take a while to operate, and user may think the
236;; response didn't take
237;; fixes to the argument conventions for the
238;; feedmail-queue-runner-* functions; allows
239;; feedmail-run-the-queue[-no-prompts] to properly be called
240;; non-interactively
241;; eliminate reliance on directory-sep-char and feedmail-sep-thing
242;; tweak smart filling (reminded of comma problem by levitte@lp.se)
243;; option to control writing in text vs binary mode
6287be55 244;; patchlevel 8, 15 June 1998
bd1cd4c2 245;; reliable re-editing of text-mode (vs binary) queued messages
37aa9115
KH
246;; user option to keep Bcc: in Fcc: copy (keep by default)
247;; user option to delete body from Fcc: copy (keep by default)
bd1cd4c2
KH
248;; feedmail-deduce-bcc-where for envelope (API change for
249;; feedmail-deduce-address list)
250;; feedmail-queue-alternative-mail-header-separator
251;; at message action prompt, "I"/"S" bypass message confirmation prompt
252;; feedmail-mail-send-hook-splitter, feedmail-mail-send-hook,
253;; feedmail-mail-send-hook-queued
254;; user can supply stuff for message action prompt
255;; variable feedmail-queue-runner-confirm-global, function feedmail-run-the-queue-global-prompt
256;; bugfix: absolute argument to directory-files (tracked down for me
257;; by gray@austin.apc.slb.com (Douglas Gray Stephens)); relative
258;; pathnames can tickle stuff in ange-ftp remote directories
259;; (perhaps because feedmail is careless about its working
260;; directory)
261;; feedmail-deduce-envelope-from
262;; always supply envelope "from" (user-mail-address) to sendmail
263;; feedmail-message-id-suffix
264;; feedmail-queue-reminder, feedmail-queue-reminder-alist (after suggestions
265;; and/or code fragments from tonyl@Eng.Sun.COM (Tony Lam) and
266;; burge@newvision.com (Shane Burgess); bumped up the default value of
267;; feedmail-queue-chatty-sit-for since info is more complex sometimes
268;; feedmail-enable-spray (individual transmissions, crude mailmerge)
37aa9115 269;; blank Subject: no longer a special case; see feedmail-nuke-empty-headers
bd1cd4c2
KH
270;; fiddle-plexes data structure used lots of places; see feedmail-fiddle-plex-blurb
271;; feedmail-fiddle-plex-user-list
272;; feedmail-is-a-resend
273;; honor mail-from-style in constructing default for feedmail-from-line
274;; re-implement feedmail-from-line and feedmail-sender-line with
275;; fiddle-plexes; slightly modified semantics for feedmail-sender-line
276;; feedmail-queue-default-file-slug; tidy up some other slug details
277;; feedmail-queue-auto-file-nuke
278;; feedmail-queue-express-to-queue and feedmail-queue-express-to-draft
279;; strong versions of "q"ueue and "d"raft answers (always make a new file)
280;;
281;; todo (probably in patchlevel 9):
282;; write texinfo manual
283;; maybe partition into multiple files, including files of examples
284;;
285;;; Code:
286
287(defconst feedmail-patch-level "8")
288
705e5bd9 289(eval-when-compile (require 'smtpmail) (require 'cl))
49267116 290(autoload 'mail-do-fcc "sendmail")
bd1cd4c2
KH
291
292(defgroup feedmail nil
293 "Assist other email packages to massage outgoing messages."
49267116 294 :link '(url-link "http://www.carpenter.org/feedmail/feedmail.html")
adb92798 295 :link '(emacs-commentary-link "feedmail")
bd1cd4c2
KH
296 :group 'mail)
297
298(defgroup feedmail-misc nil
299 "Miscellaneous feedmail options that don't fit in other groups."
300 :group 'feedmail)
301
302(defgroup feedmail-headers nil
303 "Options related to manipulating specific headers or types of headers."
304 :group 'feedmail)
305
306(defgroup feedmail-queue nil
307 "Options related to queuing messages for later sending."
308 :group 'feedmail)
309
310
311(defcustom feedmail-confirm-outgoing nil
312 "*If non-nil, give a y-or-n confirmation prompt before sending mail.
313This is done after the message is completely prepped, and you'll be
314looking at the top of the message in a buffer when you get the prompt.
315If set to the symbol 'queued, give the confirmation prompt only while
316running the queue (however, the prompt is always suppressed if you are
27772f10 317processing the queue via `feedmail-run-the-queue-no-prompts'). If set
bd1cd4c2
KH
318to the symbol 'immediate, give the confirmation prompt only when
319sending immediately. For any other non-nil value, prompt in both
320cases. You can give a timeout for the prompt; see variable
27772f10 321`feedmail-confirm-outgoing-timeout'."
bd1cd4c2
KH
322 :group 'feedmail-misc
323 :type 'boolean
324 )
325
326
327(defcustom feedmail-confirm-outgoing-timeout nil
328 "*If non-nil, a timeout in seconds at the send confirmation prompt.
329If a positive number, it's a timeout before sending. If a negative
330number, it's a timeout before not sending. This will not work if your
27772f10 331version of Emacs doesn't include the function `y-or-n-p-with-timeout'
0bb37c1a 332\(e.g., some versions of XEmacs\)."
bd1cd4c2
KH
333 :group 'feedmail-misc
334 :type '(choice (const nil) integer)
c7d4a777 335 )
bd1cd4c2
KH
336
337
338(defcustom feedmail-nuke-bcc t
37aa9115
KH
339 "*If non-nil remove Bcc: lines from the message headers.
340In any case, the Bcc: lines do participate in the composed address
bd1cd4c2 341list. You may want to leave them in if you're using sendmail
27772f10 342\(see `feedmail-buffer-eating-function'\)."
bd1cd4c2
KH
343 :group 'feedmail-headers
344 :type 'boolean
c7d4a777 345 )
bd1cd4c2
KH
346
347
348(defcustom feedmail-nuke-resent-bcc t
37aa9115
KH
349 "*If non-nil remove Resent-Bcc: lines from the message headers.
350In any case, the Resent-Bcc: lines do participate in the composed
bd1cd4c2 351address list. You may want to leave them in if you're using sendmail
27772f10 352\(see `feedmail-buffer-eating-function'\)."
bd1cd4c2
KH
353 :group 'feedmail-headers
354 :type 'boolean
c7d4a777 355 )
bd1cd4c2
KH
356
357
358(defcustom feedmail-deduce-bcc-where nil
0bb37c1a 359 "*Where Bcc:/Resent-Bcc: addresses should appear in the envelope list.
bd1cd4c2
KH
360Addresses for the message envelope are deduced by examining
361appropriate address headers in the message. Generally, they will show
362up in the list of deduced addresses in the order that the headers
363happen to appear (duplicate addresses are eliminated in any case).
364This variable can be set to the symbol 'first, in which case the
0bb37c1a 365Bcc:/Resent-Bcc: addresses will appear at the beginning in the list;
bd1cd4c2
KH
366or, it can be set to the symbol 'last, in which case they will appear
367at the end of the list.
368
369Why should you care? Well, maybe you don't, and certainly the same
370things could be accomplished by affecting the order of message headers
37aa9115
KH
371in the outgoing message. Some people use Bcc: as a way of getting
372their own \"come back\" copy of each message they send. If Bcc:
bd1cd4c2
KH
373addresses are not handled first, there can be substantial delays in
374seeing the message again. Some configurations of sendmail, for example,
375seem to try to deliver to each addressee at least once, immediately
376and serially, so slow SMTP conversations can add up to a delay. There
377is an option for either 'first or 'last because you might have a
378delivery agent that processes the addresses backwards."
379 :group 'feedmail-headers
380 :type 'boolean
c7d4a777 381 )
bd1cd4c2
KH
382
383
384(defcustom feedmail-fill-to-cc t
385 "*If non-nil do smart filling of addressee header lines.
386Smart filling means breaking long lines at appropriate points and
387making continuation lines. Despite the function name, it includes
37aa9115
KH
388To:, Cc:, Bcc: (and their Resent-* forms), as well as From: and
389Reply-To: (though they seldom need it). If nil, the lines are left
bd1cd4c2
KH
390as-is. The filling is done after mail address alias expansion."
391 :group 'feedmail-headers
392 :type 'boolean
c7d4a777 393 )
bd1cd4c2
KH
394
395
396(defcustom feedmail-fill-to-cc-fill-column default-fill-column
27772f10 397 "*Fill column used by `feedmail-fill-to-cc'."
bd1cd4c2
KH
398 :group 'feedmail-headers
399 :type 'integer
c7d4a777 400 )
bd1cd4c2
KH
401
402
403(defcustom feedmail-nuke-bcc-in-fcc nil
37aa9115
KH
404 "*If non-nil remove [Resent-]Bcc: lines in message copies saved via Fcc:.
405This is independent of whether the Bcc: header lines are actually sent
bd1cd4c2 406with the message (see feedmail-nuke-bcc). Though not implied in the name,
37aa9115 407the same Fcc: treatment applies to both Bcc: and Resent-Bcc: lines."
bd1cd4c2
KH
408 :group 'feedmail-headers
409 :type 'boolean
c7d4a777 410 )
bd1cd4c2
KH
411
412
413(defcustom feedmail-nuke-body-in-fcc nil
37aa9115 414 "*If non-nil remove body of message in copies saved via Fcc:.
afbc4a8a 415If a positive integer value, leave (up to) that many lines of the
37aa9115 416beginning of the body intact. The result is that the Fcc: copy will
bd1cd4c2
KH
417consist only of the message headers, serving as a sort of an outgoing
418message log."
419 :group 'feedmail-headers
420 :type '(choice (const nil) (const t) integer)
c7d4a777 421 )
bd1cd4c2
KH
422
423
424(defcustom feedmail-force-expand-mail-aliases nil
0bb37c1a 425 "*If non-nil, force the calling of `expand-mail-aliases'.
bd1cd4c2 426Normally, feedmail tries to figure out if you're using mailalias or
0bb37c1a 427mailabbrevs and only calls `expand-mail-aliases' if it thinks you're
bd1cd4c2
KH
428using the mailalias package. This user option can be used to force
429the issue since there are configurations which fool the figuring
430out."
431 :group 'feedmail-headers
432 :type 'boolean
c7d4a777 433 )
bd1cd4c2
KH
434
435
436(defcustom feedmail-nuke-empty-headers t
437 "*If non-nil, remove header lines which have no contents.
37aa9115 438A completely empty Subject: header is always removed, regardless of
bd1cd4c2
KH
439the setting of this variable. The only time you would want them left
440in would be if you used some headers whose presence indicated
441something rather than their contents. This is rare in Internet email
442but common in some proprietary systems."
443 :group 'feedmail-headers
444 :type 'boolean
c7d4a777 445 )
bd1cd4c2 446
37aa9115 447;; wjc sez: I think the use of the Sender: line is pretty pointless,
bd1cd4c2
KH
448;; but I left it in to be compatible with sendmail.el and because
449;; maybe some distant mail system needs it. Really, though, if you
450;; want a sender line in your mail, just put one in there and don't
451;; wait for feedmail to do it for you. (Yes, I know all about
452;; RFC-822 and RFC-1123, but are you *really* one of those cases
453;; they're talking about? I doubt it.)
454(defcustom feedmail-sender-line nil
37aa9115 455 "*If non-nil and the email has no Sender: header, use this value.
bd1cd4c2 456May be nil, in which case nothing in particular is done with respect
37aa9115 457to Sender: lines. By design, will not replace an existing Sender:
bd1cd4c2
KH
458line, but you can achieve that with a fiddle-plex 'replace action.
459NB: it makes no sense to use the value t since there is no sensible
37aa9115 460default for Sender:.
bd1cd4c2
KH
461
462If not nil, it may be a string, a fiddle-plex, or a function which
463returns either nil, t, a string, or a fiddle-plex (or, in fact,
464another function, but let's not be ridiculous). If a string, it
465should be just the contents of the header, not the name of the header
466itself nor the trailing newline. If a function, it will be called
467with no arguments. For an explanation of fiddle-plexes, see the
27772f10 468documentation for the variable `feedmail-fiddle-plex-blurb'. In all
bd1cd4c2
KH
469cases the name element of the fiddle-plex is ignored and is hardwired
470by feedmail to either \"X-Sender\" or \"X-Resent-Sender\".
471
472You can probably leave this nil, but if you feel like using it, a good
473value would be a string of a fully-qualified domain name form of your
37aa9115
KH
474address. For example, \"bill@bubblegum.net (WJCarpenter)\". The Sender:
475header is fiddled after the From: header is fiddled."
bd1cd4c2
KH
476 :group 'feedmail-headers
477 :type '(choice (const nil) string)
c7d4a777 478 )
bd1cd4c2
KH
479
480
481(defcustom feedmail-force-binary-write t
37aa9115 482 "*If non-nil, force writing file as binary (this applies to queues and Fcc:).
bd1cd4c2 483On systems where there is a difference between binary and text files,
705e5bd9
SM
484feedmail will temporarily manipulate the value of `buffer-file-type'
485to make the writing as binary. If nil, writing will be in text mode.
486On systems where there is no distinction or where it is controlled by other
487variables or other means, this option has no effect."
bd1cd4c2
KH
488 :group 'feedmail-misc
489 :type 'boolean
c7d4a777 490 )
bd1cd4c2
KH
491
492
493(defcustom feedmail-from-line t
37aa9115 494 "*If non-nil and the email has no From: header, use this value.
bd1cd4c2
KH
495May be t, in which case a default is computed (and you probably won't
496be happy with it). May be nil, in which case nothing in particular is
37aa9115
KH
497done with respect to From: lines. By design, will not replace an
498existing From: line, but you can achieve that with a fiddle-plex 'replace
bd1cd4c2
KH
499action.
500
501If neither nil nor t, it may be a string, a fiddle-plex, or a function
502which returns either nil, t, a string, or a fiddle-plex (or, in fact,
503another function, but let's not be ridiculous). If a string, it
504should be just the contents of the header, not the name of the header
505itself nor the trailing newline. If a function, it will be called
506with no arguments. For an explanation of fiddle-plexes, see the
27772f10 507documentation for the variable `feedmail-fiddle-plex-blurb'. In all
bd1cd4c2
KH
508cases the name element of the fiddle-plex is ignored and is hardwired
509by feedmail to either \"X-From\" or \"X-Resent-From\".
510
511A good value would be a string fully-qualified domain name form of
512your address. For example, \"bill@bubblegum.net (WJCarpenter)\". The
513default value of this variable uses the standard elisp variable
0bb37c1a
KH
514`user-mail-address' which should be set on every system but has a decent
515chance of being wrong. It also honors `mail-from-style'. Better to set
bd1cd4c2 516this variable explicitly to the string you want or find some other way
37aa9115 517to arrange for the message to get a From: line."
bd1cd4c2 518 :group 'feedmail-headers
19a2870f 519 :type '(choice (const t) (const nil) string)
c7d4a777 520 )
bd1cd4c2
KH
521
522
523(defcustom feedmail-deduce-envelope-from t
37aa9115
KH
524 "*If non-nil, deduce message envelope \"from\" from header From: or Sender:.
525In other words, if there is a Sender: header in the message, temporarily
0bb37c1a 526change the value of `user-mail-address' to be the same while the message
37aa9115 527is being sent. If there is no Sender: header, use the From: header,
bd1cd4c2
KH
528if any. Address values are taken from the actual message just before
529it is sent, and the process is independent of the values of
27772f10 530`feedmail-from-line' and/or `feedmail-sender-line'.
bd1cd4c2
KH
531
532There are many and good reasons for having the message header
37aa9115 533From:/Sender: be different from the message envelope \"from\"
bd1cd4c2
KH
534information. However, for most people and for most circumstances, it
535is usual for them to be the same (this is probably especially true for
536the case where the user doesn't understand the difference between the
537two in the first place).
538
539The idea behind this feature is that you can have everything set up
540some normal way for yourself. If for some reason you want to send a
37aa9115 541message with another From: line, you can just type it at the top of
bd1cd4c2
KH
542the message, and feedmail will take care of \"fixing up\" the envelope
543\"from\". This only works for mail senders which make use of
0bb37c1a 544`user-mail-address' as the envelope \"from\" value. For some mail
bd1cd4c2
KH
545senders (e.g., feedmail-buffer-to-bin-mail), there is no simple way to
546influence what they will use as the envelope."
547 :group 'feedmail-headers
548 :type 'boolean
c7d4a777 549 )
bd1cd4c2
KH
550
551
552(defcustom feedmail-x-mailer-line-user-appendage nil
553 "*See feedmail-x-mailer-line."
554 :group 'feedmail-headers
7b3237a1 555 :type '(choice (const nil) (const t) string)
c7d4a777 556 )
bd1cd4c2
KH
557
558
559(defcustom feedmail-x-mailer-line t
37aa9115 560 "*Control the form of an X-Mailer: header in an outgoing message.
bd1cd4c2
KH
561Moderately useful for debugging, keeping track of your correspondents'
562mailer preferences, or just wearing your MUA on your sleeve. You
563should probably know that some people are fairly emotional about the
37aa9115 564presence of X-Mailer: lines in email.
bd1cd4c2 565
37aa9115 566If nil, nothing is done about X-Mailer:.
bd1cd4c2 567
37aa9115
KH
568If t, an X-Mailer: header of a predetermined format is produced,
569combining its efforts with any existing X-Mailer: header. If you want
bd1cd4c2
KH
570to take the default construct and just add a little blob of your own
571at the end, define the variable feedmail-x-mailer-line-user-appendage
0bb37c1a 572as that blob string. A value of t is equivalent to using the function
bd1cd4c2
KH
573feedmail-default-x-mailer-generator.
574
575If neither nil nor t, it may be a string, a fiddle-plex, or a function
576which returns either nil, t, a string, or a fiddle-plex (or, in fact,
577another function, but let's not be ridiculous). If a string, it
578should be just the contents of the header, not the name of the header
579itself nor the trailing newline. If a function, it will be called
580with no arguments. For an explanation of fiddle-plexes, see the
27772f10 581documentation for the variable `feedmail-fiddle-plex-blurb'. In all
bd1cd4c2
KH
582cases the name element of the fiddle-plex is ignored and is hardwired
583by feedmail to either \"X-Mailer\" or \"X-Resent-Mailer\"."
584 :group 'feedmail-headers
585 :type '(choice (const t) (const nil) string function)
c7d4a777 586 )
bd1cd4c2
KH
587
588
589(defcustom feedmail-message-id-generator t
37aa9115 590 "*Specifies the creation of a Message-Id: header field.
bd1cd4c2 591
37aa9115 592If nil, nothing is done about Message-Id:.
bd1cd4c2 593
37aa9115
KH
594If t, a Message-Id: header of a predetermined format is produced, but
595only if there is not already a Message-Id: in the message. A value of
bd1cd4c2
KH
596t is equivalent to using the function feedmail-default-message-id-generator.
597
598If neither nil nor t, it may be a string, a fiddle-plex, or a function
599which returns either nil, t, a string, or a fiddle-plex (or, in fact,
600another function, but let's not be ridiculous). If a string, it
601should be just the contents of the header, not the name of the header
602itself nor the trailing newline. If a function, it will be called
603with one argument: the possibly-nil name of the file associated with
604the message buffer. For an explanation of fiddle-plexes, see the
27772f10 605documentation for the variable `feedmail-fiddle-plex-blurb'. In all
bd1cd4c2 606cases the name element of the fiddle-plex is ignored and is hardwired
37aa9115 607by feedmail to either \"Message-Id\" or \"Resent-Message-Id\".
bd1cd4c2 608
37aa9115 609You should let feedmail generate a Message-Id: for you unless you are sure
bd1cd4c2
KH
610that whatever you give your messages to will do it for you (e.g., most
611configurations of sendmail). Even if the latter case is true, it
612probably won't hurt you to generate your own, and it will then show up
37aa9115 613in the saved message if you use Fcc:."
bd1cd4c2 614 :group 'feedmail-headers
7c2288ea 615 :type '(choice (const t) (const nil) function)
c7d4a777 616 )
bd1cd4c2
KH
617
618
619(defcustom feedmail-message-id-suffix nil
0bb37c1a
KH
620 "*If non-nil, used as a suffix for generating unique Message-Id: headers.
621The function `feedmail-default-message-id-generator' creates its work based
bd1cd4c2 622on a formatted date-time string, a random number, and a domain-looking suffix.
0bb37c1a
KH
623You can control the suffix used by assigning a string value to this variable.
624If you don't supply one, the value of the variable `user-mail-address' will be
625used. If the value of `feedmail-message-id-suffix' contains an \"@\" character,
626the string will be used verbatim, else an \"@\" character will be prepended
627automatically."
bd1cd4c2 628 :group 'feedmail-headers
19a2870f 629 :type '(choice (const nil) string)
c7d4a777 630 )
bd1cd4c2
KH
631
632;; this was suggested in various forms by several people; first was
633;; Tony DeSimone in Oct 1992; sorry to be so tardy
634(defcustom feedmail-date-generator t
37aa9115 635 "*Specifies the creation of a Date: header field.
bd1cd4c2 636
37aa9115 637If nil, nothing is done about Date:.
bd1cd4c2 638
37aa9115
KH
639If t, a Date: header of a predetermined format is produced, but only
640if there is not already a Date: in the message. A value of t is
27772f10 641equivalent to using the function `feedmail-default-date-generator'.
bd1cd4c2
KH
642
643If neither nil nor t, it may be a string, a fiddle-plex, or a function
644which returns either nil, t, a string, or a fiddle-plex (or, in fact,
645another function, but let's not be ridiculous). If a string, it
646should be just the contents of the header, not the name of the header
647itself nor the trailing newline. If a function, it will be called
648with one argument: the possibly-nil name of the file associated with
649the message buffer. For an explanation of fiddle-plexes, see the
27772f10 650documentation for the variable `feedmail-fiddle-plex-blurb'. In all
bd1cd4c2
KH
651cases the name element of the fiddle-plex is ignored and is hardwired
652by feedmail to either \"Date\" or \"Resent-Date\".
653
654If you decide to format your own date field, do us all a favor and know
655what you're doing. Study the relevant parts of RFC-822 and RFC-1123.
656Don't make me come up there!
657
37aa9115 658You should let feedmail generate a Date: for you unless you are sure
bd1cd4c2
KH
659that whatever you give your messages to will do it for you (e.g., most
660configurations of sendmail). Even if the latter case is true, it
661probably won't hurt you to generate your own, and it will then show up
37aa9115 662in the saved message if you use Fcc:."
bd1cd4c2 663 :group 'feedmail-headers
7c2288ea 664 :type '(choice (const t) (const nil) function)
c7d4a777 665 )
bd1cd4c2
KH
666
667
668(defcustom feedmail-fiddle-headers-upwardly t
0bb37c1a 669 "*Non-nil means fiddled header fields should go at the top of the header.
f0529b5b 670nil means insert them at the bottom. This is mostly a novelty issue since
bd1cd4c2
KH
671the standards define the ordering of header fields to be immaterial and it's
672fairly likely that some MTA along the way will have its own idea of what the
673order should be, regardless of what you specify."
436de921 674 :group 'feedmail-headers
bd1cd4c2
KH
675 :type 'boolean
676 )
677
678
679(defcustom feedmail-fiddle-plex-user-list nil
680 "If non-nil, should be a list of one or more fiddle-plexes.
681Each element of the list can also be a function which returns a
682fiddle-plex.
683
684feedmail will use this list of fiddle-plexes to manipulate user-specified
685message header fields. It does this after it has completed all normal
27772f10 686message header field manipulation and before calling `feedmail-last-chance-hook'.
bd1cd4c2
KH
687
688For an explanation of fiddle-plexes, see the documentation for the
27772f10 689variable `feedmail-fiddle-plex-blurb'. In contrast to some other fiddle-plex
bd1cd4c2
KH
690manipulation functions, in this context, it makes no sense to have an element
691which is nil, t, or a simple string."
436de921 692 :group 'feedmail-headers
7b3237a1
AS
693 :type '(repeat (choice function)
694 sexp) ; too complex to be described accurately
bd1cd4c2
KH
695 )
696
697
698(defcustom feedmail-enable-spray nil
699 "If non-nil, transmit message separately to each addressee.
700feedmail normally accumulates a list of addressees and passes the message
701along with that list to a buffer-eating function which expects any number
702of addressees. If this variable is non-nil, however, feedmail will
703repeatedly call the same buffer-eating function. Each time, the list of
704addressees will be just one item from the original list. This only affects
0bb37c1a 705the message envelope addresses and doesn't affect what appears in the
bd1cd4c2
KH
706message headers except as noted.
707
708Spray mode is usually pointless, and if you can't think of a good reason for
0bb37c1a 709it, you should avoid it since it is inherently less efficient than normal
bd1cd4c2 710multiple delivery. One reason to use it is to overcome mis-featured mail
37aa9115 711transports which betray your trust by revealing Bcc: addressees in the
bd1cd4c2 712headers of a message. Another use is to do a crude form of mailmerge, for
27772f10 713which see `feedmail-spray-address-fiddle-plex-list'.
bd1cd4c2
KH
714
715If one of the calls to the buffer-eating function results in an error,
716what happens next is carelessly defined, so beware."
717 :group 'feedmail-spray
718 :type 'boolean
719 )
720
721(defvar feedmail-spray-this-address nil
27772f10 722 "Do not set or change this variable. See `feedmail-spray-address-fiddle-plex-list'.")
bd1cd4c2
KH
723
724(defcustom feedmail-spray-address-fiddle-plex-list nil
725 "User-supplied specification for a crude form of mailmerge capability.
726When spraying is enabled, feedmail composes a list of envelope addresses.
27772f10 727In turn, `feedmail-spray-this-address' is temporarily set to each address
0bb37c1a
KH
728\(stripped of any comments and angle brackets\) and calls a function which
729fiddles message headers according to this variable. See the documentation for
730`feedmail-fiddle-plex-blurb', for an overview of fiddle-plex data structures.
bd1cd4c2
KH
731
732May be nil, in which case nothing in particular is done about message
733headers for specific addresses.
734
37aa9115 735May be t, in which case a \"To:\" header is added to the message with
bd1cd4c2
KH
736the stripped address as the header contents. The fiddle-plex operator
737is 'supplement.
738
739May be a string, in which case the string is assumed to be the name of
740a message header field with the stripped address serving as the value.
741The fiddle-plex operator is 'supplement.
742
743May be a function, in which case it is called with no arguments and is
744expected to return nil, t, a string, another function, or a fiddle-plex.
745The result is used recursively.
746
747May be a list of any combination of the foregoing and fiddle-plexes. (A
748value for this variable which consists of a single fiddle-plex must be
749nested inside another list to avoid ambiguity.) If a list, each item
750is acted on in turn as described above.
751
752For example,
753
754 (setq feedmail-spray-address-fiddle-plex-list 'my-address-embellisher)
755
756The idea of the example is that, during spray mode, as each message is
757about to be transmitted to an individual address, the function will be
27772f10 758called and will consult `feedmail-spray-this-address' to find the
bd1cd4c2
KH
759stripped envelope email address (no comments or angle brackets). The
760function should return an embellished form of the address.
761
762The recipe for sending form letters is: (1) create a message with all
37aa9115 763addressees on Bcc: headers; (2) tell feedmail to remove Bcc: headers
0bb37c1a 764before sending the message; (3) create a function which will embellish
27772f10
JB
765stripped addresses, if desired; (4) define `feedmail-spray-address-fiddle-plex-list'
766appropriately; (5) send the message with `feedmail-enable-spray' set
bd1cd4c2
KH
767non-nil; (6) stand back and watch co-workers wonder at how efficient
768you are at accomplishing inherently inefficient things."
769 :group 'feedmail-spray
7b3237a1 770 :type 'sexp ; too complex to be described accurately
bd1cd4c2
KH
771 )
772
773
774(defcustom feedmail-enable-queue nil
775 "*If non-nil, provide for stashing outgoing messages in a queue.
776This is the master on/off switch for feedmail message queuing.
777Queuing is quite handy for laptop-based users. It's also handy if you
778get a lot of mail and process it more or less sequentially. For
779example, you might change your mind about contents of a reply based on
780a message you see a bit later.
781
782There is a separate queue for draft messages, intended to prevent
783you from accidentally sending incomplete messages. The queues are
784disk-based and intended for later transmission. The messages are
785queued in their raw state as they appear in the mail-mode buffer and
786can be arbitrarily edited later, before sending, by visiting the
787appropriate file in the queue directory (and setting the buffer to
788mail-mode or whatever). If you visit a file in the queue directory
789and try to queue it again, it will just get saved in its existing file
790name. You can move a message from the draft to the main queue or vice
791versa by pretending to send it and then selecting whichever queue
792directory you want at the prompt. The right thing will happen.
793
794To transmit all the messages in the queue, invoke the command
27772f10 795`feedmail-run-the-queue' or `feedmail-run-the-queue-no-prompts'."
bd1cd4c2
KH
796 :group 'feedmail-queue
797 :type 'boolean
c7d4a777 798 )
bd1cd4c2
KH
799
800
801(defcustom feedmail-queue-runner-confirm-global nil
802 "*If non-nil, give a y-or-n confirmation prompt before running the queue.
803Prompt even if the queue is about to be processed as a result of a call to
27772f10 804`feedmail-run-the-queue-no-prompts'. This gives you a way to bail out
bd1cd4c2
KH
805without having to answer no to the individual message prompts."
806 :group 'feedmail-queue
807 :type 'boolean)
808
809
bd1cd4c2 810(defcustom feedmail-queue-directory
7c2fb837 811 (concat (getenv "HOME") "/mail/q")
bd1cd4c2
KH
812 "*Name of a directory where messages will be queued.
813Directory will be created if necessary. Should be a string that
7c2fb837 814doesn't end with a slash. Default is \"$HOME/mail/q\"."
bd1cd4c2
KH
815 :group 'feedmail-queue
816 :type 'string
c7d4a777 817 )
bd1cd4c2
KH
818
819
820(defcustom feedmail-queue-draft-directory
7c2fb837 821 (concat (getenv "HOME") "/mail/draft")
afbc4a8a 822 "*Name of a directory where draft messages will be queued.
bd1cd4c2 823Directory will be created if necessary. Should be a string that
7c2fb837 824doesn't end with a slash. Default is \"$HOME/mail/draft\"."
bd1cd4c2
KH
825 :group 'feedmail-queue
826 :type 'string
c7d4a777 827 )
bd1cd4c2
KH
828
829
830(defcustom feedmail-ask-before-queue t
831 "*If non-nil, feedmail will ask what you want to do with the message.
832Default choices for the message action prompt will include sending it
833immediately, putting it in the main queue, putting it in the draft
834queue, or returning to the buffer to continue editing. Only matters if
835queuing is enabled. If nil, the message is placed in the main queue
836without a prompt."
837 :group 'feedmail-queue
838 :type 'boolean
c7d4a777 839 )
bd1cd4c2
KH
840
841
842(defcustom feedmail-ask-before-queue-prompt "FQM: Message action (q, i, d, e, ?)? [%s]: "
843 "*A string which will be used for the message action prompt.
844If it contains a \"%s\", that will be replaced with the value of
27772f10 845`feedmail-ask-before-queue-default'."
bd1cd4c2
KH
846 :group 'feedmail-queue
847 :type 'string
c7d4a777 848 )
bd1cd4c2
KH
849
850
851(defcustom feedmail-ask-before-queue-reprompt "FQM: Please type q, i, d, or e; or ? for help [%s]: "
852 "*A string which will be used for repompting after invalid input.
853If it contains a \"%s\", that will be replaced with the value of
27772f10 854`feedmail-ask-before-queue-default'."
bd1cd4c2
KH
855 :group 'feedmail-queue
856 :type 'string
c7d4a777 857 )
bd1cd4c2
KH
858
859
860(defcustom feedmail-ask-before-queue-default "queue"
861 "*Meaning if user hits return in response to the message action prompt.
862Should be a character or a string; if a string, only the first
863character is significant. Useful values are those described in
864the help for the message action prompt."
865 :group 'feedmail-queue
c7d4a777
KH
866 :type '(choice string integer) ;use integer to get char
867 )
bd1cd4c2
KH
868
869
870(defvar feedmail-prompt-before-queue-standard-alist
871 '((?q . feedmail-message-action-queue)
c7d4a777 872 (?Q . feedmail-message-action-queue-strong)
bd1cd4c2 873
c7d4a777
KH
874 (?d . feedmail-message-action-draft)
875 (?r . feedmail-message-action-draft)
876 (?D . feedmail-message-action-draft-strong)
877 (?R . feedmail-message-action-draft-strong)
bd1cd4c2 878
c7d4a777
KH
879 (?e . feedmail-message-action-edit)
880 (?E . feedmail-message-action-edit)
881 (?\C-g . feedmail-message-action-edit)
882 (?n . feedmail-message-action-edit)
883 (?N . feedmail-message-action-edit)
bd1cd4c2 884
c7d4a777
KH
885 (?i . feedmail-message-action-send)
886 (?I . feedmail-message-action-send-strong)
887 (?s . feedmail-message-action-send)
888 (?S . feedmail-message-action-send-strong)
bd1cd4c2 889
c7d4a777 890 (?* . feedmail-message-action-toggle-spray)
bd1cd4c2 891
c7d4a777
KH
892 (?\C-v . feedmail-message-action-help)
893 (?? . feedmail-message-action-help))
bd1cd4c2
KH
894 "An alist of choices for the message action prompt.
895All of the values are function names, except help, which is a special
896symbol that calls up help for the prompt (the help describes the
897actions from the standard alist). To customize your own choices,
27772f10 898define a similar alist called `feedmail-prompt-before-queue-user-alist'.
bd1cd4c2
KH
899The actual alist used for message action will be the standard alist
900overlaid with the user-alist. To neutralize an item in the standard
901alist without providing a replacement, define an appropriate element
902in the user alist with a value of nil." )
903
904
905(defcustom feedmail-prompt-before-queue-user-alist nil
27772f10 906 "See `feedmail-prompt-before-queue-standard-alist'."
bd1cd4c2 907 :group 'feedmail-queue
7b3237a1 908 :type '(repeat (cons character function))
bd1cd4c2
KH
909 )
910
911
912(defcustom feedmail-prompt-before-queue-help-supplement nil
913 "User-provided supplementary help string for the message action prompt.
914When the message action prompt is shown, the user can as for verbose help,
915at which point a buffer pops up describing the meaning of possible
916responses to the prompt. Through various customizations (see, for
27772f10 917example, `feedmail-prompt-before-queue-user-alist'), the available responses
bd1cd4c2
KH
918and the prompt itself can be changed. If this variable is set to a string
919value, that string is written to the help buffer after the standard info.
27772f10 920It may contain embedded line breaks. It will be printed via `princ'."
bd1cd4c2 921 :group 'feedmail-queue
7b3237a1 922 :type '(choice (const nil) string)
bd1cd4c2
KH
923 )
924
925
926(defcustom feedmail-queue-reminder-alist
927 '((after-immediate . feedmail-queue-reminder-brief)
c7d4a777
KH
928 (after-queue . feedmail-queue-reminder-medium)
929 (after-draft . feedmail-queue-reminder-medium)
930 (after-run . feedmail-queue-reminder-brief)
931 (on-demand . feedmail-run-the-queue-global-prompt))
27772f10 932 "See `feedmail-queue-reminder'."
bd1cd4c2 933 :group 'feedmail-queue
7b3237a1
AS
934 :type '(repeat (cons (choice :tag "Event"
935 (const on-demand)
936 (const after-immediate)
937 (const after-queue)
938 (const after-draft)
939 (const after-run))
940 function))
bd1cd4c2
KH
941 )
942
943
944(defcustom feedmail-queue-chatty t
945 "*If non-nil, blat a few status messages and such in the mini-buffer.
946If nil, just do the work and don't pester people about what's going on.
947In some cases, though, specific options inspire mini-buffer prompting.
948That's not affected by this variable setting. Also does not control
949reporting of error/abnormal conditions."
950 :group 'feedmail-queue
951 :type 'boolean
c7d4a777 952 )
bd1cd4c2
KH
953
954
955(defcustom feedmail-queue-chatty-sit-for 2
956 "*Duration of pause after most queue-related messages.
957After some messages are divulged, it is prudent to pause before
958something else obliterates them. This value controls the duration of
959the pause."
960 :group 'feedmail-queue
961 :type 'integer
c7d4a777 962 )
bd1cd4c2
KH
963
964
965(defcustom feedmail-queue-run-orderer nil
966 "*If non-nil, name a function which will sort the queued messages.
967The function is called during a running of the queue for sending, and
968takes one argument, a list of the files in the queue directory. It
969may contain the names of non-message files, and it's okay to leave
970them in the list when reordering it; they get skipped over later.
971When nil, the default action processes the messages in normal sort
972order by queued file name, which will typically result in the order
973they were placed in the queue."
974 :group 'feedmail-queue
975 :type '(choice (const nil) function)
c7d4a777 976 )
bd1cd4c2
KH
977
978
979(defcustom feedmail-queue-use-send-time-for-date nil
37aa9115 980 "*If non-nil, use send time for the Date: header value.
bd1cd4c2
KH
981This variable is used by the default date generating function,
982feedmail-default-date-generator. If nil, the default, the
983last-modified timestamp of the queue file is used to create the
37aa9115 984message Date: header; if there is no queue file, the current time is
bd1cd4c2
KH
985used."
986 :group 'feedmail-queue
987 :type 'boolean
c7d4a777 988 )
bd1cd4c2
KH
989
990
991(defcustom feedmail-queue-use-send-time-for-message-id nil
37aa9115
KH
992 "*If non-nil, use send time for the Message-Id: header value.
993This variable is used by the default Message-Id: generating function,
27772f10 994`feedmail-default-message-id-generator'. If nil, the default, the
bd1cd4c2 995last-modified timestamp of the queue file is used to create the
37aa9115 996message Message-Id: header; if there is no queue file, the current time is
bd1cd4c2
KH
997used."
998 :group 'feedmail-queue
999 :type 'boolean
c7d4a777 1000 )
bd1cd4c2
KH
1001
1002
1003(defcustom feedmail-ask-for-queue-slug nil
1004 "*If non-nil, prompt user for part of the queue file name.
1005The file will automatically get the FQM suffix and an embedded
1006sequence number for uniqueness, so don't specify that. feedmail will
1007get rid of all characters other than alphanumeric and hyphen in the
1008results. If this variable is nil or if you just hit return in
1009response to the prompt, feedmail queuing will take care of things
1010properly. At the prompt, completion is available if you want to see
1011what filenames are already in use, though, as noted, you will not be
1012typing a complete file name. You probably don't want to be bothered
1013with this prompting since feedmail, by default, uses queue file names
1014based on the subjects of the messages."
1015 :group 'feedmail-queue
1016 :type 'boolean
c7d4a777 1017 )
bd1cd4c2
KH
1018
1019
1020(defcustom feedmail-queue-slug-maker 'feedmail-queue-subject-slug-maker
1021 "*If non-nil, a function which creates part of the queued file name.
1022Takes a single argument giving the name of the directory into
1023which the message will be queued. The returned string should be just
1024the non-directory filename part, without FQM suffix or uniquifying
1025sequence numbers. The current buffer holds the raw message. The
1026default function creates the slug based on the message subject, if
1027any."
1028 :group 'feedmail-queue
1029 :type '(choice (const nil) function)
c7d4a777 1030 )
bd1cd4c2
KH
1031
1032
1033(defcustom feedmail-queue-default-file-slug t
1034 "*Indicates what to use for subject-less messages when forming a file name.
0bb37c1a 1035When feedmail queues a message, it creates a unique file name. By default,
bd1cd4c2
KH
1036the file name is based in part on the subject of the message being queued.
1037If there is no subject, consult this variable. See documentation for the
27772f10 1038function `feedmail-queue-subject-slug-maker'.
bd1cd4c2
KH
1039
1040If t, an innocuous default is used.
1041
1042If a string, it is used directly.
1043
1044If a function, it is called with no arguments from the buffer containing the raw
1045text of the message. It must return a string (which may be empty).
1046
1047If the symbol 'ask, you will be prompted for a string in the mini-buffer.
1048Filename completion is available so that you can inspect what's already been
1049used, but feedmail will do further manipulation on the string you return, so
1050it's not expected to be a complete filename."
1051 :group 'feedmail-queue
7b3237a1 1052 :type '(choice (const :tag "Default" t) string function (const ask))
c7d4a777 1053 )
bd1cd4c2
KH
1054
1055
1056(defcustom feedmail-queue-fqm-suffix ".fqm"
1057 "*The FQM suffix used to distinguish feedmail queued message files.
1058You probably want this to be a period followed by some letters and/or
1059digits. The distinction is to be able to tell them from other random
27772f10
JB
1060files that happen to be in the `feedmail-queue-directory' or
1061`feedmail-queue-draft-directory'. By the way, FQM stands for feedmail
bd1cd4c2
KH
1062queued message."
1063 :group 'feedmail-queue
1064 :type 'string
c7d4a777 1065 )
bd1cd4c2
KH
1066
1067
1068(defcustom feedmail-nuke-buffer-after-queue nil
1069 "*If non-nil, silently kill the buffer after a message is queued.
1070You might like that since a side-effect of queueing the message is
1071that its buffer name gets changed to the filename. That means that
1072the buffer won't be reused for the next message you compose. If you
1073are using VM for creating messages, you probably want to leave this
1074nil, since VM has its own options for managing the recycling of
1075message buffers."
1076 :group 'feedmail-queue
1077 :type 'boolean
c7d4a777 1078 )
bd1cd4c2
KH
1079
1080
1081(defcustom feedmail-queue-auto-file-nuke nil
1082 "*If non-nil, automatically delete queue files when a message is sent.
1083Normally, feedmail will notice such files when you send a message in
1084immediate mode (i.e., not when you're running the queue) and will ask if
1085you want to delete them. Since the answer is usually yes, setting this
0bb37c1a 1086variable to non-nil will tell feedmail to skip the prompt and just delete
bd1cd4c2
KH
1087the file without bothering you."
1088 :group 'feedmail-queue
1089 :type 'boolean
c7d4a777 1090 )
bd1cd4c2
KH
1091
1092
1093;; defvars to make byte-compiler happy(er)
0bb37c1a
KH
1094(defvar feedmail-error-buffer nil)
1095(defvar feedmail-prepped-text-buffer nil)
1096(defvar feedmail-raw-text-buffer nil)
1097(defvar feedmail-address-list nil)
bd1cd4c2
KH
1098
1099
7163b71c
RS
1100(defvar feedmail-queue-runner-is-active nil
1101 "*Non-nil means we're inside the logic of the queue-running loop.
1102That is, iterating over all messages in the queue to send them. In
1103that case, the value is the name of the queued message file currently
1104being processed. This can be used for differentiating customized code
1105for different scenarios. Users shouldn't set or change this
1106variable, but may depend on its value as described here.")
1107
1108
bd1cd4c2 1109(defun feedmail-mail-send-hook-splitter ()
27772f10
JB
1110 "Facilitate dividing `mail-send-hook' things into queued and immediate cases.
1111If you have `mail-send-hook' functions that should only be called for sending/
bd1cd4c2 1112queueing messages or only be called for the sending of queued messages, this is
27772f10 1113for you. Add this function to `mail-send-hook' with something like this:
bd1cd4c2
KH
1114
1115 (add-hook 'mail-send-hook 'feedmail-mail-send-hook-splitter)
1116
27772f10
JB
1117Then add the functions you want called to either `feedmail-mail-send-hook-queued'
1118or `feedmail-mail-send-hook', as apprpriate. The distinction is that
1119`feedmail-mail-send-hook' will be called when you send mail from a composition
bd1cd4c2 1120buffer (typically by typing C-c C-c), whether the message is sent immediately
27772f10 1121or placed in the queue or drafts directory. `feedmail-mail-send-hook-queued' is
bd1cd4c2 1122called when messages are being sent from the queue directory, typically via a
27772f10 1123call to `feedmail-run-the-queue'."
bd1cd4c2 1124 (if feedmail-queue-runner-is-active
c7d4a777
KH
1125 (run-hooks 'feedmail-mail-send-hook-queued)
1126 (run-hooks 'feedmail-mail-send-hook))
1127 )
bd1cd4c2
KH
1128
1129
1130(defvar feedmail-mail-send-hook nil
27772f10 1131 "*See documentation for `feedmail-mail-send-hook-splitter'.")
bd1cd4c2
KH
1132
1133
1134(defvar feedmail-mail-send-hook-queued nil
27772f10 1135 "*See documentation for `feedmail-mail-send-hook-splitter'.")
bd1cd4c2
KH
1136
1137
1138(defun feedmail-confirm-addresses-hook-example ()
27772f10 1139 "An example of a `feedmail-last-chance-hook'.
bd1cd4c2
KH
1140It shows the simple addresses and gets a confirmation. Use as:
1141 (setq feedmail-last-chance-hook 'feedmail-confirm-addresses-hook-example)."
1142 (save-window-excursion
c7d4a777
KH
1143 (display-buffer (set-buffer (get-buffer-create " F-C-A-H-E")))
1144 (erase-buffer)
1145 (insert (mapconcat 'identity feedmail-address-list " "))
1146 (if (not (y-or-n-p "How do you like them apples? "))
1147 (error "FQM: Sending...gave up in last chance hook")
1148 )))
bd1cd4c2
KH
1149
1150
1151(defcustom feedmail-last-chance-hook nil
1152 "*User's last opportunity to modify the message on its way out.
1153It has already had all the header prepping from the standard package.
1154The next step after running the hook will be to push the buffer into a
1155subprocess that mails the mail. The hook might be interested in
27772f10
JB
1156these: (1) `feedmail-prepped-text-buffer' contains the header and body
1157of the message, ready to go; (2) `feedmail-address-list' contains a list
bd1cd4c2 1158of simplified recipients of addresses which are to be given to the
27772f10 1159subprocess (the hook may change the list); (3) `feedmail-error-buffer'
bd1cd4c2
KH
1160is an empty buffer intended to soak up errors for display to the user.
1161If the hook allows interactive activity, the user should not send more
1162mail while in the hook since some of the internal buffers will be
1163reused and things will get confused."
1164 :group 'feedmail-misc
1165 :type 'hook
c7d4a777 1166 )
bd1cd4c2
KH
1167
1168
1169(defcustom feedmail-before-fcc-hook nil
37aa9115 1170 "*User's last opportunity to modify the message before Fcc action.
bd1cd4c2
KH
1171It has already had all the header prepping from the standard package.
1172The next step after running the hook will be to save the message via
37aa9115 1173Fcc: processing. The hook might be interested in these: (1)
27772f10
JB
1174`feedmail-prepped-text-buffer' contains the header and body of the
1175message, ready to go; (2) `feedmail-address-list' contains a list of
bd1cd4c2 1176simplified recipients of addressees to whom the message was sent (3)
27772f10 1177`feedmail-error-buffer' is an empty buffer intended to soak up errors
bd1cd4c2
KH
1178for display to the user. If the hook allows interactive activity, the
1179user should not send more mail while in the hook since some of the
1180internal buffers will be reused and things will get confused."
1181 :group 'feedmail-misc
1182 :type 'hook
c7d4a777 1183 )
bd1cd4c2
KH
1184
1185(defcustom feedmail-queue-runner-mode-setter
1186 '(lambda (&optional arg) (mail-mode))
0bb37c1a
KH
1187 "*A function to set the proper mode of a message file.
1188Called when the message is read back out of the queue directory with a single
bd1cd4c2 1189argument, the optional argument used in the call to
27772f10 1190`feedmail-run-the-queue' or `feedmail-run-the-queue-no-prompts'.
bd1cd4c2 1191
0bb37c1a 1192Most people want `mail-mode', so the default value is an anonymous
bd1cd4c2
KH
1193function which is just a wrapper to ignore the supplied argument when
1194calling it, but here's your chance to have something different.
0bb37c1a 1195Called with funcall, not `call-interactively'."
bd1cd4c2
KH
1196 :group 'feedmail-queue
1197 :type 'function
c7d4a777 1198 )
bd1cd4c2
KH
1199
1200
1201(defcustom feedmail-queue-alternative-mail-header-separator nil
1202 "*Alternative header demarcation for queued messages.
0bb37c1a 1203If you sometimes get alternative values for `mail-header-separator' in
bd1cd4c2 1204queued messages, set the value of this variable to whatever it is.
0bb37c1a 1205For example, `rmail-resend' uses a `mail-header-separator' value of empty
bd1cd4c2
KH
1206string (\"\") when you send/queue a message.
1207
1208When trying to send a queued message, if the value of this variable is
1209non-nil, feedmail will first try to send the message using the value
0bb37c1a
KH
1210of `mail-header-separator'. If it can't find that, it will temporarily
1211set `mail-header-separator' to the value of
27772f10 1212`feedmail-queue-alternative-mail-header-separator' and try again."
bd1cd4c2 1213 :group 'feedmail-queue
7b3237a1 1214 :type '(choice (const nil) string)
c7d4a777 1215 )
bd1cd4c2
KH
1216
1217
1218(defcustom feedmail-queue-runner-message-sender 'mail-send-and-exit
1219 "*Function to initiate sending a message file.
1220Called for each message read back out of the queue directory with a
1221single argument, the optional argument used in the call to
27772f10 1222`feedmail-run-the-queue' or `feedmail-run-the-queue-no-prompts'.
bd1cd4c2 1223Interactively, that argument will be the prefix argument. Most people
27772f10
JB
1224want `mail-send-and-exit' (bound to C-c C-c in mail-mode), but here's
1225your chance to have something different. Called with `funcall', not
1226`call-interactively'."
bd1cd4c2
KH
1227 :group 'feedmail-queue
1228 :type 'function
c7d4a777 1229 )
bd1cd4c2
KH
1230
1231
1232(defcustom feedmail-queue-runner-cleaner-upper
1233 '(lambda (fqm-file &optional arg)
c7d4a777
KH
1234 (delete-file fqm-file)
1235 (if (and arg feedmail-queue-chatty) (message "FQM: Nuked %s" fqm-file)))
0bb37c1a
KH
1236 "*Function that will be called after a message has been sent.
1237Not called in the case of errors. This function is called with two
1238arguments: the name of the message queue file for the message just sent,
1239and the optional argument used in the call to `feedmail-run-the-queue'
1240or `feedmail-run-the-queue-no-prompts' (prefix arg if interactive).
1241In any case, the affiliated buffer is killed elsewhere, so don't do that
bd1cd4c2
KH
1242inside this function. Return value is ignored.
1243
1244The default action is an anonymous function which gets rid of the file
1245from the queue directory. With a non-nil second argument, a brief
1246message is give for each file deleted. You could replace this
1247function, for example, to archive all of your sent messages someplace
0bb37c1a 1248\(though there are better ways to get that particular result\)."
bd1cd4c2
KH
1249 :group 'feedmail-queue
1250 :type 'function
c7d4a777 1251 )
bd1cd4c2
KH
1252
1253
bd1cd4c2 1254(defvar feedmail-is-a-resend nil
110c171f 1255 "*Non-nil means the message is a Resend (in the RFC-822 sense).
bd1cd4c2
KH
1256This affects the composition of certain headers. feedmail sets this
1257variable as soon as it starts prepping the message text buffer, so any
1258user-supplied functions can rely on it. Users shouldn't set or change this
1259variable, but may depend on its value as described here.")
1260
1261
1262(defcustom feedmail-buffer-eating-function 'feedmail-buffer-to-binmail
1263 "*Function used to send the prepped buffer to a subprocess.
1264The function's three (mandatory) arguments are: (1) the buffer
1265containing the prepped message; (2) a buffer where errors should be
1266directed; and (3) a list containing the addresses individually as
1267strings. Three popular choices for this are
27772f10
JB
1268`feedmail-buffer-to-binmail', `feedmail-buffer-to-smtpmail', and
1269`feedmail-buffer-to-sendmail'. If you use the sendmail form, you
1270probably want to set `feedmail-nuke-bcc' and/or `feedmail-nuke-resent-bcc'
bd1cd4c2 1271to nil. If you use the binmail form, check the value of
27772f10 1272`feedmail-binmail-template'."
bd1cd4c2
KH
1273 :group 'feedmail-misc
1274 :type 'function
c7d4a777 1275 )
bd1cd4c2
KH
1276
1277
1278(defcustom feedmail-binmail-template (if mail-interactive "/bin/mail %s" "/bin/rmail %s")
1279 "*Command template for the subprocess which will get rid of the mail.
1280It can result in any command understandable by /bin/sh. Might not
37aa9115 1281work at all in non-Unix environments. The single '%s', if present,
bd1cd4c2 1282gets replaced by the space-separated, simplified list of addressees.
27772f10 1283Used in `feedmail-buffer-to-binmail' to form the shell command which
bd1cd4c2
KH
1284will receive the contents of the prepped buffer as stdin. If you'd
1285like your errors to come back as mail instead of immediately in a
1286buffer, try /bin/rmail instead of /bin/mail (this can be accomplished
0bb37c1a 1287by keeping the default nil setting of `mail-interactive'). You might
bd1cd4c2
KH
1288also like to consult local mail experts for any other interesting
1289command line possibilities."
1290 :group 'feedmail-misc
1291 :type 'string
c7d4a777 1292 )
bd1cd4c2
KH
1293
1294
1295;; feedmail-buffer-to-binmail, feedmail-buffer-to-sendmail, and
1296;; feedmail-buffer-to-smptmail are the only things provided for values
1297;; for the variable feedmail-buffer-eating-function. It's pretty easy
1298;; to write your own, though.
1299(defun feedmail-buffer-to-binmail (prepped errors-to addr-listoid)
1300 "Function which actually calls /bin/mail as a subprocess.
1301Feeds the buffer to it."
1302 (set-buffer prepped)
1303 (apply
1304 'call-process-region
1305 (append (list (point-min) (point-max) "/bin/sh" nil errors-to nil "-c"
c7d4a777
KH
1306 (format feedmail-binmail-template
1307 (mapconcat 'identity addr-listoid " "))))))
bd1cd4c2
KH
1308
1309
1310(defun feedmail-buffer-to-sendmail (prepped errors-to addr-listoid)
1311 "Function which actually calls sendmail as a subprocess.
37aa9115 1312Feeds the buffer to it. Probably has some flaws for Resent-* and other
bd1cd4c2
KH
1313complicated cases."
1314 (set-buffer prepped)
1315 (apply 'call-process-region
c7d4a777 1316 (append (list (point-min) (point-max)
82695714
CY
1317 (cond ((boundp 'sendmail-program)
1318 sendmail-program)
1319 ((file-exists-p "/usr/sbin/sendmail")
1320 "/usr/sbin/sendmail")
1321 ((file-exists-p "/usr/lib/sendmail")
1322 "/usr/lib/sendmail")
1323 ((file-exists-p "/usr/ucblib/sendmail")
1324 "/usr/ucblib/sendmail")
1325 (t "fakemail"))
c7d4a777
KH
1326 nil errors-to nil "-oi" "-t")
1327 ;; provide envelope "from" to sendmail; results will vary
1328 (list "-f" user-mail-address)
1329 ;; These mean "report errors by mail" and "deliver in background".
1330 (if (null mail-interactive) '("-oem" "-odb")))))
bd1cd4c2
KH
1331
1332;; provided by jam@austin.asc.slb.com (James A. McLaughlin);
1333;; simplified by WJC after more feedmail development;
1334;; idea (but not implementation) of copying smtpmail trace buffer to
1335;; feedmail error buffer from:
1336;; Mon 14-Oct-1996; Douglas Gray Stephens
1337;; modified to insert error for displaying
1338(defun feedmail-buffer-to-smtpmail (prepped errors-to addr-listoid)
49267116 1339 "Function which actually calls `smtpmail-via-smtp' to send buffer as e-mail."
bd1cd4c2
KH
1340 ;; I'm not sure smtpmail.el is careful about the following
1341 ;; return value, but it also uses it internally, so I will fear
1342 ;; no evil.
1343 (require 'smtpmail)
1344 (if (not (smtpmail-via-smtp addr-listoid prepped))
c7d4a777
KH
1345 (progn
1346 (set-buffer errors-to)
1347 (insert "Send via smtpmail failed. Probable SMTP protocol error.\n")
1348 (insert "Look for details below or in the *Messages* buffer.\n\n")
1349 (let ((case-fold-search t)
1350 ;; don't be overconfident about the name of the trace buffer
1351 (tracer (concat "trace.*smtp.*" (regexp-quote smtpmail-smtp-server))))
1352 (mapcar
1353 '(lambda (buffy)
1354 (if (string-match tracer (buffer-name buffy))
1355 (progn
1356 (insert "SMTP Trace from " (buffer-name buffy) "\n---------------")
bf714905 1357 (insert-buffer-substring buffy)
c7d4a777
KH
1358 (insert "\n\n"))))
1359 (buffer-list))))))
bd1cd4c2
KH
1360
1361
1362;; just a place to park a docstring
1363(defconst feedmail-fiddle-plex-blurb nil
0bb37c1a 1364 "A fiddle-plex is a concise way of specifying header field fiddling.
bd1cd4c2
KH
1365It is a list of up to 4 elements: NAME, VALUE, ACTION, FOLDING. The element
1366VALUE can also be a list sometimes.
1367
0bb37c1a
KH
1368NAME is the name of the header field to be fiddled with. Although case
1369doesn't matter in looking for headers, case of NAME is preserved when a header
1370is inserted via fiddling. It shouldn't include the trailing colon.
bd1cd4c2
KH
1371
1372VALUE is either nil, a simple string, a function returning nil or a string, or,
0bb37c1a 1373as described below for ACTION `combine', a list of up to three values.
bd1cd4c2
KH
1374
1375ACTION describes the nature of the fiddling to be done. Possibilities
0bb37c1a 1376for ACTION (default is `supplement'):
bd1cd4c2 1377
0bb37c1a 1378 `supplement' Leave other like fields as-is, insert this one.
bd1cd4c2 1379
0bb37c1a 1380 `replace' Delete other like fields, if any, and insert this one.
bd1cd4c2 1381
0bb37c1a 1382 `create' Insert this one only if no like field exists.
bd1cd4c2 1383
0bb37c1a 1384 `combine' Combine aggregate values of like fields with this one.
bd1cd4c2
KH
1385 In this case, VALUE has a special form. It is a list
1386 of three items: VAL-PRE, VAL-LIKE, and VAL-POST.
1387 VAL-PRE and VAL-POST are strings or nil. VAL-LIKE may
1388 be either a string or a function (it may also be nil,
1389 but there's not much point to that).
1390
1391 Values of like header fields are aggregated, leading and
1392 trailing whitespace is removed, and embedded
1393 whitespace is left as-is. If there are no like
1394 fields, or the aggregate value is an empty string,
1395 VAL-LIKE is not used. Else, if VAL-LIKE is a function,
1396 it is called with two arguments: NAME and the
0bb37c1a 1397 aggregate like values. Else, if VAL-LIKE is a string, it is
bd1cd4c2
KH
1398 used as a format string where a single \%s will be
1399 replaced by the aggregate values of like fields.
1400
1401 VAL-PRE, the results of using VAL-LIKE, and VAL-POST
1402 are concatenated, and the result, if not nil and not
1403 an empty string, is used as the new value for the
1404 field. Although this description sounds a bit
1405 complicated, the idea is to provide a mechanism for
1406 combining the old value with a new value in a flexible
1407 way. For example, if you wanted to add a new value to
1408 an existing header field by adding a semi-colon and
1409 then starting the new value on a continuation line,
1410 you might specify this:
1411
1412 (nil \"%s;\\n\\t\" \"This is my new value\")
1413
1414FOLDING can be nil, in which case VALUE is used as-is. If FOLDING is
1415non-nil, feedmail \"smart filling\" is done on VALUE just before
0bb37c1a 1416insertion.")
bd1cd4c2 1417
49267116 1418;;;###autoload
bd1cd4c2 1419(defun feedmail-send-it ()
fc066c54
DL
1420 "Send the current mail buffer using the Feedmail package.
1421This is a suitable value for `send-mail-function'. It can be used
1422with various lower-level mechanisms to provide features such as queueing."
bd1cd4c2
KH
1423
1424 ;; avoid matching trouble over slash vs backslash by getting canonical
1425 (if feedmail-queue-directory
c7d4a777 1426 (setq feedmail-queue-directory (expand-file-name feedmail-queue-directory)))
bd1cd4c2 1427 (if feedmail-queue-draft-directory
c7d4a777 1428 (setq feedmail-queue-draft-directory (expand-file-name feedmail-queue-draft-directory)))
bd1cd4c2 1429 (if (not feedmail-enable-queue) (feedmail-send-it-immediately)
c7d4a777
KH
1430 ;; else, queuing is enabled, should we ask about it or just do it?
1431 (if feedmail-ask-before-queue
1432 (funcall (feedmail-queue-send-edit-prompt))
1433 (feedmail-dump-message-to-queue feedmail-queue-directory 'after-queue))))
bd1cd4c2
KH
1434
1435
1436(defun feedmail-message-action-send ()
1437 ;; hooks can make this take a while so clear the prompt
1438 (message "FQM: Immediate send...")
1439 (feedmail-send-it-immediately))
1440
1441
1442;; From a VM mailing list discussion and some suggestions from Samuel Mikes <smikes@alumni.hmc.edu>
1443(defun feedmail-queue-express-to-queue ()
1444 "*Send message directly to the queue, with a minimum of fuss and bother."
1445 (interactive)
1446 (let ((feedmail-enable-queue t)
c7d4a777
KH
1447 (feedmail-ask-before-queue nil)
1448 (feedmail-queue-reminder-alist nil)
1449 (feedmail-queue-chatty-sit-for 0))
1450 (feedmail-send-it)
1451 )
1452 )
bd1cd4c2
KH
1453
1454
1455(defun feedmail-queue-express-to-draft ()
1456 "*Send message directly to the draft queue, with a minimum of fuss and bother."
1457 (interactive)
1458 (let ((feedmail-queue-directory feedmail-queue-draft-directory))
c7d4a777
KH
1459 (feedmail-queue-express-to-queue)
1460 )
1461 )
bd1cd4c2
KH
1462
1463
1464(defun feedmail-message-action-send-strong ()
1465 (let ((feedmail-confirm-outgoing nil)) (feedmail-message-action-send)))
1466
1467
1468(defun feedmail-message-action-edit ()
1469 (error "FQM: Message not queued; returning to edit"))
1470
1471
1472(defun feedmail-message-action-draft ()
1473 (feedmail-dump-message-to-queue feedmail-queue-draft-directory 'after-draft))
1474
1475
1476(defun feedmail-message-action-draft-strong ()
1477 (let ((buffer-file-name nil))
c7d4a777 1478 (feedmail-message-action-draft)))
bd1cd4c2
KH
1479
1480
1481(defun feedmail-message-action-queue ()
1482 (feedmail-dump-message-to-queue feedmail-queue-directory 'after-queue))
1483
1484
1485(defun feedmail-message-action-queue-strong ()
1486 (let ((buffer-file-name nil))
c7d4a777 1487 (feedmail-message-action-queue)))
bd1cd4c2
KH
1488
1489
1490(defun feedmail-message-action-toggle-spray ()
1491 (let ((feedmail-enable-spray (not feedmail-enable-spray)))
c7d4a777
KH
1492 (if feedmail-enable-spray
1493 (message "FQM: For this message, spray toggled ON")
1494 (message "FQM: For this message, spray toggled OFF"))
1495 (sit-for 3)
1496 ;; recursion, but harmless
1497 (feedmail-send-it)))
bd1cd4c2
KH
1498
1499
1500(defun feedmail-message-action-help ()
c7d4a777
KH
1501 (let ((d-string " "))
1502 (if (stringp feedmail-ask-before-queue-default)
1503 (setq d-string feedmail-ask-before-queue-default)
1504 (setq d-string (char-to-string feedmail-ask-before-queue-default)))
1505 (feedmail-queue-send-edit-prompt-help d-string)
1506 ;; recursive, but no worries (it goes deeper on user action)
1507 (feedmail-send-it)))
bd1cd4c2
KH
1508
1509
1510;;;###autoload
1511(defun feedmail-run-the-queue-no-prompts (&optional arg)
27772f10 1512 "Like `feedmail-run-the-queue', but suppress confirmation prompts."
bd1cd4c2
KH
1513 (interactive "p")
1514 (let ((feedmail-confirm-outgoing nil)) (feedmail-run-the-queue arg)))
1515
1516;;;###autoload
1517(defun feedmail-run-the-queue-global-prompt (&optional arg)
27772f10 1518 "Like `feedmail-run-the-queue', but with a global confirmation prompt.
0bb37c1a 1519This is generally most useful if run non-interactively, since you can
bd1cd4c2
KH
1520bail out with an appropriate answer to the global confirmation prompt."
1521 (interactive "p")
1522 (let ((feedmail-queue-runner-confirm-global t)) (feedmail-run-the-queue arg)))
1523
1524;;;###autoload
1525(defun feedmail-run-the-queue (&optional arg)
1526 "Visit each message in the feedmail queue directory and send it out.
1527Return value is a list of three things: number of messages sent, number of
1528messages skipped, and number of non-message things in the queue (commonly
1529backup file names and the like)."
1530 (interactive "p")
1531 ;; avoid matching trouble over slash vs backslash by getting canonical
1532 (if feedmail-queue-directory
c7d4a777 1533 (setq feedmail-queue-directory (expand-file-name feedmail-queue-directory)))
bd1cd4c2 1534 (if feedmail-queue-draft-directory
c7d4a777 1535 (setq feedmail-queue-draft-directory (expand-file-name feedmail-queue-draft-directory)))
bd1cd4c2 1536 (let* ((maybe-file)
c7d4a777
KH
1537 (qlist (feedmail-look-at-queue-directory feedmail-queue-directory))
1538 (dlist (feedmail-look-at-queue-directory feedmail-queue-draft-directory))
1539 (q-cnt (nth 0 qlist))
1540 (q-oth (nth 1 qlist))
1541 (d-cnt (nth 0 dlist))
1542 (d-oth (nth 1 dlist))
1543 (messages-sent 0)
1544 (messages-skipped 0)
1545 (blobby-buffer)
1546 (already-buffer)
1547 (this-mhsep)
1548 (do-the-run t)
1549 (list-of-possible-fqms))
1550 (if (and (> q-cnt 0) feedmail-queue-runner-confirm-global)
1551 (setq do-the-run
1552 (if (fboundp 'y-or-n-p-with-timeout)
1553 (y-or-n-p-with-timeout (format "FQM: Draft: %dm+%d, Queue: %dm+%d; run the queue? "
1554 d-cnt d-oth q-cnt q-oth)
1555 5 nil)
1556 (y-or-n-p (format "FQM: Draft: %dm+%d, Queue: %dm+%d; run the queue? "
1557 d-cnt d-oth q-cnt q-oth))
1558 )))
1559 (if (not do-the-run)
1560 (setq messages-skipped q-cnt)
1561 (save-window-excursion
1562 (setq list-of-possible-fqms (directory-files feedmail-queue-directory t))
1563 (if feedmail-queue-run-orderer
1564 (setq list-of-possible-fqms (funcall feedmail-queue-run-orderer list-of-possible-fqms)))
3d3cfc90 1565 (mapc
c7d4a777
KH
1566 '(lambda (blobby)
1567 (setq maybe-file (expand-file-name blobby feedmail-queue-directory))
1568 (cond
1569 ((file-directory-p maybe-file) nil) ; don't care about subdirs
1570 ((feedmail-fqm-p blobby)
1571 (setq blobby-buffer (generate-new-buffer (concat "FQM " blobby)))
1572 (setq already-buffer
1573 (if (fboundp 'find-buffer-visiting) ; missing from XEmacs
1574 (find-buffer-visiting maybe-file)
1575 (get-file-buffer maybe-file)))
1576 (if (and already-buffer (buffer-modified-p already-buffer))
1577 (save-window-excursion
1578 (display-buffer (set-buffer already-buffer))
1579 (if (fboundp 'y-or-n-p-with-timeout)
1580 ;; make a guess that the user just forgot to save
1581 (if (y-or-n-p-with-timeout (format "FQM: Visiting %s; save before send? " blobby) 10 t)
1582 (save-buffer))
1583 (if (y-or-n-p (format "FQM: Visiting %s; save before send? " blobby))
1584 (save-buffer))
1585 )))
1586
1587 (set-buffer blobby-buffer)
1588 (setq buffer-offer-save nil)
1589 (buffer-disable-undo blobby-buffer)
1590 (insert-file-contents-literally maybe-file)
bb85b31e 1591 ;; work around text-vs-binary weirdness and also around rmail-resend's creative
c7d4a777
KH
1592 ;; manipulation of mail-header-separator
1593 ;;
1594 ;; if we don't find the normal M-H-S, and the alternative is defined but also
1595 ;; not found, try reading the file a different way
1596 ;;
1597 ;; if M-H-S not found and (a-M-H-S is nil or not found)
1598 (if (and (not (feedmail-find-eoh t))
1599 (or (not feedmail-queue-alternative-mail-header-separator)
1600 (not
1601 (let ((mail-header-separator feedmail-queue-alternative-mail-header-separator))
1602 (feedmail-find-eoh t)))))
705e5bd9
SM
1603 (letf ((file-name-buffer-file-type-alist nil)
1604 ((default-value 'buffer-file-type) nil))
1605 (erase-buffer) (insert-file-contents maybe-file)))
c7d4a777
KH
1606 ;; if M-H-S not found and (a-M-H-S is non-nil and is found)
1607 ;; temporarily set M-H-S to the value of a-M-H-S
1608 (if (and (not (feedmail-find-eoh t))
1609 feedmail-queue-alternative-mail-header-separator
1610 (let ((mail-header-separator feedmail-queue-alternative-mail-header-separator))
1611 (feedmail-find-eoh t)))
1612 (setq this-mhsep feedmail-queue-alternative-mail-header-separator)
1613 (setq this-mhsep mail-header-separator))
1614 (funcall feedmail-queue-runner-mode-setter arg)
1615 (condition-case nil ; don't give up the loop if user skips some
1616 (let ((feedmail-enable-queue nil)
1617 (mail-header-separator this-mhsep)
1618 (feedmail-queue-runner-is-active maybe-file))
1619 (funcall feedmail-queue-runner-message-sender arg)
1620 (set-buffer blobby-buffer)
1621 (if (buffer-modified-p) ; still modified, means wasn't sent
1622 (setq messages-skipped (1+ messages-skipped))
1623 (setq messages-sent (1+ messages-sent))
1624 (funcall feedmail-queue-runner-cleaner-upper maybe-file arg)
1625 (if (and already-buffer (not (file-exists-p maybe-file)))
1626 ;; we have gotten rid of the file associated with the
1627 ;; buffer, so update the buffer's notion of that
1628 (save-excursion
1629 (set-buffer already-buffer)
1630 (setq buffer-file-name nil)))))
1631 (error (setq messages-skipped (1+ messages-skipped))))
1632 (kill-buffer blobby-buffer)
1633 (if feedmail-queue-chatty
1634 (progn
1635 (message "FQM: %d to go, %d sent, %d skipped (%d other files ignored)"
1636 (- q-cnt messages-sent messages-skipped)
1637 messages-sent messages-skipped q-oth)
1638 (sit-for feedmail-queue-chatty-sit-for))))))
1639 list-of-possible-fqms)))
1640 (if feedmail-queue-chatty
1641 (progn
1642 (message "FQM: %d sent, %d skipped (%d other files ignored)"
1643 messages-sent messages-skipped q-oth)
1644 (sit-for feedmail-queue-chatty-sit-for)
1645 (feedmail-queue-reminder 'after-run)
1646 (sit-for feedmail-queue-chatty-sit-for)))
1647 (list messages-sent messages-skipped q-oth)))
bd1cd4c2
KH
1648
1649
1650;;;###autoload
1651(defun feedmail-queue-reminder (&optional what-event)
1652 "Perform some kind of reminder activity about queued and draft messages.
1653Called with an optional symbol argument which says what kind of event
1654is triggering the reminder activity. The default is 'on-demand, which
27772f10 1655is what you typically would use if you were putting this in your Emacs start-up
bd1cd4c2
KH
1656or mail hook code. Other recognized values for WHAT-EVENT (these are passed
1657internally by feedmail):
1658
1659 after-immediate (a message has just been sent in immediate mode)
1660 after-queue (a message has just been queued)
1661 after-draft (a message has just been placed in the draft directory)
1662 after-run (the queue has just been run, possibly sending messages)
1663
27772f10 1664WHAT-EVENT is used as a key into the table `feedmail-queue-reminder-alist'. If
bd1cd4c2 1665the associated value is a function, it is called without arguments and is expected
0bb37c1a 1666to perform the reminder activity. You can supply your own reminder functions
27772f10
JB
1667by redefining `feedmail-queue-reminder-alist'. If you don't want any reminders,
1668you can set `feedmail-queue-reminder-alist' to nil."
bd1cd4c2
KH
1669 (interactive "p")
1670 (let ((key (if (and what-event (symbolp what-event)) what-event 'on-demand)) entry reminder)
c7d4a777
KH
1671 (setq entry (assoc key feedmail-queue-reminder-alist))
1672 (setq reminder (cdr entry))
1673 (if (fboundp reminder) (funcall reminder)))
bd1cd4c2
KH
1674 )
1675
1676
1677(defun feedmail-queue-reminder-brief ()
1678 "Brief display of draft and queued message counts in modeline."
1679 (interactive)
1680 (let (q-cnt d-cnt q-lis d-lis)
c7d4a777
KH
1681 (setq q-lis (feedmail-look-at-queue-directory feedmail-queue-directory))
1682 (setq d-lis (feedmail-look-at-queue-directory feedmail-queue-draft-directory))
1683 (setq q-cnt (car q-lis))
1684 (setq d-cnt (car d-lis))
1685 (if (or (> q-cnt 0) (> d-cnt 0))
1686 (progn
1687 (message "FQM: [D: %d, Q: %d]" d-cnt q-cnt))))
bd1cd4c2
KH
1688 )
1689
1690
1691(defun feedmail-queue-reminder-medium ()
1692 "Verbose display of draft and queued message counts in modeline."
1693 (interactive)
1694 (let (q-cnt d-cnt q-oth d-oth q-lis d-lis)
c7d4a777
KH
1695 (setq q-lis (feedmail-look-at-queue-directory feedmail-queue-directory))
1696 (setq d-lis (feedmail-look-at-queue-directory feedmail-queue-draft-directory))
1697 (setq q-cnt (car q-lis))
1698 (setq d-cnt (car d-lis))
1699 (setq q-oth (nth 1 q-lis))
1700 (setq d-oth (nth 1 d-lis))
1701 (if (or (> q-cnt 0) (> d-cnt 0))
1702 (progn
1703 (message "FQM: Draft: %dm+%d in \"%s\", Queue: %dm+%d in \"%s\""
1704 d-cnt d-oth (file-name-nondirectory feedmail-queue-draft-directory)
1705 q-cnt q-oth (file-name-nondirectory feedmail-queue-directory)))))
bd1cd4c2
KH
1706 )
1707
1708
1709(defun feedmail-queue-send-edit-prompt ()
1710 "Ask whether to queue, send immediately, or return to editing a message."
1711 ;; Some implementation ideas here came from the userlock.el code
1712 (discard-input)
1713 (save-window-excursion
c7d4a777
KH
1714 (let ((answer) (d-char) (d-string " "))
1715 (if (stringp feedmail-ask-before-queue-default)
1716 (progn
1717 (setq d-char (string-to-char feedmail-ask-before-queue-default))
1718 (setq d-string feedmail-ask-before-queue-default))
1719 (setq d-string (char-to-string feedmail-ask-before-queue-default))
1720 (setq d-char feedmail-ask-before-queue-default)
1721 )
bd1cd4c2 1722 (while (null answer)
c7d4a777
KH
1723 (message feedmail-ask-before-queue-prompt d-string)
1724 (let ((user-sez
1725 (let ((inhibit-quit t) (cursor-in-echo-area t) (echo-keystrokes 0))
1726 (read-char-exclusive))))
1727 (if (= user-sez help-char)
1728 (setq answer '(^ . feedmail-message-action-help))
1729 (if (or (eq user-sez ?\C-m) (eq user-sez ?\C-j) (eq user-sez ?y))
1730 (setq user-sez d-char))
1731 ;; these char-to-int things are because of some
1732 ;; incomprensible difference between the two in
1733 ;; byte-compiled stuff between Emacs and XEmacs
1734 ;; (well, I'm sure someone could comprehend it,
1735 ;; but I say 'uncle')
1736 (setq answer (or (assoc user-sez feedmail-prompt-before-queue-user-alist)
1737 (and (fboundp 'char-to-int)
1738 (assoc (char-to-int user-sez) feedmail-prompt-before-queue-user-alist))
1739 (assoc user-sez feedmail-prompt-before-queue-standard-alist)
1740 (and (fboundp 'char-to-int)
1741 (assoc (char-to-int user-sez) feedmail-prompt-before-queue-standard-alist))))
1742 (if (or (null answer) (null (cdr answer)))
1743 (progn
1744 (beep)
1745 (message feedmail-ask-before-queue-reprompt d-string)
1746 (sit-for 3)))
1747 )))
1748 (cdr answer)
1749 )))
bd1cd4c2
KH
1750
1751(defconst feedmail-p-h-b-n "*FQM Help*")
1752
1753(defun feedmail-queue-send-edit-prompt-help (d-string)
1754 (let ((fqm-help (get-buffer feedmail-p-h-b-n)))
6eb94ddb 1755 (if (and fqm-help (get-buffer-window fqm-help 'visible))
c7d4a777
KH
1756 (feedmail-queue-send-edit-prompt-help-later fqm-help d-string)
1757 (feedmail-queue-send-edit-prompt-help-first d-string))))
bd1cd4c2
KH
1758
1759(defun feedmail-queue-send-edit-prompt-help-later (fqm-help d-string)
1760 ;; scrolling fun
1761 (save-selected-window
c7d4a777
KH
1762 (let ((signal-error-on-buffer-boundary nil)
1763 (fqm-window (display-buffer fqm-help)))
1764 (select-window fqm-window)
1765 (if (pos-visible-in-window-p (point-max) fqm-window)
1766 (feedmail-queue-send-edit-prompt-help-first d-string)
1767 ;;(goto-char (point-min))
1768 (scroll-up nil)
1769 ))))
bd1cd4c2
KH
1770
1771(defun feedmail-queue-send-edit-prompt-help-first (d-string)
1772 (with-output-to-temp-buffer feedmail-p-h-b-n
1773 (princ "You're dispatching a message and feedmail queuing is enabled.
1774Typing ? or C-v will normally scroll this help buffer.
1775
1776Choices:
1777 q QUEUE for later sending (via feedmail-run-the-queue)
1778 Q QUEUE! like \"q\", but always make a new file
1779 i IMMEDIATELY send this (but not the other queued messages)
1780 I IMMEDIATELY! like \"i\", but skip following confirmation prompt
1781 d DRAFT queue in the draft directory
1782 D DRAFT! like \"d\", but always make a new file
1783 e EDIT return to the message edit buffer (don't send or queue)
1784 * SPRAY toggle spray mode (individual message transmissions)
1785
1786Synonyms:
1787 s SEND immediately (same as \"i\")
1788 S SEND! immediately (same as \"I\")
1789 r ROUGH draft (same as \"d\")
bb85b31e 1790 R ROUGH! draft (same as \"D\")
bd1cd4c2
KH
1791 n NOPE didn't mean it (same as \"e\")
1792 y YUP do the default behavior (same as \"C-m\")
1793
1794The user-configurable default is currently \"")
c7d4a777
KH
1795 (princ d-string)
1796 (princ "\". For other possibilities,
bd1cd4c2
KH
1797see the variable feedmail-prompt-before-queue-user-alist.
1798")
c7d4a777
KH
1799 (and (stringp feedmail-prompt-before-queue-help-supplement)
1800 (princ feedmail-prompt-before-queue-help-supplement))
bd1cd4c2
KH
1801 (save-excursion (set-buffer standard-output) (if (fboundp 'help-mode) (help-mode)))))
1802
1803(defun feedmail-look-at-queue-directory (queue-directory)
1804 "Find out some things about a queue directory.
1805Result is a list containing a count of queued messages in the
1806directory, a count of other files in the directory, and a high water
1807mark for prefix sequence numbers. Subdirectories are not included in
1808the counts."
1809 (let ((q-cnt 0) (q-oth 0) (high-water 0) (blobbet))
c7d4a777
KH
1810 ;; iterate, counting things we find along the way in the directory
1811 (if (file-directory-p queue-directory)
3d3cfc90 1812 (mapc
c7d4a777
KH
1813 '(lambda (blobby)
1814 (cond
1815 ((file-directory-p blobby) nil) ; don't care about subdirs
1816 ((feedmail-fqm-p blobby)
1817 (setq blobbet (file-name-nondirectory blobby))
1818 (if (string-match "^[0-9][0-9][0-9]-" blobbet)
1819 (let ((water-mark))
027a4b6b 1820 (setq water-mark (string-to-number (substring blobbet 0 3)))
c7d4a777
KH
1821 (if (> water-mark high-water) (setq high-water water-mark))))
1822 (setq q-cnt (1+ q-cnt)))
1823 (t (setq q-oth (1+ q-oth)))
1824 ))
1825 (directory-files queue-directory t)))
1826 (list q-cnt q-oth high-water)))
bd1cd4c2
KH
1827
1828(defun feedmail-tidy-up-slug (slug)
0bb37c1a 1829 "Utility for mapping out suspect characters in a potential filename."
bd1cd4c2
KH
1830 ;; even programmers deserve a break sometimes, so cover nil for them
1831 (if (null slug) (setq slug ""))
1832 ;; replace all non-alphanumerics with hyphen for safety
1833 (while (string-match "[^a-z0-9-]+" slug) (setq slug (replace-match "-" nil nil slug)))
1834 ;; collapse multiple hyphens to one
1835 (while (string-match "--+" slug) (setq slug (replace-match "-" nil nil slug)))
1836 ;; for tidyness, peel off leading hyphens
1837 (if (string-match "^-*" slug) (setq slug (replace-match "" nil nil slug)))
1838 ;; for tidyness, peel off trailing hyphens
1839 (if (string-match "-*$" slug) (setq slug (replace-match "" nil nil slug)))
1840 slug
c7d4a777 1841 )
bd1cd4c2
KH
1842
1843(defun feedmail-queue-subject-slug-maker (&optional queue-directory)
1844 "Create a name for storing the message in the queue.
1845Optional argument QUEUE-DIRECTORY specifies into which directory the
37aa9115 1846file will be placed. The name is based on the Subject: header (if
bd1cd4c2 1847there is one). If there is no subject,
27772f10 1848`feedmail-queue-default-file-slug' is consulted. Special characters are
bd1cd4c2
KH
1849mapped to mostly alphanumerics for safety."
1850 (let ((eoh-marker) (case-fold-search t) (subject "") (s-point))
c7d4a777
KH
1851 (setq eoh-marker (feedmail-find-eoh))
1852 (goto-char (point-min))
1853 ;; get raw subject value (first line, anyhow)
37aa9115 1854 (if (re-search-forward "^Subject:" eoh-marker t)
c7d4a777
KH
1855 (progn (setq s-point (point))
1856 (end-of-line)
1857 (setq subject (buffer-substring s-point (point)))))
1858 (setq subject (feedmail-tidy-up-slug subject))
1859 (if (zerop (length subject))
1860 (setq subject
1861 (cond
1862 ((stringp feedmail-queue-default-file-slug) feedmail-queue-default-file-slug)
1863 ((fboundp feedmail-queue-default-file-slug)
1864 (save-excursion (funcall feedmail-queue-default-file-slug)))
1865 ((eq feedmail-queue-default-file-slug 'ask)
1866 (file-name-nondirectory
1867 (read-file-name "FQM: Message filename slug? "
1868 (file-name-as-directory queue-directory) subject nil subject)))
1869 (t "no subject"))
1870 ))
1871 ;; one more time, with feeling
1872 (feedmail-tidy-up-slug subject)
1873 ))
bd1cd4c2
KH
1874
1875
1876(defun feedmail-create-queue-filename (queue-directory)
1877 (let ((slug "wjc"))
c7d4a777
KH
1878 (cond
1879 (feedmail-queue-slug-maker
1880 (save-excursion (setq slug (funcall feedmail-queue-slug-maker queue-directory))))
1881 (feedmail-ask-for-queue-slug
1882 (setq slug (file-name-nondirectory
1883 (read-file-name (concat "FQM: Message filename slug? [" slug "]? ")
1884 (file-name-as-directory queue-directory) slug nil slug))))
1885 )
1886 (setq slug (feedmail-tidy-up-slug slug))
1887 (setq slug (format "%03d-%s" (1+ (nth 2 (feedmail-look-at-queue-directory queue-directory))) slug))
1888 (concat
1889 (expand-file-name slug queue-directory)
1890 feedmail-queue-fqm-suffix)
1891 ))
bd1cd4c2
KH
1892
1893
1894(defun feedmail-dump-message-to-queue (queue-directory what-event)
1895 (or (file-accessible-directory-p queue-directory)
c7d4a777
KH
1896 ;; progn to get nil result no matter what
1897 (progn (make-directory queue-directory t) nil)
1898 (file-accessible-directory-p queue-directory)
a867ead0 1899 (error "FQM: Message not queued; trouble with directory %s" queue-directory))
bd1cd4c2 1900 (let ((filename)
c7d4a777
KH
1901 (is-fqm)
1902 (is-in-this-dir)
1903 (previous-buffer-file-name buffer-file-name))
1904 (if buffer-file-name
1905 (progn
1906 (setq is-fqm (feedmail-fqm-p buffer-file-name))
1907 (setq is-in-this-dir (string-equal
1908 (directory-file-name queue-directory)
1909 (directory-file-name (expand-file-name (file-name-directory buffer-file-name)))))))
1910 ;; if visiting a queued message, just save
1911 (if (and is-fqm is-in-this-dir)
1912 (setq filename buffer-file-name)
1913 (setq filename (feedmail-create-queue-filename queue-directory)))
1914 ;; make binary file on DOS/Win95/WinNT, etc
705e5bd9
SM
1915 (let ((buffer-file-type feedmail-force-binary-write))
1916 (write-file filename))
c7d4a777
KH
1917 ;; convenient for moving from draft to q, for example
1918 (if (and previous-buffer-file-name (or (not is-fqm) (not is-in-this-dir))
1919 (y-or-n-p (format "FQM: Was previously %s; delete that? " previous-buffer-file-name)))
1920 (delete-file previous-buffer-file-name))
1921 (if feedmail-nuke-buffer-after-queue
1922 (let ((a-s-file-name buffer-auto-save-file-name))
1923 ;; be aggressive in nuking auto-save files
1924 (and (kill-buffer (current-buffer))
1925 delete-auto-save-files
1926 (file-exists-p a-s-file-name)
1927 (delete-file a-s-file-name))))
1928 (if feedmail-queue-chatty
83816142 1929 (progn (message "%s" (concat "FQM: Queued in " filename))
c7d4a777
KH
1930 (sit-for feedmail-queue-chatty-sit-for)))
1931 (if feedmail-queue-chatty
1932 (progn
1933 (feedmail-queue-reminder what-event)
1934 (sit-for feedmail-queue-chatty-sit-for)))))
bd1cd4c2
KH
1935
1936
1937;; from a similar function in mail-utils.el
1938(defun feedmail-rfc822-time-zone (time)
1939 (let* ((sec (or (car (current-time-zone time)) 0))
c7d4a777 1940 (absmin (/ (abs sec) 60)))
bd1cd4c2
KH
1941 (format "%c%02d%02d" (if (< sec 0) ?- ?+) (/ absmin 60) (% absmin 60))))
1942
1943(defun feedmail-rfc822-date (arg-time)
1944 (let ((time (if arg-time arg-time (current-time))))
c7d4a777
KH
1945 (concat
1946 (format-time-string "%a, %e %b %Y %T " time)
1947 (feedmail-rfc822-time-zone time)
1948 )))
bd1cd4c2
KH
1949
1950
1951(defun feedmail-send-it-immediately ()
1952 "Handle immediate sending, including during a queue run."
1953 (let* ((feedmail-error-buffer (get-buffer-create " *FQM Outgoing Email Errors*"))
c7d4a777
KH
1954 (feedmail-prepped-text-buffer (get-buffer-create " *FQM Outgoing Email Text*"))
1955 (feedmail-raw-text-buffer (current-buffer))
1956 (feedmail-address-list)
1957 (eoh-marker)
1958 (bcc-holder)
1959 (resent-bcc-holder)
37aa9115
KH
1960 (a-re-rtcb "^Resent-\\(To\\|Cc\\|Bcc\\):")
1961 (a-re-rtc "^Resent-\\(To\\|Cc\\):")
1962 (a-re-rb "^Resent-Bcc:")
1963 (a-re-dtcb "^\\(To\\|Cc\\|Bcc\\):")
1964 (a-re-dtc "^\\(To\\|Cc\\):")
1965 (a-re-db "^Bcc:")
c7d4a777
KH
1966 ;; to get a temporary changable copy
1967 (mail-header-separator mail-header-separator)
1968 )
bd1cd4c2 1969 (unwind-protect
c7d4a777
KH
1970 (save-excursion
1971 (set-buffer feedmail-error-buffer) (erase-buffer)
1972 (set-buffer feedmail-prepped-text-buffer) (erase-buffer)
1973
1974 ;; jam contents of user-supplied mail buffer into our scratch buffer
bf714905 1975 (insert-buffer-substring feedmail-raw-text-buffer)
c7d4a777
KH
1976
1977 ;; require one newline at the end.
1978 (goto-char (point-max))
1979 (or (= (preceding-char) ?\n) (insert ?\n))
1980
1981 (let ((case-fold-search nil))
1982 ;; Change header-delimiter to be what mailers expect (empty line).
1983 ;; leaves match data in place or signals error
1984 (setq eoh-marker (feedmail-find-eoh))
1985 (replace-match "\n")
1986 (setq mail-header-separator ""))
1987
1988 ;; mail-aliases nil = mail-abbrevs.el
1989 (if (or feedmail-force-expand-mail-aliases
1990 (and (fboundp 'expand-mail-aliases) mail-aliases))
1991 (expand-mail-aliases (point-min) eoh-marker))
1992
1993 ;; make it pretty
1994 (if feedmail-fill-to-cc (feedmail-fill-to-cc-function eoh-marker))
1995 ;; ignore any blank lines in the header
1996 (goto-char (point-min))
1997 (while (and (re-search-forward "\n\n\n*" eoh-marker t) (< (point) eoh-marker))
1998 (replace-match "\n"))
1999
2000 (let ((case-fold-search t) (addr-regexp))
2001 (goto-char (point-min))
2002 ;; there are some RFC-822 combinations/cases missed here,
2003 ;; but probably good enough and what users expect
2004 ;;
2005 ;; use resent-* stuff only if there is at least one non-empty one
2006 (setq feedmail-is-a-resend
2007 (re-search-forward
2008 ;; header name, followed by optional whitespace, followed by
2009 ;; non-whitespace, followed by anything, followed by newline;
37aa9115
KH
2010 ;; the idea is empty Resent-* headers are ignored
2011 "^\\(Resent-To:\\|Resent-Cc:\\|Resent-Bcc:\\)\\s-*\\S-+.*$"
c7d4a777 2012 eoh-marker t))
37aa9115 2013 ;; if we say so, gather the Bcc stuff before the main course
c7d4a777
KH
2014 (if (eq feedmail-deduce-bcc-where 'first)
2015 (progn (if feedmail-is-a-resend (setq addr-regexp a-re-rb) (setq addr-regexp a-re-db))
2016 (setq feedmail-address-list (feedmail-deduce-address-list feedmail-prepped-text-buffer (point-min) eoh-marker addr-regexp feedmail-address-list))))
2017 ;; the main course
2018 (if (or (eq feedmail-deduce-bcc-where 'first) (eq feedmail-deduce-bcc-where 'last))
37aa9115 2019 ;; handled by first or last cases, so don't get Bcc stuff
c7d4a777
KH
2020 (progn (if feedmail-is-a-resend (setq addr-regexp a-re-rtc) (setq addr-regexp a-re-dtc))
2021 (setq feedmail-address-list (feedmail-deduce-address-list feedmail-prepped-text-buffer (point-min) eoh-marker addr-regexp feedmail-address-list)))
37aa9115 2022 ;; not handled by first or last cases, so also get Bcc stuff
c7d4a777
KH
2023 (progn (if feedmail-is-a-resend (setq addr-regexp a-re-rtcb) (setq addr-regexp a-re-dtcb))
2024 (setq feedmail-address-list (feedmail-deduce-address-list feedmail-prepped-text-buffer (point-min) eoh-marker addr-regexp feedmail-address-list))))
37aa9115 2025 ;; if we say so, gather the Bcc stuff after the main course
c7d4a777
KH
2026 (if (eq feedmail-deduce-bcc-where 'last)
2027 (progn (if feedmail-is-a-resend (setq addr-regexp a-re-rb) (setq addr-regexp a-re-db))
2028 (setq feedmail-address-list (feedmail-deduce-address-list feedmail-prepped-text-buffer (point-min) eoh-marker addr-regexp feedmail-address-list))))
2029 (if (not feedmail-address-list) (error "FQM: Sending...abandoned, no addressees"))
2030 ;; not needed, but meets user expectations
2031 (setq feedmail-address-list (nreverse feedmail-address-list))
37aa9115
KH
2032 ;; Find and handle any Bcc fields.
2033 (setq bcc-holder (feedmail-accume-n-nuke-header eoh-marker "^Bcc:"))
2034 (setq resent-bcc-holder (feedmail-accume-n-nuke-header eoh-marker "^Resent-Bcc:"))
c7d4a777
KH
2035 (if (and bcc-holder (not feedmail-nuke-bcc))
2036 (progn (goto-char (point-min))
2037 (insert bcc-holder)))
2038 (if (and resent-bcc-holder (not feedmail-nuke-resent-bcc))
2039 (progn (goto-char (point-min))
2040 (insert resent-bcc-holder)))
2041 (goto-char (point-min))
2042
2043 ;; fiddle about, fiddle about, fiddle about....
2044 (feedmail-fiddle-from)
2045 (feedmail-fiddle-sender)
2046 (feedmail-fiddle-x-mailer)
2047 (feedmail-fiddle-message-id
2048 (or feedmail-queue-runner-is-active (buffer-file-name feedmail-raw-text-buffer)))
2049 (feedmail-fiddle-date
2050 (or feedmail-queue-runner-is-active (buffer-file-name feedmail-raw-text-buffer)))
2051 (feedmail-fiddle-list-of-fiddle-plexes feedmail-fiddle-plex-user-list)
2052
2053 ;; don't send out a blank headers of various sorts
2054 ;; (this loses on continued line with a blank first line)
2055 (goto-char (point-min))
2056 (and feedmail-nuke-empty-headers ; hey, who's an empty-header?
2057 (while (re-search-forward "^[A-Za-z0-9-]+:[ \t]*\n" eoh-marker t)
2058 (replace-match ""))))
2059
2060 (run-hooks 'feedmail-last-chance-hook)
2061
37aa9115 2062 (let ((fcc (feedmail-accume-n-nuke-header eoh-marker "^Fcc:"))
c7d4a777
KH
2063 (also-file)
2064 (confirm (cond
2065 ((eq feedmail-confirm-outgoing 'immediate)
2066 (not feedmail-queue-runner-is-active))
2067 ((eq feedmail-confirm-outgoing 'queued) feedmail-queue-runner-is-active)
2068 (t feedmail-confirm-outgoing))))
2069 (if (or (not confirm) (feedmail-one-last-look feedmail-prepped-text-buffer))
2070 (let ((user-mail-address (feedmail-envelope-deducer eoh-marker)))
2071 (feedmail-give-it-to-buffer-eater)
2072 (if (and (not feedmail-queue-runner-is-active) (setq also-file (buffer-file-name feedmail-raw-text-buffer)))
2073 (progn ; if a file but not running the queue, offer to delete it
2074 (setq also-file (expand-file-name also-file))
2075 (if (or feedmail-queue-auto-file-nuke
2076 (y-or-n-p (format "FQM: Delete message file %s? " also-file)))
2077 (save-excursion
2078 ;; if we delete the affiliated file, get rid
2079 ;; of the file name association and make sure we
2080 ;; don't annoy people with a prompt on exit
2081 (delete-file also-file)
2082 (set-buffer feedmail-raw-text-buffer)
2083 (setq buffer-offer-save nil)
2084 (setq buffer-file-name nil)
2085 )
2086 )))
bd1cd4c2 2087 (goto-char (point-min))
37aa9115 2088 ;; re-insert and handle any Fcc fields (and, optionally, any Bcc).
705e5bd9
SM
2089 (if fcc (letf (((default-value 'buffer-file-type)
2090 feedmail-force-binary-write))
c7d4a777
KH
2091 (insert fcc)
2092 (if (not feedmail-nuke-bcc-in-fcc)
2093 (progn (if bcc-holder (insert bcc-holder))
2094 (if resent-bcc-holder (insert resent-bcc-holder))))
2095
2096 (run-hooks 'feedmail-before-fcc-hook)
2097
2098 (if feedmail-nuke-body-in-fcc
2099 (progn (goto-char eoh-marker)
2100 (if (natnump feedmail-nuke-body-in-fcc)
2101 (forward-line feedmail-nuke-body-in-fcc))
2102 (delete-region (point) (point-max))
2103 ))
2104 (mail-do-fcc eoh-marker)
2105 )))
2106 (error "FQM: Sending...abandoned") ; user bailed out of one-last-look
2107 ))) ; unwind-protect body (save-excursion)
2108
2109 ;; unwind-protect cleanup forms
2110 (kill-buffer feedmail-prepped-text-buffer)
2111 (set-buffer feedmail-error-buffer)
2112 (if (zerop (buffer-size)) (kill-buffer feedmail-error-buffer)
2113 (progn (display-buffer feedmail-error-buffer)
2114 ;; read fast ... the meter is running
2115 (if (and feedmail-queue-runner-is-active feedmail-queue-chatty)
2116 (progn (message "FQM: Sending...failed") (ding t) (sit-for 3)))
2117 (error "FQM: Sending...failed")))
2118 (set-buffer feedmail-raw-text-buffer))
2119 ) ; let
bd1cd4c2 2120 (if (and feedmail-queue-chatty (not feedmail-queue-runner-is-active))
c7d4a777
KH
2121 (progn
2122 (feedmail-queue-reminder 'after-immediate)
2123 (sit-for feedmail-queue-chatty-sit-for)))
bd1cd4c2
KH
2124 )
2125
2126
2127(defun feedmail-fiddle-header (name value &optional action folding)
2128 "Internal feedmail function for jamming fields into message header.
2129NAME, VALUE, ACTION, and FOLDING are the four elements of a
2130fiddle-plex, as described in the documentation for the variable
27772f10 2131`feedmail-fiddle-plex-blurb'."
bd1cd4c2 2132 (let ((case-fold-search t)
c7d4a777
KH
2133 (header-colon (concat (regexp-quote name) ":"))
2134 header-regexp eoh-marker has-like ag-like val-like that-point)
2135 (setq header-regexp (concat "^" header-colon))
2136 (setq eoh-marker (feedmail-find-eoh))
2137 (goto-char (point-min))
2138 (setq has-like (re-search-forward header-regexp eoh-marker t))
2139
2140 (if (not action) (setq action 'supplement))
2141 (cond
2142 ((eq action 'supplement)
2143 ;; trim leading/trailing whitespace
2144 (if (string-match "\\`[ \t\n]+" value)
2145 (setq value (substring value (match-end 0))))
2146 (if (string-match "[ \t\n]+\\'" value)
2147 (setq value (substring value 0 (match-beginning 0))))
2148 (if (> (length value) 0)
2149 (progn
2150 (if feedmail-fiddle-headers-upwardly
2151 (goto-char (point-min))
2152 (goto-char eoh-marker))
2153 (setq that-point (point))
2154 (insert name ": " value "\n")
2155 (if folding (feedmail-fill-this-one that-point (point))))))
2156
2157 ((eq action 'replace)
2158 (if has-like (feedmail-accume-n-nuke-header eoh-marker header-regexp))
2159 (feedmail-fiddle-header name value 'supplement folding))
2160
2161 ((eq action 'create)
2162 (if (not has-like) (feedmail-fiddle-header name value 'supplement folding)))
2163
2164 ((eq action 'combine)
2165 (setq val-like (nth 1 value))
2166 (setq ag-like (or (feedmail-accume-n-nuke-header eoh-marker header-regexp) ""))
2167 ;; get rid of initial header name from first instance (front of string)
2168 (if (string-match (concat header-regexp "[ \t\n]+") ag-like)
2169 (setq ag-like (replace-match "" t t ag-like)))
2170 ;; get rid of embedded header names from subsequent instances
2171 (while (string-match (concat "\n" header-colon "[ \t\n]+") ag-like)
2172 (setq ag-like (replace-match "\n\t" t t ag-like)))
2173 ;; trim leading/trailing whitespace
2174 (if (string-match "\\`[ \t\n]+" ag-like)
2175 (setq ag-like (substring ag-like (match-end 0))))
2176 (if (string-match "[ \t\n]+\\'" ag-like)
2177 (setq ag-like (substring ag-like 0 (match-beginning 0))))
2178 ;; if ag-like is not nil and not an empty string, transform it via a function
2179 ;; call or format operation
2180 (if (> (length ag-like) 0)
2181 (setq ag-like
2182 (cond
2183 ((and (symbolp val-like) (fboundp val-like))
2184 (funcall val-like name ag-like))
2185 ((stringp val-like)
2186 (format val-like ag-like))
2187 (t nil))))
2188 (feedmail-fiddle-header name (concat (nth 0 value) ag-like (nth 2 value)) 'supplement folding)))
2189 ))
bd1cd4c2
KH
2190
2191(defun feedmail-give-it-to-buffer-eater ()
2192 (save-excursion
c7d4a777
KH
2193 (if feedmail-enable-spray
2194 (mapcar
2195 '(lambda (feedmail-spray-this-address)
2196 (let ((spray-buffer (get-buffer-create " *FQM Outgoing Email Spray*")))
2197 (save-excursion
2198 (set-buffer spray-buffer)
2199 (erase-buffer)
2200 ;; not life's most efficient methodology, but spraying isn't
2201 ;; an every-5-minutes event either
bf714905 2202 (insert-buffer-substring feedmail-prepped-text-buffer)
c7d4a777 2203 ;; There's a good case to me made that each separate transmission of
37aa9115 2204 ;; a message in the spray should have a distinct Message-Id:. There
c7d4a777 2205 ;; is also a less compelling argument in the other direction. I think
37aa9115 2206 ;; they technically should have distinct Message-Id:s, but I doubt that
c7d4a777
KH
2207 ;; anyone cares, practically. If someone complains about it, I'll add
2208 ;; it.
2209 (feedmail-fiddle-list-of-spray-fiddle-plexes feedmail-spray-address-fiddle-plex-list)
2210 ;; this (let ) is just in case some buffer eater
2211 ;; is cheating and using the global variable name instead
2212 ;; of its argument to find the buffer
2213 (let ((feedmail-prepped-text-buffer spray-buffer))
2214 (funcall feedmail-buffer-eating-function
bd1cd4c2
KH
2215 feedmail-prepped-text-buffer
2216 feedmail-error-buffer
c7d4a777
KH
2217 (list feedmail-spray-this-address))))
2218 (kill-buffer spray-buffer)
2219 ))
2220 feedmail-address-list)
2221 (funcall feedmail-buffer-eating-function
2222 feedmail-prepped-text-buffer
2223 feedmail-error-buffer
2224 feedmail-address-list))))
bd1cd4c2
KH
2225
2226
2227(defun feedmail-envelope-deducer (eoh-marker)
27772f10 2228 "If `feedmail-deduce-envelope-from' is false, simply return `user-mail-address'.
37aa9115 2229Else, look for Sender: or From: (or Resent-*) and
bd1cd4c2
KH
2230return that value."
2231 (if (not feedmail-deduce-envelope-from)
c7d4a777
KH
2232 user-mail-address
2233 (let ((from-list))
2234 (setq from-list
2235 (feedmail-deduce-address-list
37aa9115 2236 (current-buffer) (point-min) eoh-marker (if feedmail-is-a-resend "^Resent-Sender:" "^Sender:")
c7d4a777
KH
2237 from-list))
2238 (if (not from-list)
bd1cd4c2 2239 (setq from-list
c7d4a777 2240 (feedmail-deduce-address-list
37aa9115 2241 (current-buffer) (point-min) eoh-marker (if feedmail-is-a-resend "^Resent-From:" "^From:")
c7d4a777
KH
2242 from-list)))
2243 (if (and from-list (car from-list)) (car from-list) user-mail-address))))
bd1cd4c2
KH
2244
2245
2246(defun feedmail-fiddle-from ()
37aa9115 2247 "Fiddle From:."
bd1cd4c2
KH
2248 ;; default is to fall off the end of the list and do nothing
2249 (cond
2250 ;; nil means do nothing
2251 ((eq nil feedmail-from-line) nil)
2252 ;; t is the same a using the default computation, so compute it and recurse
2253 ;; user-full-name suggested by kpc@ptolemy.arc.nasa.gov (=Kimball Collins)
2254 ;; improvement using user-mail-address suggested by
2255 ;; gray@austin.apc.slb.com (Douglas Gray Stephens)
2256 ((eq t feedmail-from-line)
c7d4a777
KH
2257 (let ((feedmail-from-line
2258 (let ((at-stuff
2259 (if user-mail-address user-mail-address (concat (user-login-name) "@" (system-name)))))
2260 (cond
2261 ((eq mail-from-style nil) at-stuff)
2262 ((eq mail-from-style 'parens) (concat at-stuff " (" (user-full-name) ")"))
2263 ((eq mail-from-style 'angles) (concat "\"" (user-full-name) "\" <" at-stuff ">"))
2264 ))))
2265 (feedmail-fiddle-from)))
bd1cd4c2
KH
2266
2267 ;; if it's a string, simply make a fiddle-plex out of it and recurse
2268 ((stringp feedmail-from-line)
c7d4a777
KH
2269 (let ((feedmail-from-line (list "ignored" feedmail-from-line 'create)))
2270 (feedmail-fiddle-from)))
bd1cd4c2
KH
2271
2272 ;; if it's a function, call it and recurse with the resulting value
2273 ((and (symbolp feedmail-from-line) (fboundp feedmail-from-line))
c7d4a777
KH
2274 (let ((feedmail-from-line (funcall feedmail-from-line)))
2275 (feedmail-fiddle-from)))
bd1cd4c2
KH
2276
2277 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2278 ((listp feedmail-from-line)
c7d4a777
KH
2279 (feedmail-fiddle-header
2280 (if feedmail-is-a-resend "Resent-From" "From")
2281 (nth 1 feedmail-from-line) ; value
2282 (nth 2 feedmail-from-line) ; action
2283 (nth 3 feedmail-from-line))))) ; folding
bd1cd4c2
KH
2284
2285
2286(defun feedmail-fiddle-sender ()
37aa9115 2287 "Fiddle Sender:."
bd1cd4c2
KH
2288 ;; default is to fall off the end of the list and do nothing
2289 (cond
2290 ;; nil means do nothing
2291 ((eq nil feedmail-sender-line) nil)
2292 ;; t is not allowed, but handled it just to avoid bugs later
2293 ((eq t feedmail-sender-line) nil)
2294
2295 ;; if it's a string, simply make a fiddle-plex out of it and recurse
2296 ((stringp feedmail-sender-line)
c7d4a777
KH
2297 (let ((feedmail-sender-line (list "ignored" feedmail-sender-line 'create)))
2298 (feedmail-fiddle-sender)))
bd1cd4c2
KH
2299
2300 ;; if it's a function, call it and recurse with the resulting value
2301 ((and (symbolp feedmail-sender-line) (fboundp feedmail-sender-line))
c7d4a777
KH
2302 (let ((feedmail-sender-line (funcall feedmail-sender-line)))
2303 (feedmail-fiddle-sender)))
bd1cd4c2
KH
2304
2305 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2306 ((listp feedmail-sender-line)
c7d4a777
KH
2307 (feedmail-fiddle-header
2308 (if feedmail-is-a-resend "Resent-Sender" "Sender")
2309 (nth 1 feedmail-sender-line) ; value
2310 (nth 2 feedmail-sender-line) ; action
2311 (nth 3 feedmail-sender-line))))) ; folding
bd1cd4c2
KH
2312
2313
2314(defun feedmail-default-date-generator (maybe-file)
37aa9115 2315 "Default function for generating Date: header contents."
bd1cd4c2 2316 (let ((date-time))
c7d4a777
KH
2317 (if (and (not feedmail-queue-use-send-time-for-date) maybe-file)
2318 (setq date-time (nth 5 (file-attributes maybe-file))))
2319 (feedmail-rfc822-date date-time))
bd1cd4c2
KH
2320 )
2321
2322
2323(defun feedmail-fiddle-date (maybe-file)
27772f10 2324 "Fiddle Date:. See documentation of `feedmail-date-generator'."
bd1cd4c2
KH
2325 ;; default is to fall off the end of the list and do nothing
2326 (cond
2327 ;; nil means do nothing
2328 ((eq nil feedmail-date-generator) nil)
2329 ;; t is the same a using the function feedmail-default-date-generator, so let it and recurse
2330 ((eq t feedmail-date-generator)
c7d4a777
KH
2331 (let ((feedmail-date-generator (feedmail-default-date-generator maybe-file)))
2332 (feedmail-fiddle-date maybe-file)))
bd1cd4c2
KH
2333
2334 ;; if it's a string, simply make a fiddle-plex out of it and recurse
2335 ((stringp feedmail-date-generator)
c7d4a777
KH
2336 (let ((feedmail-date-generator (list "ignored" feedmail-date-generator 'create)))
2337 (feedmail-fiddle-date maybe-file)))
bd1cd4c2
KH
2338
2339 ;; if it's a function, call it and recurse with the resulting value
2340 ((and (symbolp feedmail-date-generator) (fboundp feedmail-date-generator))
c7d4a777
KH
2341 (let ((feedmail-date-generator (funcall feedmail-date-generator maybe-file)))
2342 (feedmail-fiddle-date maybe-file)))
bd1cd4c2
KH
2343
2344 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2345 ((listp feedmail-date-generator)
c7d4a777
KH
2346 (feedmail-fiddle-header
2347 (if feedmail-is-a-resend "Resent-Date" "Date")
2348 (nth 1 feedmail-date-generator) ; value
2349 (nth 2 feedmail-date-generator) ; action
2350 (nth 3 feedmail-date-generator))))) ; folding
bd1cd4c2
KH
2351
2352
2353(defun feedmail-default-message-id-generator (maybe-file)
37aa9115 2354 "Default function for generating Message-Id: header contents.
bd1cd4c2 2355Based on a date and a sort of random number for tie breaking. Unless
27772f10 2356`feedmail-message-id-suffix' is defined, uses `user-mail-address', so be
bd1cd4c2
KH
2357sure it's set."
2358 (let ((date-time)
c7d4a777
KH
2359 (end-stuff (if feedmail-message-id-suffix feedmail-message-id-suffix user-mail-address)))
2360 (if (string-match "^\\(.*\\)@" end-stuff)
2361 (setq end-stuff
2362 (concat (if (equal (match-beginning 1) (match-end 1)) "" "-") end-stuff))
2363 (setq end-stuff (concat "@" end-stuff)))
2364 (if (and (not feedmail-queue-use-send-time-for-message-id) maybe-file)
2365 (setq date-time (nth 5 (file-attributes maybe-file))))
2366 (format "<%d-%s%s%s>"
2367 (mod (random) 10000)
2368 (format-time-string "%a%d%b%Y%H%M%S" date-time)
2369 (feedmail-rfc822-time-zone date-time)
2370 end-stuff))
bd1cd4c2
KH
2371 )
2372
2373(defun feedmail-fiddle-message-id (maybe-file)
27772f10 2374 "Fiddle Message-Id:. See documentation of `feedmail-message-id-generator'."
bd1cd4c2
KH
2375 ;; default is to fall off the end of the list and do nothing
2376 (cond
2377 ;; nil means do nothing
2378 ((eq nil feedmail-message-id-generator) nil)
2379 ;; t is the same a using the function feedmail-default-message-id-generator, so let it and recurse
2380 ((eq t feedmail-message-id-generator)
c7d4a777
KH
2381 (let ((feedmail-message-id-generator (feedmail-default-message-id-generator maybe-file)))
2382 (feedmail-fiddle-message-id maybe-file)))
bd1cd4c2
KH
2383
2384 ;; if it's a string, simply make a fiddle-plex out of it and recurse
2385 ((stringp feedmail-message-id-generator)
c7d4a777
KH
2386 (let ((feedmail-message-id-generator (list "ignored" feedmail-message-id-generator 'create)))
2387 (feedmail-fiddle-message-id maybe-file)))
bd1cd4c2
KH
2388
2389 ;; if it's a function, call it and recurse with the resulting value
2390 ((and (symbolp feedmail-message-id-generator) (fboundp feedmail-message-id-generator))
c7d4a777
KH
2391 (let ((feedmail-message-id-generator (funcall feedmail-message-id-generator maybe-file)))
2392 (feedmail-fiddle-message-id maybe-file)))
bd1cd4c2
KH
2393
2394 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2395 ((listp feedmail-message-id-generator)
c7d4a777 2396 (feedmail-fiddle-header
37aa9115 2397 (if feedmail-is-a-resend "Resent-Message-Id" "Message-Id")
c7d4a777
KH
2398 (nth 1 feedmail-message-id-generator) ; value
2399 (nth 2 feedmail-message-id-generator) ; action
2400 (nth 3 feedmail-message-id-generator))))) ; folding
bd1cd4c2
KH
2401
2402
2403(defun feedmail-default-x-mailer-generator ()
37aa9115 2404 "Default function for generating X-Mailer: header contents."
bd1cd4c2
KH
2405 (concat
2406 (let ((case-fold-search t)) (if (string-match "emacs" emacs-version) "" "emacs "))
2407 emacs-version " (via feedmail " feedmail-patch-level
2408 (if feedmail-queue-runner-is-active " Q" " I")
2409 (if feedmail-enable-spray "S" "")
2410 (if feedmail-x-mailer-line-user-appendage ") " ")")
2411 feedmail-x-mailer-line-user-appendage))
2412
2413
2414(defun feedmail-fiddle-x-mailer ()
27772f10 2415 "Fiddle X-Mailer:. See documentation of `feedmail-x-mailer-line'."
bd1cd4c2
KH
2416 ;; default is to fall off the end of the list and do nothing
2417 (cond
2418 ;; t is the same a using the function feedmail-default-x-mailer-generator, so let it and recurse
2419 ((eq t feedmail-x-mailer-line)
c7d4a777
KH
2420 (let ((feedmail-x-mailer-line (feedmail-default-x-mailer-generator)))
2421 (feedmail-fiddle-x-mailer)))
bd1cd4c2
KH
2422
2423 ;; if it's a string, simply make a fiddle-plex out of it and recurse
2424 ((stringp feedmail-x-mailer-line)
c7d4a777
KH
2425 (let ((feedmail-x-mailer-line (list "ignored" (list feedmail-x-mailer-line ";\n\t%s") 'combine)))
2426 (feedmail-fiddle-x-mailer)))
bd1cd4c2
KH
2427
2428 ;; if it's a function, call it and recurse with the resulting value
2429 ((and (symbolp feedmail-x-mailer-line) (fboundp feedmail-x-mailer-line))
c7d4a777
KH
2430 (let ((feedmail-x-mailer-line (funcall feedmail-x-mailer-line)))
2431 (feedmail-fiddle-x-mailer)))
bd1cd4c2
KH
2432
2433 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2434 ((listp feedmail-x-mailer-line)
c7d4a777
KH
2435 (feedmail-fiddle-header
2436 (if feedmail-is-a-resend "X-Resent-Mailer" "X-Mailer")
2437 (nth 1 feedmail-x-mailer-line) ; value
2438 (nth 2 feedmail-x-mailer-line) ; action
2439 (nth 3 feedmail-x-mailer-line))))) ; folding
bd1cd4c2
KH
2440
2441
2442(defun feedmail-fiddle-spray-address (addy-plex)
27772f10 2443 "Fiddle header for single spray address. Uses `feedmail-spray-this-address'."
bd1cd4c2
KH
2444 ;; default is to fall off the end of the list and do nothing
2445 (cond
2446 ;; nil means do nothing
2447 ((eq nil addy-plex) nil)
37aa9115 2448 ;; t means the same as using "To:" and unembellished addy
bd1cd4c2 2449 ((eq t addy-plex)
c7d4a777
KH
2450 (let ((addy-plex (list "To" feedmail-spray-this-address)))
2451 (feedmail-fiddle-spray-address addy-plex)))
bd1cd4c2
KH
2452
2453 ;; if it's a string, simply make a fiddle-plex out of it and recurse, assuming
37aa9115 2454 ;; the string names a header field (e.g., "To")
bd1cd4c2 2455 ((stringp addy-plex)
c7d4a777
KH
2456 (let ((addy-plex (list addy-plex feedmail-spray-this-address)))
2457 (feedmail-fiddle-spray-address addy-plex)))
bd1cd4c2
KH
2458
2459 ;; if it's a function, call it and recurse with the resulting value
2460 ((and (symbolp addy-plex) (fboundp addy-plex))
c7d4a777
KH
2461 (let ((addy-plex (funcall addy-plex)))
2462 (feedmail-fiddle-spray-address addy-plex)))
bd1cd4c2
KH
2463
2464 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2465 ((listp addy-plex)
c7d4a777
KH
2466 (feedmail-fiddle-header
2467 (nth 0 addy-plex) ; name
2468 (nth 1 addy-plex) ; value
2469 (nth 2 addy-plex) ; action
2470 (nth 3 addy-plex))))) ; folding
bd1cd4c2
KH
2471
2472
2473(defun feedmail-fiddle-list-of-spray-fiddle-plexes (list-of-fiddle-plexes)
2474 "Fiddling based on a list of fiddle-plexes for spraying."
2475 ;; default is to fall off the end of the list and do nothing
2476 (let ((lofp list-of-fiddle-plexes) fp)
0bb37c1a
KH
2477 (if (listp lofp)
2478 (while lofp
2479 (setq fp (car lofp))
2480 (setq lofp (cdr lofp))
2481 (feedmail-fiddle-spray-address fp))
2482 (feedmail-fiddle-spray-address lofp))))
bd1cd4c2
KH
2483
2484
2485(defun feedmail-fiddle-list-of-fiddle-plexes (list-of-fiddle-plexes)
2486 "Fiddling based on a list of fiddle-plexes. Values t, nil, and string are pointless."
2487 ;; default is to fall off the end of the list and do nothing
2488 (let ((lofp list-of-fiddle-plexes) fp)
0bb37c1a
KH
2489 (while lofp
2490 (setq fp (car lofp))
2491 (setq lofp (cdr lofp))
2492 (cond
bd1cd4c2 2493
0bb37c1a
KH
2494 ;; if it's a function, call it and recurse with the resulting value
2495 ((and (symbolp fp) (fboundp fp))
2496 (let ((lofp (list (funcall fp)))) (feedmail-fiddle-list-of-fiddle-plexes lofp)))
bd1cd4c2 2497
0bb37c1a
KH
2498 ;; if it's a list, it must be a fiddle-plex -- so fiddle, man, fiddle
2499 ((listp fp)
2500 (feedmail-fiddle-header
2501 (nth 0 fp)
c7d4a777
KH
2502 (nth 1 fp) ; value
2503 (nth 2 fp) ; action
2504 (nth 3 fp))))))) ; folding
bd1cd4c2
KH
2505
2506
2507(defun feedmail-accume-n-nuke-header (header-end header-regexp)
2508 "Delete headers matching a regexp and their continuation lines.
2509There may be multiple such lines, and each may have arbitrarily
2510many continuation lines. Return an accumulation of the deleted
2511headers, including the intervening newlines."
2512 (let ((case-fold-search t) (dropout))
0bb37c1a
KH
2513 (save-excursion
2514 (goto-char (point-min))
2515 ;; iterate over all matching lines
2516 (while (re-search-forward header-regexp header-end t)
2517 (forward-line 1)
2518 (setq dropout (concat dropout (buffer-substring (match-beginning 0) (point))))
2519 (delete-region (match-beginning 0) (point))
2520 ;; get rid of any continuation lines
2521 (while (and (looking-at "^[ \t].*\n") (< (point) header-end))
2522 (forward-line 1)
2523 (setq dropout (concat dropout (buffer-substring (match-beginning 0) (point))))
2524 (replace-match ""))))
c7d4a777 2525 (identity dropout)))
bd1cd4c2
KH
2526
2527(defun feedmail-fill-to-cc-function (header-end)
2528 "Smart filling of address headers (don't be fooled by the name).
2529The filling tries to avoid splitting lines except at commas. This
2530avoids, in particular, splitting within parenthesized comments in
37aa9115
KH
2531addresses. Headers filled include From:, Reply-To:, To:, Cc:, Bcc:,
2532Resent-To:, Resent-Cc:, and Resent-Bcc:."
bd1cd4c2 2533 (let ((case-fold-search t)
c7d4a777
KH
2534 this-line
2535 this-line-end)
2536 (save-excursion
2537 (goto-char (point-min))
37aa9115 2538 ;; iterate over all To:/Cc:, etc, lines
c7d4a777
KH
2539 (while
2540 (re-search-forward
37aa9115 2541 "^\\(From:\\|Reply-To:\\|To:\\|Cc:\\|Bcc:\\|Resent-To:\\|Resent-Cc:\\|Resent-Bcc:\\)"
c7d4a777
KH
2542 header-end t)
2543 (setq this-line (match-beginning 0))
2544 ;; replace 0 or more leading spaces with a single space
2545 (and (looking-at "[ \t]*") (replace-match " "))
2546 (forward-line 1)
2547 ;; get any continuation lines
2548 (while (and (looking-at "[ \t]+") (< (point) header-end))
2549 (forward-line 1))
2550 (setq this-line-end (point-marker))
2551 (save-excursion (feedmail-fill-this-one this-line this-line-end))
2552 ))))
bd1cd4c2
KH
2553
2554
2555(defun feedmail-fill-this-one (this-line this-line-end)
2556 "In-place smart filling of the region bounded by the two arguments."
2557 (let ((fill-prefix "\t")
c7d4a777
KH
2558 (fill-column feedmail-fill-to-cc-fill-column))
2559 ;; The general idea is to break only on commas. Collapse
2560 ;; multiple whitespace to a single blank; change
2561 ;; all the blanks to something unprintable; change the
2562 ;; commas to blanks; fill the region; change it back.
2563 (goto-char this-line)
2564 (while (re-search-forward "\\s-+" (1- this-line-end) t)
2565 (replace-match " "))
2566
2567 (subst-char-in-region this-line this-line-end ? 2 t) ; blank->C-b
2568 (subst-char-in-region this-line this-line-end ?, ? t) ; comma->blank
2569
2570 (fill-region-as-paragraph this-line this-line-end)
2571
2572 (subst-char-in-region this-line this-line-end ? ?, t) ; comma<-blank
2573 (subst-char-in-region this-line this-line-end 2 ? t) ; blank<-C-b
2574
2575 ;; look out for missing commas before continuation lines
2576 (goto-char this-line)
2577 (while (re-search-forward "\\([^,]\\)\n\t[ ]*" this-line-end t)
2578 (replace-match "\\1,\n\t"))
2579 ))
2580
2581
2582(require 'mail-utils) ; pick up mail-strip-quoted-names
bd1cd4c2
KH
2583(defun feedmail-deduce-address-list (message-buffer header-start header-end addr-regexp address-list)
2584 "Get address list with all comments and other excitement trimmed.
2585Addresses are collected only from headers whose names match the fourth
27772f10 2586argument. Returns a list of strings. Duplicate addresses will have
bd1cd4c2
KH
2587been weeded out."
2588 (let ((simple-address)
c7d4a777
KH
2589 (address-blob)
2590 (this-line)
2591 (this-line-end))
2592 (unwind-protect
2593 (save-excursion
2594 (set-buffer (get-buffer-create " *FQM scratch*")) (erase-buffer)
2595 (insert-buffer-substring message-buffer header-start header-end)
2596 (goto-char (point-min))
2597 (let ((case-fold-search t))
2598 (while (re-search-forward addr-regexp (point-max) t)
2599 (replace-match "")
2600 (setq this-line (match-beginning 0))
2601 (forward-line 1)
2602 ;; get any continuation lines
2603 (while (and (looking-at "^[ \t]+") (< (point) (point-max)))
2604 (forward-line 1))
2605 (setq this-line-end (point-marker))
2606 ;; only keep if we don't have it already
2607 (setq address-blob
2608 (mail-strip-quoted-names (buffer-substring this-line this-line-end)))
2609 (while (string-match "\\([, \t\n\r]*\\)\\([^, \t\n\r]+\\)" address-blob)
2610 (setq simple-address (substring address-blob (match-beginning 2) (match-end 2)))
2611 (setq address-blob (replace-match "" t t address-blob))
2612 (if (not (member simple-address address-list))
2613 (add-to-list 'address-list simple-address)))
2614 ))
2615 (kill-buffer nil)))
2616 (identity address-list)))
bd1cd4c2
KH
2617
2618
2619(defun feedmail-one-last-look (feedmail-prepped-text-buffer)
2620 "Offer the user one last chance to give it up."
2621 (save-excursion
c7d4a777
KH
2622 (save-window-excursion
2623 (switch-to-buffer feedmail-prepped-text-buffer)
2624 (if (and (fboundp 'y-or-n-p-with-timeout) (numberp feedmail-confirm-outgoing-timeout))
2625 (y-or-n-p-with-timeout
2626 "FQM: Send this email? "
2627 (abs feedmail-confirm-outgoing-timeout)
2628 (> feedmail-confirm-outgoing-timeout 0))
2629 (y-or-n-p "FQM: Send this email? "))
2630 )))
bd1cd4c2
KH
2631
2632(defun feedmail-fqm-p (might-be)
2633 "Internal; does filename end with FQM suffix?"
2634 (string-match (concat (regexp-quote feedmail-queue-fqm-suffix) "$") might-be))
2635
2636
2637(defun feedmail-find-eoh (&optional noerror)
2638 "Internal; finds the end of message header fields, returns mark just before it"
2639 (save-excursion
c7d4a777 2640 (goto-char (point-min))
2771a002
GM
2641 (when (or (re-search-forward (concat "^"
2642 (regexp-quote mail-header-separator)
2643 "\n")
2644 nil noerror)
2645 (and feedmail-queue-alternative-mail-header-separator
2646 (re-search-forward
2647 (concat "^"
2648 (regexp-quote
2649 feedmail-queue-alternative-mail-header-separator)
2650 "\n")
2651 nil noerror)))
2652 (forward-line -1)
2653 (point-marker))))
bd1cd4c2
KH
2654
2655(provide 'feedmail)
e8af40ee 2656
cbee283d 2657;; arch-tag: ec27b380-11c0-4dfd-8436-f636cf2bb992
bd1cd4c2 2658;;; feedmail.el ends here