18 |
/* MH send command */ |
/* MH send command */ |
19 |
|
|
20 |
#include <mh.h> |
#include <mh.h> |
21 |
|
#include <sys/stat.h> |
22 |
|
#include <unistd.h> |
23 |
|
#include <stdarg.h> |
24 |
|
|
25 |
const char *argp_program_version = "send (" PACKAGE_STRING ")"; |
const char *argp_program_version = "send (" PACKAGE_STRING ")"; |
26 |
static char doc[] = N_("GNU MH send\v" |
static char doc[] = N_("GNU MH send\v" |
57 |
{"alias", ARG_ALIAS, N_("FILE"), 0, |
{"alias", ARG_ALIAS, N_("FILE"), 0, |
58 |
N_("* Specify additional alias file") }, |
N_("* Specify additional alias file") }, |
59 |
{"draft", ARG_DRAFT, NULL, 0, |
{"draft", ARG_DRAFT, NULL, 0, |
60 |
N_("* Use prepared draft") }, |
N_("Use prepared draft") }, |
61 |
{"draftfolder", ARG_DRAFTFOLDER, N_("FOLDER"), 0, |
{"draftfolder", ARG_DRAFTFOLDER, N_("FOLDER"), 0, |
62 |
N_("* Specify the folder for message drafts") }, |
N_("* Specify the folder for message drafts") }, |
63 |
{"draftmessage", ARG_DRAFTMESSAGE, N_("MESSAGE"), 0, |
{"draftmessage", ARG_DRAFTMESSAGE, N_("MESSAGE"), 0, |
81 |
N_("* Add Message-ID: field") }, |
N_("* Add Message-ID: field") }, |
82 |
{"nomsgid", ARG_NOMSGID, NULL, OPTION_HIDDEN, ""}, |
{"nomsgid", ARG_NOMSGID, NULL, OPTION_HIDDEN, ""}, |
83 |
{"push", ARG_PUSH, N_("BOOL"), OPTION_ARG_OPTIONAL, |
{"push", ARG_PUSH, N_("BOOL"), OPTION_ARG_OPTIONAL, |
84 |
N_("* Run in the backround.") }, |
N_("Run in the backround.") }, |
85 |
{"nopush", ARG_NOPUSH, NULL, OPTION_HIDDEN, "" }, |
{"nopush", ARG_NOPUSH, NULL, OPTION_HIDDEN, "" }, |
86 |
{"split", ARG_SPLIT, N_("SECONDS"), 0, |
{"split", ARG_SPLIT, N_("SECONDS"), 0, |
87 |
N_("* Split the draft into several partial messages and send them with SECONDS interval") }, |
N_("* Split the draft into several partial messages and send them with SECONDS interval") }, |
88 |
{"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL, |
{"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL, |
89 |
N_("* Print the transcript of interactions with the transport system") }, |
N_("Print the transcript of interactions with the transport system") }, |
90 |
{"noverbose", ARG_NOVERBOSE, NULL, OPTION_HIDDEN, "" }, |
{"noverbose", ARG_NOVERBOSE, NULL, OPTION_HIDDEN, "" }, |
91 |
{"watch", ARG_WATCH, N_("BOOL"), OPTION_ARG_OPTIONAL, |
{"watch", ARG_WATCH, N_("BOOL"), OPTION_ARG_OPTIONAL, |
92 |
N_("* Monitor the delivery of mail") }, |
N_("Monitor the delivery of mail") }, |
93 |
{"nowatch", ARG_NOWATCH, NULL, OPTION_HIDDEN, "" }, |
{"nowatch", ARG_NOWATCH, NULL, OPTION_HIDDEN, "" }, |
94 |
{"width", ARG_WIDTH, N_("NUMBER"), 0, |
{"width", ARG_WIDTH, N_("NUMBER"), 0, |
95 |
N_("* Make header fields no longer than NUMBER columns") }, |
N_("* Make header fields no longer than NUMBER columns") }, |
117 |
{ 0 } |
{ 0 } |
118 |
}; |
}; |
119 |
|
|
120 |
|
static int use_draft; /* Use the prepared draft */ |
121 |
static int reformat_recipients; /* --format option */ |
static int reformat_recipients; /* --format option */ |
122 |
static int forward_notice; /* Forward the failure notice to the sender, |
static int forward_notice; /* Forward the failure notice to the sender, |
123 |
--forward flag */ |
--forward flag */ |
133 |
static int watch; /* Watch the delivery process */ |
static int watch; /* Watch the delivery process */ |
134 |
static unsigned width = 76; /* Maximum width of header fields */ |
static unsigned width = 76; /* Maximum width of header fields */ |
135 |
|
|
136 |
|
#define WATCH(c) do {\ |
137 |
|
if (watch)\ |
138 |
|
watch_printf c;\ |
139 |
|
} while (0) |
140 |
|
|
141 |
static int |
static int |
142 |
opt_handler (int key, char *arg, void *unused) |
opt_handler (int key, char *arg, void *unused) |
143 |
{ |
{ |
146 |
switch (key) |
switch (key) |
147 |
{ |
{ |
148 |
case ARG_ALIAS: |
case ARG_ALIAS: |
149 |
case ARG_DRAFT: |
return 1; |
150 |
|
|
151 |
|
case ARG_DRAFT: |
152 |
|
use_draft = 1; |
153 |
|
break; |
154 |
|
|
155 |
case ARG_DRAFTFOLDER: |
case ARG_DRAFTFOLDER: |
156 |
case ARG_DRAFTMESSAGE: |
case ARG_DRAFTMESSAGE: |
157 |
case ARG_NODRAFTFOLDER: |
case ARG_NODRAFTFOLDER: |
239 |
} |
} |
240 |
return 0; |
return 0; |
241 |
} |
} |
242 |
|
|
243 |
|
static int |
244 |
|
watch_printf (const char *fmt, ...) |
245 |
|
{ |
246 |
|
va_list ap; |
247 |
|
|
248 |
|
va_start (ap, fmt); |
249 |
|
vfprintf (stderr, fmt, ap); |
250 |
|
fprintf (stderr, "\n"); |
251 |
|
va_end (ap); |
252 |
|
} |
253 |
|
|
254 |
|
static char * |
255 |
|
draft_name() |
256 |
|
{ |
257 |
|
char *draftfolder = mh_global_profile_get ("Draft-Folder", |
258 |
|
mu_path_folder_dir); |
259 |
|
return mh_expand_name (draftfolder, "draft", 0); |
260 |
|
} |
261 |
|
|
262 |
|
static list_t mbox_list; |
263 |
|
static mh_context_t *mts_profile; |
264 |
|
|
265 |
|
int |
266 |
|
check_file (char *name) |
267 |
|
{ |
268 |
|
mailbox_t mbox; |
269 |
|
|
270 |
|
mbox = mh_open_msg_file (name); |
271 |
|
if (!mbox) |
272 |
|
return 1; |
273 |
|
if (!mbox_list && list_create (&mbox_list)) |
274 |
|
{ |
275 |
|
mh_error (_("can't create mailbox list")); |
276 |
|
return 1; |
277 |
|
} |
278 |
|
|
279 |
|
return list_append (mbox_list, mbox); |
280 |
|
} |
281 |
|
|
282 |
|
void |
283 |
|
read_mts_profile () |
284 |
|
{ |
285 |
|
char *p; |
286 |
|
|
287 |
|
p = mh_expand_name (MHLIBDIR, "mtstailor", 0); |
288 |
|
if (!p) |
289 |
|
{ |
290 |
|
char *home = mu_get_homedir (); |
291 |
|
if (!home) |
292 |
|
abort (); /* shouldn't happen */ |
293 |
|
asprintf (&p, "%s/%s", home, ".mtstailor"); |
294 |
|
free (home); |
295 |
|
} |
296 |
|
mts_profile = mh_context_create (p, 1); |
297 |
|
mh_context_read (mts_profile); |
298 |
|
} |
299 |
|
|
300 |
|
|
301 |
|
mailer_t |
302 |
|
open_mailer () |
303 |
|
{ |
304 |
|
char *url = mh_context_get_value (mts_profile, |
305 |
|
"url", |
306 |
|
"sendmail:/usr/sbin/sendmail"); |
307 |
|
mailer_t mailer; |
308 |
|
int status; |
309 |
|
|
310 |
|
WATCH(("creating mailer %s", url)); |
311 |
|
status = mailer_create (&mailer, url); |
312 |
|
if (status) |
313 |
|
{ |
314 |
|
mh_error(_("cannot create mailer \"%s\""), url); |
315 |
|
return NULL; |
316 |
|
} |
317 |
|
|
318 |
|
if (verbose) |
319 |
|
{ |
320 |
|
mu_debug_t debug = NULL; |
321 |
|
mailer_get_debug (mailer, &debug); |
322 |
|
mu_debug_set_level (debug, MU_DEBUG_TRACE | MU_DEBUG_PROT); |
323 |
|
} |
324 |
|
|
325 |
|
WATCH(("opening mailer %s", url)); |
326 |
|
status = mailer_open (mailer, MU_STREAM_RDWR); |
327 |
|
if (status) |
328 |
|
{ |
329 |
|
mh_error(_("cannot open mailer \"%s\""), url); |
330 |
|
return NULL; |
331 |
|
} |
332 |
|
return mailer; |
333 |
|
} |
334 |
|
|
335 |
|
int |
336 |
|
_action_send (void *item, void *data) |
337 |
|
{ |
338 |
|
mailbox_t mbox = item; |
339 |
|
message_t msg; |
340 |
|
int rc; |
341 |
|
mailer_t mailer; |
342 |
|
|
343 |
|
WATCH(("Getting message")); |
344 |
|
if ((rc = mailbox_get_message (mbox, 1, &msg))) |
345 |
|
{ |
346 |
|
mh_error(_("cannot get message: %s"), mu_strerror (rc)); |
347 |
|
return 1; |
348 |
|
} |
349 |
|
|
350 |
|
mailer = open_mailer (); |
351 |
|
if (!mailer) |
352 |
|
return 1; |
353 |
|
|
354 |
|
WATCH(("Sending message")); |
355 |
|
rc = mailer_send_message (mailer, msg, NULL, NULL); |
356 |
|
if (rc) |
357 |
|
{ |
358 |
|
mh_error(_("cannot send message: %s"), mu_strerror (rc)); |
359 |
|
return 1; |
360 |
|
} |
361 |
|
|
362 |
|
WATCH(("Destroying the mailer")); |
363 |
|
mailer_close (mailer); |
364 |
|
mailer_destroy (&mailer); |
365 |
|
|
366 |
|
return 0; |
367 |
|
} |
368 |
|
|
369 |
|
int |
370 |
|
send (int argc, char **argv) |
371 |
|
{ |
372 |
|
int i, rc; |
373 |
|
|
374 |
|
for (i = 0; i < argc; i++) |
375 |
|
if (check_file (argv[i])) |
376 |
|
return 1; |
377 |
|
|
378 |
|
read_mts_profile (); |
379 |
|
|
380 |
|
if (background && daemon (0, 0) < 0) |
381 |
|
{ |
382 |
|
mh_error(_("cannot switch to background: %s"), mu_strerror (errno)); |
383 |
|
return 1; |
384 |
|
} |
385 |
|
|
386 |
|
rc = list_do (mbox_list, _action_send, NULL); |
387 |
|
return rc; |
388 |
|
} |
389 |
|
|
390 |
int |
int |
391 |
main (int argc, char **argv) |
main (int argc, char **argv) |
392 |
{ |
{ |
397 |
mh_argp_parse (argc, argv, options, mh_option, args_doc, doc, |
mh_argp_parse (argc, argv, options, mh_option, args_doc, doc, |
398 |
opt_handler, NULL, &index); |
opt_handler, NULL, &index); |
399 |
|
|
400 |
return 0; |
argc -= index; |
401 |
|
argv += index; |
402 |
|
|
403 |
|
if (argc == 0) |
404 |
|
{ |
405 |
|
struct stat st; |
406 |
|
static char *xargv[2]; |
407 |
|
xargv[0] = draft_name(); |
408 |
|
|
409 |
|
if (stat (xargv[0], &st)) |
410 |
|
{ |
411 |
|
mh_error(_("cannot stat %s: %s"), xargv[0], mu_strerror (errno)); |
412 |
|
return 1; |
413 |
|
} |
414 |
|
|
415 |
|
if (!use_draft && !mh_usedraft (xargv[0])) |
416 |
|
exit (0); |
417 |
|
xargv[1] = NULL; |
418 |
|
argv = xargv; |
419 |
|
argc = 1; |
420 |
|
} |
421 |
|
|
422 |
|
return send(argc, argv); |
423 |
} |
} |