summaryrefslogtreecommitdiff
path: root/src/qmail.c
blob: 7bdfd29804350e6be1d11cdf6b196cb96d0f5571 (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
139
#include <unistd.h>
#include "readwrite.h"
#include "buffer.h"
#include "wait.h"
#include "exit.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(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]);
  buffer_init(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf));
  qq->flagerr = 0;
  return 0;
}

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

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

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

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

void qmail_from(struct qmail *qq,char *s)
{
  if (buffer_flush(&qq->ss) == -1) qq->flagerr = 1;
  close(qq->fdm);
  buffer_init(&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(struct qmail *qq,char *s)
{
  qmail_put(qq,"T",1);
  qmail_puts(qq,s);
  qmail_put(qq,"",1);
}

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

  qmail_put(qq,"",1);
  if (!qq->flagerr) 
    if (buffer_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 0: if (!qq->flagerr) return ""; /* fall through */
    case 11: return "Denvelope address too long for qq (#5.1.3)";
    case 31: return "Dmail server permanently rejected message (#5.3.0)";
    case 32: return "Vmail server does not accept message (#5.3.0)";
    case 33: return "Smail server does not accept message (#5.3.0)";
    case 34: return "Amail server does not accept message (#5.3.0)";
    case 35: return "Imail server fails to verify DKIM signed 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 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 62: return "Zqq trouble creating files in queue (#4.3.0)";
    case 63: /* qmail-queue: fstat/unlinking problem */
    case 64: /* qmail-queue: linking pidfn -> messfn */
    case 65: /* qmail-queue: exclusive open failed */
    case 66: /* qmail-queue: linking intdfn -> todofn */
    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 115: /* compatibility */
    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)";
  }
}