예제 #1
0
int main(int argc,char **argv)
{
  const char *subdir;
  unsigned long n;
  int i;
  char strnum[FMT_ULONG];

  i = getconfopt(argc,argv,options,1,0);
  initsub(flagsubdb);
  subdir = argv[i];

  if (flagnumber) {
    n = putsubs(subdir,0L,52L,dummywrite);
    if (substdio_put(subfdout,strnum,fmt_ulong(strnum,n)) == -1) die_write();
    if (substdio_put(subfdout,"\n",1) == -1) die_write();
  } else
    (void) putsubs(subdir,0L,52L,subwrite);
  if (substdio_flush(subfdout) == -1) die_write();
  closesub();
  _exit(0);
}
예제 #2
0
void main(int argc,char **argv)
{
  const char *subdir;
  const char *addr;
  int opt;
  int senderissub;
  int i;

  addr = get_sender();
  if (!addr) die_sender();	/* REQUIRE sender */

  opt = getconfopt(argc,argv,options,1,0);
  initsub(0);

  if (opt >= argc)
    senderissub = !!issub(0,addr,0);
  else {
    /* If all the options are absolute, scan each one; else treat the
     * first option as the base directory and the rest as database
     * names. */
    for (i = --opt; i < argc; ++i) {
      if (argv[i][0] != '/') {
        ++opt;
	break;
      }
    }
    senderissub = 0;
    while ((subdir = argv[opt++]) != 0) {
      if (issub(subdir,addr,0)) {
	senderissub = 1;
	break;
      }
    }
  }
  closesub();
  _exit(senderissub ? flagsub	/* is a subscriber */
	: flagsub ? 0 : 99);	/* not subscriber anywhere */
}
예제 #3
0
int main(int argc,char **argv)
{
  const char *dir;
  const char *sender;
  const char *moddir;
  int opt;
  int ret = 0;
  unsigned int i,j;
  const char *program;
  stralloc *opts;
  stralloc cmds = {0};
  int child;
  int ismod;

  umask(022);
  sig_pipeignore();

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

	/* storeopts to ezmlm-store only. Others to both (ezmlm-store may */
	/* pass them on to ezmlm-send. */
  if (!stralloc_catb(&storeopt,sendopt.s+1,sendopt.len-1)) die_nomem();

  initsub(0);

  sender = get_sender();

  ismod = 0;

  if (queryext) {
    getconf(&cmds,queryext,1);
    i = 0;
    for (j = 0;j < cmds.len; ++j)
      if (!cmds.s[j]) {
	switch (cmds.s[i]) {
	  case '\0': case '#': break;	/* ignore blank/comment */
	  case '|':
		ret = mailprog(cmds.s + i + 1); break;
	  default:
		ret = mailprog(cmds.s + i); break;
	}
	if (ret) break;
	i = j + 1;
    }
    if (!ret || ret == 99)		/* 111 => temp error */
      ismod = 1;			/* 0, 99 => post */
					/* other => moderate */
  }
  moddir = argv[opt++];
  if (moddir && !ret) {			/* if exit 0 and moddir, add issub */
    ismod = 0;
    while (moddir && !ismod && sender) {
      ismod = issub(moddir,sender,0);
      closesub();
      moddir = argv[opt++];
    }
  }

  if (ismod) {
    program = "/ezmlm-send";
    opts = &sendopt;
  }
  else {
    program = "/ezmlm-store";
    opts = &storeopt;
  }

  if (dontact) {
    substdio_puts(subfderr, auto_bin());
    substdio_puts(subfderr, program);
    substdio_put(subfderr, " ", 1);
    substdio_put(subfderr, opts->s, opts->len);
    substdio_put(subfderr, " ", 1);
    substdio_puts(subfderr, dir);
    substdio_putsflush(subfderr, "\n");
    _exit(0);
  }

  if ((child = wrap_fork()) == 0)
    wrap_execbin(program, opts, dir);
  /* parent */
  wrap_exitcode(child);
  _exit(0);
}
예제 #4
0
int main(int argc,char **argv)
{
  char *action;
  const char *err;
  unsigned int i;
  int act = AC_NONE;	/* desired action */
  unsigned int actlen = 0;/* str_len of above */

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

  getconfopt(argc,argv,options,1,&dir);
  initsub(0);

  sender = get_sender();
  if (!sender) die_sender();
  action = env_get("DEFAULT");
  if (!action) 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));

  action = set_workdir(action);

  stralloc_copys(&target,sender);
  if (action[0]) {
    i = str_chr(action,'-');
    if (action[i]) {
      action[i] = 0;
      stralloc_copys(&target,action + i + 1);
      i = byte_rchr(target.s,target.len,'=');
      if (i < target.len)
	target.s[i] = '@';
    }
  }
  stralloc_0(&target);
  set_cptarget(target.s);	/* for copy() */
  make_verptarget();

  act = get_act_ismod(action,&actlen);

  stralloc_copy(&from,&outlocal);
  stralloc_cats(&from,"-return-@");
  stralloc_cat(&from,&outhost);
  stralloc_0(&from);

  if (qmail_open(&qq) == -1)
    strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));
  msg_headers(act);

  if (act == AC_SUBSCRIBE)
    do_subscribe(action);
  else if (act == AC_SC)
    do_sc(action);
  else if (str_start(action,ACTION_RC))
    do_rc_tc(action,ACTION_RC);
  else if(str_start(action,ACTION_TC))
    do_rc_tc(action,ACTION_TC);
  else if (act == AC_UNSUBSCRIBE)
    do_unsubscribe(action);
  else if (str_start(action,ACTION_UC))
    do_uc(action);
  else if (str_start(action,ACTION_VC))
    do_vc_wc(action,ACTION_VC);
  else if (str_start(action,ACTION_WC))
    do_vc_wc(action,ACTION_WC);
  else if (act == AC_LIST || act == AC_LISTN) 
    do_list(act);
  else if (act == AC_LOG)
    do_log(action,actlen);
  else if (act == AC_EDIT)
    do_edit(action);
  else if (str_start(action,ACTION_ED))
    do_ed(action);
  else if (act == AC_GET)
    do_get(action);
  else if (case_starts(action,ACTION_QUERY) ||
		case_starts(action,ALT_QUERY))
    do_query();
  else if (case_starts(action,ACTION_INFO) ||
		case_starts(action,ALT_INFO))
    do_info();
  else if (case_starts(action,ACTION_FAQ) ||
		case_starts(action,ALT_FAQ))
    do_faq();
  else if (ismod && (act == AC_HELP))
    do_mod_help();
  else
    do_help();

  err = qmail_close(&qq);
  closesub();
  if (*err != '\0')
    strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);
  strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
  strerr_die3x(0,INFO,"qp ",strnum);
}
예제 #5
0
파일: ezmlm-get.c 프로젝트: abh/ezmlm-idx
void main(int argc,char **argv)
{
  char *def;
  char *local;
  const char *action = "";
  char *psz;
  const char *err;
  int fd;
  unsigned int i,j;
  int flagremote;
  int match;
  int goodexit = 0;			/* exit code for normal exit */
					/* in manager this will be set to 0 */
  unsigned long from,u,to,issue,prevmax;
  unsigned long mno = 0;
  unsigned long chunk;
  unsigned long subs = 0;
  unsigned int pos,pos1;
  unsigned int len;
  int opt;
  char outformat = 0;
  msgentry *msgtable;
  subentry *subtable;
  authentry *authtable;
  dateentry *datetable;
  struct datetime dt;
  char date[DATE822FMT];

  (void) umask(022);
  sig_pipeignore();
  when = now();
  datetime_tai(&dt,when);

  opt = getconfopt(argc,argv,options,1,0);

  initsub(0);
  if (flagformat != 0)
    if (FORMATS[str_chr(FORMATS,flagformat[0])])
      outformat = flagformat[0];
  if (outformat == 0) {
    outformat =
      (getconf_line(&line,"digformat",0)
       && FORMATS[str_chr(FORMATS,line.s[0])])
      ? line.s[0]
      : DEFAULT_FORMAT;
  }

  /* code to activate digest (-digest-code)*/
  if ((digestcode = argv[opt]) == 0) {
    if (getconf_line(&digestcodefile,"digestcode",0)
	&& digestcodefile.len > 0) {
      if (!stralloc_0(&digestcodefile)) die_nomem();
      digestcode = digestcodefile.s;
    }
  }
  /* ignore any extra args */

  if (!stralloc_copy(&subject,&outlocal)) die_nomem();	/* for subjects */
  if (!stralloc_copy(&listname,&outlocal)) die_nomem();	/* for content disp */

  local = env_get("LOCAL");
  def = env_get("DEFAULT");
  sender = get_sender();
  if (local && *local) {	/* in editor local = outlocal */
    if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER));
    if (!*sender)
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
    if (str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
    if (!sender[str_chr(sender,'@')])
      strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS));
    if (def) {
      if (*def) {
	action = def;
	goodexit = 99;
      } else
	_exit(0);		/* list-@host should do -help from manager */
    } else {			/* editor */
      act = AC_DIGEST;		/* on list-@host ! */
      flageditor = 1;		/* to avoid Mailing-list error on sublists */
				/* when running out of dir/editor. */
    }
    if (case_starts(action,"dig")) {
      action += 3;
      if (action[0] == '-' || action [0] == '.') {
        action++;
	if (!digestcode)
            strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE));
        len = str_len(digestcode);
        if (len <= str_len(action) && case_startb(action,len,digestcode)) {
          if (FORMATS[str_chr(FORMATS,*(action+len))])
            outformat = *(action+len);
          act = AC_DIGEST;
        } else
          strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE));
      }
    }
  } else			/* Command line operation */
    act = AC_DIGEST;

	/* Things we deal with. If anything else just die with success!   */
	/* At the moment this is -index, -thread, and -get.               */
	/* If flagdo = 0 we only service -dig commands. This is to support*/
	/* "secret" lists that are still archived and digested. -c on     */
	/* cmd line. */

  if (act == AC_NONE) {
    if (case_equals(action,ACTION_DIGEST)) {
      act = AC_GET;		/* list-digest@ => msg since last digest */
      action = ACTION_GET;
    } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET))
      act = AC_GET;
    else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX))
      act = AC_INDEX;
    else if (case_starts(action,ACTION_THREAD) ||
	 case_starts(action,ALT_THREAD))
      act = AC_THREAD;
  }
  if (act == AC_NONE)			/* not for us. Pass the buck. */
    _exit(0);
  if (act != AC_INDEX) {		/* need to do header processing */
    if(!getconf(&digheaders,"digheaders",0)) {
      if(!stralloc_copys(&digheaders,digsz)) die_nomem();
      if (!stralloc_0(&digheaders)) die_nomem();
      psz = digheaders.s;
      while (*psz) {
        if (*psz == '\\') *psz = '\0';
        ++psz;
      }
    }
    if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0))
	die_nomem();
  }
  if (act != AC_DIGEST) {
    if (!flagdo)			/* only do digests */
      strerr_die2x(100,FATAL,MSG(ERR_NOCMD));
    if (flagpublic < 0)
      flagpublic = !getconf_isset("modgetonly") && getconf_isset("public");
    if (!flagpublic) {
		/* This all to take care of non-public lists. They should*/
		/* still do digests, but do other things only for        */
		/* moderators that have remote access. Since this is rare*/
		/* efforts have been made to keep everything that's not  */
		/* needed elsewhere in here.                   */
      getconf_line(&moddir,"modsub",0);
      flagremote = getconf_line(&line,"remote",0);
      if (!flagremote)
        strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC));
      if (!moddir.len) {
        if (line.len) {
          if (!stralloc_copy(&moddir,&line)) die_nomem();
        } else {
          if (!stralloc_copys(&moddir,"mod")) die_nomem();
        }
      }
      if (!stralloc_0(&moddir)) die_nomem();
      ismod = issub(moddir.s,sender,&mod);
      if (!ismod)			/* sender = moderator? */
        strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC));
    }
  }

  if (act == AC_DIGEST) {
    workdir = "digest";
    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
    if (getconf_line(&line,"chunk",0)) {
      if (!stralloc_0(&line)) die_nomem();
      (void) scan_ulong(line.s,&chunk);		/* same chunk as main list */
      if (chunk == 0)				/* limit range to 1-53 */
	chunk = 1L;
      else if (chunk > 52)
	chunk = 52L;
    } else {
      chunk = 0L;
    }
  } else
    workdir = ".";


  if (!flagarchived)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_ARCHIVED));

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

  set_cpnum("");	/* default for <#n#> replacement */

  switch (act) {

  case AC_DIGEST:

/* -dig{.|-}'digestcode'[f] returns an rfc1153 digest                        */
/* of messages from the archive. Messages                                    */
/* dignum+1 through the last message received by the list are processed and  */
/* dignum is updated to the last message processed. digissue is advanced.    */

    get_num();				/* max = last successful message */
    to = max;
    lockup();			/* another digest could corrupt dignum */
				/* but will be saved only if flagdigrange==0 */
    if(getconf_line(&num,"dignum",0)) {
      if(!stralloc_0(&num)) die_nomem();
      pos = scan_ulong(num.s,&prevmax);
      if (num.s[pos] == ':') pos++;
      pos += 1 + scan_ulong(num.s+pos,&cumsize);	/* last cumsize */
      if (num.s[pos] == ':') pos++;
      scan_ulong(num.s+pos,&digwhen);			/* last reg dig */
    } else {
      prevmax = 0L;
      cumsize = 0L;
      digwhen = 0L;
    }
    mno = prevmax + 1L;
    if(!max || mno > max)	/* if a digest-list is "sending" the request, */
				/* don't make noise: errors go to postmaster!*/
      strerr_die2x(goodexit,FATAL,MSG(ERR_EMPTY_DIGEST));
    szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0';
    set_cpnum(szmsgnum);	/* for copy */
				/* prepare subject to get entropy for tagmsg*/
    if (!stralloc_cats(&subject," Digest ")) die_nomem();
    if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1))
          die_nomem();		/* skip trailing in date '\n' */
    if (!stralloc_cats(&subject," Issue ")) die_nomem();
    if (getconf_line(&num,"digissue",0)) {
      if(!stralloc_0(&num)) die_nomem();
      scan_ulong(num.s,&issue);
      issue++;
    } else {
      issue = 1;
    }
    if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue)))
      die_nomem();
					/* use the subject as entropy */
    if (!stralloc_copy(&line,&subject)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();

    if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem();
    seed.len = HASHLEN + 1;
    seed.s[HASHLEN] = '\0';
    makehash(line.s,line.len,seed.s);
    if (chunk) {			/* only if slaves are used */
      qmail_puts(&qq,"Ezauth: ");
      qmail_put(&qq,seed.s,HASHLEN);
      qmail_puts(&qq,"\n");
    }

    doheaders();
    qmail_puts(&qq,"To: ");
    if (!quote(&quoted,&listname)) die_nomem();
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"@");
    qmail_put(&qq,outhost.s,outhost.len);
    qmail_puts(&qq,"\n");
    if (flagindexed && (outformat != NATIVE))
      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
	mno,to,max,flaglocked);
    else
      idx_mklist(&msgtable,&subtable,&authtable,mno,to);
    digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat);

    write_ulong(issue,0L,0L,"digissue","digissuen");
    write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn");
    break;

  case AC_GET:

/* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted   */
/* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET.  */

    zapnonsub(ACTION_GET);		/* restrict to subs if requested */
    tosender();
				/* for rfc1153 */
    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();

    to = 0;
    pos = str_len(ACTION_GET);
    if (!case_starts(action,ACTION_GET))
      pos = str_len(ALT_GET);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];
       ++pos;
    }
					/* optional - or . after '-get' */
    if (action[pos] == '-' || action[pos] == '.') pos++;
    get_num();				/* max = last successful message */
					/* accept any separator. It may be  */
					/* the terminal '\n', but then      */
					/* scan will = 0 on the \0 so should*/
					/* be safe                          */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/
    doheaders();
    if(action[pos += scan_ulong(action + pos,&u)])
      scan_ulong(action + pos + 1, &to);
    if (u == 0 && to == 0) {		/* default: messages since last */
					/* digest, or last MAXGET if too many */
      to= max;
      u = dignum();
      if (u == 0) {		/* no digest => last up to HISTGET msgs */
	to = max;
	if (max > HISTGET) u = max - HISTGET; else u = 1;
      }
      if (to - u >= MAXGET) u = to - MAXGET + 1;	/* max MAXGET */
    } else if (u > max) {
      if (to) {			/* -get.999999_x returns 30 and msg since last*/
	to = max;		/* digest 30*/
        u = dignum();
	if (u > HISTGET) u -= HISTGET; else u = 1;
        if (to - u >= MAXGET) u = to - MAXGET + 1;
      } else
	u = max;
    }
    if (u == 0) u = 1;			/* -get.5 => 1-5 */
    if (to < u) to = u;			/* -get23_2 => 23 */
    if (to >= u + MAXGET) to = u + MAXGET - 1;
					/* no more than MAXGET at a time */
    if (to > max) to = max;
    if (flagindexed && (outformat != NATIVE))	/* fake out threading */
      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
	u,to,max,0);
    else
      idx_mklist(&msgtable,&subtable,&authtable,u,to);
    digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat);
    break;

  case AC_INDEX:

/* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/
/* sets of 100.                                                              */
/* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */
/* limited to num+MAXINDEX to limit the amount of data sent.                 */

    if (!flagindexed)
      strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED));
    zapnonsub(ACTION_INDEX);	/* restrict to subs if requested */
    to = 0;
    pos = str_len(ACTION_INDEX);
    if (!case_starts(action,ACTION_INDEX))
      pos = str_len(ALT_INDEX);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];		/* ignored, but be nice ... */
       ++pos;
    }
    get_num();				/* max = last successful message */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/

    doheaders();
    tosender();
    if (!stralloc_cats(&subject," Result of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();
    presub(1,1,&subject,AC_INDEX,outformat);

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

    if (u == 0 && to == 0) { to = max; u = max - 100; }
    if (u <= 0) u = 1;
    if (u > max) u = max;
    if (to < u) to = u;
    if (to > u + MAXINDEX) to = u+MAXINDEX;	/* max MAXINDEX index files */
    if (to > max) to = max;
    u /= 100;
    to /= 100;
    while (u <= to) {
      if (!stralloc_copys(&fn,"archive/")) die_nomem();
      if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem();
      if (!stralloc_cats(&fn,"/index")) die_nomem();
      if (!stralloc_0(&fn)) die_nomem();

      if (u == max/100)	/* lock if last index file in archive */
        lockup();

      fd = open_read(fn.s);
      if (fd == -1)
        if (errno != error_noent)
          strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s));
        else
          code_qputs(MSG(TXT_NOINDEX));
      else {
        substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
        for (;;) {
          if (getln(&sstext,&line,&match,'\n') == -1)
            strerr_die2sys(111,FATAL,MSG1(ERR_READ,fn.s));
          if (match) {
            if (line.s[0] != '\t') {	/* subject line */
              pos = byte_chr(line.s,line.len,' ');
	      pos1 = 0;
	      if (pos && pos != line.len && line.s[pos - 1] == ':')
                pos1 = pos + HASHLEN + 1;	/* after hash */
              if (pos1 >= line.len) {	/* bad! */
                pos = 0;
                pos1 = 0;		/* output as is */
              }
              if (!stralloc_copyb(&line2,line.s,pos)) die_nomem();
              if (!stralloc_catb(&line2,line.s+pos1,line.len-pos1)) die_nomem();
            } else {
	      pos = byte_chr(line.s,line.len,';');
	      if (pos + HASHLEN + 1 < line.len && pos > 15 &&
				line.s[pos + 1] != ' ') {
		  if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem();
		  pos++;
		  if (!stralloc_catb(&line2,line.s + pos + HASHLEN,
			line.len - pos - HASHLEN)) die_nomem();
	      } else			/* old format - no author hash */
                if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem();
	    }
            code_qput(line2.s,line2.len);
          } else
            break;
        }
        close(fd);
      }

      if (u == max/100)	/* unlock if last index in archive file */
        unlock();

      u++;
    }
    normal_bottom(outformat);
    postmsg(outformat);
    break;

  case AC_THREAD:

