Beispiel #1
0
void mail_autoexpunge(struct mail *mail)
{
	struct mail_private *p = (struct mail_private *)mail;
	p->autoexpunged = TRUE;
	mail_expunge(mail);
	p->autoexpunged = FALSE;
}
static int cmd_deduplicate_uidlist(struct mailbox *box, struct uidlist *uidlist)
{
	struct mailbox_transaction_context *trans;
	struct mail_search_context *search_ctx;
	struct mail_search_args *search_args;
	struct mail_search_arg *arg;
	struct mail *mail;
	ARRAY_TYPE(seq_range) uids;
	int ret = 0;

	/* the uidlist is reversed with oldest mails at the end.
	   we'll delete everything but the oldest mail. */
	if (uidlist->next == NULL)
		return 0;

	t_array_init(&uids, 8);
	for (; uidlist->next != NULL; uidlist = uidlist->next)
		seq_range_array_add(&uids, uidlist->uid);

	search_args = mail_search_build_init();
	arg = mail_search_build_add(search_args, SEARCH_UIDSET);
	arg->value.seqset = uids;

	trans = mailbox_transaction_begin(box, 0);
	search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
	mail_search_args_unref(&search_args);

	while (mailbox_search_next(search_ctx, &mail))
		mail_expunge(mail);
	if (mailbox_search_deinit(&search_ctx) < 0)
		ret = -1;
	if (mailbox_transaction_commit(&trans) < 0)
		ret = -1;
	return ret;
}
Beispiel #3
0
static void virtual_mail_expunge(struct mail *mail)
{
	struct virtual_mail *vmail = (struct virtual_mail *)mail;

	if (virtual_mail_handle_lost(vmail) < 0)
		return;
	mail_expunge(vmail->backend_mail);
}
Beispiel #4
0
static int
cmd_expunge_box(struct doveadm_mail_cmd_context *_ctx,
		const struct mailbox_info *info,
		struct mail_search_args *search_args)
{
	struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx;
	struct doveadm_mail_iter *iter;
	struct mailbox *box;
	struct mail *mail;
	enum mail_error error;
	int ret = 0;

	if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, FALSE,
				   &iter) < 0)
		return -1;

	while (doveadm_mail_iter_next(iter, &mail)) {
		if (doveadm_debug) {
			i_debug("expunge: box=%s uid=%u",
				info->vname, mail->uid);
		}
		mail_expunge(mail);
	}

	if (doveadm_mail_iter_deinit_keep_box(&iter, &box) < 0)
		ret = -1;
	else if (mailbox_sync(box, 0) < 0) {
		i_error("Syncing mailbox '%s' failed: %s",
			mailbox_get_vname(box),
			mailbox_get_last_internal_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		ret = -1;
	}

	if (ctx->delete_empty_mailbox && ret == 0) {
		if (mailbox_delete_empty(box) < 0) {
			error = mailbox_get_last_mail_error(box);
			if (error != MAIL_ERROR_EXISTS) {
				i_error("Deleting mailbox '%s' failed: %s",
					mailbox_get_vname(box),
					mailbox_get_last_internal_error(box, NULL));
				doveadm_mail_failed_mailbox(_ctx, box);
				ret = -1;
			}
		} else {
			if (mailbox_set_subscribed(box, FALSE) < 0) {
				i_error("Unsubscribing mailbox '%s' failed: %s",
					mailbox_get_vname(box),
					mailbox_get_last_internal_error(box, NULL));
				doveadm_mail_failed_mailbox(_ctx, box);
				ret = -1;
			}
		}
	}
	mailbox_free(&box);
	return ret;
}
  bool
  ImapClient::expunge(const std::string& aHost, 
                      const std::string& aUsername, 
                      const std::string& aPassword, 
                      const std::string& aMailbox) {
    
#include "linkage.c"
    std::string lHost = "{" + aHost + "}" + aMailbox;
    MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, true); 
    if (lSource) {  mail_expunge(lSource); }
    return true;
  }
