Exemplo n.º 1
0
int
qldap_get_mailstore(qldap *q, stralloc *hd, stralloc *ms)
{
	int	r;
	/* 
	 * get and check the mailstores.
	 * Both homedir and maildir are set from the three
	 * values ~control/ldapmessagestore, homedirectory
	 * and mailmessagestore.
	 * ms is only filled with a value if both homedir
	 * and maildir is used.
	 */
	r = qldap_get_attr(q, LDAP_HOMEDIR, hd, SINGLE_VALUE);
	if (r == NOSUCH) {
		if (!stralloc_copys(hd, "")) return ERRNO;
	} else if (r != OK)
		return r;
	if (0 < hd->len) {
		if (hd->s[0] != '/' || check_paths(hd->s) == 0) {
			/* probably some log warning would be good */
			return ILLVAL;
		}
	}
	
	r = qldap_get_attr(q, LDAP_MAILSTORE, ms, SINGLE_VALUE);
	if (r == NOSUCH) {
		if (!stralloc_copys(ms, "")) return ERRNO;
	} else if (r != OK)
		return r;
	if (ms->len > 0)
		if (check_paths(ms->s) == 0) {
			/* probably some log warning would be good */
			return ILLVAL;
		}
	
	if (hd->len > 0 && ms->len > 0) return OK;
	if (hd->len > 0) return OK;
	if (ms->len > 0) {
		if (ms->s[0] != '/') {
			if (default_messagestore.s == 0 ||
			    default_messagestore.len == 0)
				return ILLVAL;
			if (!stralloc_cat(hd, &default_messagestore))
				return ERRNO;
		}
		if (!stralloc_cat(hd, ms))
			return ERRNO;
		if (!stralloc_copys(ms, "")) return ERRNO;
		return OK;
	}
	return NEEDED;
}
Exemplo n.º 2
0
/* Searches the subscriber log and outputs via subwrite(s,len) any entry
 * that matches search. A '_' is search is a wildcard. Any other
 * non-alphanum/'.' char is replaced by a '_'. */
void sub_sql_searchlog(struct subdbinfo *info,
		       const char *table,
		       char *search,		/* search string */
		       int subwrite())		/* output fxn */
{
  void *result;
  datetime_sec when;
  struct datetime dt;
  char date[DATE822FMT];
  int nparams;
  char strnum[FMT_ULONG];

  make_name(info,table?"_":0,table,0);
/* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address   */
/* LIKE '%search%' ORDER BY tai; */
/* The '*' is formatted to look like the output of the non-mysql version */
/* This requires reading the entire table, since search fields are not   */
/* indexed, but this is a rare query and time is not of the essence.     */

  stralloc_copys(&query,"SELECT ");
  stralloc_cats(&query,sql_searchlog_select_defn);
  stralloc_cats(&query," FROM ");
  stralloc_cat(&query,&name);
  stralloc_cats(&query,"_slog");
  if (*search) {	/* We can afford to wait for LIKE '%xx%' */
    stralloc_copys(&params[0],search);
    stralloc_copys(&params[1],search);
    nparams = 2;
    stralloc_cats(&query," WHERE ");
    stralloc_cats(&query,sql_searchlog_where_defn);
  }
  else
    nparams = 0;
  /* ordering by tai which is an index */
  stralloc_cats(&query," ORDER by tai");

  result = sql_select(info,&query,nparams,params);
  while (sql_fetch_row(info,result,2,params)) {
    stralloc_0(&params[0]);
    (void)scan_ulong(params[0].s,&when);
    datetime_tai(&dt,when);
    stralloc_copyb(&params[0],date,date822fmt(date,&dt)-1);
    stralloc_cats(&params[0],": ");
    stralloc_catb(&params[0],strnum,fmt_ulong(strnum,when));
    stralloc_cats(&params[0]," ");
    stralloc_cat(&params[0],&params[1]);
    if (subwrite(params[0].s,params[0].len) == -1) die_write();
  }
  sql_free_result(info,result);
}
Exemplo n.º 3
0
/* Outputs all addresses in the table through subwrite. subwrite must be
 * a function returning >=0 on success, -1 on error, and taking
 * arguments (char* string, unsigned int length). It will be called once
 * per address and should take care of newline or whatever needed for
 * the output form. */
unsigned long sub_sql_putsubs(struct subdbinfo *info,
			      const char *table,
			      unsigned long hash_lo,
			      unsigned long hash_hi,
			      int subwrite()) /* write function. */
{
  void *result;
  unsigned long no = 0L;
  char strnum[FMT_ULONG];

  stralloc_copyb(&params[0],strnum,fmt_ulong(strnum,hash_lo));
  stralloc_copyb(&params[1],strnum,fmt_ulong(strnum,hash_hi));
  make_name(info,table?"_":0,table,0);

  /* main query */
  stralloc_copys(&query,"SELECT address FROM ");
  stralloc_cat(&query,&name);
  stralloc_cats(&query," WHERE ");
  stralloc_cats(&query,sql_putsubs_where_defn);

  result = sql_select(info,&query,2,params);

  no = 0;
  while (sql_fetch_row(info,result,1,&addr)) {
    if (subwrite(addr.s,addr.len) == -1) die_write();
    no++;					/* count for list-list fxn */
  }
  sql_free_result(info,result);
  return no;
}
Exemplo n.º 4
0
int stralloc_copy(stralloc *x, stralloc *y) {

    if (!x || !y) { errno = EINVAL; return 0; }

    x->len = 0;
    return stralloc_cat(x, y);
}
Exemplo n.º 5
0
/* take an username and create a filename from it by 
   prepending datadir, return it in \0 terminated tmpname */
