chiark / gitweb /
Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / qmail-qmqpc.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <arpa/inet.h>
5 #include "substdio.h"
6 #include "getln.h"
7 #include "readwrite.h"
8 #include "exit.h"
9 #include "stralloc.h"
10 #include "slurpclose.h"
11 #include "error.h"
12 #include "sig.h"
13 #include "ip.h"
14 #include "timeoutconn.h"
15 #include "timeoutread.h"
16 #include "timeoutwrite.h"
17 #include "auto_qmail.h"
18 #include "control.h"
19 #include "fmt.h"
20
21 #define PORT_QMQP 628
22
23 void die_success() { _exit(0); }
24 void die_perm() { _exit(31); }
25 void nomem() { _exit(51); }
26 void die_read() { if (errno == error_nomem) nomem(); _exit(54); }
27 void die_control() { _exit(55); }
28 void die_socket() { _exit(56); }
29 void die_home() { _exit(61); }
30 void die_temp() { _exit(71); }
31 void die_conn() { _exit(74); }
32 void die_format() { _exit(91); }
33
34 int lasterror = 55;
35 int qmqpfd;
36
37 int saferead(fd,buf,len) int fd; char *buf; int len;
38 {
39   int r;
40   r = timeoutread(60,qmqpfd,buf,len);
41   if (r <= 0) die_conn();
42   return r;
43 }
44 int safewrite(fd,buf,len) int fd; char *buf; int len;
45 {
46   int r;
47   r = timeoutwrite(60,qmqpfd,buf,len);
48   if (r <= 0) die_conn();
49   return r;
50 }
51
52 char buf[1024];
53 substdio to = SUBSTDIO_FDBUF(safewrite,-1,buf,sizeof buf);
54 substdio from = SUBSTDIO_FDBUF(saferead,-1,buf,sizeof buf);
55 substdio envelope = SUBSTDIO_FDBUF(read,1,buf,sizeof buf);
56 /* WARNING: can use only one of these at a time! */
57
58 stralloc beforemessage = {0};
59 stralloc message = {0};
60 stralloc aftermessage = {0};
61
62 char strnum[FMT_ULONG];
63 stralloc line = {0};
64
65 void getmess()
66 {
67   int match;
68
69   if (slurpclose(0,&message,1024) == -1) die_read();
70
71   strnum[fmt_ulong(strnum,(unsigned long) message.len)] = 0;
72   if (!stralloc_copys(&beforemessage,strnum)) nomem();
73   if (!stralloc_cats(&beforemessage,":")) nomem();
74   if (!stralloc_copys(&aftermessage,",")) nomem();
75
76   if (getln(&envelope,&line,&match,'\0') == -1) die_read();
77   if (!match) die_format();
78   if (line.len < 2) die_format();
79   if (line.s[0] != 'F') die_format();
80
81   strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0;
82   if (!stralloc_cats(&aftermessage,strnum)) nomem();
83   if (!stralloc_cats(&aftermessage,":")) nomem();
84   if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem();
85   if (!stralloc_cats(&aftermessage,",")) nomem();
86
87   for (;;) {
88     if (getln(&envelope,&line,&match,'\0') == -1) die_read();
89     if (!match) die_format();
90     if (line.len < 2) break;
91     if (line.s[0] != 'T') die_format();
92
93     strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0;
94     if (!stralloc_cats(&aftermessage,strnum)) nomem();
95     if (!stralloc_cats(&aftermessage,":")) nomem();
96     if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem();
97     if (!stralloc_cats(&aftermessage,",")) nomem();
98   }
99 }
100
101 void doit(server)
102 char *server;
103 {
104   struct ip_address ip;
105   char ch;
106
107   if (!ip_scan(server,&ip)) return;
108
109   qmqpfd = socket(AF_INET,SOCK_STREAM,0);
110   if (qmqpfd == -1) die_socket();
111
112   if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) {
113     lasterror = 73;
114     if (errno == error_timeout) lasterror = 72;
115     close(qmqpfd);
116     return;
117   }
118
119   strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0;
120   substdio_puts(&to,strnum);
121   substdio_puts(&to,":");
122   substdio_put(&to,beforemessage.s,beforemessage.len);
123   substdio_put(&to,message.s,message.len);
124   substdio_put(&to,aftermessage.s,aftermessage.len);
125   substdio_puts(&to,",");
126   substdio_flush(&to);
127
128   for (;;) {
129     substdio_get(&from,&ch,1);
130     if (ch == 'K') die_success();
131     if (ch == 'Z') die_temp();
132     if (ch == 'D') die_perm();
133   }
134 }
135
136 stralloc servers = {0};
137
138 main(argc,argv)
139 int argc;
140 char **argv;
141 {
142   int i;
143   int j;
144
145   sig_pipeignore();
146
147   if (!argv[1]) {               /* std behavior */
148     if (chdir(auto_qmail) == -1) die_home();
149     if (control_init() == -1) die_control();
150     if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control();
151
152     getmess();
153
154     i = 0;
155     for (j = 0;j < servers.len;++j)
156       if (!servers.s[j]) {
157         doit(servers.s + i);
158         i = j + 1;
159       }
160   } else {                      /* servers on cmd line */
161
162     getmess();
163
164     i = 1;
165     while (argv[i])
166       doit(argv[i++]);
167   }
168
169   _exit(lasterror);
170 }