static int
cmd_copy_box(struct copy_cmd_context *ctx, struct mailbox *destbox,
	     const struct mailbox_info *info)
{
	struct doveadm_mail_iter *iter;
	struct mailbox_transaction_context *desttrans;
	struct mail_save_context *save_ctx;
	struct mail *mail;
	int ret = 0;

	if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0,
				   NULL, &iter) < 0)
		return -1;

	/* use a separately committed transaction for each mailbox.
	   this guarantees that mails aren't expunged without actually having
	   been copied. */
	desttrans = mailbox_transaction_begin(destbox,
					MAILBOX_TRANSACTION_FLAG_EXTERNAL);

	while (doveadm_mail_iter_next(iter, &mail)) {
		save_ctx = mailbox_save_alloc(desttrans);
		mailbox_save_copy_flags(save_ctx, mail);
		if (mailbox_copy(&save_ctx, mail) == 0) {
			if (ctx->move)
				mail_expunge(mail);
		} else {
			i_error("Copying message UID %u from '%s' failed: %s",
				mail->uid, info->vname,
				mailbox_get_last_error(destbox, NULL));
			doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
			ret = -1;
		}
	}

	if (mailbox_transaction_commit(&desttrans) < 0) {
		i_error("Committing %s mails failed: %s",
			ctx->move ? "moved" : "copied",
			mailbox_get_last_error(destbox, NULL));
		doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
		/* rollback expunges */
		doveadm_mail_iter_deinit_rollback(&iter);
		ret = -1;
	} else {
		if (doveadm_mail_iter_deinit_sync(&iter) < 0)
			ret = -1;
	}
	return ret;
}
Beispiel #7
0
int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg,
		 unsigned int *expunged_count)
{
	struct mail_search_context *ctx;
        struct mailbox_transaction_context *t;
	struct mail *mail;
	struct mail_search_args *search_args;
	bool expunges = FALSE;

	if (mailbox_is_readonly(box)) {
		/* silently ignore */
		return 0;
	}

	search_args = mail_search_build_init();
	search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
	search_args->args->type = SEARCH_FLAGS;
	search_args->args->value.flags = MAIL_DELETED;
	search_args->args->next = next_search_arg;

	/* Refresh the flags so we'll expunge all messages marked as \Deleted
	   by any session. */
	t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_REFRESH);
	ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
	mail_search_args_unref(&search_args);

	while (mailbox_search_next(ctx, &mail)) {
		*expunged_count += 1;
		mail_expunge(mail);
		expunges = TRUE;
	}

	if (mailbox_search_deinit(&ctx) < 0) {
		mailbox_transaction_rollback(&t);
		return -1;
	} else {
		if (mailbox_transaction_commit(&t) < 0)
			return -1;
	}

	return expunges ? 1 : 0;
}
Beispiel #8
0
static int snarf(struct mailbox *srcbox, struct mailbox *destbox)
{
	struct mail_search_args *search_args;
	struct mail_search_context *search_ctx;
        struct mailbox_transaction_context *src_trans, *dest_trans;
	struct mail_save_context *save_ctx;
	struct mail *mail;
	enum mail_error error;
	int ret;

	/* make sure the destination mailbox has been opened.
	   note that this locks the mailbox. */
	if (mailbox_open(destbox) < 0)
		return -1;

	if (mailbox_sync(srcbox, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
		return -1;

	src_trans = mailbox_transaction_begin(srcbox, 0);
	dest_trans = mailbox_transaction_begin(destbox,
					MAILBOX_TRANSACTION_FLAG_EXTERNAL);

	search_args = mail_search_build_init();
	mail_search_build_add_all(search_args);
	search_ctx = mailbox_search_init(src_trans, search_args, NULL,
					 MAIL_FETCH_STREAM_HEADER |
					 MAIL_FETCH_STREAM_BODY, NULL);
	mail_search_args_unref(&search_args);

	ret = 0;
	while (mailbox_search_next(search_ctx, &mail)) {
		if (mail->expunged)
			continue;

		save_ctx = mailbox_save_alloc(dest_trans);
		if (mailbox_copy(&save_ctx, mail) < 0 && !mail->expunged) {
			error = mailbox_get_last_mail_error(destbox);
			/* if we failed because of out of disk space, just
			   move those messages we managed to move so far. */
			if (error != MAIL_ERROR_NOQUOTA)
				ret = -1;
			break;
		}
		mail_expunge(mail);
	}

	if (mailbox_search_deinit(&search_ctx) < 0)
		ret = -1;

	/* commit the copied messages to the destination mailbox. if we crash
	   between that and between expunging the messages from the source
	   mailbox, we're left with duplicates. */
	if (ret < 0)
		mailbox_transaction_rollback(&dest_trans);
	else if (mailbox_transaction_commit(&dest_trans) < 0)
		ret = -1;

	if (ret < 0)
		mailbox_transaction_rollback(&src_trans);
	else {
		if (mailbox_transaction_commit(&src_trans) < 0)
			ret = -1;
	}
	if (ret == 0) {
		if (mailbox_sync(srcbox, 0) < 0)
			ret = -1;
	}
	return ret;
}
Beispiel #9
0
bool f_imap_expunge(const Resource& imap_stream) {
  ImapStream *obj = imap_stream.getTyped<ImapStream>();
  mail_expunge(obj->m_stream);
  return true;
}
int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
	     int mode)
{
  char *s,tmp[MAILTMPLEN];
  APPENDPACKAGE ap;
  STRING st;
  char *ndst = NIL;
  int ret = NIL;
  trycreate = NIL;		/* no TRYCREATE yet */
  if (create) while (!mail_create (dest,dst) && (mode != mAPPEND)) {
    switch (mode) {
    case mPROMPT:		/* prompt user for new name */
      tmp[0] = '\0';
      while (!tmp[0]) {		/* read name */
	fputs ("alternative name: ",stdout);
	fflush (stdout);
	fgets (tmp,MAILTMPLEN-1,stdin);
	if (s = strchr (tmp,'\n')) *s = '\0';
      }
      if (ndst) fs_give ((void **) &ndst);
      ndst = cpystr (tmp);
      break;
    case mSUFFIX:		/* try again with new suffix */
      if (ndst) fs_give ((void **) &ndst);
      sprintf (ndst = (char *) fs_get (strlen (dst) + strlen (suffix) + 1),
	       "%s%s",dst,suffix);
      printf ("retry to create %s\n",ndst);
      mode = mPROMPT;		/* switch to prompt mode if name fails */
      break;
    case NIL:			/* not merging */
      return NIL;
    }
    if (ndst) dst = ndst;	/* if alternative name given, use it */
  }

  if (kwcopyp) {
    int i;
    size_t len;
    char *dummymsg = "Date: Thu, 18 May 2006 00:00 -0700\r\nFrom: [email protected]\r\nSubject: dummy\r\n\r\ndummy\r\n";
    for (i = 0,len = 0; i < NUSERFLAGS; ++i)
      if (source->user_flags[i]) len += strlen (source->user_flags[i]) + 1;
    if (len) {			/* easy if no user flags to copy... */
      char *t;
      char *tail = "\\Deleted)";
      char *flags = (char *) fs_get (1 + len + strlen (tail) + 1);
      s = flags; *s++ = '(';
      for (i = 0; i < NUSERFLAGS; ++i) if (t = source->user_flags[i]) {
	while (*t) *s++ = *t++;
	*s++ = ' ';
      }
      strcpy (s,tail);		/* terminate flags list */
      if ((dst[0] == '#') && ((dst[1] == 'D') || (dst[1] == 'd')) &&
	  ((dst[2] == 'R') || (dst[2] == 'r')) &&
	  ((dst[3] == 'I') || (dst[3] == 'i')) &&
	  ((dst[4] == 'V') || (dst[4] == 'v')) &&
	  ((dst[5] == 'E') || (dst[5] == 'e')) &&
	  ((dst[6] == 'R') || (dst[6] == 'r')) && (dst[7] == '.') &&
	  (t = strchr (dst+8,'/'))) ++t;
      else t = dst;
      INIT (&st,mail_string,dummymsg,strlen (dummymsg));
      if (!(mail_append (dest,dst,&st) &&
	    (dest = mail_open (dest,t,debugp ? OP_DEBUG : NIL)))) {
	fs_give ((void **) &flags);
	return NIL;
      }
      mail_setflag (dest,"*",flags);
      mail_expunge (dest);
      fs_give ((void **) &flags);
    }
  }

  if (source->nmsgs) {		/* non-empty source */
    if (verbosep) printf ("%s [%lu message(s)] => %s\n",
			      source->mailbox,source->nmsgs,dst);
    ap.stream = source;		/* prepare append package */
    ap.msgno = 0;
    ap.msgmax = source->nmsgs;
    ap.flags = ap.date = NIL;
    ap.message = &st;
				/* make sure we have all messages */
    sprintf (tmp,"1:%lu",ap.msgmax);
    mail_fetchfast (source,tmp);
    if (mail_append_multiple (dest,dst,mm_append,(void *) &ap)) {
      --ap.msgno;		/* make sure user knows it won */
      if (verbosep) printf ("[Ok %lu messages(s)]\n",ap.msgno);
      if (del && ap.msgno) {	/* delete source messages */
	sprintf (tmp,"1:%lu",ap.msgno);
	mail_flag (source,tmp,"\\Deleted",ST_SET);
				/* flush moved messages */
	mail_expunge (source);
      }
      ret = T;
    }
    else if ((mode == mAPPEND) && trycreate)
      ret = mbxcopy (source,dest,dst,create,del,mPROMPT);
    else if (verbosep) puts ("[Failed]");
  }
  else {			/* empty source */
    if (verbosep) printf ("%s [empty] => %s\n",source->mailbox,dst);
    ret = T;
  }
  if (ndst) fs_give ((void **) &ndst);
  return ret;
}
int main (int argc,char *argv[])
{
  MAILSTREAM *source = NIL;
  MAILSTREAM *dest = NIL;
  SEARCHPGM *criteria;
  char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN];
  unsigned long m,len,curlen,start,last;
  int i;
  int merge = NIL;
  int retcode = 1;
  int moreswitchp = T;
  char *cmd = NIL;
  char *src = NIL;
  char *dst = NIL;
  char *pgm = argc ? argv[0] : "mailutil";
#include "linkage.c"
  for (i = 1; i < argc; i++) {
    s = argv[i];		/* pick up argument */
				/* parse switches */
    if (moreswitchp && (*s == '-')) {
      if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T;
      else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T;
      else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T;
      else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T;
      else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T;
      else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) {
	if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT;
	else if (!strcmp (s,"append")) merge = mAPPEND;
	else if (!strncmp (s,"suffix=",7) && s[7]) {
	  merge = mSUFFIX;
	  suffix = cpystr (s+7);
	}
	else {
	  printf ("unknown merge option: %s\n",s);
	  exit (retcode);
	}
      }

#ifdef SYSCONFIG
      else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) {
	struct passwd *pw = getpwnam (s = argv[i]);
	if (!pw) {
	  printf ("unknown user id: %s\n",argv[i]);
	  exit (retcode);
	}
	else if (setuid (pw->pw_uid)) {
	  perror ("unable to change user id");
	  exit (retcode);
	}
      }
#endif
				/* -- means no more switches, so mailbox
				   name can start with "-" */
      else if ((s[1] == '-') && !s[2]) moreswitchp = NIL;
      else {
	printf ("unknown switch: %s\n",s);
	exit (retcode);
      }
    }
    else if (!cmd) cmd = s;	/* first non-switch is command */
    else if (!src) src = s;	/* second non-switch is source */
    else if (!dst) dst = s;	/* third non-switch is destination */
    else {
      printf ("unknown argument: %s\n",s);
      exit (retcode);
    }
  }
  if (kwcopyp && ignorep) {
    puts ("-kwcopy and -ignore are mutually exclusive");
    exit (retcode);
  }
  if (!cmd) cmd = "";		/* prevent SEGV */

  if (!strcmp (cmd,"check")) {	/* check for new messages */
    if (!src) src = "INBOX";
    if (dst || merge || rwcopyp || kwcopyp || ignorep)
      printf (usage2,pgm,usgchk,stdsw);
    else if (mail_status (source = (*src == '{') ?
			  mail_open (NIL,src,OP_HALFOPEN |
				     (debugp ? OP_DEBUG : NIL)) : NIL,
			  src,SA_MESSAGES | SA_RECENT | SA_UNSEEN))
      retcode = 0;
  }
  else if (!strcmp (cmd,"create")) {
    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
      printf (usage2,pgm,usgcre,stdsw);
    else if (mail_create (source = (*src == '{') ?
			  mail_open (NIL,src,OP_HALFOPEN |
				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
      retcode = 0;
  }
  else if (!strcmp (cmd,"delete")) {
    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
      printf (usage2,pgm,usgdel,stdsw);
    else if (mail_delete (source = (*src == '{') ?
			  mail_open (NIL,src,OP_HALFOPEN |
				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
      retcode = 0;
  }
  else if (!strcmp (cmd,"rename")) {
    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep)
      printf (usage2,pgm,usgren,stdsw);
    else if (mail_rename (source = (*src == '{') ?
			  mail_open (NIL,src,OP_HALFOPEN |
				     (debugp ? OP_DEBUG : NIL)) : NIL,src,dst))
      retcode = 0;
  }

  else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) {
    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw);
    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
				 (debugp ? OP_DEBUG : NIL))) {
      dest = NIL;		/* open destination stream if network */
      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
					      (debugp ? OP_DEBUG : NIL)))) {
	if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0;
      }
    }
  }
  else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) {
    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw);
    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
				 (debugp ? OP_DEBUG : NIL))) {
      dest = NIL;		/* open destination stream if network */
      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
					      (debugp ? OP_DEBUG : NIL)))) {
	if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0;
      }
    }
  }

  else if (!strcmp (cmd,"prune")) {
    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep ||
	!(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw);
    else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) &&
	     mail_search_full (source,NIL,criteria,SE_FREE)) {
      for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++)
	if (mail_elt (source,m)->searched) {
	  if (s) {		/* continuing a range? */
	    if (m == last + 1) last = m;
	    else {		/* no, end of previous range? */
	      if (last != start) sprintf (t,":%lu,%lu",last,m);
				/* no, just this message */
	      else sprintf (t,",%lu",m);
	      start = last = m;	/* either way, start new range */
				/* running out of space? */
	      if ((len - (curlen = (t += strlen (t)) - s)) < 20) {
		fs_resize ((void **) &s,len += MAILTMPLEN);
		t = s + curlen;	/* relocate current pointer */
	      }
	    }
	  }
	  else {		/* first time, start new buffer */
	    s = (char *) fs_get (len = MAILTMPLEN);
	    sprintf (s,"%lu",start = last = m);
	    t = s + strlen (s);	/* end of buffer */
	  }
	}
				/* finish last range if necessary */
      if (last != start) sprintf (t,":%lu",last);
      if (s) {			/* delete/expunge any matching messages */
	mail_flag (source,s,"\\Deleted",ST_SET);
	m = source->nmsgs;	/* get number of messages before purge */
	mail_expunge (source);
	printf ("%lu message(s) purged\n",m - source->nmsgs);
	fs_give ((void **) &s);	/* flush buffer */
      }
      else puts ("No matching messages, so nothing purged");
      source = mail_close (source);
    }
  }

  else if (!strcmp (cmd,"transfer")) {
    if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw);
    else if ((*src == '{') &&	/* open source mailbox */
	     !(source = mail_open (NIL,src,OP_HALFOPEN |
				   (debugp ? OP_DEBUG : NIL))));
    else if ((*dst == '{') &&	/* open destination server */
	     !(dest = mail_open (NIL,dst,OP_HALFOPEN |
				 (debugp ? OP_DEBUG : NIL))));
    else if (!(f = tmpfile ())) puts ("can't open temporary file");
    else {
      if (verbosep) puts ("Listing mailboxes...");
      if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1,
			dp = strchr (dst,'}') + 1);
      else {
	dp = dst;
	tmp[0] = '\0';
      }
      mail_list (dest,tmp,"");
      rewind (f);		/* list all mailboxes matching prefix */
      if (ddelim < 0) {		/* if server failed to give delimiter */
	puts ("warning: unable to get destination hierarchy delimiter!");
	ddelim = 0;		/* default to none */
      }
      if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1,
			  strchr (src,'}') + 1);
      else strcpy (tmp,src);
      mail_list (source,tmp,"*");
      rewind (f);
				/* read back mailbox names */
      for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) {
	if (t = strchr (tmp+1,'\n')) *t = '\0';
	for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1;
	     *t++ = c= *t1++);
	for (t1 = dp; *t1; *t++ = *t1++);
				/* point to name without delim or netspec */
	t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1;
				/* src and mbx have different delimiters? */
	if (ddelim && (ddelim != tmp[0]))
	  while (c = *t1++) {	/* swap delimiters then */
	    if (c == ddelim) c = tmp[0] ? tmp[0] : 'x';
	    else if (c == tmp[0]) c = ddelim;
	    *t++ = c;
	  }
				/* easy case */
	else while (*t1) *t++ = *t1++;
	*t++ = '\0';
	if (verbosep) {
	  printf ("Copying %s\n  => %s\n",tmp+1,mbx);
	  fflush (stdout);
	}
	if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) | 
				(rwcopyp ? NIL : OP_READONLY))) {
	  if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1;
	  if (source->dtb->flags & DR_LOCAL) source = mail_close (source);
	}
	else printf ("can't open source mailbox %s\n",tmp+1);
      }
    }
  }

  else {
    printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version);
    printf (usage2,pgm,"command [switches] arguments",stdsw);
    printf ("\nCommands:\n %s\n",usgchk);
    puts   ("   ;; report number of messages and new messages");
    printf (" %s\n",usgcre);
    puts   ("   ;; create new mailbox");
    printf (" %s\n",usgdel);
    puts   ("   ;; delete existing mailbox");
    printf (" %s\n",usgren);
    puts   ("   ;; rename mailbox to a new name");
    printf (" copy %s\n",usgcpymov);
    printf (" move %s\n",usgcpymov);
    puts   ("   ;; create new mailbox and copy/move messages");
    printf (" append %s\n",usgappdel);
    printf (" appenddelete %s\n",usgappdel);
    puts   ("   ;; copy/move messages to existing mailbox");
    printf (" %s\n",usgprn);
    puts   ("   ;; prune mailbox of messages matching criteria");
    printf (" %s\n",usgxfr);
    puts   ("   ;; copy source hierarchy to destination");
    puts   ("   ;;  -merge modes are prompt, append, or suffix=xxxx");
  }
				/* close streams */
  if (source) mail_close (source);
  if (dest) mail_close (dest);
  exit (retcode);
  return retcode;		/* stupid compilers */
}