void copymsg(int fd,char format) /* Copy archive message "msg" itself from open file handle fd, in "format" */ { int match; int flaginheader; int flagskipblanks; int flaggoodfield; switch(format) { case VIRGIN: case NATIVE: substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s)); if (match) { qmail_put(&qq,line.s,line.len); msgsize += line.len; } else break; } break; case MIME: case MIXED: flaginheader = 1; flaggoodfield = 0; substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s)); if (match) { if (flaginheader) { if (line.len == 1) { flaginheader = 0; flaggoodfield = 1; } else if (line.s[0] != ' ' && line.s[0] != '\t') { flaggoodfield = 0; if (constmap(&digheadersmap,line.s, byte_chr(line.s,line.len,':'))) flaggoodfield = 1; } if (flaggoodfield) { qmail_put(&qq,line.s,line.len); /* header */ msgsize += line.len; } } else { qmail_put(&qq,line.s,line.len); /* body */ msgsize += line.len; } } else break; } break; case RFC1153: /* Not worth optimizing. Rarely used */ flaginheader = 1; flagskipblanks = 1; /* must skip terminal blanks acc to rfc1153 */ archtype = ' '; /* rfc1153 requires ordered headers */ if (!stralloc_copys(&archblanklines,"")) die_nomem(); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s)); if (match) { if (flaginheader) { if (line.len == 1) { flaginheader = 0; if (archdate.len) { qmail_put(&qq,archdate.s,archdate.len); archdate.len = 0; msgsize += archdate.len; } if (archto.len) { qmail_put(&qq,archto.s,archto.len); msgsize += archto.len; archto.len = 0; } if (archfrom.len) { qmail_put(&qq,archfrom.s,archfrom.len); msgsize += archfrom.len; archfrom.len = 0; } if (archcc.len) { qmail_put(&qq,archcc.s,archcc.len); msgsize += archcc.len; archcc.len = 0; } if (archsubject.len) { qmail_put(&qq,archsubject.s,archsubject.len); msgsize += archsubject.len; archsubject.len = 0; } if (archmessageid.len) { qmail_put(&qq,archmessageid.s,archmessageid.len); msgsize += archmessageid.len; archmessageid.len = 0; } if (archkeywords.len) { qmail_put(&qq,archkeywords.s,archkeywords.len); msgsize += archkeywords.len; archkeywords.len = 0; } qmail_puts(&qq,"\n"); } else if (line.s[0] == ' ' || line.s[0] == '\t') { switch (archtype) { /* continuation lines */ case ' ': break; case 'D': if (!stralloc_cat(&archdate,&line)) die_nomem(); break; case 'F': if (!stralloc_cat(&archfrom,&line)) die_nomem(); break; case 'T': if (!stralloc_cat(&archto,&line)) die_nomem(); break; case 'C': if (!stralloc_cat(&archcc,&line)) die_nomem(); break; case 'S': if (!stralloc_cat(&archsubject,&line)) die_nomem(); break; case 'M': if (!stralloc_cat(&archmessageid,&line)) die_nomem(); break; case 'K': if (!stralloc_cat(&archkeywords,&line)) die_nomem(); break; default: strerr_die2x(111,FATAL, "Program error: Bad archive header type"); } } else { archtype = ' '; if (case_startb(line.s,line.len,"cc:")) { archtype='C'; if (!stralloc_copy(&archcc,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"date:")) { archtype='D'; if (!stralloc_copy(&archdate,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"from:")) { archtype='F'; if (!stralloc_copy(&archfrom,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"keywords:")) { archtype='K'; if (!stralloc_copy(&archkeywords,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"message-id:")) { archtype='M'; if (!stralloc_copy(&archmessageid,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"subject:")) { archtype='S'; if (!stralloc_copy(&archsubject,&line)) die_nomem(); } else if (case_startb(line.s,line.len,"to:")) { archtype='T'; if (!stralloc_copy(&archto,&line)) die_nomem(); } } } else if (line.len == 1) { if (!flagskipblanks) if (!stralloc_copys(&archblanklines,"\n")) die_nomem(); } else { if (archblanklines.len) { qmail_put(&qq,archblanklines.s,archblanklines.len); archblanklines.len = 0; } flagskipblanks = 0; qmail_put(&qq,line.s,line.len); msgsize += line.len; } } else break; } break; default: strerr_die2x(100,FATAL,"Program error: bad format in copymsg()"); } }
char * filter_mail(char *mail, int *done) { char *domain, *alias; unsigned int at; int round; #ifdef DASH_EXT unsigned int i; #endif if (mail == (char *)0) { ext = 0; return 0; } at = str_rchr(mail, '@'); if (at == 0 || mail[at] != '@') { ext = 0; return 0; } domain = mail + at + 1; if (adok) { alias = constmap(&ad_map, domain, str_len(domain)); if (alias && *alias) domain = alias; } if (ext == 0) { ext = at; extcnt = -1; *done = 0; } else { if (extcnt == 0) { *done = 1; ext = 0; return 0; } #ifdef DASH_EXT /* * limit ext to the first DASH_EXT_LEVELS extensions. * We will only check for (DASH_EXT_LEVELS = 4): * [email protected] * [email protected] * [email protected] * [email protected] * [email protected] * [email protected] */ if (ext == at) for (i = 0, ext = 0, extcnt = 1; ext < at && extcnt <= DASH_EXT_LEVELS; ext++) if (mail[ext] == *auto_break) extcnt++; while (ext != 0 && --ext > 0) { if (mail[ext] == *auto_break) break; } extcnt--; #else #error XXX XXX /* basic qmail-ldap behavior test for [email protected] and [email protected] */ ext = 0; extcnt = 0; #endif } for (round = 0; round < 2; round++) { switch (round) { case 0: /* build the search string for the email address */ /* mail address */ if (!filter_start(&filter) || !stralloc_cats(&filter, "(|(") || !stralloc_cats(&filter, LDAP_MAIL) || !stralloc_cats(&filter, "=")) return 0; break; case 1: /* mailalternate address */ if (!stralloc_cats(&filter, ")(") || !stralloc_cats(&filter, LDAP_MAILALTERNATE) || !stralloc_cats(&filter, "=")) return 0; break; } /* username till current '-' or '@' */ if (!filter_escape(&filter, mail, ext)) return 0; /* do not append catchall in the first round */ if (ext != at) { /* catchall or default */ if (extcnt > 0) /* add '-' */ if (!stralloc_cats(&filter, auto_break)) return 0; if (!stralloc_cats(&filter, LDAP_CATCH_ALL)) return 0; } /* @domain.com */ if (!stralloc_append(&filter, "@") || !filter_escape(&filter, domain, str_len(domain))) return 0; } if (!stralloc_cats(&filter, "))") || !filter_end(&filter)) return 0; if (extcnt == 0) *done = 1; if (mail[0] == *auto_break) *done = 1; // OSC: do not do DASH_EXT loop if first char is auto_break return filter.s; }
int main(int argc,char **argv) { unsigned long maxmsgsize = 0L; unsigned long minmsgsize = 0L; unsigned long msgsize = 0L; char linetype = ' '; char *cp, *cpstart, *cpafter; const char *dir; const char *err; const char *sender; unsigned int len; int match; getconfopt(argc,argv,options,-1,&dir); if (dir) { startup(dir); flagparsemime = 1; /* only if dir do we have mimeremove/reject */ if (getconf_line(&line,"msgsize",0)) { if (!stralloc_0(&line)) die_nomem(); len = scan_ulong(line.s,&maxmsgsize); if (line.s[len] == ':') scan_ulong(line.s+len+1,&minmsgsize); } if (flagforward) { if (!stralloc_copys(&mydtline,"Delivered-To: command forwarder for ")) die_nomem(); if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); if (!stralloc_cats(&mydtline,"@")) die_nomem(); if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); if (!stralloc_cats(&mydtline,"\n")) die_nomem(); } } else { flagtook = 1; /* if no "dir" we can't get outlocal/outhost */ flagforward = 0; /* nor forward requests */ } sender = get_sender(); if (!sender) die_sender(); if (!*sender) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (flagparsemime) { /* set up MIME parsing */ if (getconf(&mimeremove,"mimekeep",0)) mimeremoveflag = 1; else getconf(&mimeremove,"mimeremove",0); constmap_init(&mimeremovemap,mimeremove.s,mimeremove.len,0); getconf(&mimereject,"mimereject",0); constmap_init(&mimerejectmap,mimereject.s,mimereject.len,0); } if (flagheaderreject && dir) { getconf(&headerreject,"headerreject",0); constmap_init(&headerrejectmap,headerreject.s,headerreject.len,0); } for (;;) { if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; if (flagheaderreject && dir) if (constmap(&headerrejectmap,line.s,byte_chr(line.s,line.len,':'))) strerr_die2x(100,FATAL,MSG(ERR_MAILING_LIST)); if (line.len == 1) break; cp = line.s; len = line.len; if ((*cp == ' ' || *cp == '\t')) { switch(linetype) { case 'T': if (!stralloc_catb(&to,cp,len-1)) die_nomem(); break; case 'S': if (!stralloc_catb(&subject,cp,len-1)) die_nomem(); break; case 'C': if (!stralloc_catb(&content,cp,len-1)) die_nomem(); break; case 'P': if (!stralloc_catb(&precd,cp,len-1)) die_nomem(); break; default: break; } } else { if (!flagtook && (case_startb(cp,len,"to:") || case_startb(cp,len,"cc:"))) { linetype = 'T'; /* cat so that To/Cc don't overwrite */ if (!stralloc_catb(&to,line.s + 3,line.len - 4)) die_nomem(); } else if ((flagneedsubject || flagrejectcommands) && case_startb(cp,len,"subject:")) { if (!stralloc_copyb(&subject,cp+8,len-9)) die_nomem(); linetype = 'S'; } else if (case_startb(cp,len,"content-type:")) { if (!stralloc_copyb(&content,cp+13,len-14)) die_nomem(); linetype = 'C'; } else if (case_startb(cp,len,"precedence:")) { if (!stralloc_copyb(&precd,cp+11,len-12)) die_nomem(); linetype = 'P'; } else { if (flagforward && line.len == mydtline.len) { if (!byte_diff(line.s,line.len,mydtline.s)) strerr_die2x(100,FATAL,MSG(ERR_LOOPING)); } linetype = ' '; } } } if (precd.len >= 4 && (!case_diffb(precd.s + precd.len - 4,4,"junk") || !case_diffb(precd.s + precd.len - 4,4,"bulk"))) strerr_die1x(99,MSG(ERR_JUNK)); /* ignore precedence junk/bulk */ cp = subject.s; len = subject.len; while (len && (cp[len-1] == ' ' || cp[len-1] == '\t')) --len; while (len && ((*cp == ' ') || (*cp == '\t'))) { ++cp; --len; } flaghavesubject = 1; if (flagbody) if ((len > 9 && case_starts(cp,"subscribe")) || (len > 11 && case_starts(cp,"unsubscribe"))) flaghavecommand = 1; switch(len) { case 0: flaghavesubject = 0; break; case 4: if (!case_diffb("help",4,cp)) flaghavecommand = 1; break; case 6: /* Why can't they just leave an empty subject empty? */ if (!case_diffb("(null)",6,cp)) flaghavesubject = 0; else if (!case_diffb("(none)",6,cp)) flaghavesubject = 0; else if (!case_diffb("remove",6,cp)) flaghavecommand = 1; break; case 9: if (!case_diffb("subscribe",9,cp)) flaghavecommand = 1; break; case 11: if (!case_diffb("unsubscribe",11,cp)) flaghavecommand = 1; break; case 12: if (!case_diffb("(no subject)",12,cp)) flaghavesubject = 0; break; default: break; } if (!flagtook && !getto(&to)) strerr_die2x(exitquiet,FATAL,MSG(ERR_NO_ADDRESS)); if (flagneedsubject && !flaghavesubject) strerr_die2x(100,FATAL,MSG(ERR_NO_SUBJECT)); if (flagrejectcommands && flaghavecommand) { if (flagforward) { /* flagforward => forward */ if (qmail_open(&qq) == -1) /* open queue */ strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); qmail_put(&qq,mydtline.s,mydtline.len); if (seek_begin(0) == -1) strerr_die2sys(111,FATAL,MSG(ERR_SEEK_INPUT)); if (qmail_copy(&qq,&ssin2,copylines) != 0) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!stralloc_copy(&to,&outlocal)) die_nomem(); if (!stralloc_cats(&to,"-request@")) die_nomem(); if (!stralloc_cat(&to,&outhost)) die_nomem(); if (!stralloc_0(&to)) die_nomem(); qmail_from(&qq,sender); qmail_to(&qq,to.s); if (*(err = qmail_close(&qq)) == '\0') { strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(99,"ezmlm-request: info: forward qp ",strnum); } else strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); } else strerr_die2x(100,FATAL,MSG(ERR_SUBCOMMAND)); } if (content.len) { /* MIME header */ cp = content.s; len = content.len; while (len && (*cp == ' ' || *cp == '\t')) { ++cp; --len; } cpstart = cp; if (*cp == '"') { /* might be commented */ ++cp; cpstart = cp; while (len && *cp != '"') { ++cp; --len; } } else { while (len && *cp != ' ' && *cp != '\t' && *cp != ';') { ++cp; --len; } } if (flagparsemime) if ((!!constmap(&mimeremovemap,cpstart,cp-cpstart) ^ mimeremoveflag) || constmap(&mimerejectmap,cpstart,cp-cpstart)) { *(cp) = (char) 0; strerr_die2x(100,FATAL,MSG1(ERR_BAD_TYPE,cpstart)); } cpafter = content.s+content.len; while((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) { ++cp; while (cp < cpafter && (*cp == ' ' || *cp == '\t')) ++cp; if (case_startb(cp,cpafter - cp,"boundary=")) { cp += 9; /* after boundary= */ if (cp < cpafter && *cp == '"') { ++cp; cpstart = cp; while (cp < cpafter && *cp != '"') ++cp; if (cp == cpafter) strerr_die1x(100,MSG(ERR_MIME_QUOTE)); } else { cpstart = cp; while (cp < cpafter && *cp != ';' && *cp != ' ' && *cp != '\t') ++cp; } if (!stralloc_copys(&boundary,"--")) die_nomem(); if (!stralloc_catb(&boundary,cpstart,cp-cpstart)) die_nomem(); break; } } /* got boundary, now parse for parts */ } for (;;) { if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; if (line.len == 1) { flagcheck = 0; continue; /* Doesn't do continuation lines. _very_ unusual, and worst */ /* case one slips through that shouldn't have */ } else if (flagcheck && case_startb(line.s,line.len,"content-type:")) { cp = line.s + 13; len = line.len - 14; /* zap '\n' */ while (*cp == ' ' || *cp == '\t') { ++cp; --len; } cpstart = cp; if (*cp == '"') { /* quoted */ ++cp; cpstart = cp; while (len && *cp != '"') { ++cp; --len; } } else { /* not quoted */ while (len && *cp != ' ' && *cp != '\t' && *cp != ';') { ++cp; --len; } } if (flagparsemime && constmap(&mimerejectmap,cpstart,cp-cpstart)) { *cp = '\0'; strerr_die2x(100,FATAL,MSG1(ERR_BAD_PART,cpstart)); } } else if (boundary.len && *line.s == '-' && line.len > boundary.len && !str_diffn(line.s,boundary.s,boundary.len)) { flagcheck = 1; } else { if (!msgsize && flagbody) if (case_startb(line.s,line.len,"subscribe") || case_startb(line.s,line.len,"unsubscribe")) strerr_die2x(100,FATAL,MSG(ERR_BODYCOMMAND)); if (!flagcheck) { msgsize += line.len; if (maxmsgsize && msgsize > maxmsgsize) { strnum[fmt_ulong(strnum,maxmsgsize)] = 0; strerr_die2x(100,FATAL,MSG1(ERR_MAX_SIZE,strnum)); } } } } if (msgsize < minmsgsize) { strnum[fmt_ulong(strnum,minmsgsize)] = 0; strerr_die2x(100,FATAL,MSG1(ERR_MIN_SIZE,strnum)); } _exit(0); }