Problem deleting a parent folder with child folder(s)

David Härdeman david at hardeman.nu
Tue Aug 24 18:45:41 EEST 2021


Hi,

I'm seeing some odd behavior wrt deleting a parent folder which has child/inferior folders:

root at vmtest2:~# telnet localhost 143
Trying ::1...
Connected to localhost.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ STARTTLS AUTH=PLAIN AUTH=LOGIN] Dovecot (Debian) ready.
1 LOGIN "test at example.com" "foobar"
1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE QUOTA] Logged in
2 LIST "" "*"
* LIST (\HasNoChildren \UnMarked \Trash) "." INBOX.Trash
* LIST (\HasNoChildren \UnMarked \Sent) "." INBOX.Sent
* LIST (\HasNoChildren \UnMarked \Junk) "." INBOX.Spam
* LIST (\HasNoChildren \UnMarked \Archive) "." INBOX.Read
* LIST (\HasNoChildren \UnMarked \Drafts) "." INBOX.Drafts
* LIST (\HasChildren) "." INBOX
2 OK List completed (0.002 + 0.000 + 0.001 secs).
3 CREATE ParentA.ChildA
3 OK Create completed (0.017 + 0.000 + 0.017 secs).
4 LIST "" "*"
* LIST (\Noselect \HasChildren) "." ParentA
* LIST (\HasNoChildren) "." ParentA.ChildA
* LIST (\HasNoChildren \UnMarked \Trash) "." INBOX.Trash
* LIST (\HasNoChildren \UnMarked \Sent) "." INBOX.Sent
* LIST (\HasNoChildren \UnMarked \Junk) "." INBOX.Spam
* LIST (\HasNoChildren \UnMarked \Archive) "." INBOX.Read
* LIST (\HasNoChildren \UnMarked \Drafts) "." INBOX.Drafts
* LIST (\HasChildren) "." INBOX
4 OK List completed (0.001 + 0.000 secs).
5 EXAMINE ParentA
5 NO Mailbox doesn't exist: ParentA (0.001 + 0.000 secs).
6 DELETE ParentA.ChildA
6 OK Delete completed (0.022 + 0.000 + 0.021 secs).
7 CREATE ParentB
7 OK Create completed (0.019 + 0.000 + 0.018 secs).
8 CREATE ParentB.ChildB
8 OK Create completed (0.009 + 0.000 + 0.008 secs).
9 LIST "" "*"
* LIST (\HasChildren) "." ParentB
* LIST (\HasNoChildren) "." ParentB.ChildB
* LIST (\HasNoChildren \UnMarked \Trash) "." INBOX.Trash
* LIST (\HasNoChildren \UnMarked \Sent) "." INBOX.Sent
* LIST (\HasNoChildren \UnMarked \Junk) "." INBOX.Spam
* LIST (\HasNoChildren \UnMarked \Archive) "." INBOX.Read
* LIST (\HasNoChildren \UnMarked \Drafts) "." INBOX.Drafts
* LIST (\HasChildren) "." INBOX
9 OK List completed (0.001 + 0.000 secs).
10 DELETE ParentB
10 OK Delete completed (0.015 + 0.000 + 0.014 secs).
11 LIST "" "*"
* LIST (\HasChildren) "." ParentB
* LIST (\HasNoChildren) "." ParentB.ChildB
* LIST (\HasNoChildren \UnMarked \Trash) "." INBOX.Trash
* LIST (\HasNoChildren \UnMarked \Sent) "." INBOX.Sent
* LIST (\HasNoChildren \UnMarked \Junk) "." INBOX.Spam
* LIST (\HasNoChildren \UnMarked \Archive) "." INBOX.Read
* LIST (\HasNoChildren \UnMarked \Drafts) "." INBOX.Drafts
* LIST (\HasChildren) "." INBOX
11 OK List completed (0.001 + 0.000 secs).
12 EXAMINE ParentB
12 NO Mailbox doesn't exist: ParentB (0.001 + 0.000 secs).

I would have expected the output from the "11 LIST..." command to be identical to that of the "4 LIST..." command, i.e. that "ParentB" would be listed as "\Noselect" in the response to "11 LIST...".

I've tracked the contents of the local /var/vmail/.../Maildir folder while executing the above commands, and it appears to correspond to the expected situation (i.e. ".ParentA.ChildA" is created, then deleted, then ".ParentB" is created, then ".ParentB.ChildB" is created, and finally ".ParentB" is deleted - in other words, neither the ".ParentA" nor the ".ParentB" folders exist at the time when I issue the "4 LIST..." and "11 LIST..." commands). 

