diff options
Diffstat (limited to 'src/srsforward.c')
-rw-r--r-- | src/srsforward.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/srsforward.c b/src/srsforward.c new file mode 100644 index 0000000..c8aefc9 --- /dev/null +++ b/src/srsforward.c @@ -0,0 +1,169 @@ +#include <unistd.h> +#include <sys/types.h> +#include "control.h" +#include "sig.h" +#include "constmap.h" +#include "readwrite.h" +#include "exit.h" +#include "env.h" +#include "qmail.h" +#include "auto_qmail.h" +#include "buffer.h" +#include "str.h" +#include "fmt.h" +#include "stralloc.h" +#include "logmsg.h" +#include "srs2.h" + +#define WHO "srsforward" + +void die_nomem() { logmsg(WHO,111,FATAL,"out of memory"); } +void die_control() { logmsg(WHO,110,FATAL,"Unable to read control files"); } + +struct qmail qqt; +char *srsdomaininfo = 0; +stralloc srsdomains = {0}; +struct constmap mapsrsdomains; +stralloc srshost = {0}; +stralloc srserror = {0}; + +/** @file srsforward.c + @brief forwarding mails with SRS enhanced addresss + @return 0 on success (forwarded or not) + -3 SRS error with error output + 111 no memory / processing error + 110 control file not readable +*/ + +static int srserror_str(int code) { + if (!stralloc_copys(&srserror,"SRS: ")) die_nomem(); + if (!stralloc_cats(&srserror,srs_strerror(code))) die_nomem(); + if (!stralloc_0(&srserror)) die_nomem(); + return -3; +} + +ssize_t mywrite(int fd,char *buf,int len) +{ + qmail_put(&qqt,buf,len); + return len; +} + +char inbuf[BUFFER_INSIZE]; +char outbuf[1]; +buffer bi = BUFFER_INIT(read,0,inbuf,sizeof(inbuf)); +buffer bo = BUFFER_INIT(mywrite,-1,outbuf,sizeof(outbuf)); + +char num[FMT_ULONG]; + +int main(int argc,char **argv) +{ + int i, j, r; + char *qqx; + srs_t *srs; + stralloc cookie = {0}; + char separator = '='; + char srssender[512]; + char *host = 0; + char *sender = 0; + char *dtline = 0; + char *sendhost = 0; + int alwaysrewrite = 0; + + sig_pipeignore(); + + sender = env_get("NEWSENDER"); + if (!sender) + logmsg(WHO,100,FATAL,"NEWSENDER not set"); + host = env_get("HOST"); + if (!host) + logmsg(WHO,100,FATAL,"HOST not set"); + dtline = env_get("DTLINE"); + if (!dtline) + logmsg(WHO,100,FATAL,"DTLINE not set"); + + if (chdir(auto_qmail) == -1) + logmsg(WHO,111,FATAL,B("unable to chdir to: ",auto_qmail)); + + if (!stralloc_cats(&srshost,"!")) die_nomem(); + if (!stralloc_cats(&srshost,host)) die_nomem(); + + switch (control_readfile(&srsdomains,"control/srsdomains",0)) { + case -1: die_control(); + case 0: if (!constmap_init(&mapsrsdomains,"",0,1)) die_nomem(); break; + case 1: if (!constmap_init(&mapsrsdomains,srsdomains.s,srsdomains.len,1)) die_nomem(); break; + } + if (constmap(&mapsrsdomains,srshost.s,srshost.len)) return 0; // domain blacklisted + if ((srsdomaininfo = constmap(&mapsrsdomains,host,str_len(host))) == 0) { + if ((srsdomaininfo = constmap(&mapsrsdomains,"*",1)) == 0) return 0; // '*' means always SRS + else alwaysrewrite = 1; + } + + if (*srsdomaininfo) { + i = str_chr(srsdomaininfo,'|'); // multiple cookies; separated by ' ' + if (srsdomaininfo[i] == '|') { + srsdomaininfo[i] = 0; + j = str_chr(srsdomaininfo + i + 1,'|'); + if (srsdomaininfo[i + j + 1] == '|') { + srsdomaininfo[i + j + 1] = 0; + sendhost = srsdomaininfo + i + j + 2; // separator: - + = + } + separator = srsdomaininfo[i + 1]; + } + if (!stralloc_copys(&cookie,srsdomaininfo)) die_nomem(); + if (!stralloc_0(&cookie)) die_nomem(); + if (!stralloc_copys(&srshost,"")) die_nomem(); + if (*sendhost) { + j = str_len(sendhost); + if (sendhost[j - 1] == '.') { + if (!stralloc_copys(&srshost,sendhost)) die_nomem(); + if (!stralloc_cats(&srshost,host)) die_nomem(); + } else + if (!stralloc_copys(&srshost,sendhost)) die_nomem(); + } else + if (!stralloc_copys(&srshost,host)) die_nomem(); + if (!stralloc_0(&srshost)) die_nomem(); + } else + die_control(); + + /* Let's go SRS rewrite */ + + srs = srs_new(); + + if (separator == '-' || separator == '+' || separator == '=') { // '=' is default + r = srs_set_separator(srs,separator); + if (r != SRS_SUCCESS) return srserror_str(r); + } + if (alwaysrewrite) { + r = srs_set_alwaysrewrite(srs,alwaysrewrite); + if (r != SRS_SUCCESS) return srserror_str(r); + } + + for (j = 0, i = 0; j < cookie.len; j++) { + if (cookie.s[j] == ' ' || cookie.s[j] == '\0' ) { + cookie.s[j] = '\0'; + r = srs_add_secret(srs,cookie.s + i); + if (r != SRS_SUCCESS) return srserror_str(r); + i = j + 1; + if (cookie.s[i] == ' ') { j++; continue; } + } + } + + if ((r = srs_forward(srs,srssender,sizeof(srssender),sender,srshost.s)) != SRS_SUCCESS) + logmsg(WHO,100,FATAL,B("Unable to forward: ",sender," ",srs_strerror(r))); + + if (qmail_open(&qqt) == -1) + logmsg(WHO,111,FATAL,"unable to fork: "); + qmail_puts(&qqt,dtline); + if (buffer_copy(&bo,&bi) != 0) + logmsg(WHO,111,FATAL,"unable to read message: "); + buffer_flush(&bo); + + num[fmt_ulong(num,qmail_qp(&qqt))] = 0; + + qmail_from(&qqt,srssender); + while (*++argv) qmail_to(&qqt,*argv); + qqx = qmail_close(&qqt); + if (*qqx) logmsg(WHO,*qqx == 'D' ? 100 : 111,FATAL,qqx + 1); + logmsg(WHO,0,LOG,B(srssender,": qp ",num)); + +} |