void create_datafilename(stralloc *tmpname, stralloc *username)
{
  /* create the filename in our datastructure */
  if(!stralloc_copys(tmpname, datadir)) die_nomem();
  if(!stralloc_cats(tmpname, "/")) die_nomem();
  if(!stralloc_cat(tmpname, username)) die_nomem();
  if(!stralloc_0(tmpname)) die_nomem();
}
Exemplo n.º 6
0
void to_owner(void)
{
	stralloc_copy(&owner,&outlocal);
	stralloc_cats(&owner,"-owner@");
	stralloc_cat(&owner,&outhost);
	stralloc_0(&owner);
	qmail_to(&qq,owner.s);
}
Exemplo n.º 7
0
int main(int argc, const char ** argv )
{
    cmd = (char*) *argv++; --argc;
    section = (char*) *argv++; --argc;
    manual = (char*) *argv++; --argc;
    
    stralloc tempCMD1 = {0};
    tempCMD1 = generateSearchCMD( manual,tempCMD1);
    
    int fd[2];
    pipe(fd);
    int status;
    
    pid_t child;
    
    if ( (child = fork() ) < 0 )
    {
        return 0;
    }
    else if( child == 0 )
    {
        dup2(fd[1],1);
        close(fd[0]);
	close(fd[1]);
        system(tempCMD1.s);
        stralloc_free(&tempCMD1);
        exit(255);
    }
    else {
        stralloc tempCMD2 = {0};
        ssize_t nbytes;
        char buff[64];
       

        close(fd[1]);
        while(( nbytes = read(fd[0] , buff , sizeof buff )) > 0 )
        {
            stralloc_catb( &tempCMD2 , buff , nbytes );
        };
        
        stralloc temp = {0};
        stralloc_copys( &temp , cmdCAT );
        stralloc_cat( &temp , &tempCMD2 );
        
        char *t = temp.s;
	
        printManual(t);        
        
        stralloc_free(&tempCMD2);
        stralloc_free(&temp);
    }
     
    close(fd[0]);
    close(fd[1]);
    wait(&status);
    return 0;
}
Exemplo n.º 8
0
int geton(const char *action)
{
  const char *fl;
  int r;
  unsigned int i;
  unsigned char ch;

  fl = get_from(target.s,action);		/* try to match up */
  r = subscribe(workdir,target.s,1,fl,(*action == ACTION_RC[0]) ? "+mod" : "+",-1);
  if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
    strerr_die2x(0,INFO,MSG1(ERR_EXTRA_SUB,target.s));
  switch (r) {
    case 1:
	    qmail_puts(&qq,"List-Unsubscribe: <mailto:");	/*rfc2369 */
	    qmail_put(&qq,outlocal.s,outlocal.len);
	    qmail_puts(&qq,"-unsubscribe-");
		/* url-encode since verptarget is controlled by sender */
		/* note &verptarget ends in '\0', hence len - 1! */
	    for (i = 0; i < verptarget.len - 1; i++) {
	      ch = verptarget.s[i];
	      if (str_chr("\"?;<>&/:%+#",ch) < 10 ||
			 (ch <= ' ') || (ch & 0x80)) {
		urlstr[1] = hex[ch / 16];
	        urlstr[2] = hex[ch & 0xf];
		qmail_put(&qq,urlstr,3);
	      } else {
		qmail_put(&qq,verptarget.s + i, 1);
	      }
	    }
	    qmail_puts(&qq,"@");
	    qmail_put(&qq,outhost.s,outhost.len);	/* safe */
	    qmail_puts(&qq,">\n");
	    hdr_subject(MSG(SUB_WELCOME));
            hdr_ctboundary();
	    stralloc_copy(&confirm,&outlocal);
	    stralloc_cats(&confirm,"-unsubscribe-");
	    stralloc_cats(&confirm,verptarget.s);
	    stralloc_append(&confirm,'@');
	    stralloc_cat(&confirm,&outhost);
	    stralloc_0(&confirm);
	    set_cpconfirm(confirm.s,outlocal.len);	/* for !R in copy */
            copy(&qq,"text/top",flagcd);
            copy_act("text/sub-ok");
            break;
    default:
            if (str_start(action,ACTION_TC))
              strerr_die2x(0,INFO,MSG(ERR_SUB_NOP));
	    hdr_subject(MSG(SUB_SUBSCRIBE_NOP));
            hdr_ctboundary();
            copy(&qq,"text/top",flagcd);
            copy_act("text/sub-nop");
            break;
  }
  return r;
}
Exemplo n.º 9
0
int pathexec_env(const char *s,const char *t)
{
  if (!s) return 1;
  if (!stralloc_copys(&tmp,s)) return 0;
  if (t) {
    if (!stralloc_cats(&tmp,"=")) return 0;
    if (!stralloc_cats(&tmp,t)) return 0;
  }
  if (!stralloc_0(&tmp)) return 0;
  return stralloc_cat(&plus,&tmp);
}
Exemplo n.º 10
0
/* usage: rellink "http://www.nytimes.com/2005/10/06/international/middleeast/06cnd-prexy.html?ex=1129262400&en=30e300dafe83d0fc&ei=5065&partner=MYWAY" downloaded-data.html */
int main(int argc,char* argv[]) {
  char* baseurl;
  char* map,* max,* x;
  struct stat ss;
  static stralloc sa;
  if (argc!=3)
    die(0,"usage: rellink http://base/url downloaded-data.html");
  errmsg_iam("rellink");
  baseurl=argv[1];

  map=mmap_read_stat(argv[2],&ss);
  if (map==0)
    diesys(111,"open \"",argv[2],"\" failed");

  max=map+ss.st_size;
  for (x=map; x<max; ) {
    stralloc tag;
    /* copy non-tag */
    for (; x<max && *x!='<'; ++x)
      if (stralloc_append(&sa,x)==0)
nomem:
	die(111,"out of memory");

    if (x>=max) break;
    stralloc_copys(&tag,"");

    {
      int indq,insq,ok;
      indq=insq=ok=0;
      for (; x<max; ++x) {
	if (*x == '\'') insq^=1; else
	if (*x == '"') indq^=1;
	if (stralloc_append(&tag,x)==0) goto nomem;
	if (*x == '>' && !insq && !indq) { ok=1; ++x; break; }
      }
      if (ok)
	if (mangleurl(&tag,baseurl)==-1) goto nomem;
    }
    if (stralloc_cat(&sa,&tag)==0) goto nomem;
  }
  if (sa.len == ss.st_size && byte_equal(sa.s,ss.st_size,map)) return 0;
  munmap(map,ss.st_size);
  {
    struct utimbuf utb;
    int fd=open(argv[2],O_WRONLY|O_TRUNC,0600);
    if (fd==-1) die(111,"open(\"",argv[2],"\")");
    write(fd,sa.s,sa.len);
    close(fd);
    utb.actime=ss.st_atime;
    utb.modtime=ss.st_mtime;
    utime(argv[2],&utb);
  }
  return 0;
}
Exemplo n.º 11
0
static int _issub(struct subdbinfo *info,
                  const char *table,
                  const char *userhost,
                  stralloc *recorded)
{
    sqlite3_stmt *stmt;
    unsigned int j;
    int res;

    /* SELECT address FROM list WHERE address = 'userhost' AND hash */
    /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
    /* even easier to defeat. Just faking sender to the list name would*/
    /* work. Since sender checks for posts are bogus anyway, I don't */
    /* know if it's worth the cost of the "WHERE ...". */

    if (!stralloc_copys(&addr,userhost)) die_nomem();
    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len) return 0;
    case_lowerb(addr.s + j + 1,addr.len - j - 1);

    if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem();
    if (!stralloc_cat_table(&line,info,table)) die_nomem();
    if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem();
    if (!stralloc_cat(&line,&addr)) die_nomem();
    if (!stralloc_cats(&line,"'")) die_nomem();
    if (!stralloc_0(&line)) die_nomem();

    if ((stmt = _sqlquery(info, &line)) == NULL)	/* select */
        strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

    /* No data returned in QUERY */
    res = sqlite3_step(stmt);
    if (res != SQLITE_ROW)
    {
        if (res != SQLITE_DONE)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        sqlite3_finalize(stmt);
        return 0;
    }

    if (recorded)
    {
        if (!stralloc_copyb(recorded, (const char*)sqlite3_column_text(stmt, 0), sqlite3_column_bytes(stmt, 0)))
            die_nomem();
        if (!stralloc_0(recorded)) die_nomem();
    }

    sqlite3_finalize(stmt);
    return 1;
}
Exemplo n.º 12
0
void makeacthash(stralloc *act)
/* act is expected to be -reject-ddddd.ttttt or -accept-ddddd.ttttt and
 * has to be 0-terminated. */
