int getoff(const char *action)
{
  int r;

  r = subscribe(workdir,target.s,0,"",(*action == ACTION_WC[0]) ? "-mod" : "-",-1);
  if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
    strerr_die2x(0,INFO,MSG1(ERR_EXTRA_UNSUB,target.s));
  switch (r) {
			/* no comment for unsubscribe */
    case 1:
	    hdr_subject(MSG(SUB_GOODBYE));
            qmail_puts(&qq,"\n");
            hdr_ctboundary();
            copy(&qq,"text/top",flagcd);
            copy_act("text/unsub-ok");
            break;
    default:
	    hdr_subject(MSG(SUB_UNSUBSCRIBE_NOP));
            hdr_ctboundary();
            copy(&qq,"text/top",flagcd);
            copy_act("text/unsub-nop");
            break;
  }
  return r;
}
int geton(const char *action)
{
  const char *fl;
  int r;
  unsigned int i;
  unsigned char ch;

  fl = get_from(target.s,action);		/* try to match up */
  r = subscribe(workdir,target.s,1,fl,(*action == ACTION_RC[0]) ? "+mod" : "+",-1);
  if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
    strerr_die2x(0,INFO,MSG1(ERR_EXTRA_SUB,target.s));
  switch (r) {
    case 1:
	    qmail_puts(&qq,"List-Unsubscribe: <mailto:");	/*rfc2369 */
	    qmail_put(&qq,outlocal.s,outlocal.len);
	    qmail_puts(&qq,"-unsubscribe-");
		/* url-encode since verptarget is controlled by sender */
		/* note &verptarget ends in '\0', hence len - 1! */
	    for (i = 0; i < verptarget.len - 1; i++) {
	      ch = verptarget.s[i];
	      if (str_chr("\"?;<>&/:%+#",ch) < 10 ||
			 (ch <= ' ') || (ch & 0x80)) {
		urlstr[1] = hex[ch / 16];
	        urlstr[2] = hex[ch & 0xf];
		qmail_put(&qq,urlstr,3);
	      } else {
		qmail_put(&qq,verptarget.s + i, 1);
	      }
	    }
	    qmail_puts(&qq,"@");
	    qmail_put(&qq,outhost.s,outhost.len);	/* safe */
	    qmail_puts(&qq,">\n");
	    hdr_subject(MSG(SUB_WELCOME));
            hdr_ctboundary();
	    stralloc_copy(&confirm,&outlocal);
	    stralloc_cats(&confirm,"-unsubscribe-");
	    stralloc_cats(&confirm,verptarget.s);
	    stralloc_append(&confirm,'@');
	    stralloc_cat(&confirm,&outhost);
	    stralloc_0(&confirm);
	    set_cpconfirm(confirm.s,outlocal.len);	/* for !R in copy */
            copy(&qq,"text/top",flagcd);
            copy_act("text/sub-ok");
            break;
    default:
            if (str_start(action,ACTION_TC))
              strerr_die2x(0,INFO,MSG(ERR_SUB_NOP));
	    hdr_subject(MSG(SUB_SUBSCRIBE_NOP));
            hdr_ctboundary();
            copy(&qq,"text/top",flagcd);
            copy_act("text/sub-nop");
            break;
  }
  return r;
}
static void do_list(int act)
{
  unsigned int i;
  if (!flaglist || (modsub.s == 0 && remote.s == 0))
    strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE));
  if (!ismod)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED));
  hdr_subject(MSG(SUB_LIST));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);

  if (act == AC_LIST) {
    showsend("list");
    (void) code_qputs("");
    (void) code_qputs(MSG(TXT_LISTMEMBERS));
    (void) code_qputs("\n");
    i = putsubs(workdir,0L,52L,code_subto);
  } else {			/* listn */
    showsend("listn");
    i = putsubs(workdir,0L,52L,dummy_to);
  }
  (void) code_qput("\n  ======> ",11);
  (void) code_qput(strnum,fmt_ulong(strnum,i));
  (void) code_qput("\n",1);
  copybottom(0);
  qmail_to(&qq,mod.s);
}
static void do_help(void)
{
  hdr_subject(MSG(SUB_HELP));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/help");
  copybottom(1);
  qmail_to(&qq,sender);
}
static void do_faq(void)
{
  hdr_subject(MSG(SUB_FAQ));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/faq");
  copybottom(0);
  qmail_to(&qq,target.s);
}
static void do_info(void)
{
  hdr_subject(MSG(SUB_INFO));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/info");
  copybottom(0);
  qmail_to(&qq,target.s);
}
static void do_get(const char *action)
{
  unsigned long u;
  struct stat st;
  char ch;
  int r;
  unsigned int pos;
  int fd;

  if (!flagget)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE));
  hdr_subject(MSG(SUB_GET_MSG));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);

  pos = str_len(ACTION_GET);
  if (!case_starts(action,ACTION_GET))
    pos = str_len(ALT_GET);

  if (action[pos] == '.' || action [pos] == '_') pos++;
  scan_ulong(action + pos,&u);

  stralloc_copys(&line,"archive/");
  stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100));
  stralloc_cats(&line,"/");
  stralloc_catb(&line,strnum,fmt_uint0(strnum,(unsigned int) (u % 100),2));
  stralloc_0(&line);

  fd = open_read(line.s);
  if (fd == -1)
    if (errno != error_noent)
      strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,line.s));
    else
      copy_act("text/get-bad");
  else {
    if (fstat(fd,&st) == -1)
      copy_act("text/get-bad");
    else if (!(st.st_mode & 0100))
      copy_act("text/get-bad");
    else {
      showsend("get");
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      qmail_puts(&qq,"> ");
      for (;;) {
	r = substdio_get(&sstext,&ch,1);
	if (r == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
	if (r == 0) break;
	qmail_put(&qq,&ch,1);
	if (ch == '\n') qmail_puts(&qq,"> ");
      }
      qmail_puts(&qq,"\n");
    }
    close(fd);
  }
  copybottom(0);
  qmail_to(&qq,target.s);
}
static void do_mod_help(void)
{
  hdr_subject(MSG(SUB_MOD_HELP));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/mod-help");
  copy(&qq,"text/help",flagcd);
  copybottom(0);
  qmail_to(&qq,mod.s);
}
static void do_query(void)
{
  hdr_subject(MSG(SUB_STATUS));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  if (issub(workdir,target.s,0))
    copy_act("text/sub-nop");
  else
    copy_act("text/unsub-nop");
  copybottom(0);
  qmail_to(&qq,ismod ? mod.s : target.s);
}
static void do_log(char *action,unsigned int actlen)
{
  action += actlen;
  if (*action == '.' || *action == '_') ++action;
  if (!flaglist || remote.s == 0)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE));
  if (!ismod)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED));
  showsend("log");
  hdr_subject((*action == 0) ? MSG(SUB_LOG) : MSG(SUB_LOG_SEARCH));
  hdr_ctboundary();
  searchlog(workdir,action,code_subto);
  copybottom(0);
  qmail_to(&qq,mod.s);
}
void doconfirm(const char *act)
/* This should only be called with valid act for sub/unsub confirms. If act */
/* is not ACTION_[RST]C, it is assumed to be an unsubscribe conf.*/
/* "act" is the first letter of desired confirm request only as STRING! */
{
  strnum[fmt_ulong(strnum,when)] = 0;
  cookie(hash,key.s,key.len-flagdig,strnum,target.s,act);
  stralloc_copy(&confirm,&outlocal);
  stralloc_append(&confirm,'-');
  stralloc_catb(&confirm,act,1);
  stralloc_cats(&confirm,"c.");
  stralloc_cats(&confirm,strnum);
  stralloc_append(&confirm,'.');
  stralloc_catb(&confirm,hash,COOKIE);
  stralloc_append(&confirm,'-');
  stralloc_cats(&confirm,verptarget.s);
  stralloc_append(&confirm,'@');
  stralloc_cat(&confirm,&outhost);
  stralloc_0(&confirm);
  set_cpconfirm(confirm.s,outlocal.len);		/* for copy */
  set_cpaction(act);
  set_cphash(hash);
  set_cpwhen(when);

  qmail_puts(&qq,"Reply-To: ");
  quote2(&quoted,confirm.s);
  qmail_put(&qq,quoted.s,quoted.len);
  qmail_puts(&qq,"\n");

  hdr_subject((*act == ACTION_SC[0]) ? MSG(SUB_USR_SUBSCRIBE)
	      : (*act == ACTION_UC[0]) ? MSG(SUB_USR_UNSUBSCRIBE)
	      : (*act == ACTION_TC[0] || *act == ACTION_RC[0])
	      ? MSG(SUB_MOD_SUBSCRIBE)
	      : MSG(SUB_MOD_UNSUBSCRIBE));
  hdr_ctboundary();
    copy(&qq,"text/top",flagcd);
}
static void do_ed(char *action)
{
  datetime_sec u;
  int flaggoodfield;
  int fd;
  char *x, *y;
  char *cp,*cplast,*cpnext,*cpafter;
  int flagdone;
  unsigned int len;
  const char *fname;
  unsigned int i;

  x = action + LENGTH_ED;
  x += scan_ulong(x,&u);
  if ((u > when) || (u < when - 100000)) die_cookie();
  if (*x == '.') ++x;
  fname = x;
  x += str_chr(x,'.');
  if (!*x) die_cookie();
  *x = (char) 0;
  ++x;
  stralloc_copys(&fnedit,"text/");
  stralloc_cats(&fnedit,fname);
  stralloc_0(&fnedit);
  y = fnedit.s + 5;		/* after "text/" */
  while (*++y) {		/* Name should be guaranteed by the cookie, */
				/* but better safe than sorry ... */
    if (((*y > 'z') || (*y < 'a')) && (*y != '_'))
      strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME));
    if (*y == '_') *y = '-';
  }

  lock();			/* file must not change while here */

  switch (slurp(fnedit.s,&text,1024)) {
  case -1:
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s));
  case 0:
    strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST));
  }
  stralloc_copy(&line,&text);

  subst_nuls(&line);

  stralloc_cat(&line,&fnedit);	/* including '\0' */
  strnum[fmt_ulong(strnum,(unsigned long) u)] = 0;
  cookie(hash,key.s,key.len,strnum,line.s,"-e");
  if (str_len(x) != COOKIE) die_cookie();
  if (byte_diff(hash,COOKIE,x)) die_cookie();
	/* cookie is ok, file exists, lock's on, new file ends in '_' */
  stralloc_copys(&fneditn,fnedit.s);
  stralloc_append(&fneditn,'_');
  stralloc_0(&fneditn);
  fd = open_trunc(fneditn.s);
  if (fd == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s));
  substdio_fdbuf(&sstext,write,fd,textbuf,sizeof(textbuf));
  stralloc_copys(&quoted,"");	/* clear */
  stralloc_copys(&text,"");

  for (;;) {			/* get message body */
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    if (!match) break;
    stralloc_cat(&text,&line);
  }
  if (encin) {			/* decode if necessary */
    if (encin == 'B')
      decodeB(text.s,text.len,&line);
    else
      decodeQ(text.s,text.len,&line);
    stralloc_copy(&text,&line);
  }
  cp = text.s;
  cpafter = text.s+text.len;
  flaggoodfield = 0;
  flagdone = 0;
  len = 0;
  while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
    i = byte_chr(cp,cpnext-cp,'%');
    if (i != (unsigned int) (cpnext - cp)) {
      if (!flaggoodfield) {	/* MSG(TXT_EDIT_START)/END */
	if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_START))) {
		/* start tag. Store users 'quote characters', e.g. '> ' */
	  stralloc_copyb(&quoted,cp,i);
	  flaggoodfield = 1;
	  cp = cpnext + 1;
	  continue;
	}
      } else
	if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_END))) {
	  flagdone = 1;
	  break;
	}
    }
    if (flaggoodfield) {
      if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT)
	strerr_die1x(100,MSG(ERR_EDSIZE));

      if (quoted.len && cpnext-cp >= (int) quoted.len &&
	  !str_diffn(cp,quoted.s,quoted.len))
	cp += quoted.len;	/* skip quoting characters */
      cplast = cpnext - 1;
      if (*cplast == '\r')	/* CRLF -> '\n' for base64 encoding */
	*cplast = '\n';
      else
	++cplast;
      if (substdio_put(&sstext,cp,cplast-cp+1) == -1)
	strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s));
    }
    cp = cpnext + 1;
  }
  if (!flagdone)
    strerr_die2x(100,FATAL,MSG(ERR_NO_MARK));
  if (substdio_flush(&sstext) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s));
  if (fsync(fd) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,fneditn.s));
  if (fchmod(fd, 0600) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_CHMOD,fneditn.s));
  if (close(fd) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,fneditn.s));
  wrap_rename(fneditn.s,fnedit.s);

  unlock();
  hdr_subject(MSG1(SUB_EDIT_SUCCESS,fname));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/edit-done");
  copybottom(0);
  qmail_to(&qq,sender);		/* not necessarily from mod */
}
static void do_edit(const char *action)
{
  unsigned int i;
  unsigned int len;
  char ch;

  /* only remote admins and only if -e is specified may edit */
  if (!flagedit || remote.s == 0)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE));
  if (!ismod)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED));
  len = str_len(ACTION_EDIT);
  if (!case_starts(action,ACTION_EDIT))
    len = str_len(ALT_EDIT);
  if (action[len]) {			/* -edit.file, not just -edit */
    if (action[len] != '.')
      strerr_die2x(100,FATAL,MSG(ERR_BAD_REQUEST));
    showsend2("edit ",action+len+1);
    stralloc_copys(&fnedit,"text/");
    stralloc_cats(&fnedit,action+len+1);
    stralloc_0(&fnedit);
    case_lowerb(fnedit.s,fnedit.len);
    i = 5;	/* after the "text/" */
    while ((ch = fnedit.s[i++])) {
      if (((ch > 'z') || (ch < 'a')) && (ch != '_'))
	strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME));
      if (ch == '_') fnedit.s[i-1] = '-';
    }
    switch(slurp(fnedit.s,&text,1024)) {	/* entire file! */
    case -1:
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s));
    case 0:
      strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST));
    }
    stralloc_copy(&line,&text);

    subst_nuls(&line);

    stralloc_cat(&line,&fnedit);	/* including '\0' */
    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
    cookie(hash,key.s,key.len,strnum,line.s,"-e");
    stralloc_copy(&confirm,&outlocal);
    stralloc_append(&confirm,'-');
    stralloc_catb(&confirm,ACTION_ED,LENGTH_ED);
    stralloc_cats(&confirm,strnum);
    stralloc_append(&confirm,'.');
		/* action part has been checked for bad chars */
    stralloc_cats(&confirm,action + len + 1);
    stralloc_append(&confirm,'.');
    stralloc_catb(&confirm,hash,COOKIE);
    stralloc_append(&confirm,'@');
    stralloc_cat(&confirm,&outhost);
    stralloc_0(&confirm);
    set_cpconfirm(confirm.s,outlocal.len);
    set_cpaction(ACTION_ED);
    set_cphash(hash);
    set_cpwhen(when);

    qmail_puts(&qq,"Reply-To: ");
    quote2(&quoted,confirm.s);
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"\n");

    hdr_subject(MSG1(SUB_EDIT_REQUEST,action+len+1));
    hdr_ctboundary();
    copy(&qq,"text/top",flagcd);
    copy(&qq,"text/edit-do",flagcd);
    (void) code_qputs(MSG(TXT_EDIT_START));
    (void) code_qput(text.s,text.len);
    (void) code_qputs(MSG(TXT_EDIT_END));

  } else {	/* -edit only, so output list of editable files */
    hdr_subject(MSG(SUB_EDIT_LIST));
    hdr_ctboundary();
    copy(&qq,"text/top",flagcd);
    copy_act("text/edit-list");
  }
  qmail_puts(&qq,"\n\n");
  copybottom(0);
  qmail_to(&qq,mod.s);
}
Exemple #14
0
void main(int argc,char **argv)
{
  char *sender;
  char *def;
  char *local;
  char *action;
  int flaginheader;
  int flagcomment;
  int flaggoodfield;
  int flagdone;
  int fd, fdlock;
  int match;
  const char *err;
  char encin = '\0';
  unsigned int start,confnum;
  unsigned int pos,i;
  int child;
  int opt;
  char *cp,*cpnext,*cpfirst,*cplast,*cpafter;

  (void) umask(022);
  sig_pipeignore();
  when = now();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  opt = getconfopt(argc,argv,options,1,&dir);

  sender = get_sender();
  if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER));
  local = env_get("LOCAL");
  if (!local) strerr_die2x(100,FATAL,MSG(ERR_NOLOCAL));
  def = env_get("DEFAULT");
  if (!def) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT));

  if (!*sender)
    strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
  if (!sender[str_chr(sender,'@')])
    strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS));
  if (str_equal(sender,"#@[]"))
    strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));

  /* local should be >= def, but who knows ... */
  cp = local + str_len(local) - str_len(def) - 2;
  if (cp < local) die_badformat();
  action = local + byte_rchr(local,cp - local,'-');
  if (action == cp) die_badformat();
  action++;

  if (!action[0]) die_badformat();
  if (!str_start(action,ACTION_ACCEPT) && !str_start(action,ACTION_REJECT))
    die_badformat();
  start = str_chr(action,'-');
  if (!action[start]) die_badformat();
  confnum = 1 + start + str_chr(action + start + 1,'.');
  if (!action[confnum]) die_badformat();
  confnum += 1 + str_chr(action + confnum + 1,'.');
  if (!action[confnum]) die_badformat();
  if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem();
  if (!stralloc_0(&fnbase)) die_nomem();
  cookie(hash,key.s,key.len,fnbase.s,"","a");
  if (byte_diff(hash,COOKIE,action+confnum+1))
    die_badformat();

  fdlock = lockfile("mod/lock");

  switch(checkfile(fnbase.s)) {
    case 0:
      strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT));
    case -1:			/* only error if new request != action taken */
      if (str_start(action,ACTION_ACCEPT))
        strerr_die2x(0,INFO,MSG(ERR_MOD_ACCEPTED));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_ACCEPTED));
    case -2:
      if (str_start(action,ACTION_REJECT))
        strerr_die2x(0,INFO,MSG(ERR_MOD_REJECTED));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_REJECTED));
    default:
      break;
  }
