Exemple #1
0
void main(int argc,char **argv)
{
  int fdlock;
  unsigned long delay;
  (void) umask(022);
  sig_pipeignore();
  when = now();

  getconfopt(argc,argv,options,1,0);
  if (flagreturn < 0)
    /* default to returning timed-out messages */
    flagreturn = !getconf_isset("noreturnposts");

  getconf_line(&modtime,"modtime",0);
  if (!stralloc_0(&modtime)) die_nomem();
  scan_ulong(modtime.s,&delay);
  if (!delay) delay = DELAY_DEFAULT;
  else if (delay < DELAY_MIN) delay = DELAY_MIN;
  else if (delay > DELAY_MAX) delay = DELAY_MAX;
  older = (unsigned long) when - 3600L * delay;	/* delay is in hours */

  fdlock = lockfile("mod/lock");

  dodir("mod/pending/",flagreturn);
  dodir("mod/accepted/",0);
  dodir("mod/rejected/",0);
  dodir("mod/unconfirmed/",0);
  _exit(0);
}
Exemple #2
0
int main(int argc, char **argv)
{
  sig_alarmcatch(die);
  sig_pipeignore();
 
  hostname = argv[1];
  if (!hostname) die_usage();
  childargs = argv + 2;
  if (!*childargs) die_usage();
 
  pop3_greet();
  commands(&ssin,pop3commands);
  return 1;
}
Exemple #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);
}
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);
}
Exemple #5
0
int main(int argc,char **argv)
{
  int child;
  const char *sendargs[4];
  stralloc addr = {0};
  unsigned int pos = 0,pos2,poslocal,len;
  const char *cp;

  unsigned long hh = 4L;		/* default time 04:12 */
  unsigned long mm = 12L;
  const char *dow = "*";		/* day of week */
  const char *qmail_inject = "/bin/qmail-inject ";
  char strnum[FMT_ULONG];
  unsigned long uid,euid = 0;

  stralloc rp = {0};
  stralloc user = {0};
  stralloc euser = {0};
  stralloc dir = {0};
  stralloc listaddr = {0};
  stralloc line = {0};

  struct passwd *ppasswd;

  int match;
  int hostmatch;
  int localmatch;
  unsigned long dh,t;
  int founduser = 0;
  int listmatch = 0;
  int flagdigit = 0;
  int flagours;
  int foundlocal = 0;
  int foundmatch = 0;
  unsigned int nolists = 0;
  unsigned long maxlists;
  unsigned int lenhost,lenlocal;
  int fdin,fdout = -1;

  char *local = (char *) 0;	/* list = local@host */
  const char *host = (char *) 0;
  char *code = (char *) 0;	/* digest code */

  char inbuf[512];
  substdio ssin;

  char outbuf[512];
  substdio ssout;

  (void) umask(077);
  sig_pipeignore();

  optind = getconfopt(argc,argv,options,0,0);
  if (flagt != 0) {
    pos = scan_ulong(flagt,&hh);
    if (flagt[pos++] != ':') die_usage();
    (void) scan_ulong(flagt + pos,&mm);
  }
  if (flagw != 0) {
    dow = flagw;
    cp = flagw - 1;
    while (*(++cp)) {
      if (*cp >= '0' && *cp <= '7') {
	if (flagdigit) die_dow();
	flagdigit = 1;
      } else if (*cp == ',') {
	if (!flagdigit) die_dow();
	flagdigit = 0;
      } else
	die_dow();
    }
  }

  if (flaglist + flagdelete + flagconfig > 1)
    strerr_die2x(100,FATAL,MSG(ERR_EXCLUSIVE));
  uid = getuid();
  if (uid && !(euid = geteuid()))
    strerr_die2x(100,FATAL,MSG(ERR_SUID));
  if (!(ppasswd = getpwuid(uid)))
    strerr_die2x(100,FATAL,MSG(ERR_UID));
  if (!stralloc_copys(&user,ppasswd->pw_name)) die_nomem();
  if (!stralloc_0(&user)) die_nomem();
  if (!(ppasswd = getpwuid(euid)))
    strerr_die2x(100,FATAL,MSG(ERR_EUID));
  if (!stralloc_copys(&dir,ppasswd->pw_dir)) die_nomem();
  if (!stralloc_0(&dir)) die_nomem();
  if (!stralloc_copys(&euser,ppasswd->pw_name)) die_nomem();
  if (!stralloc_0(&euser)) die_nomem();

  wrap_chdir(dir.s);

  local = argv[optind++];	/* list address, optional for -c & -l */
  if (!local) {
    if (!flagconfig && !flaglist)
      die_usage();
    lenlocal = 0;
    lenhost = 0;
  } else {
    if (!stralloc_copys(&listaddr,local)) die_nomem();
    if (!isclean(local,1))
      die_argument();
    pos = str_chr(local,'@');
    lenlocal = pos;
    local[pos] = '\0';
    host = local + pos + 1;
    lenhost = str_len(host);
    code = argv[optind];
    if (!code) {		/* ignored for -l, -c, and -d */
      if (flagdelete || flaglist || flagconfig)
				/* get away with not putting code for delete */
        code = (char*)"a";	/* a hack - so what! */
      else
        die_usage();
    } else
      if (!isclean(code,0))
        die_argument();
  }
  if ((fdin = open_read(TXT_EZCRONRC)) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,TXT_EZCRONRC));
	/* first line is special */
  substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
  if (getln(&ssin,&line,&match,'\n') == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));

  if (!match)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));
	/* (since we have match line.len has to be >= 1) */
  line.s[line.len - 1] = '\0';
  if (!isclean(line.s,0))	 /* host for bounces */
    strerr_die2x(100,FATAL,MSG1(ERR_CFHOST,TXT_EZCRONRC));
  if (!stralloc_copys(&rp,line.s)) die_nomem();

  match = 1;
  for(;;) {
    if (!match) break;		/* to allow last line without '\n' */
    if (getln(&ssin,&line,&match,'\n') == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));
    if (!line.len)
      break;
    line.s[line.len-1] = '\0';
    if (!case_startb(line.s,line.len,user.s))
      continue;
    pos = user.len - 1;
    if (pos >= line.len || line.s[pos] != ':')
      continue;
    founduser = 1;		 /* got user line */
    break;
  }
  close(fdin);
  if (!founduser)
    strerr_die2x(100,FATAL,MSG(ERR_BADUSER));
  
  if (flagconfig) {
    line.s[line.len-1] = '\n';	/* not very elegant ;-) */
    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
    if (substdio_put(&ssout,line.s,line.len) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    if (substdio_flush(&ssout) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    _exit(0);
  }
  ++pos;				/* points to first ':' */
  len = str_chr(line.s+pos,':');	/* second ':' */
    if (!line.s[pos + len])
      die_syntax(&line);
  if (!local) {				/* only -d and std left */
    localmatch = 1;
    hostmatch = 1;
  } else {
    hostmatch = 0;
    if (len <= str_len(local))
      if (!str_diffn(line.s+pos,local,len))
        localmatch = 1;
  }
  pos += len + 1;
  len = str_chr(line.s + pos,':');	/* third */
  if (!line.s[pos + len])
    die_syntax(&line);
  if (local) {				/* check host */
    if (len == 0)			/* empty host => any host */
      hostmatch = 1;
    else
      if (len == str_len(host))
        if (!case_diffb(line.s+pos,len,host))
          hostmatch = 1;
  }
  pos += len + 1;
  pos += scan_ulong(line.s+pos,&maxlists);
  if (line.s[pos]) {			/* check additional lists */
    if (line.s[pos] != ':')
      die_syntax(&line);
    if (line.s[pos+1+str_chr(line.s+pos+1,':')])
      die_syntax(&line);	/* reminder lists are not separated by ':'  */
				/* otherwise a ':' or arg miscount will die */
				/* silently */
    if (local) {
      while (++pos < line.len) {
        len = str_chr(line.s + pos,'@');
        if (len == lenlocal && !str_diffn(line.s + pos,local,len)) {
          pos += len;
          if (!line.s[pos]) break;
          pos++;
          len = str_chr(line.s+pos,',');
            if (len == lenhost && !case_diffb(line.s+pos,len,host)) {
              listmatch = 1;
              break;
            }
        }
        pos += len;
      }
    }
  }
  if (!listmatch) {
    if (!hostmatch)
      strerr_die2x(100,FATAL,MSG(ERR_BADHOST));
    if (!localmatch)
      strerr_die2x(100,FATAL,MSG(ERR_BADLOCAL));
  }
	/* assemble correct line */
  if (!flaglist) {
    if (!stralloc_copyb(&addr,strnum,fmt_ulong(strnum,mm))) die_nomem();
    if (!stralloc_cats(&addr," ")) die_nomem();
    dh = 0L;
    if (deltah <= 3L) dh = deltah;
    else if (deltah <= 6L) dh = 6L;
    else if (deltah <= 12L) dh = 12L;
    else if (deltah <= 24L) dh = 24L;
    else if (deltah <= 48L) {
      if (dow[0] == '*') dow = "1,3,5";
    } else if (deltah <= 72L) {
      if (dow[0] == '*') dow = "1,4";
    } else
    if (dow[0] == '*') dow = "1";

    if (!dh) {
      if (!stralloc_cats(&addr,"*")) die_nomem();
    } else {
      if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,hh))) die_nomem();
      for (t = hh + dh; t < hh + 24L; t+=dh) {
        if (!stralloc_cats(&addr,",")) die_nomem();
        if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,t % 24L))) die_nomem();
      }
    }
    if (!stralloc_cats(&addr," * * ")) die_nomem();
    if (!stralloc_cats(&addr,dow)) die_nomem();
    if (!stralloc_cats(&addr," ")) die_nomem();
    if (!stralloc_cats(&addr,auto_qmail)) die_nomem();
    if (!stralloc_cats(&addr,qmail_inject)) die_nomem();
    if (!stralloc_cats(&addr,local)) die_nomem();
    if (!stralloc_cats(&addr,"-dig-")) die_nomem();
    if (!stralloc_cats(&addr,code)) die_nomem();
    if (!stralloc_cats(&addr,"@")) die_nomem();
    if (!stralloc_cats(&addr,host)) die_nomem();
		/* feed 'Return-Path: <user@host>' to qmail-inject */
    if (!stralloc_cats(&addr,"%Return-path: <")) die_nomem();
    if (!stralloc_cats(&addr,user.s)) die_nomem();
    if (!stralloc_cats(&addr,"@")) die_nomem();
    if (!stralloc_cat(&addr,&rp)) die_nomem();
    if (!stralloc_cats(&addr,">\n")) die_nomem();
  }
  if (!stralloc_0(&addr)) die_nomem();

  if (!flaglist) {
	/* now to rewrite crontab we need to lock */
    lockfile("crontabl");
  } /* if !flaglist */
  if ((fdin = open_read("crontab")) == -1) {
    if (errno != error_noent)
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab"));
  } else
    substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
  if (flaglist)
    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
  else {
    if ((fdout = open_trunc("crontabn")) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
    substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
  }
  line.len = 0;

  if (fdin != -1) {
    for (;;) {
      if (!flaglist && line.len) {
        line.s[line.len-1] = '\n';
        if (substdio_put(&ssout,line.s,line.len) == -1)
          strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
      }
      if (getln(&ssin,&line,&match,'\n') == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab"));
      if (!match)
        break;
      flagours = 0;			/* assume entry is not ours */
      foundlocal = 0;
      line.s[line.len - 1] = '\0';	/* match so at least 1 char */
      pos = 0;
      while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
      if (line.s[pos] == '#')
        continue;			/* cron comment */
      pos = str_chr(line.s,'/');
      if (!str_start(line.s+pos,auto_qmail)) continue;
      pos += str_len(auto_qmail);
      if (!str_start(line.s+pos,qmail_inject)) continue;
      pos += str_len(qmail_inject);
      poslocal = pos;
      pos = byte_rchr(line.s,line.len,'<');	/* should be Return-Path: < */
      if (pos == line.len)
        continue;			/* not ezmlm-cron line */
      pos++;
     len = str_chr(line.s+pos,'@');
      if (len == user.len - 1 && !str_diffn(line.s+pos,user.s,len)) {
        flagours = 1;
        ++nolists;		/* belongs to this user */
      }
      if (!local) {
        foundlocal = 1;
      } else {
        pos = poslocal + str_chr(line.s+poslocal,'@');
        if (pos + lenhost +1 >= line.len) continue;
        if (case_diffb(line.s+pos+1,lenhost,host)) continue;
        if (line.s[pos+lenhost+1] != '%') continue;
				/* check local */
        if (poslocal + lenlocal + 5 >= line.len) continue;
        if (!str_start(line.s+poslocal,local)) continue;
        pos2 = poslocal+lenlocal;
        if (!str_start(line.s+pos2,"-dig-")) continue;
        foundlocal = 1;
      }
      if (foundlocal) {
        foundmatch = 1;
        if (flaglist && (local || flagours)) {
          if (substdio_put(&ssout,line.s,line.len) == -1)
            strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
          if (substdio_put(&ssout,"\n",1) == -1)
            strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
        }
        line.len = 0;		/* same - kill line */
        if (flagours)
          --nolists;
      }
    }
    close(fdin);
  }
  if (flaglist) {
    if (substdio_flush(&ssout) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"stdout"));
    if (foundmatch)		/* means we had a match */
      _exit(0);
    else
      strerr_die2x(100,FATAL,MSG(ERR_NO_MATCH));
  }
	/* only -d and regular use left */

  if (nolists >= maxlists && !flagdelete)
    strerr_die2x(100,FATAL,MSG(ERR_LISTNO));
  if (!flagdelete)
    if (substdio_put(&ssout,addr.s,addr.len-1) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
  if (flagdelete && !foundlocal)
    strerr_die2x(111,FATAL,MSG(ERR_NO_MATCH));
  if (substdio_flush(&ssout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"crontabn"));
  if (fsync(fdout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,"crontabn++"));
  if (close(fdout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,"crontabn"));
  wrap_rename("crontabn","crontab");
  sendargs[0] = "sh";
  sendargs[1] = "-c";

  if (!stralloc_copys(&line,auto_cron)) die_nomem();
  if (!stralloc_cats(&line,"/crontab '")) die_nomem();
  if (!stralloc_cats(&line,dir.s)) die_nomem();
  if (!stralloc_cats(&line,"/crontab'")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  sendargs[2] = line.s;
  sendargs[3] = 0;
  if ((child = wrap_fork()) == 0) {
    if (setreuid(euid,euid) == -1)
      strerr_die2sys(100,FATAL,MSG(ERR_SETUID));
    wrap_execvp(sendargs);
  }
  /* parent */
  switch (wrap_waitpid(child)) {
      case 0:
        _exit(0);
      default:
        strerr_die2x(111,FATAL,MSG(ERR_CRONTAB));
  }
}
Exemple #6
0
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);
  }
}
Exemple #7
0
int main(int argc, char **argv)
{
    if (argc != 3 && argc != 4) {
        usage(argv[0]);
        exit(0);
    }
    
    char cfg_file[MAX_LINE] = {0};
    int make_deamon = 0;
    
    int ch;
    const char *args = "c:dh";
    while ((ch = getopt(argc, argv, args)) != -1) {
        switch (ch) {
            case 'c':
                snprintf(cfg_file, sizeof(cfg_file), "%s", optarg);
                break;
            case 'd':
                make_deamon = 1;
                break;
                
            case 'h':
            default:
                usage(argv[0]);
                exit(0);
                break;
        }
    }
    
    if (make_deamon == 1) {
        // create deamon
        create_daemon(config_st.chdir_path);
    }
    
    // init log
    ctlog("ctserver", LOG_PID|LOG_NDELAY, LOG_MAIL);
    
    // read config
    dict_conf = open_config(cfg_file);
    if (dict_conf == NULL) {
        printf("parse config fail");
        return 1;
    }
    if (read_config(dict_conf) != 0) {
        return 1;
    }
    log_level = atoi(config_st.log_level);
    
    if (chdir(config_st.chdir_path) == -1) {
        log_error("can not start: unable to change directory:%s", config_st.chdir_path);
        return 1;
    }
    log_debug("bind_port:%s", config_st.bind_port);
    log_debug("log_level:%s", config_st.log_level);
    log_debug("chdir_path:%s", config_st.chdir_path);
    log_debug("max_childs:%s", config_st.max_childs);
    log_debug("child_prog:%s", config_st.child_prog);
    log_debug("child_cf:%s", config_st.child_cf);
    
    // Get Local Host Name
    char local_hostname[MAX_LINE] = {0};
    if (gethostname(local_hostname, sizeof(local_hostname)) != 0) {
        snprintf(local_hostname, sizeof(local_hostname), "unknown");
    }
    log_debug("local_hostname:%s", local_hostname);
    
    
    // ---------- ----------
    
    childs_st = (struct childs_t *)malloc((atoi(config_st.max_childs) + 1) * sizeof(struct childs_t));
    if (childs_st == NULL) {
        log_error("malloc childs [%d] faild:[%d]:%s", (atoi(config_st.max_childs) + 1), errno, strerror(errno));
        exit(1);
    }
    
    int i = 0;
    for (i=0; i<(atoi(config_st.max_childs) +1); i++) {
        init_child_with_idx(i);
    }
    
    
    // Start Server
    int connfd, epfd, sockfd, n, nread, nwrite;
    struct sockaddr_in local, remote;
    socklen_t addrlen;
    
    
    // Create Listen Socket
    int bind_port = atoi(config_st.bind_port);
    if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        log_error("socket fail:[%d]:%s", errno, strerror(errno));
        exit(1);
    }

	// 设置套接字选项避免地址使用错误,解决: Address already in use
	int on = 1;
    if ((setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
        log_error("setsockopt failed");
        exit(1);
    }
    
    // Set Listen FD Nonblock
    if (set_nonblocking(listen_fd) != 0) {
        exit(1);
    }
    
    bzero(&local, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    local.sin_port = htons(bind_port);
    if (bind(listen_fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
        log_error("bind local %d failed:[%d]%s", bind_port, errno, strerror(errno));
        exit(1);
    }
    log_info("bind local %d succ", bind_port);
    
    if (listen(listen_fd, atoi(config_st.max_childs)) != 0) {
        log_error("listen fd[%d] max_number[%d] failed:[%d]%s", listen_fd, atoi(config_st.max_childs), errno, strerror(errno));
        exit(1);
    }
    
    // Ignore pipe signal
    sig_pipeignore();
    // Catch signal which is child program exit
    sig_catch(SIGCHLD, sigchld_exit);
    
    // epoll create fd
    epoll_event_num = atoi(config_st.max_childs) + 1;
    epoll_evts = NULL;
    epoll_fd = -1;
    epoll_nfds = -1;
    
    int epoll_i = 0;
    
    epoll_evts = (struct epoll_event *)malloc(epoll_event_num * sizeof(struct epoll_event));
    if (epoll_evts == NULL) {
        log_error("malloc for epoll event fail");
        exit(1);
    }
    
    epoll_fd = epoll_create(epoll_event_num);
    if (epoll_fd == -1) {
        log_error("epoll_create max_number[%d] failed:[%d]%s", epoll_event_num, errno, strerror(errno));
        exit(1);
    }
    
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = listen_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
        log_error("epoll_ctl: listen_socket failed:[%d]%s", errno, strerror(errno));
        exit(1);
    }
    
    epoll_num_running = 0;
    
    for (;;) {
        
        epoll_nfds = epoll_wait(epoll_fd, epoll_evts, epoll_event_num, -1);
        
        if (epoll_nfds == -1) {
            if (errno == EINTR) {
                // 收到中断信号
                log_info("epoll_wait recive EINTR signal, continue");
                continue;
            }
            
            exit(1);
        }
        
        log_debug("epoll_num_running:%d nfds:%d", epoll_num_running, epoll_nfds);
        for (epoll_i = 0; epoll_i < epoll_nfds; epoll_i++) {
            sig_childblock();
            
            int evt_fd = epoll_evts[epoll_i].data.fd;
            if (evt_fd == listen_fd) {
                // new connect
                if ((connfd = accept(listen_fd, (struct sockaddr *)&remote, &addrlen)) > 0) {

                    char *ipaddr = inet_ntoa(remote.sin_addr);
                    log_debug("accept client:%s", ipaddr);
                    
                    char greet_buf[MAX_LINE] = {0};
                    
                    // get a new index from child list
                    int i = get_idle_idx_from_childs();
                    if (i == -1) {
                        log_error("get_idle_idx_from_childs_t fail: maybe client queue is full.");
                        
                        // send to client error information
                        n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END);
                        nwrite = write(connfd, greet_buf, n);
                        log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf);
                        
                        continue;
                    }
                    childs_st[i].used = 1;
                    
                    // get client ip and port.
                    struct sockaddr_in sa;
                    int len = sizeof(sa);
                    if (!getpeername(connfd, (struct sockaddr *)&sa, &len)) {
                        n = snprintf(childs_st[i].client_info.ip, sizeof(childs_st[i].client_info.ip), "%s", inet_ntoa(sa.sin_addr));
                        n = snprintf(childs_st[i].client_info.port, sizeof(childs_st[i].client_info.port), "%d", ntohs(sa.sin_port));
                        log_info("accept client:%s:%s", childs_st[i].client_info.ip, childs_st[i].client_info.port);
                    }
                    
                    
                    int pi1[2];
                    int pi2[2];
                    if (pipe(pi1) == -1) {
                        log_error("unable to create pipe:[%d]%s", errno, strerror(errno));
                        
                        // send to client error information
                        n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END);
                        nwrite = write(connfd, greet_buf, n);
                        log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf);
                        
                        continue;
                    }
                    if (pipe(pi2) == -1) {
                        log_error("unable to create pipe:[%d]%s", errno, strerror(errno));
                        
                        close(pi1[0]);
                        close(pi1[1]);
                        pi1[0] = -1;
                        pi1[1] = -1;
                        
                        // send to client error information
                        n = snprintf(greet_buf, sizeof(greet_buf), "%s ERR %s%s", FAIL_CODE, local_hostname, DATA_END);
                        nwrite = write(connfd, greet_buf, n);
                        log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf);
                        
                        continue;
                    }
                    log_debug("create pi1[0]:%d pi1[1]:%d", pi1[0], pi1[1]);
                    log_debug("create pi2[0]:%d pi2[1]:%d", pi2[0], pi2[1]);
                    
                    // create unique id
                    n = create_unique_id(childs_st[i].sid, sizeof(childs_st[i].sid));
                    if (n != 16) {
                        log_error("create unique id fail");
                        
                        close(pi1[0]);
                        close(pi1[1]);
                        close(pi2[0]);
                        close(pi2[1]);
                        
                        // send to client error information
                        n = snprintf(greet_buf, sizeof(greet_buf), "%s SYSTEM ERR %s%s", FAIL_CODE, local_hostname, DATA_END);
                        nwrite = write(connfd, greet_buf, n);
                        log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf);
                        
                        continue;
                    }
                    log_debug("create mid:%s", childs_st[i].sid);
                    
                    // 当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程
                    fcntl(pi1[1], F_SETFD, FD_CLOEXEC);
                    fcntl(pi2[0], F_SETFD, FD_CLOEXEC);
                    fcntl(listen_fd, F_SETFD, FD_CLOEXEC);
                    
                    
                    int f = fork();
                    if (f < 0) {
                        log_error("fork fail:[%d]%s", errno, strerror(errno));
                        
                        close(pi1[0]);
                        close(pi1[1]);
                        pi1[0] = -1;
                        pi1[1] = -1;
                        
                        close(pi2[0]);
                        close(pi2[1]);
                        pi2[0] = -1;
                        pi2[1] = -1;
                        
                        // send to client error information
                        n = snprintf(greet_buf, sizeof(greet_buf), "%s SYSTEM ERR %s%s", FAIL_CODE, local_hostname, DATA_END);
                        nwrite = write(connfd, greet_buf, n);
                        log_debug("send client fd[%d]:[%d]%s", connfd, nwrite, greet_buf);
                        
                        continue;
                    
                    } else if (f == 0) {
                        // 子进程
                        close(pi1[1]);
                        close(pi2[0]);
                        pi1[1] = -1;
                        pi2[0] = -1;
                        
                        close(listen_fd);
                        listen_fd = -1;
                        
                        if (fd_move(2, connfd) == -1) {
                            log_error("%s fd_move(2, %d) failed:[%d]%s", childs_st[i].sid, connfd, errno, strerror(errno));
                            _exit(111);
                        }
                        
                        // read from 0
                        if (fd_move(0, pi1[0])) {
                            log_error("%s fd_move(0, %d) failed:[%d]%s", childs_st[i].sid, pi1[0], errno, strerror(errno));
                            _exit(111);
                        }
                        
                        // write to 1
                        if (fd_move(1, pi2[1])) {
                            log_error("%s fd_move(1, %d) failed:[%d]%s", childs_st[i].sid, pi2[1], errno, strerror(errno));
                            _exit(111);
                        }
                        
                        // lunach child program
                        char exe_sid[MAX_LINE] = {0};
                        char exe_cfg[MAX_LINE] = {0};
                        char exe_remote[MAX_LINE] = {0};
                        
                        snprintf(exe_sid, sizeof(exe_sid), "-m%s", childs_st[i].sid);
                        snprintf(exe_cfg, sizeof(exe_cfg), "-c%s", config_st.child_cf);
                        snprintf(exe_remote, sizeof(exe_remote), "-r%s:%s", childs_st[i].client_info.ip, childs_st[i].client_info.port);
                        
                        char *args[5];
                        args[0] = config_st.child_prog;
                        args[1] = exe_sid;
                        args[2] = exe_cfg;
                        args[3] = exe_remote;
                        args[4] = 0;
                        
						char log_exec[MAX_LINE*3] = {0};
						char *plog_exec = log_exec;
						int len = 0;
						int i=0;
						while (args[i] != 0) {
							int n = snprintf(plog_exec + len, sizeof(log_exec) - len, "%s ", args[i]);
							len += n;	
							i++;
						}

                        log_info("Exec:[%s]", log_exec);
                        
                        if (execvp(*args, args) == -1) {
                            log_error("execvp fail:[%d]%s", errno, strerror(errno));
                            _exit(111);
                        }
                        
                        _exit(100);
                        
                    }
                    
                    // 父进程
                    log_debug("add child index:%d pid:%lu", i, f);
                    childs_st[i].pid = f;
                    
                    close(pi1[0]);
                    close(pi2[1]);
                    pi1[0] = -1;
                    pi2[1] = -1;
                    
                    close(connfd);
                    connfd = -1;
                    
                    childs_st[i].pfd_r = pi2[0];
                    childs_st[i].pfd_w = pi1[1];
                    
                    if (set_nonblocking(childs_st[i].pfd_r)) {
                        log_error("set nonblocking fd[%d] fail", childs_st[i].pfd_r);
                    }
                    
                    struct epoll_event pipe_r_ev;
                    pipe_r_ev.events = EPOLLIN | EPOLLET;
                    pipe_r_ev.data.fd = childs_st[i].pfd_r;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_r_ev.data.fd, &pipe_r_ev) == -1) {
                        log_error("epoll_ctl client fd[%d] EPOLL_CTL_ADD failed:[%d]%s", pipe_r_ev.data.fd, errno, strerror(errno));
                    }
                    log_debug("epoll_add fd[%d]", pipe_r_ev.data.fd);
                    
                    epoll_num_running++;
                    
                } else if (connfd == -1) {
                    if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) {
                        log_error("accept failed:[%d]%s", errno, strerror(errno));
                    }
                    
                    continue;
                }
                
            } else if (epoll_evts[epoll_i].events & EPOLLIN) {
                // 有可读事件从子进程过来
                int idx = get_idx_with_sockfd(evt_fd);
                if (idx < 0) {
                    log_error("get_idx_with_sockfd(%d) fail, so not process", evt_fd);
                    continue;
                }
                log_debug("%s get event EPOLLIN: epoll_i[%d] fd[%d] get fd[%d], used[%d]", childs_st[idx].sid, epoll_i, epoll_evts[epoll_i].data.fd, childs_st[idx].pfd_r, childs_st[idx].used);
                
                // 读取内容
                char cbuf[MAX_LINE] = {0};
                nread = read(childs_st[idx].pfd_r, cbuf, sizeof(cbuf));
                log_debug("read buf:'[%d]%s' from child", n, cbuf);

                
            } else if ((epoll_evts[epoll_i].events & EPOLLHUP)
                       && (epoll_evts[epoll_i].data.fd != listen_fd)) {
                // 有子进程退出
                int idx = get_idx_with_sockfd(evt_fd);
                if (idx < 0) {
                    log_error("get_idx_with_sockfd(%d) fail, so not process", evt_fd);
                    
                    continue;
                }
                log_debug("%s get event EPOLLHUP: epoll_i[%d] fd[%d] get fd[%d], used[%d]", childs_st[idx].sid, epoll_i, epoll_evts[epoll_i].data.fd, childs_st[idx].pfd_r, childs_st[idx].used);
                
                epoll_delete_evt(epoll_fd, childs_st[idx].pfd_r);
                
                // 子进程清理
                clean_child_with_idx(idx);
                
                continue;
                
            }
            
        }
        
        sig_childunblock();
    }
    
    close(epoll_fd);
    close(listen_fd);
    
    epoll_fd = -1;
    listen_fd = -1;

	if (childs_st != NULL) {
		free(childs_st);
		childs_st = NULL;
	}

	if (epoll_evts != NULL) {
		free(epoll_evts);
		epoll_evts = NULL;
	}
    
    log_info("I'm finish");
    
    return 0;
    
}
Exemple #8
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);
}
Exemple #9
0
int main(int argc, char **argv)
{
	liao_log("liao_server", LOG_PID|LOG_NDELAY, LOG_MAIL);

	if (argc != 3) {
		usage(argv[0]);
		exit(0);
	}

	if (chdir(LIAO_HOME) == -1) {
		log_alert("cannot start: unable to switch to home directory");	
		exit(0);
	}

	snprintf(msg_id, sizeof(msg_id), "00000000");
	
	char cfg_file[MAX_LINE] = CFG_FILE;
	
	int c;
	const char *args = "c:h";
	while ((c = getopt(argc, argv, args)) != -1) {
		switch (c) {
			case 'c':
				snprintf(cfg_file, sizeof(cfg_file), "%s", optarg);
				break;
				
			case 'h':
			default:
				usage(argv[0]);
				exit(0);
		}
	}

	// 处理配置文件 
	if (conf_init(cfg_file)) {
		fprintf(stderr, "Unable to read control files:%s\n", cfg_file);
		log_error("Unable to read control files:%s", cfg_file);
		exit(1);
	}

	/*	
	// 检查队列目录
	if (strlen(config_st.queue_path) <= 0) {
		fprintf(stderr, "Unable to read queue path.\n");
		log_error("Unable to read queue path.");
		exit(1);
	}
	if ( access(config_st.queue_path, F_OK) ) {
		fprintf(stderr, "Queue path:%s not exists:%s, so create it.\n", config_st.queue_path, strerror(errno));	
		log_error("Queue path:%s not exists:%s, so create it.", config_st.queue_path, strerror(errno));	

		umask(0);
		mkdir(config_st.queue_path, 0777);
	}*/
	

	online_d = dictionary_new(atoi(config_st.max_works) + 1);
	

	child_st = (struct childs *)malloc((atoi(config_st.max_works) + 1) * sizeof(struct childs));
	if (!child_st) {
		log_error("malloc childs [%d] failed:[%d]%s", (atoi(config_st.max_works) + 1), errno, strerror(errno));
		exit(1);
	}
	
	int i = 0;
	for (i=0; i<(atoi(config_st.max_works) + 1); i++) {
		child_st[i].used = 0;
		child_st[i].pid = -1;
		child_st[i].client_fd = -1;
		child_st[i].pipe_r_in = -1;
		child_st[i].pipe_r_out = -1;
		child_st[i].pipe_w_in = -1;
		child_st[i].pipe_w_out = -1;
		memset(child_st[i].mid, 0, sizeof(child_st[i].mid));
		child_st[i].mfp_out = NULL;
	}

	// 开始服务
	int connfd, epfd, sockfd, n, nread;
	struct sockaddr_in local, remote;
	socklen_t addrlen;

	// 初始化buffer
	char buf[BUF_SIZE];

	size_t pbuf_len = 0;
	size_t pbuf_size = BUF_SIZE + 1;
	char *pbuf = (char *)calloc(1, pbuf_size);
	if (pbuf == NULL) {
		log_error("calloc fail: size[%d]", pbuf_size);
		exit(1);
	}

	// 创建listen socket
	int bind_port = atoi(config_st.bind_port);
	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		log_error("socket failed:[%d]:%s", errno, strerror(errno));
		exit(1);
	}
	if (setnonblocking(listenfd) > 0) {
		exit(1);
	}

	bzero(&local, sizeof(local));
	local.sin_family = AF_INET;
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_port = htons(bind_port);
	if (bind(listenfd, (struct sockaddr *)&local, sizeof(local)) < 0) {
		log_error("bind local %d failed:[%d]%s", bind_port, errno, strerror(errno));
		exit(1);
	}
	log_info("bind local %d succ", bind_port);

	if (listen(listenfd, atoi(config_st.max_works)) != 0) {
		log_error("listen fd[%d] max_number[%d] failed:[%d]%s", listenfd, atoi(config_st.max_works), errno, strerror(errno));
		exit(1);
	}
	
	// 忽略pipe信号 
	sig_pipeignore();
	// 捕抓子进程退出信号
	sig_catch(SIGCHLD, sigchld);

	// epoll create fd
	epoll_event_num = atoi(config_st.max_works) + 1;
	epoll_evts = NULL;
	epoll_fd = -1;
	epoll_nfds = -1;

	int epoll_i = 0;

	epoll_evts = (struct epoll_event *)malloc(epoll_event_num * sizeof(struct epoll_event));
	if (epoll_evts == NULL) {
		log_error("alloc epoll event failed");
    	_exit(111);
    }

	epoll_fd = epoll_create(epoll_event_num);
	if (epoll_fd == -1) {
		log_error("epoll_create max_number[%d] failed:[%d]%s", epoll_event_num, errno, strerror(errno));
		exit(1);
	}

	struct epoll_event ev;
	ev.events = EPOLLIN;
	ev.data.fd = listenfd;
	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
		log_error("epoll_ctl: listen_socket failed:[%d]%s", errno, strerror(errno));
		exit(1);
	}
	epoll_num_running = 1;

	for (;;) {

		epoll_nfds = epoll_wait(epoll_fd, epoll_evts, epoll_event_num, -1);
		
		if (epoll_nfds == -1) {
			if (errno == EINTR)	{
				// 收到中断信号
				log_info("epoll_wait recive EINTR signal, continue");
				continue;
			}

			_exit(111);
		}

		log_debug("epoll_num_running:%d nfds:%d", epoll_num_running, epoll_nfds);
		for (epoll_i = 0; epoll_i < epoll_nfds; epoll_i++) {
			sig_childblock();

			int evt_fd = epoll_evts[epoll_i].data.fd;
			if (evt_fd == listenfd) {
				if ((connfd = accept(listenfd, (struct sockaddr *) &remote, &addrlen)) > 0) {
					char *ipaddr = inet_ntoa(remote.sin_addr);
					log_info("accept client:%s", ipaddr);
					
					char greetting[512] = {0};
					char hostname[1024] = {0};
					if (gethostname(hostname, sizeof(hostname)) != 0) {
						snprintf(hostname, sizeof(hostname), "unknown");
					}

					// 取客户端IP,Port
					char client_ip[20] = {0};
					char client_port[20] = {0};
					struct sockaddr_in sa;
					int len = sizeof(sa);
					if (!getpeername(connfd, (struct sockaddr *)&sa, &len)) {
						snprintf(client_ip, sizeof(client_ip), "%s", inet_ntoa(sa.sin_addr));
						snprintf(client_port, sizeof(client_port), "%d", ntohs(sa.sin_port));
					}

					
					// 取一个新的client
					int i = new_idx_from_child_st();
					if (i == -1) {
						log_error("new_idx_from_client_st fail: maybe client queue is full.");

						// send error
						snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END);
						write(connfd, greetting, strlen(greetting));
						log_debug("send fd[%d]:%s", connfd, greetting);

						continue;		
					}
					child_st[i].used = 1;
					
					int pir[2];
					int piw[2];
					if (pipe(pir) == -1) {
						log_error("unable to create pipe:%s", strerror(errno));
					
						// send error
						snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END);
						write(connfd, greetting, strlen(greetting));
						log_debug("send fd[%d]:%s", connfd, greetting);
						
						continue;
					}
					if (pipe(piw) == -1) {
						log_error("unable to create pipe:%s", strerror(errno));

						close(pir[0]);
						close(pir[1]);
						pir[0] = -1;
						pir[1] = -1;

						// send error
                        snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END);
                        write(connfd, greetting, strlen(greetting));
                        log_debug("send fd[%d]:%s", connfd, greetting);

                        continue;
					}
					log_debug("create pir[0]:%d pir[1]:%d", pir[0], pir[1]);
					log_debug("create piw[0]:%d piw[1]:%d", piw[0], piw[1]);
					
					
					// 当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程
					//fcntl(pir[0], F_SETFD, FD_CLOEXEC);			
					//fcntl(piw[1], F_SETFD, FD_CLOEXEC);			

					int f = fork();
					if (f < 0) {
						log_error("fork fail:%s", strerror(errno));

						close(pir[0]);
						close(pir[1]);
						pir[0] = -1;
						pir[1] = -1;

						close(piw[0]);
						close(piw[1]);
						piw[0] = -1;
						piw[1] = -1;
						
						child_st[i].used = 0;

						// send error
                        snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END);
                        write(connfd, greetting, strlen(greetting));
                        log_debug("send fd[%d]:%s", connfd, greetting);

                        continue;
					}

					struct timeval tm;
					gettimeofday(&tm, NULL);
					snprintf(child_st[i].mid, sizeof(child_st[i].mid), "%05u%u", (uint32_t)tm.tv_usec, (uint32_t)f);
					snprintf(msg_id, sizeof(msg_id), "%s", child_st[i].mid);

					if (f == 0) {
						// 子进程
						close(pir[0]);
						close(piw[1]);
						close(listenfd);

						char _cmid[512] = {0};
						char _cchild_st[512] = {0};
						char _ccip[20] = {0};
						char _ccport[20] = {0};

						snprintf(_cmid, sizeof(_cmid), "-m%s", child_st[i].mid);
						snprintf(_cchild_st, sizeof(_cchild_st), "-c%s", config_st.child_cf);
						snprintf(_ccip, sizeof(_ccip), "-i%s", client_ip);
						snprintf(_ccport, sizeof(_ccport), "-p%s", client_port);

						char *args[6];
						args[0] = "./liao_command";
						args[1] = _cmid;
						args[2] = _cchild_st;
						args[3] = _ccip;
						args[4] = _ccport;
						args[5] = 0;

						if (fd_move(0, connfd) == -1) {
							log_info("%s fd_move(0, %d) failed:%d %s", child_st[i].mid, connfd, errno, strerror(errno));
							_exit(111);
						}

						if (fd_move(1, pir[1]) == -1) {
							log_info("%s fd_move(pipe_w, %d) failed:%d %s", child_st[i].mid, pir[1], errno, strerror(errno));
							_exit(111);
						}
						if (fd_move(2, piw[0]) == -1) {
							log_info("%s fd_move(pipe_r, %d) failed:%d %s", child_st[i].mid, piw[0], errno, strerror(errno));
							_exit(111);
						}

						if (execvp(*args, args) == -1) {
							log_error("execp fail:%s", strerror(errno));
							_exit(111);
						}
						//if (error_temp(errno))
						//	_exit(111);
						log_debug("execp succ");
						_exit(100);							

					}

					close(connfd);
			
					child_st[i].pipe_r_in = pir[0];
					close(pir[1]);
					pir[1] = -1;
					child_st[i].pipe_r_out = -1;

					child_st[i].pipe_w_out = piw[1];
					close(piw[0]);
					piw[0] = -1;
					child_st[i].pipe_w_in = -1;


					child_st[i].pid = f;

					
					if (setnonblocking(child_st[i].pipe_r_in) != 0) {
						log_error("setnonblocking fd[%d] failed", child_st[i].pipe_r_in);
					}

					
					struct epoll_event pipe_in_ev;
					pipe_in_ev.events = EPOLLIN | EPOLLET;	
					pipe_in_ev.data.fd = child_st[i].pipe_r_in;
					if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_in_ev.data.fd, &pipe_in_ev) == -1) {
						log_error("epoll_ctl client fd[%d] EPOLL_CTL_ADD failed:[%d]%s", pipe_in_ev.data.fd, errno, strerror(errno));
					}
					log_debug("epoll_add fd[%d]", pipe_in_ev.data.fd);

					

				} else if (connfd == -1) {
					if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) {
						log_error("accept failed:[%d]%s", errno, strerror(errno));
					}

					continue;
				}

			} else if (epoll_evts[epoll_i].events & EPOLLIN) {
				
				int ci = get_idx_with_sockfd(evt_fd);
				if (ci < 0) {
					log_error("socket fd[%d] get_idx_with_sockfd fail", evt_fd);
					continue;
				}	
				log_debug("%s get event EPOLLIN: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used);

				// 读取内容 ----------------------
				char inbuf[BUF_SIZE] = {0};
				char *pinbuf = inbuf;
				int inbuf_size = BUF_SIZE;
				int inbuf_len = 0;
				char ch;
				
				
				do {
					i = 0;
					nread = read(child_st[ci].pipe_r_in, inbuf, inbuf_size);
					log_debug("%s read from liao_command:[%d]", child_st[ci].mid, nread);

					if (nread == -1) {
						// read error on a readable pipe? be serious
						//log_error("it is failed from fd[%d] read. error:%d %s", child_st[ci].fd_in, errno, strerror(errno));
						//log_debug("it is failed from fd[%d] read. error:%d %s", child_st[ci].pipe_r_in, errno, strerror(errno));
						break;

					} else if (nread > 0) {
						if (child_st[ci].mfp_out == NULL) {
							child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL);
							if (child_st[ci].mfp_out == NULL) {
								log_debug("%s mopen for body fail", child_st[ci].mid);
								break;
							}
						}	

						while (i < nread) {	
							ch = inbuf[i];	
							
							if ((inbuf_size - inbuf_len) < 2) {
								int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len);
								if (r == 0) {
									log_error("%s fast_write fail", child_st[ci].mid);
									break;
								}	

								memset(inbuf, 0, inbuf_size);
								inbuf_len = 0;
							}	

							mybyte_copy(pinbuf + inbuf_len, 1, &ch);
							inbuf_len++;	

							if (ch == '\n') {
								if (inbuf_len > 0) {
									int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len);
									if (r == 0) {
										log_error("%s fast_write fail", child_st[ci].mid);
										break;
									}

									memset(inbuf, 0, inbuf_size);
									inbuf_len = 0;
								}
								
								// 处理当前指令
								// ...
								process_system(&child_st[ci]);
								// ...
								
								// 处理完成后
								if (child_st[ci].mfp_out != NULL) {
									mclose(child_st[ci].mfp_out);
									child_st[ci].mfp_out = NULL;
									
									child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL);
									if (child_st[ci].mfp_out == NULL) {
										log_error("mopen fail for mfp_out");
										break;
									}
								}
								
								pinbuf = inbuf + 0;
							}

							i++;
						}
						
						
					} else {
						break;
					}

				} while (1);	


			} else if ((epoll_evts[epoll_i].events & EPOLLHUP) && (epoll_evts[epoll_i].data.fd != listenfd)) {

				int ci = get_idx_with_sockfd(evt_fd);
				if ( ci < 0 ) {
					log_error("get_idx_with_sockfd(%d) fail, so not write", evt_fd);

					continue;
				}
				log_debug("%s get event EPOLLHUP: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used);

				epoll_delete_evt(epoll_fd, child_st[ci].pipe_r_in);

				continue;

			}


		}
		sig_childunblock();

	}

	close(epoll_fd);
	close(listenfd);

	log_info("i'm finish");
    
	return 0;
}
Exemple #10
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 #11
0
void main(int argc,char **argv)
{
  char *dir;
  char *action;
  char *dtline;
  char *nhost;
  const char *err;
  unsigned int i;
  int match;
  int opt;

  sig_pipeignore();

  while ((opt = getopt(argc,argv,"dDvV")) != opteof) {
    switch (opt) {
    case 'd': flagdo = 1; break;
    case 'D': flagdo = 0; break;
    case 'v':
    case 'V':
      strerr_die2x(0, "ezmlm-split version: ",auto_version);
    default:
      die_usage();
    }
  }

  startup(dir = argv[optind++]);
  load_config(dir);
  if (!(split = argv[optind]))
    split = "split";

  if (flagdo) {
    sender = env_get("SENDER");
    if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
    if (!*sender)
      strerr_die2x(100,FATAL,ERR_BOUNCE);
    if (!sender[str_chr(sender,'@')])
      strerr_die2x(100,FATAL,ERR_ANONYMOUS);
    if (str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,ERR_BOUNCE);

    action = env_get("DEFAULT");
    if (!action) strerr_die2x(100,FATAL,ERR_NODEFAULT);
    if (!stralloc_copys(&target,sender)) die_nomem();
    if (action[0]) {
      i = str_chr(action,'-');
      if (action[i]) {
        action[i] = '\0';
        if (!stralloc_copys(&target,action + i + 1)) die_nomem();
        i = byte_rchr(target.s,target.len,'=');
        if (i < target.len)
	  target.s[i] = '@';
      }
    }
    if (!stralloc_0(&target)) die_nomem();

    if (case_diffs(action,ACTION_SUBSCRIBE) &&
      case_diffs(action,ALT_SUBSCRIBE) &&
      case_diffs(action,ACTION_UNSUBSCRIBE) &&
      case_diffs(action,ALT_UNSUBSCRIBE))
    _exit(0);			/* not for us */

    if (findname()) {
				/* new sender */
      if (!stralloc_copy(&from,&outlocal)) die_nomem();
      if (!stralloc_cats(&from,"-return-@")) die_nomem();
      if (!stralloc_cat(&from,&outhost)) die_nomem();
      if (!stralloc_0(&from)) die_nomem();
      nhost = name.s + str_rchr(name.s,'@');		/* name must have '@'*/
      *(nhost++) = '\0';
      if (!stralloc_copys(&to,name.s)) die_nomem();	/* local */
      if (!stralloc_append(&to,"-")) die_nomem();	/* - */
      if (!stralloc_cats(&to,action)) die_nomem();	/* subscribe */
      if (!stralloc_append(&to,"-")) die_nomem();	/* - */
      if (target.s[i = str_rchr(target.s,'@')])
	target.s[i] = '=';
      if (!stralloc_cats(&to,target.s)) die_nomem();	/* target */
      if (!stralloc_append(&to,"@")) die_nomem();	/* - */
      if (!stralloc_cats(&to,nhost)) die_nomem();	/* host */
      if (!stralloc_0(&to)) die_nomem();
      dtline = env_get("DTLINE");
      if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE);

      if (qmail_open(&qq,(stralloc *) 0) == -1)
        strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
      qmail_puts(&qq,dtline);				/* delivered-to */
      if (qmail_copy(&qq,subfdin,0) != 0)
        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
      qmail_from(&qq,from.s);
      qmail_to(&qq,to.s);

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

      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die3x(99,INFO,"qp ",strnum);
    }
    _exit(0);
  } else {

    for (;;) {
      if (getln(subfdin,&line,&match,'\n') == -1)
	  strerr_die2sys(111,FATAL,ERR_READ_INPUT);
      if (!match) break;
      if (line.len == 1) continue;	/* ignore blank lines */
      if (line.s[0] == '#') continue;	/* ignore comments */
      if (!stralloc_copy(&target,&line)) die_nomem();
      target.s[target.len - 1] = '\0';
      (void) findname();
      if (!stralloc_cats(&name,": ")) die_nomem();
      if (!stralloc_cats(&name,target.s)) die_nomem();
      if (!stralloc_append(&name,"\n")) die_nomem();
      if (substdio_put(subfdout,name.s,name.len) == -1)
	strerr_die2sys(111,ERR_WRITE,"output: ");
    }
    if (substdio_flush(subfdout) == -1)
      strerr_die2sys(111,ERR_FLUSH,"output: ");
    _exit(0);
  }
  (void)argc;
}
Exemple #12
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);
}
Exemple #13
0
int main(int argc,char **argv)
{
  char strnum[FMT_ULONG];
  char *action;
  char *dtline;
  char *nhost;
  const char *err;
  unsigned int i;
  int match;
  int opt;

  sig_pipeignore();

  opt = getconfopt(argc,argv,options,1,0);
  if (!(split = argv[opt]))
    split = "split";

  if (flagdo) {
    sender = get_sender();
    if (!sender) die_sender();
    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 = env_get("DEFAULT");
    if (!action) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT));
    if (!stralloc_copys(&target,sender)) die_nomem();
    if (action[0]) {
      i = str_chr(action,'-');
      if (action[i]) {
        action[i] = '\0';
        if (!stralloc_copys(&target,action + i + 1)) die_nomem();
        i = byte_rchr(target.s,target.len,'=');
        if (i < target.len)
	  target.s[i] = '@';
      }
    }
    if (!stralloc_0(&target)) die_nomem();

    if (case_diffs(action,ACTION_SUBSCRIBE) &&
      case_diffs(action,ALT_SUBSCRIBE) &&
      case_diffs(action,ACTION_UNSUBSCRIBE) &&
      case_diffs(action,ALT_UNSUBSCRIBE))
    _exit(0);			/* not for us */

    if (findname()) {
				/* new sender */
      if (!stralloc_copy(&from,&outlocal)) die_nomem();
      if (!stralloc_cats(&from,"-return-@")) die_nomem();
      if (!stralloc_cat(&from,&outhost)) die_nomem();
      if (!stralloc_0(&from)) die_nomem();
      nhost = name.s + str_rchr(name.s,'@');		/* name must have '@'*/
      *(nhost++) = '\0';
      if (!stralloc_copys(&to,name.s)) die_nomem();	/* local */
      if (!stralloc_append(&to,'-')) die_nomem();	/* - */
      if (!stralloc_cats(&to,action)) die_nomem();	/* subscribe */
      if (!stralloc_append(&to,'-')) die_nomem();	/* - */
      if (target.s[i = str_rchr(target.s,'@')])
	target.s[i] = '=';
      if (!stralloc_cats(&to,target.s)) die_nomem();	/* target */
      if (!stralloc_append(&to,'@')) die_nomem();	/* - */
      if (!stralloc_cats(&to,nhost)) die_nomem();	/* host */
      if (!stralloc_0(&to)) die_nomem();
      dtline = env_get("DTLINE");
      if (!dtline) strerr_die2x(100,FATAL,MSG(ERR_NODTLINE));

      if (qmail_open(&qq) == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));
      qmail_puts(&qq,dtline);				/* delivered-to */
      if (qmail_copy(&qq,subfdin,0) != 0)
        strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      qmail_from(&qq,from.s);
      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_die3x(99,INFO,"qp ",strnum);
    }
    _exit(0);
  } else {

    for (;;) {
      if (getln(subfdin,&line,&match,'\n') == -1)
	  strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      if (!match) break;
      if (line.len == 1) continue;	/* ignore blank lines */
      if (line.s[0] == '#') continue;	/* ignore comments */
      if (!stralloc_copy(&target,&line)) die_nomem();
      target.s[target.len - 1] = '\0';
      (void) findname();
      if (!stralloc_cats(&name,": ")) die_nomem();
      if (!stralloc_cats(&name,target.s)) die_nomem();
      if (!stralloc_append(&name,'\n')) die_nomem();
      if (substdio_put(subfdout,name.s,name.len) == -1)
	strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    }
    if (substdio_flush(subfdout) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_FLUSH_STDOUT));
    _exit(0);
  }
  (void)argc;
}
Exemple #14
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);
}
Exemple #15
0
int main(int argc,char *argv[])
//int argc;
//char *argv[];
{
  int dummy;
  char *proto;
  int opt;
  int flagremoteinfo;
  unsigned long timeout;
// struct sockaddr_in *v4;

  sig_pipeignore();

  flagremoteinfo = 1;
  timeout = 30;
  while ((opt = getopt(argc,argv,"rRt:")) != opteof)
    switch(opt)
    {
     case 'r': flagremoteinfo = 1; break;
     case 'R': flagremoteinfo = 0; break;
     case 't': scan_ulong(subgetoptarg,&timeout); break;
    }

  argv += subgetoptind;
  argc -= subgetoptind;

  if (argc < 1) die();
  if (!env_init()) die();

  proto = env_get("PROTO");
  if (!proto || str_diff(proto,"TCP"))
  {
    if (!env_puts("PROTO=TCP")) die();

    dummy = sizeof(salocal);
    if (getsockname(0,(struct sockaddr *) &salocal, (socklen_t *) &dummy) == -1) die();
    mappedtov4(&salocal);
    switch(salocal.sa.sa_family) {
    case AF_INET:
      localport = ntohs(salocal.sa4.sin_port);
      temp[fmt_ulong(temp,localport)] = 0;
    if (!env_put("TCPLOCALPORT",temp)) die();
      temp[ip4_fmt(temp,(char *) &salocal.sa4.sin_addr)] = 0;
    if (!env_put("TCPLOCALIP",temp)) die();

    switch(dns_ptr(&localname,&salocal.sa4.sin_addr)) {
      case DNS_MEM: die();
      case DNS_SOFT:
        if (!stralloc_copys(&localname,"softdnserror")) die();
      case 0:
        if (!stralloc_0(&localname)) die();
        case_lowers(localname.s);
        if (!env_put("TCPLOCALHOST",localname.s)) die();
        break;
      default:
        if (!env_unset("TCPLOCALHOST")) die();
    }
    break;
#ifdef INET6
    case AF_INET6:
      localport = ntohs(salocal.sa6.sin6_port);
      temp[fmt_ulong(temp,localport)] = 0;
      if (!env_put("TCPLOCALPORT",temp)) die();
      temp[ip6_fmt(temp,(char *) &salocal.sa6.sin6_addr)] = 0;
      if (!env_put("TCPLOCALIP",temp)) die();
      switch(dns_ptr6(&localname,&salocal.sa6.sin6_addr)) {
        case DNS_MEM: die();
        case DNS_SOFT:
             if (!stralloc_copys(&localname,"softdnserror")) die();
        case 0:
             if (!stralloc_0(&localname)) die();
          case_lowers(localname.s);
          if (!env_put("TCPLOCALHOST",localname.s)) die();
          break;
        default:
             if (!env_unset("TCPLOCALHOST")) die();
      }
      break;
#endif
    default:
      die();
    }

    dummy = sizeof(saremote);
    if (getpeername(0,(struct sockaddr *) &saremote, (socklen_t *) &dummy) == -1) die();
      mappedtov4(&saremote);

    switch(saremote.sa.sa_family) {
    case AF_INET:
      remoteport = ntohs(saremote.sa4.sin_port);
      temp[fmt_ulong(temp,remoteport)] = 0;
    if (!env_put("TCPREMOTEPORT",temp)) die();

    temp[ip4_fmt(temp,(char *)&saremote.sa4.sin_addr)] = 0;
    if (!env_put("TCPREMOTEIP",temp)) die();

    switch(dns_ptr(&remotename,&saremote.sa4.sin_addr)) {
    case DNS_MEM: die();
    case DNS_SOFT:
      if (!stralloc_copys(&remotename,"softdnserror")) die();
    case 0:
      if (!stralloc_0(&remotename)) die();
      case_lowers(remotename.s);
      if (!env_put("TCPREMOTEHOST",remotename.s)) die();
      break;
    default:
      if (!env_unset("TCPREMOTEHOST")) die();
    }
    break;
#ifdef INET6
    case AF_INET6:
    remoteport = ntohs(saremote.sa6.sin6_port);
      temp[fmt_ulong(temp,remoteport)] = 0;
    if (!env_put("TCPREMOTEPORT",temp)) die();
    temp[ip6_fmt(temp,(char *) &saremote.sa6.sin6_addr)] = 0;
    if (!env_put("TCPREMOTEIP",temp)) die();
    switch(dns_ptr6(&remotename,&saremote.sa6.sin6_addr)) {
     case DNS_MEM: die();
     case DNS_SOFT:
       if (!stralloc_copys(&remotename,"softdnserror")) die();
     case 0:
       if (!stralloc_0(&remotename)) die();
       case_lowers(remotename.s);
       if (!env_put("TCPREMOTEHOST",remotename.s)) die();
       break;
     default:
       if (!env_unset("TCPREMOTEHOST")) die();
    }
    break;
#endif
    default:
      die();
    }

    if (!env_unset("TCPREMOTEINFO")) die();

    if (flagremoteinfo)
    {
      char *rinfo;
      rinfo = remoteinfo_get(&saremote, &salocal,(int) timeout);
      if (rinfo)
        if (!env_put("TCPREMOTEINFO",rinfo)) die();
    }
  }

  sig_pipedefault();
  execvp(*argv,argv);
  die();
  return(0);  /* never reached */
}
Exemple #16
0
int main(int argc,char **argv)
{
  unsigned long max;
  int fd;
  int fdlock;
  msgentry *msgtable;
  subentry *subtable;
  authentry *authtable;
  dateentry *datetable;

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

  getconfopt(argc,argv,options,1,0);
  if (flagsyncall)
    flagsync = 1;
  else if (flagcreate)
    flagsync = 0;
  archnum = (archnum / 100) * 100;

	/* Lock list to assure that no ezmlm-send is working on it */
	/* and that the "num" message is final */
  fdlock = lockfile("lock");
					/* get num */
  if (!getconf_ulong(&max,"num",0)
      || max == 0)
    strerr_die1x(100,MSG(ERR_EMPTY_LIST));
  (void) close(fdlock);

  if (!optto || optto > max) optto = max;

  fdlock = lockfile("archive/lock");	/* lock index */
  if (!flagcreate && !archnum) {	/* adjust archnum (from) / to */
    if (getconf_ulong(&archnum,"archnum",0))
      ++archnum;
    else
      archnum = 0;
  }

  if (archnum > optto)
    _exit(0);				/* nothing to do */

  if (mkdir("archive/threads",0755) == -1)
    if (errno != error_exist)
      strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/threads"));
  if (mkdir("archive/subjects",0755) == -1)
    if (errno != error_exist)
      strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/subjects"));
  if (mkdir("archive/authors",0755) == -1)
    if (errno != error_exist)
      strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archive/authors"));

					/* do the subject threading */
  idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,archnum,optto,max,0);
					/* update the index */
  write_threads(msgtable,subtable,authtable,datetable,archnum,optto);
					/* update archnum */
  if ((fd = open_trunc("archnumn")) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_CREATE,"archnumn"));
  substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
  if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,optto)) == -1)
     strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn.s));
  if (substdio_puts(&ssnum,"\n") == -1)
     strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fnn.s));
  close_proper(&ssnum,"archnum","archnumn");
  switch (flagerror) {
    case 0:
       _exit(0);				/* go bye-bye */
    case -1:
       strerr_die2x(99,WARNING,"threads entry with illegal format");
    case -2:
       strerr_die2x(99,WARNING,"thread in index, but threadfile missing");
    case -3:
       strerr_die2x(99,WARNING,"a subject file lacks subject");
    case -4:
       strerr_die2x(99,WARNING,"an author file lacks author/hash");
    case -5:
       strerr_die2x(99,WARNING,"threads entry lacks message count");
    default:
       strerr_die2x(99,WARNING,"something happened that isn't quite right");
  }
}