/* The routine will add .hash@outhost to act. act will NOT be 0-terminated */
{
  int d;

  d = 2 + str_chr(act->s + 1,'-');
  cookie(hash,key.s,key.len,act->s + d,"","a");
  *(act->s + act->len - 1) = '.';	/* we put a '.' Bad, but works */
  if (!stralloc_catb(act,hash,COOKIE)) die_nomem();
  if (!stralloc_cats(act,"@")) die_nomem();
  if (!stralloc_cat(act,&outhost)) die_nomem();
}
Exemplo n.º 13
0
int
filter_start(stralloc *filter)
{
	if (!stralloc_copys(filter, ""))
		return 0;
	if (objectclass.s != (char *)0 && objectclass.len != 0) {
		/* (&(objectclass=...)%searchfilter%) */
		if (!stralloc_copys(filter, "(&(") ||
		    !stralloc_cats(filter, LDAP_OBJECTCLASS) ||
		    !stralloc_cats(filter, "=") ||
		    !stralloc_cat(filter, &objectclass) ||
		    !stralloc_cats(filter, ")"))
			return 0;
	}
	return 1;
}
Exemplo n.º 14
0
int sub_sql_issub(struct subdbinfo *info,
		  const char *table,
		  const char *userhost,
		  stralloc *recorded)
{
  unsigned int j;
  void *result;
  int ret;

  /* SELECT address FROM list WHERE address = 'userhost' AND hash */
  /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
  /* even easier to defeat. Just faking sender to the list name would*/
  /* work. Since sender checks for posts are bogus anyway, I don't */
  /* know if it's worth the cost of the "WHERE ...". */

  make_name(info,table?"_":0,table,0);

  /* Lower-case the domain portion */
  stralloc_copys(&addr,userhost);
  j = byte_rchr(addr.s,addr.len,'@');
  if (j == addr.len)
    return 0;
  case_lowerb(addr.s + j + 1,addr.len - j - 1);

  stralloc_copys(&query,"SELECT address FROM ");
  stralloc_cat(&query,&name);
  stralloc_cats(&query," WHERE ");
  stralloc_cats(&query,sql_issub_where_defn);

  result = sql_select(info,&query,1,&addr);

  if (!sql_fetch_row(info,result,1,&addr))
    ret = 0;
  else {
    /* we need to return the actual address as other dbs may accept
     * user-*@host, but we still want to make sure to send to e.g the
     * correct moderator address. */
    if (recorded != 0) {
      stralloc_copy(recorded,&addr);
      stralloc_0(recorded);
    }
    ret = 1;
  }
  sql_free_result(info,result);
  return ret;
}
Exemplo n.º 15
0
char *
filter_objectclass(char *searchfilter)
{

	if (searchfilter == (char *)0) return 0;
	if (objectclass.s == (char *)0 || objectclass.len == 0)
		return searchfilter;
	/* (&(objectclass=...)%searchfilter%) */
	if (!stralloc_copys(&ocfilter, "(&(") ||
	    !stralloc_cats(&ocfilter, LDAP_OBJECTCLASS) ||
	    !stralloc_cats(&ocfilter, "=") ||
	    !stralloc_cat(&ocfilter, &objectclass) ||
	    !stralloc_cats(&ocfilter, ")") ||
	    !stralloc_cats(&ocfilter, searchfilter) ||
	    !stralloc_cats(&ocfilter, ")") ||
	    !stralloc_0(&ocfilter))
		return 0;
	return ocfilter.s;
}
Exemplo n.º 16
0
int control_readfile(stralloc *sa,char *fn,int flagme)
{
  buffer b;
  int fd;
  int match;

  if (!stralloc_copys(sa,"")) return -1;

  fd = open_read(fn);
  if (fd == -1)
  {
    if (errno == ENOENT)
    {
      if (flagme && meok)
      {
        if (!stralloc_copy(sa,&me)) return -1;
        if (!stralloc_0(sa)) return -1;
        return 1;
      }
      return 0;
    }
    return -1;
  }

  buffer_init(&b,read,fd,inbuf,sizeof(inbuf));

  for (;;)
  {
    if (getln(&b,&line,&match,'\n') == -1) break;
    if (!match && !line.len) { close(fd); return 1; }
    striptrailingwhitespace(&line);
    if (!stralloc_0(&line)) break;
    if (line.s[0])
      if (line.s[0] != '#')
        if (!stralloc_cat(sa,&line)) break;
    if (!match) { close(fd); return 1; }
  }
  close(fd);
  return -1;
}
Exemplo n.º 17
0
void doconfirm(const char *act)
/* This should only be called with valid act for sub/unsub confirms. If act */
/* is not ACTION_[RST]C, it is assumed to be an unsubscribe conf.*/
/* "act" is the first letter of desired confirm request only as STRING! */
{
  strnum[fmt_ulong(strnum,when)] = 0;
  cookie(hash,key.s,key.len-flagdig,strnum,target.s,act);
  stralloc_copy(&confirm,&outlocal);
  stralloc_append(&confirm,'-');
  stralloc_catb(&confirm,act,1);
  stralloc_cats(&confirm,"c.");
  stralloc_cats(&confirm,strnum);
  stralloc_append(&confirm,'.');
  stralloc_catb(&confirm,hash,COOKIE);
  stralloc_append(&confirm,'-');
  stralloc_cats(&confirm,verptarget.s);
  stralloc_append(&confirm,'@');
  stralloc_cat(&confirm,&outhost);
  stralloc_0(&confirm);
  set_cpconfirm(confirm.s,outlocal.len);		/* for copy */
  set_cpaction(act);
  set_cphash(hash);
  set_cpwhen(when);

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

  hdr_subject((*act == ACTION_SC[0]) ? MSG(SUB_USR_SUBSCRIBE)
	      : (*act == ACTION_UC[0]) ? MSG(SUB_USR_UNSUBSCRIBE)
	      : (*act == ACTION_TC[0] || *act == ACTION_RC[0])
	      ? MSG(SUB_MOD_SUBSCRIBE)
	      : MSG(SUB_MOD_UNSUBSCRIBE));
  hdr_ctboundary();
    copy(&qq,"text/top",flagcd);
}
Exemplo n.º 18
0
/* convert a query to a filename mainly by adding slashes instead of 
   dots (this is an abstraction) and removing anything that is not
   a valid in DNS, which means A-Z and '-' */
