summaryrefslogtreecommitdiff
path: root/qmail.c
blob: a8ddef89dd67e2420e0df1d7a99a6f0a1b4c9ca1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "substdio.h"
#include "readwrite.h"
#include "wait.h"
#include "exit.h"
#include "fork.h"
#include "fd.h"
#include "qmail.h"
#include "auto_qmail.h"
#include "env.h"

static char *binqqargs[2] = { 0, 0 } ;

static void setup_qqargs()
{
  if(!binqqargs[0])
    binqqargs[0] = env_get("QMAILQUEUE");
  if(!binqqargs[0])
    binqqargs[0] = "bin/qmail-queue";
}

int qmail_open(qq)
struct qmail *qq;
{
  int pim[2];
  int pie[2];

  setup_qqargs();

  if (pipe(pim) == -1) return -1;
  if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }

  switch(qq->pid = vfork()) {
    case -1:
      close(pim[0]); close(pim[1]);
      close(pie[0]); close(pie[1]);
      return -1;
    case 0:
      close(pim[1]);
      close(pie[1]);
      if (fd_move(0,pim[0]) == -1) _exit(120);
      if (fd_move(1,pie[0]) == -1) _exit(120);
      if (chdir(auto_qmail) == -1) _exit(61);
      execv(*binqqargs,binqqargs);
      _exit(120);
  }

  qq->fdm = pim[1]; close(pim[0]);
  qq->fde = pie[1]; close(pie[0]);
  substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf));
  qq->flagerr = 0;
  return 0;
}

unsigned long qmail_qp(qq) struct qmail *qq;
{
  return qq->pid;
}

void qmail_fail(qq) struct qmail *qq;
{
  qq->flagerr = 1;
}

void qmail_put(qq,s,len) struct qmail *qq; char *s; int len;
{
  if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1;
}

void qmail_puts(qq,s) struct qmail *qq; char *s;
{
  if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1;
}

void qmail_from(qq,s) struct qmail *qq; char *s;
{
  if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
  close(qq->fdm);
  substdio_fdbuf(&qq->ss,write,qq->fde,qq->buf,sizeof(qq->buf));
  qmail_put(qq,"F",1);
  qmail_puts(qq,s);
  qmail_put(qq,"",1);
}

void qmail_to(qq,s) struct qmail *qq; char *s;
{
  qmail_put(qq,"T",1);
  qmail_puts(qq,s);
  qmail_put(qq,"",1);
}

char *qmail_close(qq)
struct qmail *qq;
{
  int wstat;
  int exitcode;

  qmail_put(qq,"",1);
  if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
  close(qq->fde);

  if (wait_pid(&wstat,qq->pid) != qq->pid)
    return "Zqq waitpid surprise (#4.3.0)";
  if (wait_crashed(wstat))
    return "Zqq crashed (#4.3.0)";
  exitcode = wait_exitcode(wstat);

  switch(exitcode) {
    case 115: /* compatibility ... fall through */
    case 11: return "Denvelope address too long for qq (#5.1.3)";
    case 21: return "Dmessage rejected by spam filter (#4.2.2)";
    case 31: return "Dmail server permanently rejected message (#5.3.0)";
    case 51: return "Zqq out of memory (#4.3.0)";
    case 52: return "Zqq timeout (#4.3.0)";
    case 53: return "Zqq write error or disk full (#4.3.0)";
    case 0: if (!qq->flagerr) return ""; /* else fall through */
    case 54: return "Zqq read error (#4.3.0)";
    case 55: return "Zqq unable to read configuration (#4.3.0)";
    case 56: return "Zqq trouble making network connection (#4.3.0)";
    case 61: return "Zqq trouble in home directory (#4.3.0)";
    case 63: /* fall through */
    case 64: /* fall through */
    case 65: /* fall through */
    case 66: /* fall through */
    case 62: return "Zqq trouble creating files in queue (#4.3.0)";
    case 70: return "Zgreylisting in progress; please try again in 00:15:00 (#4.3.0)";
    case 71: return "Zmail server temporarily rejected message (#4.3.0)";
    case 72: return "Zconnection to mail server timed out (#4.4.1)";
    case 73: return "Zconnection to mail server rejected (#4.4.1)";
    case 74: return "Zcommunication with mail server failed (#4.4.2)";
    case 91: /* fall through */
    case 81: return "Zqq internal bug (#4.3.0)";
    case 120: return "Zunable to exec qq (#4.3.0)";
    default:
      if ((exitcode >= 11) && (exitcode <= 40))
	return "Dqq permanent problem (#5.3.0)";
      return "Zqq temporary problem (#4.3.0)";
  }
}