19 |
|
|
20 |
int debug_level; |
int debug_level; |
21 |
int multiple_delivery; |
int multiple_delivery; |
22 |
int bounce_quota; |
int ex_quota_tempfail; |
23 |
int exit_code = EX_OK; |
int exit_code = EX_OK; |
24 |
uid_t uid; |
uid_t uid; |
25 |
char *maildir = MU_PATH_MAILDIR; |
char *maildir = MU_PATH_MAILDIR; |
27 |
int lock_timeout = 300; |
int lock_timeout = 300; |
28 |
|
|
29 |
#define MAXFD 64 |
#define MAXFD 64 |
30 |
|
#define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE) |
31 |
|
|
32 |
static void print_help (void); |
static void print_help (void); |
33 |
static void print_license (void); |
static void print_license (void); |
38 |
void deliver (FILE *fp, char *name); |
void deliver (FILE *fp, char *name); |
39 |
void guess_retval (int ec); |
void guess_retval (int ec); |
40 |
void mailer_err (char *fmt, ...); |
void mailer_err (char *fmt, ...); |
41 |
|
void notify_biff (mailbox_t mbox, char *name, size_t size); |
42 |
|
|
43 |
char short_opts[] = "hf:Llm:q:r:s:x::v"; |
char short_opts[] = "hf:Llm:q:r:s:x::vW;"; |
44 |
|
|
45 |
static struct option long_opts[] = { |
static struct option long_opts[] = { |
46 |
|
{ "ex-multiple-delivery-success", no_argument, &multiple_delivery, 1 }, |
47 |
|
{ "ex-quota-tempfail", no_argument, &ex_quota_tempfail, 1 }, |
48 |
{ "from", required_argument, 0, 'f' }, |
{ "from", required_argument, 0, 'f' }, |
49 |
{ "help", no_argument, 0, 'h' }, |
{ "help", no_argument, 0, 'h' }, |
50 |
{ "license", no_argument, 0, 'L' }, |
{ "license", no_argument, 0, 'L' }, |
51 |
{ "maildir", required_argument, 0, 'm' }, |
{ "maildir", required_argument, 0, 'm' }, |
|
{ "multiple-delivery", no_argument, 0, 'M' }, |
|
52 |
{ "quota-db", required_argument, 0, 'q' }, |
{ "quota-db", required_argument, 0, 'q' }, |
53 |
{ "source", required_argument, 0, 's' }, |
{ "source", required_argument, 0, 's' }, |
54 |
{ "timeout", required_argument, 0, 't' }, |
{ "timeout", required_argument, 0, 't' }, |
65 |
FILE *fp; |
FILE *fp; |
66 |
char *from = NULL; |
char *from = NULL; |
67 |
char *progfile_pattern = NULL; |
char *progfile_pattern = NULL; |
68 |
struct mda_data mda_data; |
char *tempfile = NULL; |
69 |
|
|
70 |
/* Preparative work: close inherited fds, force a reasonable umask |
/* Preparative work: close inherited fds, force a reasonable umask |
71 |
and prepare a logging. */ |
and prepare a logging. */ |
72 |
close_fds (); |
close_fds (); |
79 |
while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF) |
while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF) |
80 |
switch (c) |
switch (c) |
81 |
{ |
{ |
82 |
|
case 0: /* option already handled */ |
83 |
|
break; |
84 |
case 'r': |
case 'r': |
85 |
case 'f': |
case 'f': |
86 |
if (from != NULL) |
if (from != NULL) |
103 |
maildir = optarg; |
maildir = optarg; |
104 |
break; |
break; |
105 |
|
|
|
case 'M': |
|
|
multiple_delivery++; |
|
|
break; |
|
|
|
|
106 |
#ifdef USE_DBM |
#ifdef USE_DBM |
107 |
case 'q': |
case 'q': |
108 |
quotadbname = optarg; |
quotadbname = optarg; |
121 |
|
|
122 |
case 'x': |
case 'x': |
123 |
if (optarg) |
if (optarg) |
124 |
debug_level = strtoul (optarg, NULL, 0); |
{ |
125 |
|
#ifdef WITH_GUILE |
126 |
|
if (strcmp (optarg, "guile") == 0) |
127 |
|
debug_guile = 1; |
128 |
|
else |
129 |
|
#endif |
130 |
|
debug_level = strtoul (optarg, NULL, 0); |
131 |
|
} |
132 |
else |
else |
133 |
debug_level = 9; |
{ |
134 |
|
debug_level = 9; |
135 |
|
#ifdef WITH_GUILE |
136 |
|
debug_guile = 1; |
137 |
|
#endif |
138 |
|
} |
139 |
break; |
break; |
140 |
|
|
141 |
case 'v': |
case 'v': |
159 |
return 1; |
return 1; |
160 |
} |
} |
161 |
|
|
|
if (!from) |
|
|
{ |
|
|
struct passwd *pw = getpwuid (uid); |
|
|
if (pw) |
|
|
from = pw->pw_name; |
|
|
else |
|
|
{ |
|
|
mu_error ("From unknown"); |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|
|
162 |
#ifdef HAVE_MYSQL |
#ifdef HAVE_MYSQL |
163 |
mu_register_getpwnam (getMpwnam); |
mu_register_getpwnam (getMpwnam); |
164 |
#endif |
#endif |
173 |
list_append (bookie, smtp_record); |
list_append (bookie, smtp_record); |
174 |
} |
} |
175 |
|
|
176 |
memset (&mda_data, 0, sizeof mda_data); |
fp = make_tmp (from, &tempfile); |
|
fp = make_tmp (from, &mda_data.tempfile); |
|
177 |
|
|
178 |
if (multiple_delivery) |
if (multiple_delivery) |
179 |
multiple_delivery = argc > 1; |
multiple_delivery = argc > 1; |
180 |
|
|
181 |
#ifdef WITH_GUILE |
#ifdef WITH_GUILE |
|
mda_data.fp = fp; |
|
|
mda_data.argv = argv; |
|
|
mda_data.progfile_pattern = progfile_pattern; |
|
|
|
|
182 |
if (progfile_pattern) |
if (progfile_pattern) |
183 |
return prog_mda (&mda_data); |
{ |
184 |
|
struct mda_data mda_data; |
185 |
|
|
186 |
|
memset (&mda_data, 0, sizeof mda_data); |
187 |
|
mda_data.fp = fp; |
188 |
|
mda_data.argv = argv; |
189 |
|
mda_data.progfile_pattern = progfile_pattern; |
190 |
|
mda_data.tempfile = tempfile; |
191 |
|
return prog_mda (&mda_data); |
192 |
|
} |
193 |
#endif |
#endif |
194 |
|
|
195 |
unlink (mda_data.tempfile); |
unlink (tempfile); |
196 |
for (; *argv; argv++) |
for (; *argv; argv++) |
197 |
mda (fp, *argv, NULL); |
mda (fp, *argv, NULL); |
198 |
return exit_code; |
return exit_code; |
285 |
if (attribute_is_deleted (attr)) |
if (attribute_is_deleted (attr)) |
286 |
return EX_OK; |
return EX_OK; |
287 |
} |
} |
288 |
|
|
289 |
deliver (fp, username); |
deliver (fp, username); |
290 |
|
|
291 |
if (multiple_delivery) |
if (multiple_delivery) |
337 |
FILE *fp; |
FILE *fp; |
338 |
char *buf = NULL; |
char *buf = NULL; |
339 |
size_t n = 0; |
size_t n = 0; |
340 |
|
int line; |
341 |
|
|
342 |
if (fd == -1 || (fp = fdopen(fd, "w+")) == NULL) |
if (fd == -1 || (fp = fdopen (fd, "w+")) == NULL) |
343 |
{ |
{ |
344 |
mailer_err("unable to open temporary file"); |
mailer_err ("unable to open temporary file"); |
345 |
exit (exit_code); |
exit (exit_code); |
346 |
} |
} |
|
|
|
|
time (&t); |
|
|
fprintf (fp, "From %s %s", from, ctime (&t)); |
|
347 |
|
|
348 |
while (getline(&buf, &n, stdin) > 0) { |
line = 0; |
349 |
if (!memcmp(buf, "From ", 5)) |
while (getline (&buf, &n, stdin) > 0) { |
350 |
fputc('>', fp); |
line++; |
351 |
|
if (line == 1) |
352 |
|
{ |
353 |
|
if (memcmp (buf, "From ", 5)) |
354 |
|
{ |
355 |
|
if (!from) |
356 |
|
{ |
357 |
|
struct passwd *pw = getpwuid (uid); |
358 |
|
if (pw) |
359 |
|
from = pw->pw_name; |
360 |
|
} |
361 |
|
if (from) |
362 |
|
{ |
363 |
|
time (&t); |
364 |
|
fprintf (fp, "From %s %s", from, ctime (&t)); |
365 |
|
} |
366 |
|
else |
367 |
|
{ |
368 |
|
mailer_err ("Can't determine sender address"); |
369 |
|
exit (EX_UNAVAILABLE); |
370 |
|
} |
371 |
|
} |
372 |
|
} |
373 |
|
else if (!memcmp (buf, "From ", 5)) |
374 |
|
fputc ('>', fp); |
375 |
if (fputs (buf, fp) == EOF) |
if (fputs (buf, fp) == EOF) |
376 |
{ |
{ |
377 |
mailer_err ("temporary file write error"); |
mailer_err ("temporary file write error"); |
378 |
fclose(fp); |
fclose (fp); |
379 |
return NULL; |
return NULL; |
380 |
} |
} |
381 |
} |
} |
382 |
|
|
383 |
if (buf && strchr(buf, '\n') == NULL) |
if (buf && strchr (buf, '\n') == NULL) |
384 |
putc('\n', fp); |
putc ('\n', fp); |
385 |
|
|
386 |
putc('\n', fp); |
putc ('\n', fp); |
387 |
free (buf); |
free (buf); |
388 |
|
|
389 |
return fp; |
return fp; |
486 |
{ |
{ |
487 |
case MQUOTA_EXCEEDED: |
case MQUOTA_EXCEEDED: |
488 |
mailer_err ("%s: mailbox quota exceeded for this recipient", name); |
mailer_err ("%s: mailbox quota exceeded for this recipient", name); |
489 |
exit_code = EX_UNAVAILABLE; |
exit_code = EX_QUOTA(); |
490 |
failed++; |
failed++; |
491 |
break; |
break; |
492 |
case MQUOTA_UNLIMITED: |
case MQUOTA_UNLIMITED: |
502 |
{ |
{ |
503 |
mailer_err ("%s: message would exceed maximum mailbox size for this recipient", |
mailer_err ("%s: message would exceed maximum mailbox size for this recipient", |
504 |
name); |
name); |
505 |
exit_code = EX_UNAVAILABLE; |
exit_code = EX_QUOTA(); |
506 |
failed++; |
failed++; |
507 |
} |
} |
508 |
break; |
break; |
530 |
free (buf); |
free (buf); |
531 |
switch_user_id (0); |
switch_user_id (0); |
532 |
} |
} |
533 |
|
|
534 |
|
if (!failed) |
535 |
|
notify_biff (mbox, name, size); |
536 |
|
|
537 |
locker_unlock (lock); |
locker_unlock (lock); |
538 |
/* FIXME: Flush the data */ |
|
539 |
mailbox_close (mbox); |
mailbox_close (mbox); |
540 |
mailbox_destroy (&mbox); |
mailbox_destroy (&mbox); |
541 |
#if 0 /*FIXME*/ |
} |
542 |
if (!failed) |
|
543 |
notify_biff (name, size); |
void |
544 |
#endif |
notify_biff (mailbox_t mbox, char *name, size_t size) |
545 |
|
{ |
546 |
|
static int fd = -1; |
547 |
|
url_t url = NULL; |
548 |
|
char *buf = NULL; |
549 |
|
static struct sockaddr_in inaddr; |
550 |
|
|
551 |
|
if (fd == -1) |
552 |
|
{ |
553 |
|
struct servent *sp; |
554 |
|
|
555 |
|
if ((sp = getservbyname ("biff", "udp")) == NULL) |
556 |
|
return; |
557 |
|
|
558 |
|
inaddr.sin_family = AF_INET; |
559 |
|
inaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
560 |
|
inaddr.sin_port = sp->s_port; |
561 |
|
|
562 |
|
fd = socket (AF_INET, SOCK_DGRAM, 0); |
563 |
|
if (fd < 0) |
564 |
|
fd = -2; /* Mark failed initialization */ |
565 |
|
} |
566 |
|
|
567 |
|
if (fd < 0) |
568 |
|
return; |
569 |
|
|
570 |
|
mailbox_get_url (mbox, &url); |
571 |
|
asprintf (&buf, "%s@%ld:%s", name, size, url_to_string (url)); |
572 |
|
if (buf) |
573 |
|
{ |
574 |
|
sendto (fd, buf, strlen (buf), 0, (struct sockaddr *)&inaddr, |
575 |
|
sizeof inaddr); |
576 |
|
free (buf); |
577 |
|
} |
578 |
} |
} |
579 |
|
|
580 |
void |
void |
594 |
#ifdef EAGAIN |
#ifdef EAGAIN |
595 |
EAGAIN, /* Try again */ |
EAGAIN, /* Try again */ |
596 |
#endif |
#endif |
|
#ifdef EDQUOT |
|
|
EDQUOT, /* Disk quota esceeded */ |
|
|
#endif |
|
597 |
#ifdef EBUSY |
#ifdef EBUSY |
598 |
EBUSY, /* Device or resource busy */ |
EBUSY, /* Device or resource busy */ |
599 |
#endif |
#endif |
673 |
/* Temporary failures override hard errors. */ |
/* Temporary failures override hard errors. */ |
674 |
if (exit_code == EX_TEMPFAIL) |
if (exit_code == EX_TEMPFAIL) |
675 |
return; |
return; |
676 |
|
#ifdef EDQUOT |
677 |
|
if (ec == EDQUOT) |
678 |
|
{ |
679 |
|
exit_code = EX_QUOTA(); |
680 |
|
return; |
681 |
|
} |
682 |
|
#endif |
683 |
|
|
684 |
for (i = 0; i < sizeof (temp_errors)/sizeof (temp_errors[0]); i++) |
for (i = 0; i < sizeof (temp_errors)/sizeof (temp_errors[0]); i++) |
685 |
if (temp_errors[i] == ec) |
if (temp_errors[i] == ec) |
686 |
{ |
{ |
700 |
" -h, --help Display this help and exit\n" |
" -h, --help Display this help and exit\n" |
701 |
" -L, --license Display GNU General Public License\n" |
" -L, --license Display GNU General Public License\n" |
702 |
" -m, --maildir PATH Specify path to mailspool directory\n" |
" -m, --maildir PATH Specify path to mailspool directory\n" |
|
" -M, --multiple-delivery Don't return errors when delivering to multiple\n" |
|
|
" recipients\n" |
|
703 |
#ifdef USE_DBM |
#ifdef USE_DBM |
704 |
" -q, --quota-db FILE Specify path to quota database.\n" |
" -q, --quota-db FILE Specify path to quota database.\n" |
705 |
#endif |
#endif |
707 |
" -s, --source PATTERN Set name pattern for user-defined mail filters.\n" |
" -s, --source PATTERN Set name pattern for user-defined mail filters.\n" |
708 |
#endif |
#endif |
709 |
" -t, --timeout NUMBER Set timeout for acquiring the lockfile\n" |
" -t, --timeout NUMBER Set timeout for acquiring the lockfile\n" |
710 |
|
#ifdef WITH_GUILE |
711 |
|
" -x, --debug guile Start with guile debugging evaluator and backtraces\n" |
712 |
|
#endif |
713 |
" -x, --debug NUMBER Set debugging level\n" |
" -x, --debug NUMBER Set debugging level\n" |
714 |
" -v, --version Display program version and exit.\n" |
" -v, --version Display program version and exit.\n" |
715 |
|
" --ex-multiple-delivery-success Don't return errors when delivering to\n" |
716 |
|
" multiple recipients\n" |
717 |
|
" --ex-quota-tempfail Return temporary failure if disk or mailbox quota\n" |
718 |
|
" is exceeded\n" |
719 |
"\nReport bugs to bug-mailutils@gnu.org\n"; |
"\nReport bugs to bug-mailutils@gnu.org\n"; |
720 |
|
|
721 |
printf ("%s", help_message); |
printf ("%s", help_message); |