/* -thread[f][-|.]num returns messages with subject matching message        */
/* 'num' in the subject index. If 'num' is not in[1..last_message] an error */
/* message is returned.                                                     */

    if (!flagindexed)
      strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED));

    zapnonsub(ACTION_THREAD);		/* restrict to subs if requested*/

    get_num();				/* max = last successful message */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/

    doheaders();
    tosender();
				/* for rfc1153 */
    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();

    to = 0;
    pos = str_len(ACTION_THREAD);
    if (!case_starts(action,ACTION_THREAD))
      pos = str_len(ALT_THREAD);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];
       ++pos;
    }
    if (action[pos] == '-' || action[pos] == '.') pos++;
    if(action[pos += scan_ulong(action + pos,&u)])
      scan_ulong(action + pos + 1, &to);

    if(u == 0 || u > max) {
      hdr_add2("Subject: ",subject.s,subject.len);
      qmail_puts(&qq,"\n");
      copy(&qq,"text/get-bad",flagcd);
    } else {	/* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */
      if (u > THREAD_BEFORE)
        from = u-THREAD_BEFORE;
      else
        from = 1L;
      if (u + THREAD_AFTER > max) {
        idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0);
        digest(msgtable,subtable,authtable,from,max,&subject,
		AC_THREAD,outformat);
      } else {
        idx_mkthread(&msgtable,&subtable,&authtable,
		from,u+THREAD_AFTER,u,max,0);
        digest(msgtable,subtable,authtable,from,u+THREAD_AFTER,
			&subject,AC_THREAD,outformat);
      }
    }
    break;

  default:
	/* This happens if the initial check at the beginning of 'main'    */
	/* matches something that isn't matched here. Conversely, just     */
	/* adding an action here is not enough - it has to be added to the */
	/* initial check as well.                                          */

    strerr_die2x(100,FATAL,
		 "Program error: I'm supposed to deal with this but I didn't");
  }

  if (!stralloc_copy(&line,&outlocal)) die_nomem();
  if (act == AC_DIGEST) {
    if (chunk) {
      if (!stralloc_cats(&line,"-return-g-")) die_nomem();
    } else
      if (!stralloc_cats(&line,"-return-")) die_nomem();
    strnum[fmt_ulong(strnum,mno)] = '\0';
    if (!stralloc_cats(&line,strnum)) die_nomem();
    if (!stralloc_cats(&line,"-@")) die_nomem();

    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_cats(&line,"-@[]")) die_nomem();
  } else {
    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 (act == AC_DIGEST) {	 /* Do recipients */
    tagmsg(mno,seed.s,"d",hashout,qq.msgbytes,chunk);
    if (chunk) {
      if (!stralloc_copys(&line,"T")) die_nomem();
      if (!stralloc_cat(&line,&outlocal)) die_nomem();
      if (!stralloc_cats(&line,"-s-d-")) die_nomem();
      if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem();
      if (!stralloc_cats(&line,"-")) die_nomem();
      if (!stralloc_cats(&line,strnum)) die_nomem();
      if (!stralloc_cats(&line,"-")) die_nomem();
      if (!stralloc_copys(&line2,"@")) die_nomem();
      if (!stralloc_cat(&line2,&outhost)) die_nomem();
      if (!stralloc_0(&line2)) die_nomem();
      j = 0;
      for (i = 0; i <= 52; i += chunk) {		/* To slaves */
        qmail_put(&qq,line.s,line.len);
        schar[0] = '0' + i / 10;
        schar[1] = '0' + (i % 10);
        qmail_put(&qq,schar,3);
        j += (chunk - 1);
        if (j > 52) j = 52;
        schar[0] = '0' + j / 10;
        schar[1] = '0' + (j % 10);
        qmail_put(&qq,schar,2);
        qmail_put(&qq,line2.s,line2.len);
      }
    } else
      subs = putsubs(workdir,0L,52L,&subto);
  } else {			/* if local is set, sender is checked */
    if (ismod)
      qmail_to(&qq,mod.s);
    else
      qmail_to(&qq,sender);
  }

  if (*(err = qmail_close(&qq)) == '\0') {	/* Done. Skip rest. */
    if (act == AC_DIGEST) {
      if (chunk)
	(void) logmsg(mno,0L,0L,2);
      else
        (void) logmsg(mno,0L,subs,4);
    }
    closesub();			/* close db connection */
    unlock();			/* NOP if nothing locked */
    strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
    strerr_die2x(goodexit,"ezmlm-get: info: qp ",strnum);
  } else {			/* failed. Reset last msg & issue for digest */
    if(act == AC_DIGEST) {
      issue--;
      write_ulong(issue,0L,0L,"digissue","digissuen");
      write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn");
    }
    unlock();			/* NOP if nothing locked */
    strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);
  }
}
예제 #6
0
void main(int argc,char **argv)
{
  DIR *bouncedir, *bsdir, *hdir;
  direntry *d, *ds;
  unsigned long bouncedate;
  unsigned long bouncetimeout = BOUNCE_TIMEOUT;
  unsigned long lockout = 0L;
  unsigned long ld;
  unsigned long ddir,dfile;
  int fdlock,fd;
  int opt;
  char ch;

  (void) umask(022);
  sig_pipeignore();
  when = (unsigned long) now();
  while ((opt = getopt(argc,argv,"dDl:t:vV")) != opteof)
    switch(opt) {
      case 'd': flagdig = 1; break;
      case 'D': flagdig = 0; break;
      case 'l':
                if (optarg) {	/* lockout in seconds */
                  (void) scan_ulong(optarg,&lockout);
                }
                break;
      case 't':
                if (optarg) {	/* bouncetimeout in days */
                  (void) scan_ulong(optarg,&bouncetimeout);
                  bouncetimeout *= 3600L * 24L;
                }
                break;
      case 'v':
      case 'V': strerr_die2x(0, "ezmlm-warn version: ",auto_version);
      default:
	die_usage();
    }
  startup(dir = argv[optind]);
  load_config(dir);
  getconf_ulong(&copylines,"copylines",0,dir);
  if (flagdig) {
    if (!stralloc_copys(&digdir,dir)) die_nomem();
    if (!stralloc_cats(&digdir,"/digest")) die_nomem();
    if (!stralloc_0(&digdir)) die_nomem();
    workdir = digdir.s;
  } else
    workdir = dir;

  if (!stralloc_copys(&fnlastd,workdir)) die_nomem();
  if (!stralloc_cats(&fnlastd,"/bounce/lastd")) die_nomem();
  if (!stralloc_0(&fnlastd)) die_nomem();
  if (slurp(fnlastd.s,&lastd,16) == -1)		/* last time d was scanned */
      strerr_die4sys(111,FATAL,ERR_READ,fnlastd.s,": ");
  if (!stralloc_0(&lastd)) die_nomem();
  (void) scan_ulong(lastd.s,&ld);
  if (!lockout)
    lockout = bouncetimeout / 50;		/* 5.6 h for default timeout */
  if (ld + lockout > when && ld < when)
    _exit(0);		/* exit silently. Second check is to prevent lockup */
			/* if lastd gets corrupted */

  if (!stralloc_copy(&fnlasth,&fnlastd)) die_nomem();
  fnlasth.s[fnlasth.len - 2] = 'h';		/* bad, but feels good ... */

  if (flagdig)
    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();

  ddir = when / 10000;
  dfile = when - 10000 * ddir;

  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  fdlock = lockfile(line.s);

  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/bounce/d")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  bouncedir = opendir(line.s);
  if (!bouncedir) {
    if (errno != error_noent)
      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
    else
      _exit(0);		/* no bouncedir - no bounces! */
  }

  while ((d = readdir(bouncedir))) {		/* dxxx/ */
    if (str_equal(d->d_name,".")) continue;
    if (str_equal(d->d_name,"..")) continue;

    scan_ulong(d->d_name,&bouncedate);
	/* since we do entire dir, we do files that are not old enough. */
	/* to not do this and accept a delay of 10000s (2.8h) of the oldest */
	/* bounce we add to bouncedate. We don't if bouncetimeout=0 so that */
	/* that setting still processes _all_ bounces. */
    if (bouncetimeout) ++bouncedate;
    if (when >= bouncedate * 10000 + bouncetimeout) {
      if (!stralloc_copys(&bdname,workdir)) die_nomem();
      if (!stralloc_cats(&bdname,"/bounce/d/")) die_nomem();
      if (!stralloc_cats(&bdname,d->d_name)) die_nomem();
      if (!stralloc_0(&bdname)) die_nomem();
      bsdir = opendir(bdname.s);
      if (!bsdir) {
	if (errno != error_notdir)
	  strerr_die4sys(111,FATAL,ERR_OPEN,bdname.s,":y ");
	else {				/* leftover nnnnn_dmmmmm file */
	  if (unlink(bdname.s) == -1)
	    strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
	  continue;
	}
      }
      while ((ds = readdir(bsdir))) {			/* dxxxx/yyyy */
	if (str_equal(ds->d_name,".")) continue;
	if (str_equal(ds->d_name,"..")) continue;
	if (!stralloc_copy(&fn,&bdname)) die_nomem();	/* '\0' at end */
	  fn.s[fn.len - 1] = '/';
	if (!stralloc_cats(&fn,ds->d_name)) die_nomem();
	if (!stralloc_0(&fn)) die_nomem();
	if ((ds->d_name[0] == 'd') || (ds->d_name[0] == 'w'))
	  doit(ds->d_name[0] == 'w');
        else				/* other stuff is junk */
	  if (unlink(fn.s) == -1)
	    strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
      }
      closedir(bsdir);
      if (rmdir(bdname.s) == -1)	/* the directory itself */
      if (errno != error_noent)
	   strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
    }
  }
  closedir(bouncedir);

  if (!stralloc_copy(&line,&fnlastd)) die_nomem();
  line.s[line.len - 2] = 'D';
  fd = open_trunc(line.s);			/* write lastd. Do safe */
						/* since we read before lock*/
  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
  if (substdio_put(&ssout,strnum,fmt_ulong(strnum,when)) == -1)
    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
  if (substdio_put(&ssout,"\n",1) == -1)	/* prettier */
    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
  if (substdio_flush(&ssout) == -1)
    strerr_die4sys(111,FATAL,ERR_FLUSH,line.s,": ");
  if (fsync(fd) == -1)
    strerr_die4sys(111,FATAL,ERR_SYNC,line.s,": ");
  if (close(fd) == -1)
    strerr_die4sys(111,FATAL,ERR_CLOSE,line.s,": ");

  if (rename(line.s,fnlastd.s) == -1)
    strerr_die4sys(111,FATAL,ERR_MOVE,fnlastd.s,": ");

				/* no need to do h dir cleaning more than */
				/* once per 1-2 days (17-30 days for all) */
  if (stat(fnlasth.s,&st) == -1) {
    if (errno != error_noent)
      strerr_die4sys(111,FATAL,ERR_STAT,fnlasth.s,": ");
  } else if (when < (unsigned long)st.st_mtime + 100000
	     && when > (unsigned long)st.st_mtime)
    _exit(0);			/* 2nd comp to guard against corruption */

  if (slurp(fnlasth.s,&lasth,16) == -1)		/* last h cleaned */
      strerr_die4sys(111,FATAL,ERR_READ,fnlasth.s,": ");
  if (!stralloc_0(&lasth)) die_nomem();
  ch = lasth.s[0];				 /* clean h */
  if (ch >= 'a' && ch <= 'o')
    ++ch;
  else
    ch = 'a';
  lasth.s[0] = ch;
  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/bounce/h/")) die_nomem();
  if (!stralloc_catb(&line,lasth.s,1)) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  hdir = opendir(line.s);		/* clean ./h/xxxxxx */

  if (!hdir) {
    if (errno != error_noent)
    strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
  } else {

    while ((d = readdir(hdir))) {
      if (str_equal(d->d_name,".")) continue;
      if (str_equal(d->d_name,"..")) continue;
      if (!stralloc_copys(&fn,line.s)) die_nomem();
      if (!stralloc_append(&fn,"/")) die_nomem();
      if (!stralloc_cats(&fn,d->d_name)) die_nomem();
      if (!stralloc_0(&fn)) die_nomem();
      if (stat(fn.s,&st) == -1) {
	if (errno == error_noent) continue;
	strerr_die4sys(111,FATAL,ERR_STAT,fn.s,": ");
      }
      if (when > st.st_mtime + 3 * bouncetimeout)
	if (unlink(fn.s) == -1)
          strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
    }
    closedir(hdir);
  }

  fd = open_trunc(fnlasth.s);			/* write lasth */
  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
  if (substdio_put(&ssout,lasth.s,1) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  if (substdio_put(&ssout,"\n",1) == -1)	/* prettier */
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  if (substdio_flush(&ssout) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  (void) close(fd);		/* no big loss. No reason to flush/sync */
				/* See check of ld above to guard against */
				/* it being corrupted and > when */

  closesub();
  _exit(0);
}
예제 #7
0
void main(int argc,char **argv)
{
  char *dir;
  int fdlock;
  char *sender;
  int match;
  int flaginheader;
  int flagmodpost;
  int flagremote;
  const char *pmod;
  const char *err;
  int opt;
  unsigned int i;
  char szchar[2] = "-";
  int child;

  (void) umask(022);
  sig_pipeignore();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvVyY")) != opteof)
    switch(opt) {
      case 'b': flagbody = 1; break;
      case 'B': flagbody = 0; break;
      case 'm': flagmime = 1; break;
      case 'M': flagmime = 0; break;
      case 'p': flagpublic = 1; break;	/* anyone can post (still moderated)*/
      case 'P': flagpublic = 0; break;	/* only moderators can post */
      case 's': flagself = 1; break;	/* modpost and DIR/mod diff fxns */
      case 'S': flagself = 0; break;	/* same fxn */
      case 'y': flagconfirm = 1; break; /* force post confirmation */
      case 'Y': flagconfirm = 0; break; /* disable post confirmation */
      case 'c':				/* ezmlm-send flags */
      case 'C':
      case 'r':
      case 'R':
        szchar[0] = (char) opt & 0xff;
        if (!stralloc_append(&sendopt,szchar)) die_nomem();
        break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-store version: ",auto_version);
      default:
	die_usage();
    }

  sender = env_get("SENDER");

  if (sender) {
    if (!*sender || str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,ERR_BOUNCE);
  }

  startup(dir = argv[optind]);
  load_config(dir);

  if (flagconfirm == -1)
    flagconfirm = getconf_line(&confirmpost,"confirmpost",0,dir);
  else
    getconf_line(&confirmpost,"confirmpost",0,dir);

  flagmodpost = getconf_line(&moderators,"modpost",0,dir);
  flagremote = getconf_line(&line,"remote",0,dir);
  if (!flagmodpost && !flagconfirm) {	/* not msg-mod. Pipe to ezmlm-send */
    if ((child = wrap_fork()) == 0)
      wrap_execbin("/ezmlm-send", &sendopt, dir);
    /* parent */
    wrap_exitcode(child);
  }

  if (!moderators.len || !(moderators.s[0] == '/')) {
    if (!stralloc_copys(&moderators,dir)) die_nomem();
    if (!stralloc_cats(&moderators,"/mod")) die_nomem();
  }
  if (!stralloc_0(&moderators)) die_nomem();

  if (sender) {
      pmod = issub(moderators.s,0,sender);
      closesub();
				/* sender = moderator? */
  } else
    pmod = 0;

  if (!pmod && !flagpublic)
    strerr_die2x(100,FATAL,ERR_NO_POST);

  fdlock = lockfile("mod/lock");

  if (!stralloc_copys(&mydtline, flagconfirm
    ? "Delivered-To: confirm to "
    : "Delivered-To: moderator for ")) die_nomem();
  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
  if (!stralloc_append(&mydtline,"@")) die_nomem();
  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
  if (!stralloc_cats(&mydtline,"\n")) die_nomem();

  if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem();
  if (sender) {
    if (!stralloc_cats(&returnpath,sender)) die_nomem();
    for (i = 14; i < returnpath.len;++i)
      if (returnpath.s[i] == '\n' || !returnpath.s[i] )
        returnpath.s[i] = '_';
		/* NUL and '\n' are bad, but we don't quote since this is */
		/* only for ezmlm-moderate, NOT for SMTP */
  }
  if (!stralloc_cats(&returnpath,">\n")) die_nomem();

 pid = getpid();		/* unique file name */
 for (i = 0;;++i)		/* got lock - nobody else can add files */
  {
   when = now();		/* when is also used later for date! */
   if (!stralloc_copys(&fnmsg, flagconfirm?"mod/unconfirmed/":"mod/pending/")) die_nomem();
   if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem();
   if (!stralloc_append(&fnbase,".")) die_nomem();
   if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem();
   if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem();
   if (!stralloc_0(&fnmsg)) die_nomem();
   if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break;
   /* really should never get to this point */
   if (i == 2)
     strerr_die2x(111,FATAL,ERR_UNIQUE);
   sleep(2);
  }

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_DISCARD:ACTION_REJECT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_copy(&reject,&quoted)) die_nomem();
  if (!stralloc_cat(&reject,&action)) die_nomem();
  if (!stralloc_0(&reject)) die_nomem();

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_CONFIRM:ACTION_ACCEPT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!stralloc_copy(&accept,&quoted)) die_nomem();
  if (!stralloc_cat(&accept,&action)) die_nomem();
  if (!stralloc_0(&accept)) die_nomem();

  set_cptarget(accept.s);	/* for copy () */
  set_cpconfirm(reject.s,quoted.len);

  fdmsg = open_trunc(fnmsg.s);
  if (fdmsg == -1)
    strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": ");
  substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf));

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

  hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
  if (listid.len > 0)
    hdr_add2("List-ID: ",listid.s,listid.len);
  hdr_datemsgid(when);
  if (flagconfirm)
    hdr_from("-owner");
  else
    hdr_add2s("From: ",reject.s);
  hdr_add2s("Reply-To: ",accept.s);
  if (!flagconfirm && !pmod && flagremote) {	/* if remote admin add -allow- address */
    qmail_puts(&qq,"Cc: ");	/* for ezmlm-gate users */
    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
    cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t");
    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-allow-tc.")) die_nomem();
    if (!stralloc_cats(&line,strnum)) die_nomem();
    if (!stralloc_append(&line,".")) die_nomem();
    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
    if (!stralloc_append(&line,"-")) die_nomem();
    i = str_rchr(sender,'@');
    if (!stralloc_catb(&line,sender,i)) die_nomem();
    if (sender[i]) {
      if (!stralloc_append(&line,"=")) die_nomem();
      if (!stralloc_cats(&line,sender + i + 1)) die_nomem();
    }
    qmail_put(&qq,line.s,line.len);
    qmail_puts(&qq,"@");
    qmail_put(&qq,outhost.s,outhost.len);
    qmail_puts(&qq,"\n");
  }
  qmail_puts(&qq,"To: <");
  if (flagconfirm) {
    if (sender)
      qmail_puts(&qq, sender);
  } else {
    if (!quote(&quoted,&outlocal))
      die_nomem();
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"-moderators@");
    qmail_put(&qq,outhost.s,outhost.len);
  }
  qmail_puts(&qq,">\n");
  /* FIXME: Drop the custom subject hack and use hdr_listsubject1 */
  if (!stralloc_copys(&subject,"Subject: ")) die_nomem();
  if (flagconfirm) {
    if (confirmpost.len) {
      if (!stralloc_cat(&subject,&confirmpost)) die_nomem();
      if (!stralloc_cats(&subject," ")) die_nomem();
    } else {
      if (!stralloc_cats(&subject,TXT_CONFIRM_POST)) die_nomem();
    }
  } else {
    if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem();
  }
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_cat(&subject,&quoted)) die_nomem();
  if (!stralloc_append(&subject,"@")) die_nomem();
  if (!stralloc_cat(&subject,&outhost)) die_nomem();
  if (flagmime) {
    hdr_mime(CTYPE_MULTIPART);
    qmail_put(&qq,subject.s,subject.len);
    hdr_boundary(0);
    hdr_ctype(CTYPE_TEXT);
    hdr_transferenc();
  } else {
    qmail_put(&qq,subject.s,subject.len);
    qmail_puts(&qq,"\n\n");
  }
  copy(&qq,flagconfirm?"text/post-confirm":"text/mod-request",flagcd);
  if (flagcd == 'B') {
    encodeB("",0,&line,2);
    qmail_put(&qq,line.s,line.len);
  }
  if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg();
  if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg();
  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));

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

  qmail_put(&qq,returnpath.s,returnpath.len);
  qmail_put(&qq,mydtline.s,mydtline.len);
  flaginheader = 1;
  for (;;) {
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
    if (!match) break;
    if (line.len == 1) flaginheader = 0;
    if (flaginheader) {
      if ((line.len == mydtline.len) &&
		!byte_diff(line.s,line.len,mydtline.s)) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_LOOPING);
      }
      if (case_startb(line.s,line.len,"mailing-list:")) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
      }
    }

    if (flagbody || flaginheader)	/* skip body if !flagbody */
      qmail_put(&qq,line.s,line.len);
    if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg();
  }

  if (flagmime)
    hdr_boundary(1);

