39#define WHO "qmail-local"
41static void usage() { logmsg(
WHO,100,USAGE,
"qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
43static void temp_nomem() { logmsg(
WHO,111,FATAL,
"Out of memory. (#4.3.0)"); }
44static void temp_rewind() { logmsg(
WHO,111,FATAL,
"Unable to rewind message. (#4.3.0)"); }
45static void temp_childcrashed() { logmsg(
WHO,111,FATAL,
"Aack, child crashed. (#4.3.0)"); }
46static void temp_fork() { logmsg(
WHO,111,FATAL,B(
"Unable to fork: ",error_str(errno),
". (#4.3.0)")); }
47static void temp_read() { logmsg(
WHO,111,ERROR,B(
"Unable to read message: ",error_str(errno),
". (#4.3.0)")); }
48static void temp_slowlock()
49{ logmsg(
WHO,111,ERROR,
"File has been locked for 30 seconds straight. (#4.3.0)"); }
50static void temp_qmail(
fn)
char *
fn;
51{ logmsg(
WHO,111,FATAL,B(
"Unable to open: ",
fn,
" ",error_str(errno),
". (#4.3.0)")); }
87static void maildir_child(
char *dir)
100 if (chdir(dir) == -1) {
if (errno != ENOENT)
_exit(1);
_exit(2); }
106 for (loop = 0; loop < str_len(
host); ++loop) {
107 if (
host[loop] ==
'/') {
111 if (
host[loop] ==
':') {
118 for (loop = 0 ;; ++loop) {
119 gettimeofday(&time,0);
121 s += fmt_str(s,
"tmp/");
122 s += fmt_ulong(s,time.tv_sec); *s++ =
'.';
123 *s++ =
'M'; s += fmt_ulong(s,time.tv_usec);
124 *s++ =
'P'; s += fmt_ulong(s,pid); *s++ =
'.';
127 if (stat(
fntmptph,&st) == -1)
if (errno == ENOENT)
break;
129 if (loop == 2)
_exit(1);
142 switch (buffer_copy(&
bo,&
bi)) {
147 if (buffer_flush(&
bo) == -1)
goto FAIL;
148 if (fstat(
fd,&st) == -1)
goto FAIL;
149 if (fsync(
fd) == -1)
goto FAIL;
150 if (close(
fd) == -1)
goto FAIL;
153 s += fmt_str(s,
"new/");
154 s += fmt_ulong(s,time.tv_sec); *s++ =
'.';
157 *s++ =
'I'; s += fmt_xlong(s,st.st_ino);
158 *s++ =
'V'; s += fmt_xlong(s,st.st_dev);
161 *s++ =
'M'; s += fmt_ulong(s,time.tv_usec);
162 *s++ =
'P'; s += fmt_ulong(s,pid); *s++ =
'.';
167 if ((
fd = open(
fnnewtph,O_RDONLY)) < 0 || fsync(
fd) < 0 || close(
fd))
goto FAIL;
176static void maildir(
char *
fn)
181 if (seek_begin(0) == -1) temp_rewind();
183 switch (child = fork()) {
191 wait_pid(&wstat,child);
192 if (wait_crashed(wstat))
195 switch (wait_exitcode(wstat)) {
197 case 2: logmsg(
WHO,111,ERROR,
"Unable to chdir to maildir. (#4.2.1)");
198 case 3: logmsg(
WHO,111,ERROR,
"Timeout on maildir delivery. (#4.3.0)");
199 case 4: logmsg(
WHO,111,ERROR,
"Unable to read message. (#4.3.0)");
200 default: logmsg(
WHO,111,ERROR,
"Temporary error on maildir delivery. (#4.3.0)");
204static void mailfile(
char *
fn)
213 if (seek_begin(0) == -1) temp_rewind();
215 fd = open_append(
fn);
217 logmsg(
WHO,111,ERROR,B(
"Unable to open:",
fn,
" ",error_str(errno),
". (#4.2.1)"));
219 sig_alarmcatch(temp_slowlock);
221 flaglocked = (lock_ex(
fd) != -1);
236 logmsg(
WHO,0,WARN,B(
"Unable to read message: ",error_str(errno),
". (#4.3.0)"));
237 if (flaglocked) seek_trunc(
fd,pos);
243 if (buffer_puts(&
bo,
">"))
goto WRITERRS;
246 if (buffer_puts(&
bo,
"\n"))
goto WRITERRS;
251 if (buffer_puts(&
bo,
"\n"))
goto WRITERRS;
252 if (buffer_flush(&
bo))
goto WRITERRS;
253 if (fsync(
fd) == -1)
goto WRITERRS;
258 logmsg(
WHO,0,WARN,B(
"Unable to write ",
fn,
": ",error_str(errno),
". (#4.3.0)"));
259 if (flaglocked) seek_trunc(
fd,pos);
264static void mailprogram(
char *prog)
270 if (seek_begin(0) == -1) temp_rewind();
272 switch (child = fork()) {
282 logmsg(
WHO,0,ERROR,B(
"Unable to run /bin/sh: ",error_str(errno),
". (#4.3.0)"));
285 wait_pid(&wstat,child);
286 if (wait_crashed(wstat))
289 switch (wait_exitcode(wstat)) {
291 case 64:
case 65:
case 70:
case 76:
case 77:
case 78:
case 112:
_exit(100);
293 case 99:
flag99 = 1;
break;
300static void mailforward(
char **recips)
307 if (seek_begin(0) == -1) temp_rewind();
323 logmsg(
WHO,*qqx ==
'D' ? 100 : 111,ERROR,B(
"Unable to forward message: ",qqx + 1,
"."));
326static void bouncexf()
331 if (seek_begin(0) == -1) temp_rewind();
341 logmsg(
WHO,100,ERROR,
"This message is looping: it already has my Delivered-To line. (#5.4.6)");
345static void checkhome()
349 if (stat(
".",&st) == -1)
350 logmsg(
WHO,111,ERROR,B(
"Unable to stat home directory: ",error_str(errno),
". (#4.3.0)"));
352 logmsg(
WHO,111,ERROR,
"Uh-oh: home directory is writable. (#4.7.0)");
353 if (st.st_mode & 01000)
355 logmsg(
WHO,111,ERROR,
"Home directory is sticky: user is editing his .qmail file. (#4.2.1)");
357 logmsg(
WHO,0,WARN,
"Warning: home directory is sticky.");
360static int qmeox(
char *dashowner)
370 if (stat(
qme.s,&st) == -1) {
371 if (errno != ENOENT) temp_qmail(
qme.s);
377static int qmeexists(
int *
fd,
int *cutable)
383 *
fd = open_read(
qme.s);
385 if (errno != ENOENT) temp_qmail(
qme.s);
386 if (errno == EPERM) temp_qmail(
qme.s);
387 if (errno == EACCES) temp_qmail(
qme.s);
391 if (fstat(*
fd,&st) == -1) temp_qmail(
qme.s);
392 if ((st.st_mode & S_IFMT) == S_IFREG) {
394 logmsg(
WHO,111,ERROR,
"Uh-oh: .qmail file is writable. (#4.7.0)");
395 *cutable = !!(st.st_mode & 0100);
410static void qmesearch(
int *
fd,
int *cutable)
417 if (qmeexists(
fd,cutable)) {
420 if (!byte_diff(
"default",7,
safeext.s + i))
421 if (i <= str_len(
ext))
427 for (i =
safeext.len; i >= 0 ;--i)
428 if (!i || (
safeext.s[i - 1] ==
'-')) {
433 if (qmeexists(
fd,cutable)) {
434 if (i <= str_len(
ext))
450static void count_print()
452 buffer_puts(&
bl,
"did ");
454 buffer_puts(&
bl,
"+");
456 buffer_puts(&
bl,
"+");
458 buffer_puts(&
bl,
"\n");
461 buffer_puts(&
bl,
"qp ");
463 buffer_puts(&
bl,
"\n");
468static void sayit(
char *type,
char *cmd,
int len)
470 buffer_puts(&
bl,type);
471 buffer_put(&
bl,cmd,len);
472 buffer_putsflush(&
bl,
"\n");
475int main(
int argc,
char *
const *argv)
492 while ((opt = getoptb(argc,(
char **)argv,
"nN")) != opteof)
513 logmsg(
WHO,111,ERROR,B(
"Unable to switch to: ",
homedir,
" ",error_str(errno),
". (#4.3.0)"));
521#ifdef HIDEVIRTUALUSER
522 if (str_len(
ext) > 1) {
538 for (i = 0; i <
dtline.len; ++i)
563 int len;
int i;
char ch;
568 for (i = 0;i < len;++i) {
570 if ((ch ==
' ') || (ch ==
'\t') || (ch ==
'\n')) ch =
'-';
587 x += str_chr(x,
'-');
if (*x) ++x;
589 x += str_chr(x,
'-');
if (*x) ++x;
591 x += str_chr(x,
'-');
if (*x) ++x;
597 for (i = 0; i <
safeext.len; ++i)
602 i = byte_rchr(
host,i,
'.');
606 i = byte_rchr(
host,i,
'.');
610 i = byte_rchr(
host,i,
'.');
616 qmesearch(&
fd,&flagforwardonly);
620 logmsg(
WHO,100,ERROR,
"Sorry, no mailbox here by that name. (#5.1.1)");
624 if (str_diff(
sender,
"#@[]"))
625 if (qmeox(
"-owner") == 0) {
626 if (qmeox(
"-owner-default") == 0) {
657 if (
cmds.s[
j] ==
'\n') {
659 case '#':
case '.':
case '/':
case '|':
break;
660 default: ++numforward;
665 recips = (
char **) alloc((numforward + 1) *
sizeof(
char *));
673 if (
cmds.s[
j] ==
'\n') {
677 while ((
k > i) && ((
cmds.s[
k - 1] ==
' ') || (
cmds.s[
k - 1] ==
'\t')))
682 logmsg(
WHO,111,ERROR,
"Uh-oh: first line of .qmail file is blank. (#4.2.1)");
688 if (flagforwardonly) logmsg(
WHO,111,ERROR,
"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)");
689 if (
cmds.s[
k - 1] ==
'/')
691 else sayit(
"maildir ",
cmds.s + i,
k - i);
694 else sayit(
"mbox ",
cmds.s + i,
k - i);
698 if (flagforwardonly) logmsg(
WHO,111,ERROR,
"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)");
700 else sayit(
"program ",
cmds.s + i + 1,
k - i - 1);
703 if (str_equal(
cmds.s + i + 1,
"list"))
711 else sayit(
"forward ",
cmds.s + i,
k - i);
719 recips[numforward] = 0;
int stralloc_copys(stralloc *, char const *)
int gfrom(char *s, int len)
char * myctime(datetime_sec)
unsigned long count_forward
unsigned long mailforward_qp
char fntmptph[80+FMT_ULONG *2]
char fnnewtph[80+FMT_ULONG *2]
unsigned long count_program
char outbuf[BUFSIZE_LINE]
char count_buf[FMT_ULONG]
void qmail_to(struct qmail *, char *)
void qmail_from(struct qmail *, char *)
void qmail_put(struct qmail *, char *, int)
char * qmail_close(struct qmail *)
unsigned long qmail_qp(struct qmail *)
int qmail_open(struct qmail *)
void qmail_fail(struct qmail *)
int quote2(stralloc *, char *)