int query2filename(char *q, stralloc *s)
{
  int i;
  char *p;
  stralloc tmp = { 0 };

  p = q;

  /* XXX: handling of uppercase/lowercase is missing */
  while(*p)
    {
      stralloc_copy(&tmp, s);
      stralloc_copyb(s, "/", 1);
      stralloc_catb(s, p+1, (int) *p);
      /* Clean up string by changing all characters not allowed in
	 dnsnames to '+'. We need to do tis to keep strange meta
	 characters from slipping into syscalls when opening
	 files changing directorys */
      for(i = 1; i < s->len; i++)
	{
	  if(!(((s->s[i] >= 'a') && (s->s[i] <= 'z'))
	       || ((s->s[i] >= 'A') && (s->s[i] <= 'Z'))
	       || ((s->s[i] >= '0') && (s->s[i] <= '9'))
	       || s->s[i] == '-'))
	    {
	      s->s[i] = '+';
	    }
	} 
      stralloc_cat(s, &tmp);
      p += ((int) *p) + 1;
    }

  stralloc_0(s);

  return s->len;
}
Exemplo n.º 19
0
static int mangleurl(stralloc* tag,const char* baseurl) {
  char* x;
  const char* y;
  static stralloc before,arg,after,tmp;
  int found;
  struct stat ss;
  found=0;
  if (stralloc_istag(tag,"a") || stralloc_istag(tag,"link"))
    found=1;
  else if (stralloc_istag(tag,"img") || stralloc_istag(tag,"frame"))
    found=2;
  if (!found) return 0;
  if (extractparam(tag,found==1?"href":"src",&before,&arg,&after)) {
    if (stralloc_starts(&arg,"/") ||
	stralloc_starts(&arg,"http://") ||
	stralloc_starts(&arg,"https://")) {
      canonicalize(&arg,baseurl);
    } else
      return 0;	/* url was already relative */
    if (stralloc_0(&arg)==0) return -1;
    stralloc_chop(&arg);
    x=arg.s+7; if (*x=='/') ++x;
    y=baseurl+7; if (*y=='/') ++y;

    /* now x is something like
      * "www.spiegel.de/img/0,1020,525770,00.jpg"
      * and baseurl is something like
      * "www.spiegel.de/panorama/0,1518,378421,00.html"
      * and we want to change x into "../img/0,1020,525770,00.jpg" */
    if (stat(x,&ss)!=0) return 0;

    for (;;) {
      int i=str_chr(x,'/');
      int j=str_chr(y,'/');
      if (i>0 && i==j && byte_equal(x,i,y)) {
	x+=i+1;
	y+=i+1;
	while (*x=='/') ++x;
	while (*y=='/') ++y;
      } else
	break;
    }
    stralloc_zero(&tmp);
    for (;;) {
      int i=str_chr(y,'/');
      if (y[i]=='/') {
	y+=i+1;
	while (*y=='/') ++y;
	if (stralloc_cats(&tmp,"../")==0) return -1;
      } else
	break;
    }
    {
      int i,needquote;
      for (i=needquote=0; x[i]; ++i)
	if (!isalnum(x[i]) && x[i]!='/' && x[i]!='_' && x[i]!='.') needquote=1;
      if (needquote) {
	if (stralloc_cats(&before,"\"")==0 ||
	    stralloc_cat(&before,&tmp)==0 ||
	    stralloc_cats(&before,x)==0 ||
	    stralloc_cats(&before,"\"")==0) return -1;
      } else
	if (stralloc_cat(&before,&tmp)==0 ||
	    stralloc_cats(&before,x)==0) return -1;
    }
    if (stralloc_cat(&before,&after)==0) return -1;
    if (stralloc_copy(tag,&before)==0) return -1;
  }
  return 0;
}
Exemplo n.º 20
0
static void do_edit(const char *action)
{
  unsigned int i;
  unsigned int len;
  char ch;

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

    subst_nuls(&line);

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

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

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

  } else {	/* -edit only, so output list of editable files */
    hdr_subject(MSG(SUB_EDIT_LIST));
    hdr_ctboundary();
    copy(&qq,"text/top",flagcd);
    copy_act("text/edit-list");
  }
  qmail_puts(&qq,"\n\n");
  copybottom(0);
  qmail_to(&qq,mod.s);
}
Exemplo n.º 21
0
static void do_ed(char *action)
{
  datetime_sec u;
  int flaggoodfield;
  int fd;
  char *x, *y;
  char *cp,*cplast,*cpnext,*cpafter;
  int flagdone;
  unsigned int len;
  const char *fname;
  unsigned int i;

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

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

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

  subst_nuls(&line);

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

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

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

  unlock();
  hdr_subject(MSG1(SUB_EDIT_SUCCESS,fname));
  hdr_ctboundary();
  copy(&qq,"text/top",flagcd);
  copy_act("text/edit-done");
  copybottom(0);
  qmail_to(&qq,sender);		/* not necessarily from mod */
}
Exemplo n.º 22
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);
  }
}
Exemplo n.º 23
0
void copymsg(int fd,char format)
/* Copy archive message "msg" itself from open file handle fd, in "format" */
{
  int match;
  int flaginheader;
  int flagskipblanks;
  int flaggoodfield;

  switch(format) {
    case VIRGIN:
    case NATIVE:
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
           qmail_put(&qq,line.s,line.len);
	   msgsize += line.len;
        } else
           break;
      }
      break;
    case MIME:
    case MIXED:
      flaginheader = 1;
      flaggoodfield = 0;
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
          if (flaginheader) {
            if (line.len == 1) {
              flaginheader = 0;
              flaggoodfield = 1;
            } else if (line.s[0] != ' ' && line.s[0] != '\t') {
              flaggoodfield = 0;
              if (constmap(&digheadersmap,line.s,
			byte_chr(line.s,line.len,':')))
                flaggoodfield = 1;
            }
            if (flaggoodfield) {
              qmail_put(&qq,line.s,line.len);		/* header */
	      msgsize += line.len;
	    }
          } else {
            qmail_put(&qq,line.s,line.len);		/* body */
	    msgsize += line.len;
	  }
        } else
          break;
      }
      break;
    case RFC1153:		/* Not worth optimizing. Rarely used */
      flaginheader = 1;
      flagskipblanks = 1;	/* must skip terminal blanks acc to rfc1153 */
      archtype = ' ';		/* rfc1153 requires ordered headers */
      if (!stralloc_copys(&archblanklines,"")) die_nomem();
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
          if (flaginheader) {
            if (line.len == 1) {
              flaginheader = 0;
              if (archdate.len) {
                qmail_put(&qq,archdate.s,archdate.len);
                archdate.len = 0;
		msgsize += archdate.len;
              }
              if (archto.len) {
                qmail_put(&qq,archto.s,archto.len);
		msgsize += archto.len;
                archto.len = 0;
              }
              if (archfrom.len) {
                qmail_put(&qq,archfrom.s,archfrom.len);
		msgsize += archfrom.len;
                archfrom.len = 0;
              }
              if (archcc.len) {
                qmail_put(&qq,archcc.s,archcc.len);
		msgsize += archcc.len;
                archcc.len = 0;
              }
              if (archsubject.len) {
                qmail_put(&qq,archsubject.s,archsubject.len);
		msgsize += archsubject.len;
                archsubject.len = 0;
              }
              if (archmessageid.len) {
                qmail_put(&qq,archmessageid.s,archmessageid.len);
		msgsize += archmessageid.len;
                archmessageid.len = 0;
              }
              if (archkeywords.len) {
                qmail_put(&qq,archkeywords.s,archkeywords.len);
		msgsize += archkeywords.len;
                archkeywords.len = 0;
              }
              qmail_puts(&qq,"\n");
            } else if (line.s[0] == ' ' || line.s[0] == '\t') {
              switch (archtype) {	/* continuation lines */
                case ' ':
                  break;
                case 'D':
                  if (!stralloc_cat(&archdate,&line)) die_nomem(); break;
                case 'F':
                  if (!stralloc_cat(&archfrom,&line)) die_nomem(); break;
                case 'T':
                  if (!stralloc_cat(&archto,&line)) die_nomem(); break;
                case 'C':
                  if (!stralloc_cat(&archcc,&line)) die_nomem(); break;
                case 'S':
                  if (!stralloc_cat(&archsubject,&line)) die_nomem(); break;
                case 'M':
                  if (!stralloc_cat(&archmessageid,&line)) die_nomem(); break;
                case 'K':
                  if (!stralloc_cat(&archkeywords,&line)) die_nomem(); break;
                default:
                  strerr_die2x(111,FATAL,
                      "Program error: Bad archive header type");
              }
            } else {
              archtype = ' ';
              if (case_startb(line.s,line.len,"cc:")) {
                archtype='C';
                if (!stralloc_copy(&archcc,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"date:")) {
                archtype='D';
                if (!stralloc_copy(&archdate,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"from:")) {
                archtype='F';
                if (!stralloc_copy(&archfrom,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"keywords:")) {
                archtype='K';
                if (!stralloc_copy(&archkeywords,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"message-id:")) {
                archtype='M';
                if (!stralloc_copy(&archmessageid,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"subject:")) {
                archtype='S';
                if (!stralloc_copy(&archsubject,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"to:")) {
                archtype='T';
                if (!stralloc_copy(&archto,&line)) die_nomem();
              }
            }
          } else if (line.len == 1) {
            if (!flagskipblanks)
              if (!stralloc_copys(&archblanklines,"\n")) die_nomem();
          } else {
            if (archblanklines.len) {
              qmail_put(&qq,archblanklines.s,archblanklines.len);
              archblanklines.len = 0;
            }
            flagskipblanks = 0;
            qmail_put(&qq,line.s,line.len);
	    msgsize += line.len;
          }
        } else
          break;
      }
      break;
    default:
      strerr_die2x(100,FATAL,"Program error: bad format in copymsg()");
  }
}
Exemplo n.º 24
0
void sendnotice(const char *d)
/* sends file pointed to by d to the address in the return-path of the  */
/* message. */
{
  unsigned int x,y;
  const char *err;

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

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

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

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

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

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

      if (flagmime)
	hdr_boundary(1);

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

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

     strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
     strerr_warn2("ezmlm-clean: info: qp ",strnum,0);
}
Exemplo n.º 25
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);
}
Exemplo n.º 26
0
void doit(int flagw)
{
  unsigned int i;
  int fd;
  int match;
  int fdhash;
  const char *err;

  fd = open_read(fn.s);
  if (fd == -1) die_read();
  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));

  if (getln(&ssin,&addr,&match,'\0') == -1) die_read();
  if (!match) { close(fd); return; }
  if (!issub(workdir,0,addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; }
  cookie(hash,"",0,"",addr.s,"");
  if (!stralloc_copys(&fnhash,workdir)) die_nomem();
  if (!stralloc_cats(&fnhash,"/bounce/h/")) die_nomem();
  if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
  if (!stralloc_cats(&fnhash,"/h")) die_nomem();
  if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
  if (!stralloc_0(&fnhash)) die_nomem();

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

  hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
  if (listid.len > 0)
    hdr_add2("\nList-ID: ",listid.s,listid.len);
  hdr_datemsgid(now());
  if (flagcd) {
    if (!stralloc_0(&line)) die_nomem();
  }
  hdr_from("-help");
  if (!quote2(&quoted,addr.s)) die_nomem();
  hdr_add2("To: ",quoted.s,quoted.len);
  /* to accomodate transfer-encoding */
  hdr_mime(flagcd ? CTYPE_MULTIPART : CTYPE_TEXT);
  hdr_listsubject1(flagw ? "probe from " : "warning from ");

  if (flagcd) {			/* first part for QP/base64 multipart msg */
    hdr_boundary(0);
    hdr_ctype(CTYPE_TEXT);
    hdr_transferenc();
  } else
    qmail_puts(&qq,"\n");

  copy(&qq,"text/top",flagcd);
  copy(&qq,flagw ? "text/bounce-probe" : "text/bounce-warn",flagcd);

  if (!flagw) {
    if (flagdig)
      copy(&qq,"text/dig-bounce-num",flagcd);
    else
      copy(&qq,"text/bounce-num",flagcd);
    if (!flagcd) {
      fdhash = open_read(fnhash.s);
      if (fdhash == -1) {
        if (errno != error_noent)
          strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
      } else {
        substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf));
        for(;;) {
          if (getln(&sstext,&line,&match,'\n') == -1)
            strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
          if (!match) break;
          code_qput(line.s,line.len);
        }
      }
      close(fdhash);
    } else {
      if (!stralloc_copys(&line,"")) die_nomem();	/* slurp adds! */
      if (slurp(fnhash.s,&line,256) < 0)
        strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
      code_qput(line.s,line.len);
    }
  }

  copy(&qq,"text/bounce-bottom",flagcd);
  if (flagcd) {
    if (flagcd == 'B') {
      encodeB("",0,&line,2);
      qmail_put(&qq,line.s,line.len);	/* flush */
    }
    hdr_boundary(0);
    hdr_ctype(CTYPE_MESSAGE);
    qmail_puts(&qq,"\n");
  }
  if (qmail_copy(&qq,&ssin,copylines) < 0) die_read();
  close(fd);

  if (flagcd)				/* end multipart/mixed */
    hdr_boundary(1);

  strnum[fmt_ulong(strnum,when)] = 0;
  cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W");
  if (!stralloc_copy(&line,&outlocal)) die_nomem();
  if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-"))
	die_nomem();
  if (!stralloc_cats(&line,strnum)) die_nomem();
  if (!stralloc_cats(&line,".")) die_nomem();
  if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
  if (!stralloc_cats(&line,"-")) die_nomem();
  i = str_chr(addr.s,'@');
  if (!stralloc_catb(&line,addr.s,i)) die_nomem();
  if (addr.s[i]) {
    if (!stralloc_cats(&line,"=")) die_nomem();
    if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem();
  }
  if (!stralloc_cats(&line,"@")) die_nomem();
  if (!stralloc_cat(&line,&outhost)) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  qmail_from(&qq,line.s);

  qmail_to(&qq,addr.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_warn2("ezmlm-warn: info: qp ",strnum,0);

  if (!flagw) {
    if (unlink(fnhash.s) == -1)
      if (errno != error_noent)
        strerr_die4sys(111,FATAL,ERR_DELETE,fnhash.s,": ");
  }
  if (unlink(fn.s) == -1)
    strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
}
Exemplo n.º 27
0
const char *parsesql(const char *dir,
		     const char *subdir,
		     struct sqlinfo *info)