/* Here, we have an existing filename in fnbase with the complete path */
/* from the current dir in fnmsg. */

  if (str_start(action,ACTION_REJECT)) {

    if (qmail_open(&qq, (stralloc *) 0) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));


				/* Build recipient from msg return-path */
    fd = open_read(fnmsg.s);
    if (fd == -1) {
      if (errno != error_noent)
        strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT));
    }
    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));

    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    maketo();			/* extract SENDER from return-path */
						/* Build message */
    hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST));
    if (listid.len > 0)
      hdr_add2("List-ID: ",listid.s,listid.len);
    hdr_datemsgid(when);
    hdr_from("-owner");
    if (replyto)
      hdr_add2s("Reply-To: ",replyto);
    hdr_add2s("To: ",to.s);
    hdr_subject(MSG(SUB_RETURNED_POST));

    if (flagmime) {
      hdr_mime(CTYPE_MULTIPART);
      hdr_boundary(0);
      hdr_ctype(CTYPE_TEXT);
      hdr_transferenc();
    }
    copy(&qq,"text/top",flagcd);
    copy(&qq,"text/mod-reject",flagcd);

    flagcomment = 0;
    flaginheader = 1;
    if (!stralloc_copys(&text,"")) die_nomem();
    if (!stralloc_ready(&text,1024)) die_nomem(); 
    for (;;) {		/* copy moderator's rejection comment */
      if (getln(subfdin,&line,&match,'\n') == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      if (!match) break;
      if (flaginheader) {
        if (case_startb(line.s,line.len,"Content-Transfer-Encoding:")) {
          pos = 26;
          while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
          if (case_startb(line.s+pos,line.len-pos,"base64"))
            encin = 'B';
          else if (case_startb(line.s+pos,line.len-pos,"quoted-printable"))
            encin = 'Q';
        }
        if (line.len == 1)
          flaginheader = 0;
      } else
        if (!stralloc_cat(&text,&line)) die_nomem();
    }	/* got body */
    if (encin) {
      if (encin == 'B')
        decodeB(text.s,text.len,&line);
      else
        decodeQ(text.s,text.len,&line);
      if (!stralloc_copy(&text,&line)) die_nomem();
    }
    cp = text.s;
    cpafter = text.s + text.len;
    if (!stralloc_copys(&line,"\n>>>>> -------------------- >>>>>\n"))
			die_nomem();
    flaggoodfield = 0;
    flagdone = 0;
    while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
      i = byte_chr(cp,cpnext-cp,'%');
      if (i <= 5 && cpnext-cp-i >= 3) {
				/* max 5 "quote characters" and space for %%% */
        if (cp[i+1] == '%' && cp[i+2] == '%') {
          if (!flaggoodfield) {					/* Start tag */
            if (!stralloc_copyb(&quoted,cp,i)) die_nomem();	/* quote chars*/
            flaggoodfield = 1;
            cp = cpnext + 1;
            cpfirst = cp;
            continue;
          } else {						/* end tag */
            if (flagdone)	/* 0 no comment lines, 1 comment line */
              flagdone = 2;	/* 2 at least 1 comment line & end tag */
            break;
          }
        }
      }
      if (flaggoodfield) {
        cplast = cpnext - 1;
        if (*cplast == '\r')	/* CRLF -> '\n' for base64 encoding */
          *cplast = '\n';
        else
          ++cplast;
			/* NUL is now ok, so the test for it was removed */
        flagdone = 1;
        i = cplast - cp + 1;
        if (quoted.len && quoted.len <= i &&
		!str_diffn(cp,quoted.s,quoted.len)) {	/* quote chars */
          if (!stralloc_catb(&line,cp+quoted.len,i-quoted.len)) die_nomem();
        } else
          if (!stralloc_catb(&line,cp,i)) die_nomem();	/* no quote chars */
      }
      cp = cpnext + 1;
    }
    if (flagdone == 2) {
    if (!stralloc_cats(&line,"<<<<< -------------------- <<<<<\n")) die_nomem();
      code_qput(line.s,line.len);
    }
    if (flagcd == 'B') {
      encodeB("",0,&line,2);
      qmail_put(&qq,line.s,line.len);
    }
    if (flagmime) {
      hdr_boundary(0);
      hdr_ctype(CTYPE_MESSAGE);
    }
    qmail_puts(&qq,"\n");
    if (seek_begin(fd) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s));

    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
    if (qmail_copy(&qq,&sstext,-1) != 0)
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnmsg.s));
    close(fd);

    if (flagmime)
      hdr_boundary(1);

    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-return-@")) die_nomem();
    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();
    qmail_from(&qq,line.s);
    if (to.len)
      qmail_to(&qq,to.s);

    if (!stralloc_copys(&fnnew,"mod/rejected/")) die_nomem();
    if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
    if (!stralloc_0(&fnnew)) die_nomem();

