diff options
Diffstat (limited to 'src/qmail-qmqpc.c')
-rw-r--r-- | src/qmail-qmqpc.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/qmail-qmqpc.c b/src/qmail-qmqpc.c new file mode 100644 index 0000000..c92e072 --- /dev/null +++ b/src/qmail-qmqpc.c @@ -0,0 +1,178 @@ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "buffer.h" +#include "getln.h" +#include "exit.h" +#include "stralloc.h" +#include "readclose.h" +#include "timeoutconn.h" +#include "logmsg.h" +#include "str.h" +#include "sig.h" +#include "ip.h" +#include "timeout.h" +#include "auto_qmail.h" +#include "control.h" +#include "fmt.h" +#include "uint_t.h" +#include "socket_if.h" + +#define PORT_QMQP 628 + +void die_success() { _exit(0); } +void die_perm() { _exit(31); } +void nomem() { _exit(51); } +void die_read() { if (errno == ENOMEM) nomem(); _exit(54); } +void die_control() { _exit(55); } +void die_socket() { _exit(56); } +void die_home() { _exit(61); } +void die_temp() { _exit(71); } +void die_conn() { _exit(74); } +void die_format() { _exit(91); } + +int lasterror = 55; +int qmqpfd; + +ssize_t saferead(int fd,char *buf,int len) +{ + int r; + r = timeoutread(60,qmqpfd,buf,len); + if (r <= 0) die_conn(); + return r; +} + +ssize_t safewrite(int fd,char *buf,int len) +{ + int r; + r = timeoutwrite(60,qmqpfd,buf,len); + if (r <= 0) die_conn(); + return r; +} + +char buf[1024]; +buffer bo = BUFFER_INIT(safewrite,-1,buf,sizeof(buf)); +buffer bi = BUFFER_INIT(saferead,-1,buf,sizeof(buf)); +buffer be = BUFFER_INIT(read,1,buf,sizeof(buf)); // envelope +/* WARNING: can use only one of these at a time! */ + +stralloc beforemessage = {0}; +stralloc message = {0}; +stralloc aftermessage = {0}; + +char strnum[FMT_ULONG]; +stralloc line = {0}; + +void getmess() +{ + int match; + + if (readclose_append(0,&message,1024) == -1) die_read(); + + strnum[fmt_ulong(strnum,(unsigned long) message.len)] = 0; + if (!stralloc_copys(&beforemessage,strnum)) nomem(); + if (!stralloc_cats(&beforemessage,":")) nomem(); + if (!stralloc_copys(&aftermessage,",")) nomem(); + + if (getln(&be,&line,&match,'\0') == -1) die_read(); + if (!match) die_format(); + if (line.len < 2) die_format(); + if (line.s[0] != 'F') die_format(); + + strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; + if (!stralloc_cats(&aftermessage,strnum)) nomem(); + if (!stralloc_cats(&aftermessage,":")) nomem(); + if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); + if (!stralloc_cats(&aftermessage,",")) nomem(); + + for (;;) { + if (getln(&be,&line,&match,'\0') == -1) die_read(); + if (!match) die_format(); + if (line.len < 2) break; + if (line.s[0] != 'T') die_format(); + + strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; + if (!stralloc_cats(&aftermessage,strnum)) nomem(); + if (!stralloc_cats(&aftermessage,":")) nomem(); + if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); + if (!stralloc_cats(&aftermessage,",")) nomem(); + } +} + +void doit(char *server) +{ + struct ip4_address ip4s; + struct ip6_address ip6s; + char *netif = 0; + uint32 ifidx = 0; + char ch; + int i, j, r; + + i = str_chr(server,':'); + if (server[i] == ':') { + j = str_chr(server,'%'); /* IF index */ + if (server[j] == '%') { + server[j] = 0; + netif = &server[j + 1]; + ifidx = socket_getifidx(netif); + } + if (!ip6_scan(server,(char *)&ip6s.d)) return; + qmqpfd = socket(AF_INET6,SOCK_STREAM,0); + if (qmqpfd == -1) die_socket(); + r = timeoutconn6(qmqpfd,(char *)&ip6s.d,PORT_QMQP,10,ifidx); + } else { + if (!ip4_scan(server,(char *)&ip4s.d)) return; + qmqpfd = socket(AF_INET,SOCK_STREAM,0); + if (qmqpfd == -1) die_socket(); + r = timeoutconn4(qmqpfd,(char *)&ip4s.d,PORT_QMQP,10); + } + if (r != 0) { + lasterror = 73; + if (errno == ETIMEDOUT) lasterror = 72; + close(qmqpfd); + return; + } + + strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0; + buffer_puts(&bo,strnum); + buffer_puts(&bo,":"); + buffer_put(&bo,beforemessage.s,beforemessage.len); + buffer_put(&bo,message.s,message.len); + buffer_put(&bo,aftermessage.s,aftermessage.len); + buffer_puts(&bo,","); + buffer_flush(&bo); + + for (;;) { + buffer_get(&bi,&ch,1); + if (ch == 'K') die_success(); + if (ch == 'Z') die_temp(); + if (ch == 'D') die_perm(); + } +} + +stralloc servers = {0}; + +int main() +{ + int i; + int j; + + sig_pipeignore(); + + if (chdir(auto_qmail) == -1) die_home(); + if (control_init() == -1) die_control(); + if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control(); + + getmess(); + + i = 0; + for (j = 0; j < servers.len; ++j) + if (!servers.s[j]) { + doit(servers.s + i); + i = j + 1; + } + + _exit(lasterror); +} |