/* reads the file dbname/sql, and if the file exists, parses it into the    */
/* components. The string should be host:port:user:pw:db:table.         If  */
/* the file does not exists, returns "". On success returns NULL. On error  */
/* returns error string for temporary error. */
/* Note that myp is static and all pointers point to it.*/
{
  unsigned int j;

  info->db = "ezmlm";

  std_makepath(&fn,dir,subdir,"/sql",0);

		/* host:port:db:table:user:pw:name */
  myp.len = 0;
  switch (slurp(fn.s,&myp,128)) {
	case -1:	if (!stralloc_copys(&ers,ERR_READ)) return ERR_NOMEM;
			if (!stralloc_cat(&ers,&fn)) return ERR_NOMEM;
			if (!stralloc_0(&ers)) return ERR_NOMEM;
			return ers.s;
	case 0: return "";
  }
  if (!stralloc_append(&myp,"\n")) return ERR_NOMEM;
  if (myp.s[j = str_chr(myp.s,'\n')])
    myp.s[j] = '\0';
						/* get connection parameters */
  if (!stralloc_0(&myp)) return ERR_NOMEM;
  info->host = myp.s;
  if (myp.s[j = str_chr(myp.s,':')]) {
    myp.s[j++] = '\0';
    info->port = myp.s + j;
    if (myp.s[j += str_chr(myp.s+j,':')]) {
      myp.s[j++] = '\0';
      info->user = myp.s + j;
      if (myp.s[j += str_chr(myp.s+j,':')]) {
	myp.s[j++] = '\0';
        info->pw = myp.s + j;
	if (myp.s[j += str_chr(myp.s+j,':')]) {
	  myp.s[j++] = '\0';
          info->db = myp.s + j;
	  if (myp.s[j += str_chr(myp.s+j,':')]) {
	    myp.s[j++] = '\0';
	    info->table = myp.s + j;
	  }
	}
      }
    }
  }
  if (info->host && !*info->host)
    info->host = (char *) 0;
  if (info->user && !*info->user)
    info->user = (char *) 0;
  if (info->pw && !*info->pw)
    info->pw = (char *) 0;
  if (info->db && !*info->db)
    info->db = (char *) 0;
  if (!info->table || !*info->table)
    return ERR_NO_TABLE;
  return (char *) 0;
}
Exemplo n.º 28
0
int findname(void)
/* returns 1 if a matching line was found, 0 otherwise. name will contain */
/* the correct list address in either case */
{
  char *cpat,*cp1,*cp2,*cplast;
  const char *cpname;
  unsigned long u;
  unsigned char hash,hash_hi,hash_lo;
  unsigned int pos,pos_name,pos_hi;
  int fd,match;

  /* make case insensitive hash */
  flagfound = 0;			/* default */
  cpname = "";				/* default */
  if (!stralloc_copy(&lctarget,&target)) die_nomem();
  case_lowerb(lctarget.s,lctarget.len -1);
  hash = subhashs(lctarget.s);

  /* make domain pointer */
  cpat = lctarget.s + str_chr(lctarget.s,'@');
  if (!*cpat)
    strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s);
  cplast = cpat + str_len(cpat) - 1;
  if (*cplast == '.') --cplast;		/* annonying special case */
  cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
  if (cp1 != cplast) {			/* got one '.' */
    if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
    cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
    if (cp2 == cp1) cp2 = cpat;
    ++cp2;
    if (!stralloc_append(&domain,".")) die_nomem();
    if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
  } else				/* no '.' */
    if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
  if (!stralloc_0(&domain)) die_nomem();

  if ((fd = open_read(split)) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,split,": ");
  substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf));
  lineno = 0;
  for (;;) {	/* dom:hash_lo:hash_hi:listaddress */
    if (getln(&sssp,&line,&match,'\n') == -1)
      strerr_die4sys(111,FATAL,ERR_READ,split,": ");
     lineno++;
    if (!match)
      break;
    if (line.s[0] == '#') continue;	/* comment */
    line.s[line.len - 1] = '\0';	/* no need to allow \0 in lines */
    if (!line.s[pos = str_chr(line.s,':')])
      continue;				/* usually blank line */
    line.s[pos] = '\0';
    if (pos == 0 ||			/* no domain */
	  (case_starts(domain.s,line.s))) {	/* or matching domain */
	if (!line.s[++pos]) die_syntax();
	pos_hi = pos + str_chr(line.s + pos,':');
	if (!line.s[pos_hi]) die_syntax();
	pos_hi++;
	(void) scan_ulong(line.s + pos, &u);	/* scan_uint() not in ezmlm */
	hash_lo = (unsigned char) u;
	(void) scan_ulong(line.s + pos_hi, &u);
	hash_hi = (unsigned char) u;
	pos_name = pos_hi + str_chr(line.s + pos_hi,':');
	if (pos_hi == pos_name) hash_hi = 52L;	/* default hi = 52 */
	if (line.s[pos_name]) pos_name++;
	if (hash > hash_hi || hash < hash_lo) continue;	/* not us */
	cpname = line.s + pos_name;
	while (*cpname &&				/* isolate name */
	    (*cpname == ' ' || *cpname == '\t')) cpname++;
	pos = line.len - 2;
	while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' ||
		line.s[pos] == '\t')) line.s[pos--] = '\0';
	break;
    }
  }
  close(fd);

  if (*cpname) {
    if (!stralloc_copys(&name,cpname)) die_nomem();
    if (byte_chr(name.s,name.len,'@') == name.len) {	/* local sublist */
      if (!stralloc_append(&name,"@")) die_nomem();
      if (!stralloc_cat(&name,&outhost)) die_nomem();
    }
    if (!stralloc_0(&name)) die_nomem();
    return 1;
  } else {			/* match without name or no match =>this list */
    if (!stralloc_copy(&name,&outlocal)) die_nomem();
    if (!stralloc_append(&name,"@")) die_nomem();
    if (!stralloc_cat(&name,&outhost)) die_nomem();
    if (!stralloc_0(&name)) die_nomem();
    return 0;
  }
}
Exemplo n.º 29
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));
  }
}
Exemplo n.º 30
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);
   }
}