Commit 914fca55 914fca55f20d9cef0c5030263fdd2e9a50ebcd82 by Sergey Poznyakoff

Implemented biff notification.

1 parent 88524de8
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
19 19
20 int debug_level; 20 int debug_level;
21 int multiple_delivery; 21 int multiple_delivery;
22 int bounce_quota; 22 int ex_quota_tempfail;
23 int exit_code = EX_OK; 23 int exit_code = EX_OK;
24 uid_t uid; 24 uid_t uid;
25 char *maildir = MU_PATH_MAILDIR; 25 char *maildir = MU_PATH_MAILDIR;
...@@ -27,6 +27,7 @@ char *quotadbname = NULL; ...@@ -27,6 +27,7 @@ char *quotadbname = NULL;
27 int lock_timeout = 300; 27 int lock_timeout = 300;
28 28
29 #define MAXFD 64 29 #define MAXFD 64
30 #define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE)
30 31
31 static void print_help (void); 32 static void print_help (void);
32 static void print_license (void); 33 static void print_license (void);
...@@ -37,15 +38,17 @@ FILE *make_tmp (const char *from, char **tempfile); ...@@ -37,15 +38,17 @@ FILE *make_tmp (const char *from, char **tempfile);
37 void deliver (FILE *fp, char *name); 38 void deliver (FILE *fp, char *name);
38 void guess_retval (int ec); 39 void guess_retval (int ec);
39 void mailer_err (char *fmt, ...); 40 void mailer_err (char *fmt, ...);
41 void notify_biff (mailbox_t mbox, char *name, size_t size);
40 42
41 char short_opts[] = "hf:Llm:q:r:s:x::v"; 43 char short_opts[] = "hf:Llm:q:r:s:x::vW;";
42 44
43 static struct option long_opts[] = { 45 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 },
44 { "from", required_argument, 0, 'f' }, 48 { "from", required_argument, 0, 'f' },
45 { "help", no_argument, 0, 'h' }, 49 { "help", no_argument, 0, 'h' },
46 { "license", no_argument, 0, 'L' }, 50 { "license", no_argument, 0, 'L' },
47 { "maildir", required_argument, 0, 'm' }, 51 { "maildir", required_argument, 0, 'm' },
48 { "multiple-delivery", no_argument, 0, 'M' },
49 { "quota-db", required_argument, 0, 'q' }, 52 { "quota-db", required_argument, 0, 'q' },
50 { "source", required_argument, 0, 's' }, 53 { "source", required_argument, 0, 's' },
51 { "timeout", required_argument, 0, 't' }, 54 { "timeout", required_argument, 0, 't' },
...@@ -62,8 +65,8 @@ main (int argc, char *argv[]) ...@@ -62,8 +65,8 @@ main (int argc, char *argv[])
62 FILE *fp; 65 FILE *fp;
63 char *from = NULL; 66 char *from = NULL;
64 char *progfile_pattern = NULL; 67 char *progfile_pattern = NULL;
65 struct mda_data mda_data; 68 char *tempfile = NULL;
66 69
67 /* Preparative work: close inherited fds, force a reasonable umask 70 /* Preparative work: close inherited fds, force a reasonable umask
68 and prepare a logging. */ 71 and prepare a logging. */
69 close_fds (); 72 close_fds ();
...@@ -76,6 +79,8 @@ main (int argc, char *argv[]) ...@@ -76,6 +79,8 @@ main (int argc, char *argv[])
76 while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF) 79 while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF)
77 switch (c) 80 switch (c)
78 { 81 {
82 case 0: /* option already handled */
83 break;
79 case 'r': 84 case 'r':
80 case 'f': 85 case 'f':
81 if (from != NULL) 86 if (from != NULL)
...@@ -98,10 +103,6 @@ main (int argc, char *argv[]) ...@@ -98,10 +103,6 @@ main (int argc, char *argv[])
98 maildir = optarg; 103 maildir = optarg;
99 break; 104 break;
100 105
101 case 'M':
102 multiple_delivery++;
103 break;
104
105 #ifdef USE_DBM 106 #ifdef USE_DBM
106 case 'q': 107 case 'q':
107 quotadbname = optarg; 108 quotadbname = optarg;
...@@ -120,9 +121,21 @@ main (int argc, char *argv[]) ...@@ -120,9 +121,21 @@ main (int argc, char *argv[])
120 121
121 case 'x': 122 case 'x':
122 if (optarg) 123 if (optarg)
123 debug_level = strtoul (optarg, NULL, 0); 124 {
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 }
124 else 132 else
125 debug_level = 9; 133 {
134 debug_level = 9;
135 #ifdef WITH_GUILE
136 debug_guile = 1;
137 #endif
138 }
126 break; 139 break;
127 140
128 case 'v': 141 case 'v':
...@@ -146,18 +159,6 @@ main (int argc, char *argv[]) ...@@ -146,18 +159,6 @@ main (int argc, char *argv[])
146 return 1; 159 return 1;
147 } 160 }
148 161
149 if (!from)
150 {
151 struct passwd *pw = getpwuid (uid);
152 if (pw)
153 from = pw->pw_name;
154 else
155 {
156 mu_error ("From unknown");
157 return 1;
158 }
159 }
160
161 #ifdef HAVE_MYSQL 162 #ifdef HAVE_MYSQL
162 mu_register_getpwnam (getMpwnam); 163 mu_register_getpwnam (getMpwnam);
163 #endif 164 #endif
...@@ -172,22 +173,26 @@ main (int argc, char *argv[]) ...@@ -172,22 +173,26 @@ main (int argc, char *argv[])
172 list_append (bookie, smtp_record); 173 list_append (bookie, smtp_record);
173 } 174 }
174 175
175 memset (&mda_data, 0, sizeof mda_data); 176 fp = make_tmp (from, &tempfile);
176 fp = make_tmp (from, &mda_data.tempfile);
177 177
178 if (multiple_delivery) 178 if (multiple_delivery)
179 multiple_delivery = argc > 1; 179 multiple_delivery = argc > 1;
180 180
181 #ifdef WITH_GUILE 181 #ifdef WITH_GUILE
182 mda_data.fp = fp;
183 mda_data.argv = argv;
184 mda_data.progfile_pattern = progfile_pattern;
185
186 if (progfile_pattern) 182 if (progfile_pattern)
187 return prog_mda (&mda_data); 183 {
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 }
188 #endif 193 #endif
189 194
190 unlink (mda_data.tempfile); 195 unlink (tempfile);
191 for (; *argv; argv++) 196 for (; *argv; argv++)
192 mda (fp, *argv, NULL); 197 mda (fp, *argv, NULL);
193 return exit_code; 198 return exit_code;
...@@ -280,7 +285,7 @@ mda (FILE *fp, char *username, mailbox_t mbox) ...@@ -280,7 +285,7 @@ mda (FILE *fp, char *username, mailbox_t mbox)
280 if (attribute_is_deleted (attr)) 285 if (attribute_is_deleted (attr))
281 return EX_OK; 286 return EX_OK;
282 } 287 }
283 288
284 deliver (fp, username); 289 deliver (fp, username);
285 290
286 if (multiple_delivery) 291 if (multiple_delivery)
...@@ -332,31 +337,53 @@ make_tmp (const char *from, char **tempfile) ...@@ -332,31 +337,53 @@ make_tmp (const char *from, char **tempfile)
332 FILE *fp; 337 FILE *fp;
333 char *buf = NULL; 338 char *buf = NULL;
334 size_t n = 0; 339 size_t n = 0;
340 int line;
335 341
336 if (fd == -1 || (fp = fdopen(fd, "w+")) == NULL) 342 if (fd == -1 || (fp = fdopen (fd, "w+")) == NULL)
337 { 343 {
338 mailer_err("unable to open temporary file"); 344 mailer_err ("unable to open temporary file");
339 exit (exit_code); 345 exit (exit_code);
340 } 346 }
341
342 time (&t);
343 fprintf (fp, "From %s %s", from, ctime (&t));
344 347
345 while (getline(&buf, &n, stdin) > 0) { 348 line = 0;
346 if (!memcmp(buf, "From ", 5)) 349 while (getline (&buf, &n, stdin) > 0) {
347 fputc('>', fp); 350 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);
348 if (fputs (buf, fp) == EOF) 375 if (fputs (buf, fp) == EOF)
349 { 376 {
350 mailer_err ("temporary file write error"); 377 mailer_err ("temporary file write error");
351 fclose(fp); 378 fclose (fp);
352 return NULL; 379 return NULL;
353 } 380 }
354 } 381 }
355 382
356 if (buf && strchr(buf, '\n') == NULL) 383 if (buf && strchr (buf, '\n') == NULL)
357 putc('\n', fp); 384 putc ('\n', fp);
358 385
359 putc('\n', fp); 386 putc ('\n', fp);
360 free (buf); 387 free (buf);
361 388
362 return fp; 389 return fp;
...@@ -459,7 +486,7 @@ deliver (FILE *fp, char *name) ...@@ -459,7 +486,7 @@ deliver (FILE *fp, char *name)
459 { 486 {
460 case MQUOTA_EXCEEDED: 487 case MQUOTA_EXCEEDED:
461 mailer_err ("%s: mailbox quota exceeded for this recipient", name); 488 mailer_err ("%s: mailbox quota exceeded for this recipient", name);
462 exit_code = EX_UNAVAILABLE; 489 exit_code = EX_QUOTA();
463 failed++; 490 failed++;
464 break; 491 break;
465 case MQUOTA_UNLIMITED: 492 case MQUOTA_UNLIMITED:
...@@ -475,7 +502,7 @@ deliver (FILE *fp, char *name) ...@@ -475,7 +502,7 @@ deliver (FILE *fp, char *name)
475 { 502 {
476 mailer_err ("%s: message would exceed maximum mailbox size for this recipient", 503 mailer_err ("%s: message would exceed maximum mailbox size for this recipient",
477 name); 504 name);
478 exit_code = EX_UNAVAILABLE; 505 exit_code = EX_QUOTA();
479 failed++; 506 failed++;
480 } 507 }
481 break; 508 break;
...@@ -503,15 +530,51 @@ deliver (FILE *fp, char *name) ...@@ -503,15 +530,51 @@ deliver (FILE *fp, char *name)
503 free (buf); 530 free (buf);
504 switch_user_id (0); 531 switch_user_id (0);
505 } 532 }
506 533
534 if (!failed)
535 notify_biff (mbox, name, size);
536
507 locker_unlock (lock); 537 locker_unlock (lock);
508 /* FIXME: Flush the data */ 538
509 mailbox_close (mbox); 539 mailbox_close (mbox);
510 mailbox_destroy (&mbox); 540 mailbox_destroy (&mbox);
511 #if 0 /*FIXME*/ 541 }
512 if (!failed) 542
513 notify_biff (name, size); 543 void
514 #endif 544 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 }
515 } 578 }
516 579
517 void 580 void
...@@ -531,9 +594,6 @@ int temp_errors[] = { ...@@ -531,9 +594,6 @@ int temp_errors[] = {
531 #ifdef EAGAIN 594 #ifdef EAGAIN
532 EAGAIN, /* Try again */ 595 EAGAIN, /* Try again */
533 #endif 596 #endif
534 #ifdef EDQUOT
535 EDQUOT, /* Disk quota esceeded */
536 #endif
537 #ifdef EBUSY 597 #ifdef EBUSY
538 EBUSY, /* Device or resource busy */ 598 EBUSY, /* Device or resource busy */
539 #endif 599 #endif
...@@ -613,6 +673,14 @@ guess_retval (int ec) ...@@ -613,6 +673,14 @@ guess_retval (int ec)
613 /* Temporary failures override hard errors. */ 673 /* Temporary failures override hard errors. */
614 if (exit_code == EX_TEMPFAIL) 674 if (exit_code == EX_TEMPFAIL)
615 return; 675 return;
676 #ifdef EDQUOT
677 if (ec == EDQUOT)
678 {
679 exit_code = EX_QUOTA();
680 return;
681 }
682 #endif
683
616 for (i = 0; i < sizeof (temp_errors)/sizeof (temp_errors[0]); i++) 684 for (i = 0; i < sizeof (temp_errors)/sizeof (temp_errors[0]); i++)
617 if (temp_errors[i] == ec) 685 if (temp_errors[i] == ec)
618 { 686 {
...@@ -632,8 +700,6 @@ static char help_message[] = ...@@ -632,8 +700,6 @@ static char help_message[] =
632 " -h, --help Display this help and exit\n" 700 " -h, --help Display this help and exit\n"
633 " -L, --license Display GNU General Public License\n" 701 " -L, --license Display GNU General Public License\n"
634 " -m, --maildir PATH Specify path to mailspool directory\n" 702 " -m, --maildir PATH Specify path to mailspool directory\n"
635 " -M, --multiple-delivery Don't return errors when delivering to multiple\n"
636 " recipients\n"
637 #ifdef USE_DBM 703 #ifdef USE_DBM
638 " -q, --quota-db FILE Specify path to quota database.\n" 704 " -q, --quota-db FILE Specify path to quota database.\n"
639 #endif 705 #endif
...@@ -641,8 +707,15 @@ static char help_message[] = ...@@ -641,8 +707,15 @@ static char help_message[] =
641 " -s, --source PATTERN Set name pattern for user-defined mail filters.\n" 707 " -s, --source PATTERN Set name pattern for user-defined mail filters.\n"
642 #endif 708 #endif
643 " -t, --timeout NUMBER Set timeout for acquiring the lockfile\n" 709 " -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
644 " -x, --debug NUMBER Set debugging level\n" 713 " -x, --debug NUMBER Set debugging level\n"
645 " -v, --version Display program version and exit.\n" 714 " -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"
646 "\nReport bugs to bug-mailutils@gnu.org\n"; 719 "\nReport bugs to bug-mailutils@gnu.org\n";
647 720
648 printf ("%s", help_message); 721 printf ("%s", help_message);
......