diff src/masqmail.c @ 0:08114f7dcc23 0.2.21

this is masqmail-0.2.21 from oliver kurth
author meillo@marmaro.de
date Fri, 26 Sep 2008 17:05:23 +0200
parents
children 26e34ae9a3e3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/masqmail.c	Fri Sep 26 17:05:23 2008 +0200
@@ -0,0 +1,828 @@
+/*  MasqMail
+    Copyright (C) 1999-2001 Oliver Kurth
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include <glib.h>
+
+#include "masqmail.h"
+
+/* mutually exclusive modes. Note that there is neither a 'get' mode
+   nor a 'queue daemon' mode. These, as well as the distinction beween
+   the two (non exclusive) daemon (queue and listen) modes are handled
+   by flags.*/
+typedef enum _mta_mode
+{
+  MODE_ACCEPT = 0, /* accept message on stdin */
+  MODE_DAEMON,     /* run as daemon */
+  MODE_RUNQUEUE,   /* single queue run, online or offline */
+  MODE_GET_DAEMON, /* run as get (retrieve) daemon */
+  MODE_SMTP,       /* accept SMTP on stdin */
+  MODE_LIST,       /* list queue */
+  MODE_MCMD,       /* do queue manipulation */
+  MODE_VERSION,    /* show version */
+  MODE_BI,         /* fake ;-) */
+  MODE_NONE        /* to prevent default MODE_ACCEPT */    
+}mta_mode;
+
+char *pidfile = NULL;
+volatile int sigterm_in_progress = 0;
+
+static
+void sigterm_handler(int sig)
+{
+  if(sigterm_in_progress)
+    raise(sig);
+  sigterm_in_progress = 1;
+
+  if(pidfile){
+    uid_t uid;
+    uid = seteuid(0);
+    if(unlink(pidfile) != 0)
+      logwrite(LOG_WARNING, "could not delete pid file %s: %s\n",
+	       pidfile, strerror(errno));
+    seteuid(uid); /* we exit anyway after this, just to be sure */
+  }
+
+  signal(sig, SIG_DFL);
+  raise(sig);
+}
+
+#ifdef ENABLE_IDENT /* so far used for that only */
+static
+gboolean is_in_netlist(gchar *host, GList *netlist)
+{
+  guint hostip = inet_addr(host);
+  struct in_addr addr;
+
+  addr.s_addr = hostip;
+  if(addr.s_addr != INADDR_NONE){
+    GList *node;
+    foreach(netlist, node){
+      struct in_addr *net = (struct in_addr *)(node->data);
+      if((addr.s_addr & net->s_addr) == net->s_addr)
+	return TRUE;
+    }
+  }
+  return FALSE;
+}
+#endif
+
+gchar *get_optarg(char *argv[], gint argc, gint *argp, gint *pos)
+{
+  if(argv[*argp][*pos])
+    return &(argv[*argp][*pos]);
+  else{
+    if(*argp+1 < argc){
+      if(argv[(*argp)+1][0] != '-'){
+	(*argp)++;
+	*pos = 0;
+	return &(argv[*argp][*pos]);
+      }
+    }
+  }
+  return NULL;
+}  
+
+gchar *get_progname(gchar *arg0)
+{
+  gchar *p = arg0 + strlen(arg0) - 1;
+  while(p > arg0){
+    if(*p == '/')
+      return p+1;
+    p--;
+  }
+  return p;
+}
+
+gboolean write_pidfile(gchar *name)
+{
+  FILE *fptr;
+
+  if((fptr = fopen(name, "wt"))){
+    fprintf(fptr, "%d\n", getpid());
+    fclose(fptr);
+    pidfile = strdup(name);
+    return TRUE;
+  }
+  logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno));
+  return FALSE;
+}
+
+static
+void mode_daemon(gboolean do_listen, gint queue_interval, char *argv[])
+{
+  guint pid;
+
+  /* daemon */
+  if(!conf.run_as_user){
+    if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
+      fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if((pid = fork()) > 0){
+    exit(EXIT_SUCCESS);
+  }else if(pid < 0){
+    logwrite(LOG_ALERT, "could not fork!");
+    exit(EXIT_FAILURE);
+  }
+
+  signal(SIGTERM, sigterm_handler);
+  write_pidfile(PIDFILEDIR"/masqmail.pid");
+
+  conf.do_verbose = FALSE;
+
+  fclose(stdin);
+  fclose(stdout);
+  fclose(stderr);
+
+  listen_port(do_listen ? conf.listen_addresses : NULL,
+	      queue_interval, argv);
+}
+
+#ifdef ENABLE_POP3
+static
+void mode_get_daemon(gint get_interval, char *argv[])
+{
+  guint pid;
+
+  /* daemon */
+  if(!conf.run_as_user){
+    if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
+      fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if((pid = fork()) > 0){
+    exit(EXIT_SUCCESS);
+  }else if(pid < 0){
+    logwrite(LOG_ALERT, "could not fork!");
+    exit(EXIT_FAILURE);
+  }
+
+  signal(SIGTERM, sigterm_handler);
+  write_pidfile(PIDFILEDIR"/masqmail-get.pid");
+
+  conf.do_verbose = FALSE;
+
+  fclose(stdin);
+  fclose(stdout);
+  fclose(stderr);
+
+  get_daemon(get_interval, argv);
+}
+#endif
+
+#ifdef ENABLE_SMTP_SERVER
+static void mode_smtp()
+{
+  /* accept smtp message on stdin */
+  /* write responses to stderr. */
+
+  struct sockaddr_in saddr;
+  gchar *peername = NULL;
+  int dummy = sizeof(saddr);
+#ifdef ENABLE_IDENT
+  gchar *ident = NULL;
+#endif
+
+  conf.do_verbose = FALSE;
+
+  if(!conf.run_as_user){
+    seteuid(conf.orig_uid);
+    setegid(conf.orig_gid);
+  }
+
+  DEBUG(5) debugf("accepting smtp message on stdin\n");
+
+  if(getpeername(0, (struct sockaddr *)(&saddr), &dummy) == 0){
+    peername = g_strdup(inet_ntoa(saddr.sin_addr));
+#ifdef ENABLE_IDENT
+    {
+      gchar *id = NULL;
+      if((id = (gchar *)ident_id(0, 60))){
+	ident = g_strdup(id);
+      }
+    }
+#endif
+  }else if(errno != ENOTSOCK)
+    exit(EXIT_FAILURE);
+
+  //smtp_in(stdin, stdout, peername);
+  smtp_in(stdin, stderr, peername, NULL);
+
+#ifdef ENABLE_IDENT
+  if(ident) g_free(ident);
+#endif
+}
+#endif
+
+static void mode_accept(address *return_path, gchar *full_sender_name,
+			guint accept_flags, char **addresses, int addr_cnt)
+{
+  /* accept message on stdin */
+  accept_error err;
+  message *msg = create_message();
+  gint i;
+
+  if(return_path != NULL){
+    if((conf.orig_uid != 0) &&
+       (conf.orig_uid != conf.mail_uid) &&
+       (!is_ingroup(conf.orig_uid, conf.mail_gid))){
+      fprintf(stderr,
+	      "must be in root, %s or in group %s for setting return path.\n",
+	      DEF_MAIL_USER, DEF_MAIL_GROUP);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if(!conf.run_as_user){
+    seteuid(conf.orig_uid);
+    setegid(conf.orig_gid);
+  }
+
+  DEBUG(5) debugf("accepting message on stdin\n");
+
+  msg->received_prot = PROT_LOCAL;
+  for(i = 0; i < addr_cnt; i++){
+    if(addresses[i][0] != '|')
+      msg->rcpt_list =
+	g_list_append(msg->rcpt_list,
+		      create_address_qualified(addresses[i], TRUE, conf.host_name));
+    else{
+      logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  /* -f option */
+  msg->return_path = return_path;
+
+  /* -F option */
+  msg->full_sender_name = full_sender_name;
+    
+  if((err = accept_message(stdin, msg, accept_flags)) == AERR_OK){
+    if(spool_write(msg, TRUE)){
+      pid_t pid;
+      logwrite(LOG_NOTICE, "%s <= %s with %s\n",
+	       msg->uid, addr_string(msg->return_path),
+	       prot_names[PROT_LOCAL]);
+
+      if(!conf.do_queue){
+
+	if((pid = fork()) == 0){
+
+	  conf.do_verbose = FALSE;
+
+	  fclose(stdin);
+	  fclose(stdout);
+	  fclose(stderr);
+
+	  if(deliver(msg)){
+	    exit(EXIT_SUCCESS);
+	  }else
+	    exit(EXIT_FAILURE);
+	}else if(pid < 0){
+	  logwrite(LOG_ALERT, "could not fork for delivery, id = %s",
+		   msg->uid);
+	}
+      }
+    }else{
+      fprintf(stderr, "Could not write spool file\n");
+      exit(EXIT_FAILURE);
+    }
+  }else{
+    switch(err){
+    case AERR_EOF:
+      fprintf(stderr, "unexpected EOF.\n");
+      exit(EXIT_FAILURE);
+    case AERR_NORCPT:
+      fprintf(stderr, "no recipients.\n");
+      exit(EXIT_FAILURE);
+    default:
+      /* should never happen: */
+      fprintf(stderr, "Unknown error (%d)\r\n", err);
+      exit(EXIT_FAILURE);
+    }
+    exit(EXIT_FAILURE);
+  }
+}
+
+int
+main(int argc, char *argv[])
+{
+  /* cmd line flags */
+  gchar *conf_file = CONF_FILE;
+  gint arg = 1;
+  gboolean do_get = FALSE;
+  gboolean do_get_online = FALSE;
+
+  gboolean do_listen = FALSE;
+  gboolean do_runq = FALSE;
+  gboolean do_runq_online = FALSE;
+
+  gboolean do_queue = FALSE;
+
+  gboolean do_verbose = FALSE;
+  gint debug_level = -1;
+
+  mta_mode mta_mode = MODE_ACCEPT;
+
+  gint queue_interval = 0;
+  gint get_interval = 0;
+  gboolean opt_t = FALSE;
+  gboolean opt_i = FALSE;
+  gboolean opt_odb = FALSE;
+  gboolean opt_oem = FALSE;
+  gboolean exit_failure = FALSE;
+
+  gchar *M_cmd = NULL;
+
+  gint exit_code = EXIT_SUCCESS;
+  gchar *route_name = NULL;
+  gchar *get_name = NULL;
+  gchar *progname;
+  gchar *f_address = NULL;
+  gchar *full_sender_name = NULL;
+  address *return_path = NULL; /* may be changed by -f option */
+
+  progname = get_progname(argv[0]);
+
+  if(strcmp(progname, "mailq") == 0)
+    { mta_mode = MODE_LIST; }
+  else if(strcmp(progname, "mailrm") == 0)
+    { mta_mode = MODE_MCMD; M_cmd = "rm"; }
+  else if(strcmp(progname, "runq") == 0)
+    { mta_mode = MODE_RUNQUEUE; do_runq = TRUE; }
+  else if(strcmp(progname, "rmail") == 0)
+    { mta_mode = MODE_ACCEPT; opt_i = TRUE; }
+  else if(strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0)
+    { mta_mode = MODE_SMTP; }
+
+  /* parse cmd line */
+  while(arg < argc){
+    gint pos = 0;
+    if((argv[arg][pos] == '-') && (argv[arg][pos+1] != '-')){
+      pos++;
+      switch(argv[arg][pos++]){
+      case 'b':
+	switch(argv[arg][pos++]){
+	case 'd':
+	  do_listen = TRUE;
+	  mta_mode = MODE_DAEMON;
+	  break;
+	case 'i':
+	  /* ignored */
+	  mta_mode = MODE_BI;
+	  break;
+	case 's':
+	  mta_mode = MODE_SMTP;
+	  break;
+	case 'p':
+	  mta_mode = MODE_LIST;
+	  break;
+	case 'V':
+	  mta_mode = MODE_VERSION;
+	  break;
+	default:
+	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      case 'B':
+	/* we ignore this and throw the argument away */
+	get_optarg(argv, argc, &arg, &pos);
+	break;
+      case 'C':
+	if(!(conf_file = get_optarg(argv, argc, &arg, &pos))){
+	  fprintf(stderr, "-C requires a filename as argument.\n");
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      case 'F':
+	{
+	  full_sender_name = get_optarg(argv, argc, &arg, &pos);
+	  if(!full_sender_name){
+	    fprintf(stderr, "-F requires a name as an argument\n");
+	    exit(EXIT_FAILURE);
+	  }
+	}
+	break;
+      case 'd':
+	if(getuid() == 0){
+	  char *lvl = get_optarg(argv, argc, &arg, &pos);
+	  if(lvl)
+	    debug_level = atoi(lvl);
+	  else{
+	    fprintf(stderr, "-d requires a number as an argument.\n");
+	    exit(EXIT_FAILURE);
+	  }
+	}else{
+	  fprintf(stderr, "only root may set the debug level.\n");
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      case 'f':
+	/* set return path */
+	{
+	  gchar *address;
+	  address = get_optarg(argv, argc, &arg, &pos);
+	  if(address){
+	    f_address = g_strdup(address);
+	  }else{
+	    fprintf(stderr, "-f requires an address as an argument\n");
+	    exit(EXIT_FAILURE);
+	  }
+	}
+	break;
+      case 'g':
+	do_get = TRUE;
+	if(!mta_mode) mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */
+	if(argv[arg][pos] == 'o'){
+	  pos++;
+	  do_get_online = TRUE;
+	  /* can be NULL, then we use online detection method */
+	  route_name = get_optarg(argv, argc, &arg, &pos);
+
+	  if(route_name != NULL){
+	    if(isdigit(route_name[0])){
+	      get_interval = time_interval(route_name, &pos);
+	      route_name = get_optarg(argv, argc, &arg, &pos);
+	      mta_mode = MODE_GET_DAEMON;
+	      do_get = FALSE;
+	    }
+	  }
+	}else{
+	  if((optarg = get_optarg(argv, argc, &arg, &pos))){
+	    get_name = get_optarg(argv, argc, &arg, &pos);
+	  }
+	}
+	break;
+      case 'i':
+	if(argv[arg][pos] == 0){
+	  opt_i = TRUE;
+	  exit_failure = FALSE; /* may override -oem */
+	}else{
+	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      case 'M':
+	{
+	  mta_mode = MODE_MCMD;
+	  M_cmd = g_strdup(&(argv[arg][pos]));
+	}
+	break;
+      case 'o':
+	switch(argv[arg][pos++]){
+	case 'e':
+	  if(argv[arg][pos++] == 'm') /* -oem */
+	    if(!opt_i) exit_failure = TRUE;
+	    opt_oem = TRUE;
+	  break;
+	case 'd':
+	  if(argv[arg][pos] == 'b') /* -odb */
+	    opt_odb = TRUE;
+	  else if(argv[arg][pos] == 'q') /* -odq */
+	    do_queue = TRUE;
+	  break;
+	case 'i':
+	  opt_i = TRUE;
+	  exit_failure = FALSE; /* may override -oem */
+	  break;
+	}
+	break;
+
+      case 'q':
+	{
+	  gchar *optarg;
+
+	  do_runq = TRUE;
+	  mta_mode = MODE_RUNQUEUE;
+	  if(argv[arg][pos] == 'o'){
+	    pos++;
+	    do_runq = FALSE;
+	    do_runq_online = TRUE;
+	    /* can be NULL, then we use online detection method */
+	    route_name = get_optarg(argv, argc, &arg, &pos);
+	  }else if((optarg = get_optarg(argv, argc, &arg, &pos))){
+	    mta_mode = MODE_DAEMON;
+	    queue_interval = time_interval(optarg, &pos);
+	  }
+	}
+	break;
+      case 't':
+	if(argv[arg][pos] == 0){
+	  opt_t = TRUE;
+	}else{
+	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
+	  exit(EXIT_FAILURE);
+	}
+	break;
+      case 'v':
+	do_verbose = TRUE;
+	break;
+      default:
+	fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
+	exit(EXIT_FAILURE);
+      }
+    }else{
+      if(argv[arg][pos+1] == '-'){
+        if(argv[arg][pos+2] != '\0'){
+	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
+	  exit(EXIT_FAILURE);
+        }
+	arg++;
+      }
+      break;
+    }
+    arg++;
+  }
+
+  if(mta_mode == MODE_VERSION){
+    gchar *with_resolver = "", *with_smtp_server = "", *with_pop3 = "", *with_auth = "", 
+      *with_maildir = "", *with_ident = "", *with_mserver = "";
+    
+#ifdef ENABLE_RESOLVER
+    with_resolver = " +resolver";
+#endif
+#ifdef ENABLE_SMTP_SERVER
+    with_smtp_server = " +smtp-server";
+#endif
+#ifdef ENABLE_POP3
+    with_pop3 = " +pop3";
+#endif
+#ifdef ENABLE_AUTH
+    with_auth = " +auth";
+#endif
+#ifdef ENABLE_MAILDIR
+    with_maildir = " +maildir";
+#endif
+#ifdef ENABLE_IDENT
+    with_ident = " +ident";
+#endif
+#ifdef ENABLE_MSERVER
+    with_mserver = " +mserver";
+#endif
+
+    printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION,
+	   with_resolver, with_smtp_server, with_pop3, with_auth,
+	   with_maildir, with_ident, with_mserver);
+      
+    exit(EXIT_SUCCESS);
+  }
+
+  /* initialize random generator */
+  srand(time(NULL));
+  /* ignore SIGPIPE signal */
+  signal(SIGPIPE, SIG_IGN);
+
+  /* close all possibly open file descriptors */
+  {
+    int i, max_fd = sysconf(_SC_OPEN_MAX);
+
+    if(max_fd <= 0) max_fd = 64;
+    for(i = 3; i < max_fd; i++)
+      close(i);
+  }
+
+  init_conf();
+
+  /* if we are not privileged, and the config file was changed we
+     implicetely set the the run_as_user flag and give up all
+     privileges.
+
+     So it is possible for a user to run his own daemon without
+     breaking security.
+  */
+  if(strcmp(conf_file, CONF_FILE) != 0){
+    if(conf.orig_uid != 0){
+      conf.run_as_user = TRUE;
+      seteuid(conf.orig_uid);
+      setegid(conf.orig_gid);
+      setuid(conf.orig_uid);
+      setgid(conf.orig_gid);
+    }
+  }
+
+  read_conf(conf_file);
+
+  if(do_queue) conf.do_queue = TRUE;
+  if(do_verbose) conf.do_verbose = TRUE;
+  if(debug_level >= 0) /* if >= 0, it was given by argument */
+    conf.debug_level = debug_level;
+
+  chdir("/");
+
+  if(!conf.run_as_user){
+    if(setgid(0) != 0){
+      fprintf(stderr,
+	      "could not set gid to 0. Is the setuid bit set? : %s\n",
+	      strerror(errno));
+      exit(EXIT_FAILURE);
+    }
+    if(setuid(0) != 0){
+      fprintf(stderr,
+	      "could not gain root privileges. Is the setuid bit set? : %s\n",
+	      strerror(errno));
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if(!logopen()){
+    fprintf(stderr, "could not open log file\n");
+    exit(EXIT_FAILURE);
+  }
+
+  DEBUG(1) debugf("masqmail %s starting\n", VERSION);
+
+  DEBUG(5){
+    gchar **str = argv;
+    debugf("args: \n");
+    while(*str){
+      debugf("%s \n", *str);
+      str++;
+    }
+  }
+  DEBUG(5) debugf("queue_interval = %d\n", queue_interval);
+
+  if(f_address){
+    return_path = create_address_qualified(f_address, TRUE, conf.host_name);
+    g_free(f_address);
+    if(!return_path){
+      fprintf(stderr, "invalid RFC821 address: %s\n", f_address);
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if(do_get){
+#ifdef ENABLE_POP3
+    if((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)){
+
+      set_identity(conf.orig_uid, "getting mail");
+
+      if(do_get_online){
+	if(route_name != NULL){
+	  conf.online_detect = g_strdup("argument");
+	  set_online_name(route_name);
+	}
+	get_online();
+      }else{
+	if(get_name)
+	  get_from_name(get_name);
+	else
+	  get_all();
+      }
+    }else{
+      logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n");
+    }
+#else
+    fprintf(stderr, "get (pop) support not compiled in\n");
+#endif
+  }
+
+  switch(mta_mode){
+  case MODE_DAEMON:
+    mode_daemon(do_listen, queue_interval, argv);
+    break;
+  case MODE_RUNQUEUE:
+    {
+      /* queue runs */
+      set_identity(conf.orig_uid, "queue run");
+
+      if(do_runq)
+	exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE;
+
+      if(do_runq_online){
+	if(route_name != NULL){
+	  conf.online_detect = g_strdup("argument");
+	  set_online_name(route_name);
+	}
+	exit_code = queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE;
+      }
+    }
+    break;
+  case MODE_GET_DAEMON:
+#ifdef ENABLE_POP3
+    if(route_name != NULL){
+      conf.online_detect = g_strdup("argument");
+      set_online_name(route_name);
+    }
+    mode_get_daemon(get_interval, argv);
+#endif
+    break;
+
+  case MODE_SMTP:
+#ifdef ENABLE_SMTP_SERVER
+    mode_smtp();
+#else
+    fprintf(stderr, "smtp server support not compiled in\n");
+#endif
+    break;
+  case MODE_LIST:
+
+    queue_list();
+    break;
+
+  case MODE_BI:
+    
+    exit(EXIT_SUCCESS);
+    break; /* well... */
+    
+  case MODE_MCMD:
+    if(strcmp(M_cmd, "rm") == 0){
+      gboolean ok = FALSE;
+
+      set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
+
+      if(is_privileged_user(conf.orig_uid)){
+	for(; arg < argc; arg++){
+	  if(queue_delete(argv[arg]))
+	    ok = TRUE;
+	}
+      }else{
+	struct passwd *pw = getpwuid(conf.orig_uid);
+	if(pw){
+	  for(; arg < argc; arg++){
+	    message *msg = msg_spool_read(argv[arg], FALSE);
+#ifdef ENABLE_IDENT
+	    if(((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) ||
+	       is_in_netlist(msg->received_host, conf.ident_trusted_nets)){
+#else
+	      if((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)){
+#endif
+	      if(msg->ident){
+		if(strcmp(pw->pw_name, msg->ident) == 0){
+		  if(queue_delete(argv[arg]))
+		    ok = TRUE;
+		}else{
+		  fprintf(stderr, "you do not own message id %s\n", argv[arg]);
+		}
+	      }else
+		fprintf(stderr, "message %s does not have an ident.\n", argv[arg]);
+	    }else{
+	      fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]);
+	    }
+	  }
+	}else{
+	  fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno));
+	}
+      }
+      exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
+    }else{
+      fprintf(stderr, "unknown command %s\n", M_cmd);
+      exit(EXIT_FAILURE);
+    }
+    break;
+
+    case MODE_ACCEPT:
+    {
+      guint accept_flags =
+	(opt_t ? ACC_DEL_RCPTS|ACC_DEL_BCC|ACC_RCPT_FROM_HEAD : ACC_HEAD_FROM_RCPT) |
+	(opt_i ? ACC_NODOT_TERM : ACC_NODOT_RELAX);
+    
+      mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg);
+
+      exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS);
+    }
+    break;
+  case MODE_NONE:
+      break;
+  default:
+      fprintf(stderr, "unknown mode: %d\n", mta_mode);
+      break;
+    }
+    
+  logclose();
+
+  exit(exit_code);
+}