debian/rules: Use `git' potty wrapper.
[qmail] / qmail-qmqpc.c
CommitLineData
212b6f5d
MW
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
23void die_success() { _exit(0); }
24void die_perm() { _exit(31); }
25void nomem() { _exit(51); }
26void die_read() { if (errno == error_nomem) nomem(); _exit(54); }
27void die_control() { _exit(55); }
28void die_socket() { _exit(56); }
29void die_home() { _exit(61); }
30void die_temp() { _exit(71); }
31void die_conn() { _exit(74); }
32void die_format() { _exit(91); }
33
34int lasterror = 55;
35int qmqpfd;
36
37int 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}
44int 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
52char buf[1024];
53substdio to = SUBSTDIO_FDBUF(safewrite,-1,buf,sizeof buf);
54substdio from = SUBSTDIO_FDBUF(saferead,-1,buf,sizeof buf);
55substdio envelope = SUBSTDIO_FDBUF(read,1,buf,sizeof buf);
56/* WARNING: can use only one of these at a time! */
57
58stralloc beforemessage = {0};
59stralloc message = {0};
60stralloc aftermessage = {0};
61
62char strnum[FMT_ULONG];
63stralloc line = {0};
64
65void 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
101void doit(server)
102char *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
136stralloc servers = {0};
137
6d2736c0
MW
138main(argc,argv)
139int argc;
140char **argv;
212b6f5d
MW
141{
142 int i;
143 int j;
144
145 sig_pipeignore();
146
6d2736c0
MW
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();
212b6f5d 151
6d2736c0 152 getmess();
212b6f5d 153
6d2736c0
MW
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 }
212b6f5d
MW
168
169 _exit(lasterror);
170}