That "ParentB" should have a "\Noselect" flag in the last "LIST" also appears to be what's mandated by RFC3501, section 6.3.4:

      ...
      The DELETE command MUST NOT remove inferior hierarchical names.
      For example, if a mailbox "foo" has an inferior "foo.bar"
      (assuming "." is the hierarchy delimiter character), removing
      "foo" MUST NOT remove "foo.bar".  It is an error to attempt to
      delete a name that has inferior hierarchical names and also has
      the \Noselect mailbox name attribute (see the description of the
      LIST response for more details).

      It is permitted to delete a name that has inferior hierarchical
      names and does not have the \Noselect mailbox name attribute.  In
      this case, all messages in that mailbox are removed, and the name
      will acquire the \Noselect mailbox name attribute.
      ...

Tested using the default dovecot package in Debian Bullseye, which is version 1:2.3.13+dfsg1-2. The file system is ext4, and Dovecot is running in a virtual (systemd-nspawn) machine for testing purposes.

I've tried grepping through the git changelogs and sources, but I couldn't find anything which would appear to be relevant post-2.3.13.

Any ideas?

(Please CC me on replies, not subscribed)

doveconf -n output
==================
# 2.3.13 (89f716dc2): /etc/dovecot/dovecot.conf
# Pigeonhole version 0.5.13 (cdd19fe3)
# OS: Linux 5.10.0-8-amd64 x86_64 Debian 11.0 
# Hostname: localhost
auth_default_realm = example.com
auth_mechanisms = plain login
doveadm_password = # hidden, use -P to show it
doveadm_port = 12345
mail_gid = vmail
mail_home = /var/vmail/%d/%n
mail_location = maildir:~/Maildir
mail_privileged_group = vmail
mail_uid = vmail
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext imapsieve vnd.dovecot.imapsieve
namespace inbox {
  inbox = yes
  location = 
  mailbox INBOX.Drafts {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox INBOX.Read {
    auto = subscribe
    special_use = \Archive
  }
  mailbox INBOX.Sent {
    auto = subscribe
    special_use = \Sent
  }
  mailbox INBOX.Spam {
    auto = subscribe
    special_use = \Junk
  }
  mailbox INBOX.Trash {
    auto = subscribe
    special_use = \Trash
  }
  prefix = 
}
passdb {
  args = /etc/dovecot/dovecot.deny
  deny = yes
  driver = passwd-file
}
passdb {
  args = /etc/dovecot/dovecot-ldap-passdb.conf
  driver = ldap
}
plugin {
  imapsieve_mailbox1_before = file:/var/vmail/sieve/global/learn-spam.sieve
  imapsieve_mailbox1_causes = COPY
  imapsieve_mailbox1_name = INBOX.Spam
  imapsieve_mailbox2_before = file:/var/vmail/sieve/global/learn-ham.sieve
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_from = INBOX.Spam
  imapsieve_mailbox2_name = *
  quota = maildir:User quota
  sieve = file:~/sieve;active=~/.dovecot.sieve
  sieve_before = /var/vmail/sieve/global/spam-global.sieve
  sieve_global_extensions = +vnd.dovecot.pipe
  sieve_pipe_bin_dir = /usr/bin
  sieve_plugins = sieve_imapsieve sieve_extprograms
}
protocols = imap lmtp sieve
service aggregator {
  fifo_listener replication-notify-fifo {
    user = vmail
  }
  unix_listener replication-notify {
    user = vmail
  }
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  unix_listener auth-userdb {
    group = vmail
    mode = 0660
    user = vmail
  }
}
service doveadm {
  inet_listener doveadm {
    port = 12345
    ssl = yes
  }
}
service imap-login {
  inet_listener imap {
    address = 127.0.0.1, [::1]
    port = 143
  }
  inet_listener imaps {
    port = 993
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    group = postfix
    mode = 0660
    user = postfix
  }
  user = vmail
}
service managesieve-login {
  inet_listener sieve {
    port = 4190
  }
}
service replicator {
  process_min_avail = 1
  unix_listener replicator-doveadm {
    mode = 0600
    user = vmail
  }
}
ssl = required
ssl_cert = </etc/pki/realms/domain/default.crt
ssl_client_ca_dir = /etc/ssl/certs
ssl_dh = # hidden, use -P to show it
ssl_key = # hidden, use -P to show it
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
userdb {
  args = /etc/dovecot/dovecot-ldap-userdb.conf
  driver = ldap
}
protocol imap {
  mail_plugins = " notify replication quota imap_sieve imap_quota"
}
protocol lmtp {
  mail_plugins = " notify replication quota sieve"
  postmaster_address = postmaster at example.com
}


More information about the dovecot mailing list