/* this is strictly to track what happended to a message to give informative */
/* messages to the 2nd-nth moderator that acts on the same message. Since    */
/* this isn't vital we ignore errors. Also, it is no big ideal if unlinking  */
/* the old file fails. In the worst case it gets acted on again. If we issue */
/*  a temp error the reject will be redone, which is slightly worse.         */

    if (*(err = qmail_close(&qq)) == '\0') {
        fd = open_trunc(fnnew.s);
        if (fd != -1)
          close(fd);
        unlink(fnmsg.s);
        strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
        strerr_die2x(0,"ezmlm-moderate: info: qp ",strnum);
    } else
        strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);

  } else if (str_start(action,ACTION_ACCEPT)) {
        fd = open_read(fnmsg.s);
        if (fd == -1) {
          if (errno !=error_noent)
            strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s));
          else	/* shouldn't happen since we've got lock */
            strerr_die3x(100,FATAL,fnmsg.s,MSG(ERR_MOD_TIMEOUT));
	}

    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
				/* read "Return-Path:" line */
    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    maketo();			/* extract SENDER to "to" */
    env_put2("SENDER",to.s);	/* set SENDER */
    if (seek_begin(fd) == -1)	/* rewind, since we read an entire buffer */
      strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s));

    if ((child = wrap_fork()) == 0) {
      close(0);
      dup(fd);	/* make fnmsg.s stdin */
      if (argc > opt + 1)
	wrap_execvp((const char **)argv + opt);
      else if (argc > opt)
        wrap_execsh(argv[opt]);
      else
        wrap_execbin("/ezmlm-send", &sendopt, dir);
    }
      /* parent */
      close(fd);
      wrap_exitcode(child);
      if (!stralloc_copys(&fnnew,"mod/accepted/")) die_nomem();

      if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
      if (!stralloc_0(&fnnew)) die_nomem();