/* close archive before qmail. Loss of qmail will result in re-run, and   */
/* worst case this results in a duplicate msg sitting orphaned until it's */
/* cleaned out.                                                           */

  if (substdio_flush(&ssmsg) == -1) die_msg();
  if (fsync(fdmsg) == -1) die_msg();
  if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg();
  if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */

  close(fdlock);

  if (flagconfirm) {
    qmail_from(&qq,reject.s);			/* envelope sender */
  } else {
    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);			/* envelope sender */
  }
  if (flagconfirm)				/* to sender */
    qmail_to(&qq,sender);
  else if (pmod)				/* to moderator only */
    qmail_to(&qq,pmod);
  else {
    if (flagself) {				/* to all moderators */
      if (!stralloc_copys(&moderators,dir)) die_nomem();
      if (!stralloc_cats(&moderators,"/mod")) die_nomem();
      if (!stralloc_0(&moderators)) die_nomem();
    }
    putsubs(moderators.s,0,0,52,subto,1);
  }

  if (*(err = qmail_close(&qq)) == '\0') {
      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die2x(0,"ezmlm-store: info: qp ",strnum);
  } else
      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1);
}
예제 #8
0
void main(int argc,char **argv)
{
  char *dir;
  char *sender;
  char *moddir;
  const char *queryext = (char *) 0;
  int opt;
  int ret = 0;
  int dontact = 0;
  unsigned int i,j;
  const char *program;
  stralloc *opts;

  umask(022);
  sig_pipeignore();
	/* storeopts to ezmlm-store only. Others to both (ezmlm-store may */
	/* pass them on to ezmlm-send. */
  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  if (!stralloc_copys(&storeopt,"-")) die_nomem();

  while ((opt = getopt(argc,argv,
      "0cCmMpPq:Q:sSrRt:T:vVyY")) != opteof)
    switch(opt) {	/* pass on unrecognized options */
      case 'c':			/* ezmlm-send flags */
      case 'C':
      case 'r':
      case 'Q':
      case 'R':
        szchar[0] = opt;
        if (!stralloc_append(&sendopt,szchar)) die_nomem();
        if (!stralloc_append(&storeopt,szchar)) die_nomem();
        break;
      case 'm':			/* ezmlm-store flags */
      case 'M':
      case 'p':
      case 'P':
      case 's':
      case 'S':
      case 'y':
      case 'Y':
        szchar[0] = opt;
        if (!stralloc_append(&storeopt,szchar)) die_nomem();
        break;
      case 'q': if (optarg) queryext = optarg; break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-gate version: ",auto_version);
      case '0': dontact = 1; break;
      default:			/* ezmlm-store flags */
        die_usage();
    }

  startup(dir = argv[optind++]);

  sender = env_get("SENDER");

  pmod = (char *) 0;

  if (queryext) {
    getconf(&cmds,queryext,1,dir);
    i = 0;
    for (j = 0;j < cmds.len; ++j)
      if (!cmds.s[j]) {
	switch (cmds.s[i]) {
	  case '\0': case '#': break;	/* ignore blank/comment */
	  case '|':
		ret = mailprog(cmds.s + i + 1); break;
	  default:
		ret = mailprog(cmds.s + i); break;
	}
	if (ret) break;
	i = j + 1;
    }
    if (!ret || ret == 99)		/* 111 => temp error */
      pmod = "";			/* 0, 99 => post */
					/* other => moderate */
  }
  moddir = argv[optind++];
  if (moddir && !ret) {			/* if exit 0 and moddir, add issub */
    pmod = (char *) 0;
    while (moddir && !pmod && sender) {
      pmod = (moddir[0] == '/')
	? issub(moddir,0,sender)
	: issub(dir,moddir,sender);
      closesub();
      moddir = argv[optind++];
    }
  }

  if (pmod) {
    program = "/ezmlm-send";
    opts = &sendopt;
  }
  else {
    program = "/ezmlm-store";
    opts = &storeopt;
  }

  if (dontact) {
    substdio_puts(subfderr, auto_bin);
    substdio_puts(subfderr, program);
    substdio_put(subfderr, " ", 1);
    substdio_put(subfderr, opts->s, opts->len);
    substdio_put(subfderr, " ", 1);
    substdio_puts(subfderr, dir);
    substdio_putsflush(subfderr, "\n");
    _exit(0);
  }

  if ((child = wrap_fork()) == 0)
    wrap_execbin(program, opts, dir);
  /* parent */
  wrap_exitcode(child);
  _exit(0);
}