/* ignore errors */
      fd = open_trunc(fnnew.s);
      if (fd != -1)
        close(fd);
      unlink(fnmsg.s);
      _exit(0);
   }
}
Exemple #15
0
void sendnotice(const char *d)
/* sends file pointed to by d to the address in the return-path of the  */
/* message. */
{
  unsigned int x,y;
  const char *err;

      if (qmail_open(&qq, (stralloc *) 0) == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));

      fd = open_read(d);
      if (fd == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,d));
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      if (getln(&sstext,&line,&match,'\n') == -1) die_read();
      if (!match) die_read();
      if (!case_startb(line.s,line.len,"return-path:")) die_read();
      x = 12 + byte_chr(line.s + 12,line.len-12,'<');
      y = byte_rchr(line.s + x,line.len-x,'>');
      if (x != line.len && x+y != line.len) {
        if (!stralloc_copyb(&to,line.s+x+1, y-1)) die_nomem();
        if (!stralloc_0(&to)) die_nomem();
      } else
        die_read();
      hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST));
      if (listid.len > 0)
	hdr_add2("List-ID: ",listid.s,listid.len);
      hdr_datemsgid(when+msgnum++);
      hdr_from("-help");
      hdr_subject(MSG(SUB_RETURNED_POST));
      hdr_add2s("To: ",to.s);
      if (flagmime) {
	hdr_mime(CTYPE_MULTIPART);
	hdr_boundary(0);
	hdr_ctype(CTYPE_TEXT);
        hdr_transferenc();
      } else
      qmail_puts(&qq,"\n\n");

      copy(&qq,"text/top",flagcd);
      copy(&qq,"text/mod-timeout",flagcd);
      if (flagcd == 'B') {
        encodeB("",0,&line,2);
        qmail_put(&qq,line.s,line.len);
      }

      if (flagmime) {
	hdr_boundary(0);
	hdr_ctype(CTYPE_MESSAGE);
        qmail_puts(&qq,"\n");
      }

      if (seek_begin(fd) == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,d));

      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      if (qmail_copy(&qq,&sstext,-1) != 0) die_read();
      close (fd);

      if (flagmime)
	hdr_boundary(1);

      if (!stralloc_copy(&line,&outlocal)) die_nomem();
      if (!stralloc_cats(&line,"-return-@")) die_nomem();
      if (!stralloc_cat(&line,&outhost)) die_nomem();
      if (!stralloc_0(&line)) die_nomem();
      qmail_from(&qq,line.s);		/* sender */
        qmail_to(&qq,to.s);

     if (*(err = qmail_close(&qq)) != '\0')
       strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ", err + 1);

     strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
     strerr_warn2("ezmlm-clean: info: qp ",strnum,0);
}