summaryrefslogtreecommitdiffstats
path: root/source/n/alpine/maildir.patch
diff options
context:
space:
mode:
Diffstat (limited to 'source/n/alpine/maildir.patch')
-rw-r--r--source/n/alpine/maildir.patch3837
1 files changed, 3837 insertions, 0 deletions
diff --git a/source/n/alpine/maildir.patch b/source/n/alpine/maildir.patch
new file mode 100644
index 000000000..560fe9699
--- /dev/null
+++ b/source/n/alpine/maildir.patch
@@ -0,0 +1,3837 @@
+diff -rc alpine-2.24/alpine/alpine.c alpine-2.24.maildir/alpine/alpine.c
+*** alpine-2.24/alpine/alpine.c 2020-10-10 00:24:28.216554908 -0600
+--- alpine-2.24.maildir/alpine/alpine.c 2020-10-10 00:26:49.964167282 -0600
+***************
+*** 591,596 ****
+--- 591,601 ----
+ if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global))
+ mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE);
+
++ #ifndef _WINDOWS
++ rv = F_ON(F_COURIER_FOLDER_LIST, ps_global) ? 1 : 0;
++ mail_parameters(NULL,SET_COURIERSTYLE, (void *) &rv);
++ #endif
++
+ rvl = 0L;
+ if(pine_state->VAR_NNTPRANGE){
+ if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF))
+diff -rc alpine-2.24/alpine/confscroll.c alpine-2.24.maildir/alpine/confscroll.c
+*** alpine-2.24/alpine/confscroll.c 2020-10-10 00:24:28.216554908 -0600
+--- alpine-2.24.maildir/alpine/confscroll.c 2020-10-10 00:26:49.968167384 -0600
+***************
+*** 5567,5572 ****
+--- 5567,5578 ----
+ (void *)var->current_val.p);
+ }
+ #endif
++ #ifndef _WINDOWS
++ else if(var == &ps->vars[V_MAILDIR_LOCATION]){
++ if(var->current_val.p && var->current_val.p[0])
++ mail_parameters(NULL, SET_MDINBOXPATH, (void *)var->current_val.p);
++ }
++ #endif
+ else if(revert && standard_radio_var(ps, var)){
+
+ cur_rule_value(var, TRUE, FALSE);
+diff -rc alpine-2.24/imap/src/c-client/mail.c alpine-2.24.maildir/imap/src/c-client/mail.c
+*** alpine-2.24/imap/src/c-client/mail.c 2020-10-10 00:24:28.200554500 -0600
+--- alpine-2.24.maildir/imap/src/c-client/mail.c 2020-10-10 00:26:49.968167384 -0600
+***************
+*** 1063,1069 ****
+ MAILSTREAM *ts;
+ char *s,*t,tmp[MAILTMPLEN];
+ size_t i;
+! DRIVER *d;
+ /* never allow names with newlines */
+ if ((s = strpbrk (mailbox,"\015\012")) != NULL) {
+ MM_LOG ("Can't create mailbox with such a name",ERROR);
+--- 1063,1069 ----
+ MAILSTREAM *ts;
+ char *s,*t,tmp[MAILTMPLEN];
+ size_t i;
+! DRIVER *d, *md;
+ /* never allow names with newlines */
+ if ((s = strpbrk (mailbox,"\015\012")) != NULL) {
+ MM_LOG ("Can't create mailbox with such a name",ERROR);
+***************
+*** 1087,1092 ****
+--- 1087,1094 ----
+ return NIL;
+ }
+
++ /* Hack, we should do this better, but it works */
++ for (md = maildrivers; md && strcmp (md->name, "md"); md = md->next);
+ /* see if special driver hack */
+ if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) &&
+ ((mailbox[2] == 'r') || (mailbox[2] == 'R')) &&
+***************
+*** 1117,1122 ****
+--- 1119,1131 ----
+ (((*mailbox == '{') || (*mailbox == '#')) &&
+ (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
+ d = stream->dtb;
++ else if(mailbox[0] == '#'
++ && (mailbox[1] == 'm' || mailbox[1] == 'M')
++ && (mailbox[2] == 'd' || mailbox[2] == 'D'
++ || mailbox[2] == 'c' || mailbox[2] == 'C')
++ && mailbox[3] == '/'
++ && mailbox[4] != '\0')
++ return (*md->create)(stream, mailbox);
+ else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
+ else { /* failed utterly */
+ sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
+diff -rc alpine-2.24/imap/src/c-client/mail.h alpine-2.24.maildir/imap/src/c-client/mail.h
+*** alpine-2.24/imap/src/c-client/mail.h 2020-10-10 00:24:28.200554500 -0600
+--- alpine-2.24.maildir/imap/src/c-client/mail.h 2020-10-10 00:26:49.968167384 -0600
+***************
+*** 383,388 ****
+--- 383,392 ----
+ #define SET_SCANCONTENTS (long) 573
+ #define GET_MHALLOWINBOX (long) 574
+ #define SET_MHALLOWINBOX (long) 575
++ #define GET_COURIERSTYLE (long) 576
++ #define SET_COURIERSTYLE (long) 577
++ #define SET_MDINBOXPATH (long) 578
++ #define GET_MDINBOXPATH (long) 579
+
+ /* Driver flags */
+
+diff -rc alpine-2.24/imap/src/osdep/unix/dummy.c alpine-2.24.maildir/imap/src/osdep/unix/dummy.c
+*** alpine-2.24/imap/src/osdep/unix/dummy.c 2020-10-10 00:24:28.192554297 -0600
+--- alpine-2.24.maildir/imap/src/osdep/unix/dummy.c 2020-10-10 00:26:49.972167485 -0600
+***************
+*** 104,116 ****
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+!
+ DRIVER *dummy_valid (char *name)
+ {
+! char *s,tmp[MAILTMPLEN];
+ struct stat sbuf;
+ /* must be valid local mailbox */
+! if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+ /* indeterminate clearbox INBOX */
+ if (!*s) return &dummydriver;
+ else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+--- 104,122 ----
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+! char * maildir_remove_root(char *);
+ DRIVER *dummy_valid (char *name)
+ {
+! char *s,tmp[MAILTMPLEN], *rname;
+ struct stat sbuf;
++
++ if(strlen(name) > MAILTMPLEN)
++ name[MAILTMPLEN] = '\0';
++
++ strcpy(tmp, name);
++ rname = maildir_remove_root(tmp);
+ /* must be valid local mailbox */
+! if (rname && *rname && (*rname != '{') && (s = mailboxfile (tmp,rname))) {
+ /* indeterminate clearbox INBOX */
+ if (!*s) return &dummydriver;
+ else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+***************
+*** 119,126 ****
+ return &dummydriver;
+ }
+ /* blackbox INBOX does not exist yet */
+! else if (!compare_cstring (name,"INBOX")) return &dummydriver;
+ }
+ return NIL;
+ }
+
+--- 125,133 ----
+ return &dummydriver;
+ }
+ /* blackbox INBOX does not exist yet */
+! else if (!compare_cstring (rname,"INBOX")) return &dummydriver;
+ }
++ if(rname) fs_give((void **)&rname);
+ return NIL;
+ }
+
+***************
+*** 453,458 ****
+--- 460,467 ----
+ {
+ char *s,tmp[MAILTMPLEN];
+ long ret = NIL;
++ if(!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4))
++ return maildir_create(stream, mailbox);
+ /* validate name */
+ if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
+ sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+***************
+*** 518,523 ****
+--- 527,540 ----
+ {
+ struct stat sbuf;
+ char *s,tmp[MAILTMPLEN];
++ if (!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4)
++ || is_valid_maildir(&mailbox)){
++ char tmp[MAILTMPLEN] = {'\0'};
++ strcpy(tmp, mailbox);
++ if(tmp[strlen(tmp) - 1] != '/')
++ tmp[strlen(tmp)] = '/';
++ return maildir_delete(stream, tmp);
++ }
+ if (!(s = dummy_file (tmp,mailbox))) {
+ sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+ MM_LOG (tmp,ERROR);
+***************
+*** 543,554 ****
+ long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+ {
+ struct stat sbuf;
+! char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+ /* no trailing / allowed */
+! if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+ stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+ ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+! sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+ MM_LOG (mbx,ERROR);
+ return NIL;
+ }
+--- 560,582 ----
+ long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+ {
+ struct stat sbuf;
+! char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN], *rold, *rnewname;
+!
+! if(strlen(old) > MAILTMPLEN)
+! old[MAILTMPLEN] = '\0';
+!
+! if(strlen(newname) > MAILTMPLEN)
+! newname[MAILTMPLEN] = '\0';
+!
+! strcpy(tmp, old);
+! rold = maildir_remove_root(tmp);
+! strcpy(tmp, newname);
+! rnewname = maildir_remove_root(tmp);
+ /* no trailing / allowed */
+! if (!dummy_file (oldname,rold) || !(s = dummy_file (mbx,rnewname)) ||
+ stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+ ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+! sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",rold,rnewname);
+ MM_LOG (mbx,ERROR);
+ return NIL;
+ }
+***************
+*** 564,577 ****
+ }
+ }
+ /* rename of non-ex INBOX creates dest */
+! if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+ return dummy_create (NIL,mbx);
+ if (rename (oldname,mbx)) {
+! sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+ strerror (errno));
+ MM_LOG (tmp,ERROR);
+ return NIL;
+ }
+ return T; /* return success */
+ }
+
+--- 592,607 ----
+ }
+ }
+ /* rename of non-ex INBOX creates dest */
+! if (!compare_cstring (rold,"INBOX") && stat (oldname,&sbuf))
+ return dummy_create (NIL,mbx);
+ if (rename (oldname,mbx)) {
+! sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",rold,rnewname,
+ strerror (errno));
+ MM_LOG (tmp,ERROR);
+ return NIL;
+ }
++ if(rold) fs_give((void **)&rold);
++ if(rnewname) fs_give((void **)&rnewname);
+ return T; /* return success */
+ }
+
+diff -rc alpine-2.24/imap/src/osdep/unix/maildir.c alpine-2.24.maildir/imap/src/osdep/unix/maildir.c
+*** alpine-2.24/imap/src/osdep/unix/maildir.c 2020-10-10 00:26:50.012168504 -0600
+--- alpine-2.24.maildir/imap/src/osdep/unix/maildir.c 2020-10-10 00:26:49.972167485 -0600
+***************
+*** 0 ****
+--- 1,2671 ----
++ /*
++ * Maildir driver for Alpine 2.20
++ *
++ * Written by Eduardo Chappa <alpine.chappa@gmx.com>
++ * Last Update: June 10, 2014
++ *
++ */
++
++ #include <stdio.h>
++ #include <ctype.h>
++ #include <errno.h>
++ extern int errno; /* just in case */
++ #include "mail.h"
++ #include <pwd.h>
++ #include <sys/stat.h>
++ #include <sys/time.h>
++ #include "osdep.h"
++ #include "rfc822.h"
++ #include "fdstring.h"
++ #include "misc.h"
++ #include "dummy.h"
++ #include "maildir.h"
++
++ /* Driver dispatch used by MAIL */
++ DRIVER maildirdriver = {
++ "md", /* driver name, yes it's md, not maildir */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT, /* driver flags */
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ maildir_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++
++ DRIVER courierdriver = {
++ "mc", /* Why a separate driver? So that createproto will work */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT, /* driver flags */
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ courier_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++ MAILSTREAM maildirproto = {&maildirdriver}; /* prototype stream */
++ MAILSTREAM courierproto = {&courierdriver}; /* prototype stream */
++
++ long maildir_dirfmttest (char *name)
++ {
++ int i;
++ for (i = 0; mdstruct[i] && strcmp(name, mdstruct[i]); i++);
++ return (i < EndDir) || !strcmp(name, MDDIR)
++ || !strncmp(name, MDUIDLAST, strlen(MDUIDLAST))
++ || !strncmp(name, MDUIDTEMP, strlen(MDUIDTEMP)) ? LONGT : NIL;
++ }
++
++ void
++ md_domain_name(void)
++ {
++ int i, j;
++
++ strcpy(mdlocaldomain, mylocalhost ());
++ for (i = 0; mdlocaldomain[i] != '\0' ;)
++ if(mdlocaldomain[i] == '/' || mdlocaldomain[i] == ':'){
++ for(j = strlen(mdlocaldomain); j >= i; j--)
++ mdlocaldomain[j+4] = mdlocaldomain[j];
++ mdlocaldomain[i++] = '\\';
++ mdlocaldomain[i++] = '0';
++ if(mdlocaldomain[i] == '/'){
++ mdlocaldomain[i++] = '5';
++ mdlocaldomain[i++] = '7';
++ } else {
++ mdlocaldomain[i++] = '7';
++ mdlocaldomain[i++] = '2';
++ }
++ }
++ else
++ i++;
++ }
++
++ char *
++ myrootdir(char *name)
++ {
++ return myhomedir();
++ }
++
++ char *
++ mdirpath(void)
++ {
++ char *path = maildir_parameters(GET_MDINBOXPATH, NIL);
++ return path ? (path[0] ? path : ".") : "Maildir";
++ }
++
++ /* remove the "#md/" or "#mc/" part from a folder name
++ * memory freed by caller
++ */
++ char *
++ maildir_remove_root (char *name)
++ {
++ int courier = IS_COURIER(name), offset;
++ char realname[MAILTMPLEN];
++
++ offset = maildir_valid_name(name) ? (name[3] == '/' ? 4 : 3) : 0;
++ if(courier)
++ courier_realname(name+offset, realname);
++ else
++ strcpy(realname, name+offset);
++ return cpystr(realname);
++ }
++
++
++ /* Check validity of the name, we accept:
++ * a) #md/directory/folder
++ * b) #md/inbox
++ * A few considerations: We can only accept as valid
++ * a) names that start with #md/ and the directory exists or
++ * b) names that do not start with #md/ but are maildir directories (have
++ * the /cur, /tmp and /new structure)
++ */
++ int maildir_valid_name (char *name)
++ {
++ char tmpname[MAILTMPLEN] = {'\0'};
++
++ if (mdfpath)
++ fs_give((void **)&mdfpath);
++ if (name && (name[0] != '#'))
++ snprintf(tmpname, sizeof(tmpname), "%s%s",MDPREFIX(CCLIENT), name);
++ mdfpath = cpystr(tmpname[0] ? tmpname : name);
++
++ return IS_CCLIENT(name) || IS_COURIER(name);
++ }
++
++ /* Check if the directory whose path is given by name is a valid maildir
++ * directory (contains /cur, /tmp and /new)
++ */
++ int maildir_valid_dir (char *name)
++ {
++ int len;
++ DirNamesType i;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN];
++
++ if(name[strlen(name) - 1] == '/')
++ name[strlen(name) - 1] = '\0';
++ len = strlen(name);
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, name, i);
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
++ break;
++ }
++ name[len] = '\0';
++ return (i == EndDir) ? T : NIL;
++ }
++
++ void courier_realname(char *name, char *realname)
++ {
++ int i,j;
++
++ if(!name)
++ return;
++
++ for (i = 0, j = 0; i < MAILTMPLEN && j < strlen(name); j++, i++){
++ realname[i] = name[j];
++ if(name[j] == '/' && name[j+1] != '.' && name[j+1] != '%'
++ && name[j+1] != '*')
++ realname[++i] = '.';
++ }
++ if(realname[i-1] == '.')
++ i--;
++ realname[i] = '\0';
++ }
++
++
++ /* given a maildir folder, return its path. Memory freed by caller. Directory
++ * does not contain the trailing slash "/". On error NULL is returned.
++ */
++ int maildir_file_path (char *name, char *tmp, size_t sizeoftmp)
++ {
++ char *maildirpath = mdirpath(), *rname;
++ int courier = IS_COURIER(name);
++
++ /* There are several ways in which the path can come, so we will handle
++ them here. First we deal with #mc/ or #md/ prefix by removing the
++ prefix, if any */
++
++ if(strlen(name) >= MAILTMPLEN)
++ name[MAILTMPLEN] = '\0';
++ strcpy(tmp, name);
++ rname = maildir_remove_root(tmp);
++ tmp[0] = '\0'; /* just in case something fails */
++
++ if (strlen(myrootdir(rname)) +
++ max(strlen(rname), strlen(maildirpath)) > sizeoftmp){
++ errno = ENAMETOOLONG;
++ snprintf(tmp, sizeoftmp, "Error opening \"%s\": %s", rname, strerror (errno));
++ mm_log(tmp,ERROR);
++ if(rname) fs_give((void **)&rname);
++ return NIL;
++ }
++
++ /* There are two ways in which the name can come here, either as a
++ full path or not. If it is not a full path it can come in two ways,
++ either as a file system path (Maildir/.Drafts) or as a maildir path
++ (INBOX.Drafts)
++ */
++
++ if(*rname == '/'){ /* full path */
++ strncpy(tmp, rname, sizeoftmp); /* do nothing */
++ tmp[sizeoftmp-1] = '\0';
++ }
++ else
++ snprintf (tmp, sizeoftmp, "%s/%s%s%s", myrootdir (rname),
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? rname : maildirpath,
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? "" : (courier ? "/" : ""),
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? "" : (*(rname+5) == MDSEPARATOR(courier) ? rname+5 : ""));
++ if(rname) fs_give((void **)&rname);
++ return tmp[0] ? T : NIL;
++ }
++
++ /* This function is given a full path for a mailbox and returns
++ * if it is a valid maildir transformed to canonical notation
++ */
++ int
++ is_valid_maildir (char **name)
++ {
++ if (!strncmp(*name, myrootdir (*name), strlen(myrootdir(*name)))){
++ (*name) += strlen(myrootdir(*name));
++ if (**name == '/') (*name)++;
++ }
++ return maildir_valid(*name) ? T : NIL;
++ }
++
++ /* Check validity of mailbox. This routine does not send errors to log, other
++ * routines calling this one may do so, though
++ */
++
++ DRIVER *maildir_valid (char *name)
++ {
++ char tmpname[MAILTMPLEN];
++
++ maildir_file_path(name, tmpname, sizeof(tmpname));
++
++ return maildir_valid_dir(tmpname)
++ ? (IS_COURIER(name) ? &courierdriver : &maildirdriver) : NIL;
++ }
++
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags)
++ {
++ unsigned long i;
++ MESSAGECACHE *elt;
++ /* get sequence */
++ if (stream && LOCAL && ((flags & FT_UID) ?
++ mail_uid_sequence (stream,sequence) :
++ mail_sequence (stream,sequence)))
++ for (i = 1L; i <= stream->nmsgs; i++) {
++ if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
++ !(elt->day && elt->rfc822_size)) {
++ ENVELOPE **env = NIL;
++ ENVELOPE *e = NIL;
++ if (!stream->scache) env = &elt->private.msg.env;
++ else if (stream->msgno == i) env = &stream->env;
++ else env = &e;
++ if (!*env || !elt->rfc822_size) {
++ STRING bs;
++ unsigned long hs;
++ char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
++
++ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
++ stream->dtb->flags);
++ if (!elt->rfc822_size) {
++ (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
++ elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
++ }
++ }
++
++ if (!elt->day && *env && (*env)->date)
++ mail_parse_date (elt,(*env)->date);
++
++ if (!elt->day) elt->day = elt->month = 1;
++ mail_free_envelope (&e);
++ }
++ }
++ }
++
++ int
++ maildir_eliminate_duplicate (char *name, struct direct ***flist, unsigned long *nfiles)
++ {
++ int i, j, k, error = 0, scanr;
++ char new[MAILTMPLEN], old[MAILTMPLEN], tmp[MAILTMPLEN], *str;
++ struct direct **names = NIL;
++
++ if((scanr = maildir_doscandir(name, &names, CCLIENT)) < 0)
++ return -1;
++
++ if(nfiles) *nfiles = scanr;
++ for(i = 0, j = 1, k = 0; j < scanr; i++, j++){
++ if(k)
++ names[i] = names[i+k];
++ if(same_maildir_file(names[i]->d_name, names[j]->d_name)){
++ int d, f, r, s;
++ maildir_getflag(names[i]->d_name, &d, &f, &r, &s, NIL);
++ snprintf(old, sizeof(old), "%s/%s", name, names[i]->d_name);
++ snprintf(new, sizeof(new), "%s/.%s", name, names[i]->d_name);
++ if(rename(old, new) < 0 && errno != EEXIST)
++ error++;
++ if(!error){
++ for(; j < scanr
++ && same_maildir_file(names[i]->d_name, names[j]->d_name)
++ ; j++, k++){
++ maildir_getflag(names[j]->d_name, (d ? NIL : &d),
++ (f ? NIL : &f), (r ? NIL : &r), (s ? NIL : &s), NIL);
++ snprintf(tmp, sizeof(tmp), "%s/%s", name, names[j]->d_name);
++ if(unlink(tmp) < 0){ /* Hmmm... a problem, let's see */
++ struct stat sbuf;
++ if (stat(tmp, &sbuf) == 0 && (sbuf.st_mode & S_IFMT) == S_IFREG)
++ error++;
++ }
++ }
++ if((str = strrchr(names[i]->d_name,FLAGSEP)) != NULL) *str = '\0';
++ snprintf (old, sizeof(old), "%s/%s%s%s%s%s%s", name, names[i]->d_name, MDSEP(2),
++ MDFLAG(Draft, d), MDFLAG(Flagged, f), MDFLAG(Replied, r),
++ MDFLAG(Seen, s));
++ if(rename(new, old) < 0)
++ error++;
++ }
++ }
++
++ }
++ if(k > 0)
++ fs_give((void **)&names);
++ else
++ *flist = names;
++ return error ? -1 : k;
++ }
++
++ int
++ maildir_doscandir(char *name, struct direct ***flist, int flag)
++ {
++ return scandir(name, flist,
++ flag == CCLIENT ? maildir_select : courier_dir_select,
++ flag == CCLIENT ? maildir_namesort : courier_dir_sort);
++ }
++
++ /*
++ * return all files in a given directory. This is a separate call
++ * so that if there are warnings during compilation this only appears once.
++ */
++ unsigned long
++ maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag)
++ {
++ struct stat sbuf;
++ int rv = -2; /* impossible value */
++
++ if (scand)
++ *scand = -1; /* assume error for safety */
++ *nfiles = 0;
++ if((stat(name,&sbuf) < 0)
++ || (flag == CCLIENT
++ && ((rv = maildir_eliminate_duplicate(name, flist, nfiles)) < 0)))
++ return 0L;
++
++ if (scand && (rv > 0 || rv == -2))
++ *nfiles = maildir_doscandir(name, flist, flag);
++
++ if(scand) *scand = *nfiles;
++
++ return (unsigned long) sbuf.st_ctime;
++ }
++
++ /* Does a message with given name exists (or was it removed)?
++ * Returns: 1 - yes, such message exist,
++ * 0 - No, that message does not exist anymore
++ *
++ * Parameters: stream, name of mailbox, new name if his message does not
++ * exist.
++ */
++
++ int maildir_message_exists(MAILSTREAM *stream, char *name, char *newfile)
++ {
++ char tmp[MAILTMPLEN];
++ int gotit = NIL;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ /* First check directly if it exists, if not there, look for it */
++ snprintf(tmp, sizeof(tmp), "%s/%s", LOCAL->path[Cur], name);
++ if ((stat(tmp, &sbuf) == 0) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
++ return T;
++
++ if (!(dir = opendir (LOCAL->path[Cur])))
++ return NIL;
++
++ while ((d = readdir(dir)) && gotit == NIL){
++ if (d->d_name[0] == '.')
++ continue;
++ if (same_maildir_file(d->d_name, name)){
++ gotit = T;
++ strcpy(newfile, d->d_name);
++ }
++ }
++ closedir(dir);
++ return gotit;
++ }
++
++ /* Maildir open */
++
++ MAILSTREAM *maildir_open (MAILSTREAM *stream)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ if (!stream) return &maildirproto;
++ if (stream->local) fatal ("maildir recycle stream");
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain */
++ if(mypid == (pid_t) 0)
++ mypid = getpid();
++ if (!stream->rdonly){
++ stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
++ stream->perm_answered = stream->perm_draft = T;
++ }
++ stream->local = (MAILDIRLOCAL *) fs_get (sizeof (MAILDIRLOCAL));
++ memset(LOCAL, 0, sizeof(MAILDIRLOCAL));
++ LOCAL->fd = -1;
++
++ LOCAL->courier = IS_COURIER(stream->mailbox);
++ strcpy(tmp, stream->mailbox);
++ if (maildir_file_path (stream->mailbox, tmp, sizeof(tmp)))
++ LOCAL->dir = cpystr (tmp);
++ LOCAL->candouid = maildir_can_assign_uid(stream);
++ maildir_read_uid(stream, &stream->uid_last, &stream->uid_validity);
++ if (LOCAL->dir){
++ LOCAL->path = (char **) fs_get(EndDir*sizeof(char *));
++ MDFLD(tmp, LOCAL->dir, Cur); LOCAL->path[Cur] = cpystr (tmp);
++ MDFLD(tmp, LOCAL->dir, New); LOCAL->path[New] = cpystr (tmp);
++ MDFLD(tmp, LOCAL->dir, Tmp); LOCAL->path[Tmp] = cpystr (tmp);
++ if (stat (LOCAL->path[Cur],&sbuf) < 0) {
++ snprintf (tmp, sizeof(tmp), "Can't open folder %s: %s",
++ stream->mailbox,strerror (errno));
++ mm_log (tmp,ERROR);
++ maildir_close(stream, 0);
++ return NIL;
++ }
++ }
++
++ if(maildir_file_path (stream->mailbox, tmp, sizeof(tmp))){
++ fs_give ((void **) &stream->mailbox);
++ stream->mailbox = cpystr(tmp);
++ }
++
++ LOCAL->buf = (char *) fs_get (CHUNKSIZE);
++ LOCAL->buflen = CHUNKSIZE - 1;
++ stream->sequence++;
++ stream->nmsgs = stream->recent = 0L;
++
++ maildir_parse_folder(stream, 1);
++
++ return stream;
++ }
++
++ /* Maildir initial parsing of the folder */
++ void
++ maildir_parse_folder (MAILSTREAM *stream, int full)
++ {
++ char tmp[MAILTMPLEN];
++ struct direct **namescur = NIL, **namesnew = NIL;
++ unsigned long i, nfilescur = 0L, nfilesnew = 0L, oldpos, newpos, total;
++ int scan_err, rescan, loop = 0;
++
++ if (!stream) /* what??? */
++ return;
++
++ MM_CRITICAL(stream);
++
++ maildir_scandir (LOCAL->path[New], &namesnew, &nfilesnew, &scan_err, CCLIENT);
++ if (scan_err < 0)
++ maildir_abort(stream);
++
++ /* Scan old messages first, escoba! */
++ if(stream->rdonly ||
++ (LOCAL && ((maildir_initial_check(stream, Cur) == 0)
++ || nfilesnew > 0L))){
++ LOCAL->scantime = maildir_scandir (LOCAL->path[Cur], &namescur, &nfilescur,
++ &scan_err, CCLIENT);
++ if (scan_err < 0){
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ maildir_abort(stream);
++ }
++ }
++ if(LOCAL && (maildir_initial_check(stream, New) == 0)
++ && (nfilescur > 0L)){
++ while(LOCAL && loop < 10){
++ if(nfilesnew == 0L)
++ maildir_scandir (LOCAL->path[New], &namesnew, &nfilesnew, &scan_err, CCLIENT);
++ if (scan_err < 0){
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ maildir_abort(stream);
++ break;
++ }
++ for(i = 0L, rescan = 0, newpos = oldpos = 0L;
++ newpos < nfilescur && i < nfilesnew; i++){
++ if(maildir_message_in_list(namesnew[i]->d_name, namescur, oldpos,
++ nfilescur - 1L, &newpos)){
++ oldpos = newpos;
++ snprintf(tmp, sizeof(tmp), "%s/%s", LOCAL->path[New], namesnew[i]->d_name);
++ if(unlink(tmp) < 0)
++ scan_err = -1;
++ rescan++;
++ }
++ else
++ newpos = oldpos;
++ }
++ if(scan_err < 0)
++ maildir_abort(stream);
++ if(rescan == 0)
++ break;
++ else{ /* restart */
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ nfilesnew = 0L;
++ loop++;
++ }
++ }
++ }
++ if(loop == 10)
++ maildir_abort(stream);
++ if(LOCAL){
++ if(stream->rdonly)
++ stream->recent = 0L;
++ total = namescur || stream->rdonly
++ ? maildir_parse_dir(stream, 0L, Cur, namescur,
++ nfilescur, full) : stream->nmsgs;
++ stream->nmsgs = maildir_parse_dir(stream, total, New, namesnew,
++ nfilesnew, full);
++ }
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ if(namescur){
++ for(i = 0L; i < nfilescur; i++)
++ fs_give((void **)&namescur[i]);
++ fs_give((void **) &namescur);
++ }
++ MM_NOCRITICAL(stream);
++ }
++
++ int
++ maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype)
++ {
++ char *tmp;
++ struct stat sbuf;
++
++ if (access (LOCAL->path[dirtype], R_OK|W_OK|X_OK) != 0){
++ maildir_abort(stream);
++ return -1;
++ }
++
++ if (dirtype != New &&
++ (stat(LOCAL->path[Cur], &sbuf) < 0 || sbuf.st_ctime == LOCAL->scantime))
++ return -1;
++ return 0;
++ }
++
++
++ /* Return the number of messages in the directory, while filling the
++ * elt structure.
++ */
++
++ unsigned long
++ maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, struct direct **names,
++ unsigned long nfiles, int full)
++ {
++ char tmp[MAILTMPLEN], file[MAILTMPLEN], newfile[MAILTMPLEN], *mdstr;
++ struct stat sbuf;
++ unsigned long i, new = 0L, l, uid_last;
++ unsigned long recent = stream ? stream->recent : 0L;
++ int d = 0, f = 0, r = 0, s = 0, t = 0;
++ int we_compute, in_list;
++ int silent = stream ? stream->silent : NIL;
++ MESSAGECACHE *elt;
++
++ if (dirtype == Cur && !stream->rdonly)
++ for (i = 1L; i <= stream->nmsgs;){
++ elt = mail_elt(stream, i);
++ in_list = elt && elt->private.spare.ptr && nfiles > 0L
++ ? (MDPOS(elt) < nfiles
++ ? same_maildir_file(MDFILE(elt), names[MDPOS(elt)]->d_name)
++ : NIL)
++ || maildir_message_in_list(MDFILE(elt), names, 0L,
++ nfiles - 1L, &MDPOS(elt))
++ : NIL;
++ if (!in_list){
++ if (elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++
++ if (elt->recent) --recent;
++ mail_expunged(stream,i);
++ }
++ else i++;
++ }
++
++ stream->silent = T;
++ uid_last = 0L;
++ for (we_compute = 0, i = l = 1L; l <= nfiles; l++){
++ unsigned long pos, uid;
++ if (dirtype == New && !stream->rdonly){ /* move new messages to cur */
++ pos = l - 1L;
++ snprintf (file, sizeof(file), "%s/%s", LOCAL->path[New], names[pos]->d_name);
++ if(lstat(file,&sbuf) == 0)
++ switch(sbuf.st_mode & S_IFMT){
++ case S_IFREG:
++ strcpy(tmp, names[pos]->d_name);
++ if((mdstr = strstr(tmp,MDSEP(3)))
++ || (mdstr = strstr(tmp,MDSEP(2))))
++ *(mdstr+1) = '2';
++ else
++ strcat(tmp, MDSEP(2));
++ snprintf(newfile, sizeof(newfile), "%s/%s", LOCAL->path[Cur], tmp);
++ if(rename (file, newfile) != 0){
++ mm_log("Unable to read new mail!", WARN);
++ continue;
++ }
++ unlink (file);
++ new++;
++ break;
++ case S_IFLNK: /* clean up, clean up, everybody, everywhere */
++ if(unlink(file) < 0){
++ if(LOCAL->link == NIL){
++ mm_log("Unable to remove symbolic link", WARN);
++ LOCAL->link = T;
++ }
++ }
++ continue;
++ break;
++ default:
++ if(LOCAL && LOCAL->link == NIL){
++ mm_log("Unrecognized file or link in folder", WARN);
++ LOCAL->link = T;
++ }
++ continue;
++ break;
++ }
++ }
++ mail_exists(stream, i + nmsgs);
++ elt = mail_elt(stream, i + nmsgs);
++ pos = (elt && elt->private.spare.ptr) ? MDPOS(elt) : l - 1L;
++ if (dirtype == New) elt->recent = T;
++ maildir_getflag(names[pos]->d_name, &d, &f, &r ,&s, &t);
++ if (elt->private.spare.ptr)
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ else{
++ maildir_get_file((MAILDIRFILE **)&elt->private.spare.ptr);
++ we_compute++;
++ }
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ MDPOS(elt) = pos;
++ MDLOC(elt) = dirtype;
++ if (dirtype == Cur){ /* deal with UIDs */
++ if(elt->private.uid == 0L)
++ elt->private.uid = maildir_get_uid(MDFILE(elt));
++ if(elt->private.uid <= uid_last){
++ uid = (we_compute ? uid_last : stream->uid_last) + 1L;
++ if(LOCAL->candouid)
++ maildir_assign_uid(stream, i + nmsgs, uid);
++ else
++ elt->private.uid = uid;
++ }
++ else
++ uid = elt->private.uid;
++ uid_last = uid;
++ if(uid_last > stream->uid_last)
++ stream->uid_last = uid_last;
++ }
++ if(dirtype == New && !stream->rdonly){
++ maildir_free_file_only((void **)&elt->private.spare.ptr);
++ MDFILE(elt) = cpystr(tmp);
++ MDSIZE(elt) = sbuf.st_size;
++ MDMTIME(elt) = sbuf.st_mtime;
++ MDLOC(elt) = Cur;
++ }
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ if (!we_compute && !stream->rdonly)
++ MM_FLAGS(stream, i+nmsgs);
++ }
++ maildir_get_date(stream, i+nmsgs);
++ elt->valid = T;
++ i++;
++ }
++ stream->silent = silent;
++ if(LOCAL->candouid && dirtype == Cur)
++ maildir_read_uid(stream, NULL, &stream->uid_validity);
++ if (dirtype == New && stream->rdonly)
++ new = nfiles;
++ mail_exists(stream, nmsgs + ((dirtype == New) ? new : nfiles));
++ mail_recent(stream, recent + ((dirtype == New) ? new : 0L));
++
++ return (nmsgs + (dirtype == New ? new : nfiles));
++ }
++
++ long maildir_ping (MAILSTREAM *stream)
++ {
++ maildir_parse_folder(stream, 0);
++ if(stream && LOCAL){
++ if(LOCAL->candouid < 0)
++ LOCAL->candouid++;
++ else if(LOCAL->candouid)
++ maildir_uid_renew_tempfile(stream);
++ else /* try again to get uids */
++ LOCAL->candouid = maildir_can_assign_uid(stream);
++ }
++ return stream && LOCAL ? LONGT : NIL;
++ }
++
++ int maildir_select (const struct direct *name)
++ {
++ return (name->d_name[0] != '.');
++ }
++
++ /*
++ * Unfortunately, there is no way to sort by arrival in this driver, this
++ * means that opening a folder in this driver using the scandir function
++ * will always make this driver slower than any driver that has a natural
++ * way of sorting by arrival (like a flat file format, "mbox", "mbx", etc).
++ */
++ int maildir_namesort (const struct direct **d1, const struct direct **d2)
++ {
++ const struct direct *e1 = *(const struct direct **) d1;
++ const struct direct *e2 = *(const struct direct **) d2;
++
++ return comp_maildir_file((char *) e1->d_name, (char *) e2->d_name);
++ }
++
++ /* Maildir close */
++
++ void maildir_close (MAILSTREAM *stream, long options)
++ {
++ MESSAGECACHE *elt;
++ unsigned long i;
++ int silent = stream ? stream->silent : 0;
++ mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
++
++ if (!stream) return;
++
++ for (i = 1L; i <= stream->nmsgs; i++)
++ if((elt = (MESSAGECACHE *) (*mc)(stream,i,CH_ELT)) && elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++ stream->silent = T;
++ if (options & CL_EXPUNGE) maildir_expunge (stream, NIL, NIL);
++ maildir_abort(stream);
++ if (mdfpath) fs_give((void **)&mdfpath);
++ if (mypid) mypid = (pid_t) 0;
++ stream->silent = silent;
++ }
++
++ void maildir_check (MAILSTREAM *stream)
++ {
++ if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL);
++ }
++
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags)
++ {
++ char tmp[MAILTMPLEN];
++ unsigned long i;
++ MESSAGECACHE *elt;
++ char *s;
++ /* UID call "impossible" */
++ if (flags & FT_UID || !LOCAL) return NIL;
++ elt = mail_elt (stream, msgno);
++
++ if (!(flags & FT_PEEK) && !elt->seen){
++ elt->seen = T;
++ maildir_flagmsg (stream, elt);
++ MM_FLAGS(stream, elt->msgno);
++ }
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && (errno == EACCES || errno == ENOENT)){
++ INIT (bs, mail_string, "", 0);
++ elt->rfc822_size = 0L;
++ return NIL;
++ }
++
++ s = maildir_text_work(stream, elt, &i, flags);
++ INIT (bs, mail_string, s, i);
++ return LONGT;
++ }
++
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
++ unsigned long *length,long flags)
++ {
++ FDDATA d;
++ STRING bs;
++ char *s,tmp[CHUNK];
++ unsigned long msgno = elt->msgno;
++ static int try = 0;
++
++ if (length)
++ *length = 0L;
++ LOCAL->buf[0] = '\0';
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_text_work(stream, mail_elt(stream, msgno),length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ lseek (LOCAL->fd, elt->private.msg.text.offset,L_SET);
++
++ if (flags & FT_INTERNAL) { /* initial data OK? */
++ if (elt->private.msg.text.text.size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.text.text.size) + 1);
++ }
++ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
++ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
++ }
++ else {
++ if (elt->rfc822_size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
++ }
++ d.fd = LOCAL->fd; /* yes, set up file descriptor */
++ d.pos = elt->private.msg.text.offset;
++ d.chunk = tmp; /* initial buffer chunk */
++ d.chunksize = CHUNK;
++ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
++ for (s = LOCAL->buf; SIZE (&bs);) switch (CHR (&bs)) {
++ case '\r': /* carriage return seen */
++ *s++ = SNX (&bs); /* copy it and any succeeding LF */
++ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
++ break;
++ case '\n':
++ *s++ = '\r'; /* insert a CR */
++ default:
++ *s++ = SNX (&bs); /* copy characters */
++ }
++ *s = '\0'; /* tie off buffer */
++ *length = s - (char *) LOCAL->buf; /* calculate length */
++ }
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* maildir parse, fill the elt structure... well not all of it... */
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype)
++ {
++ char *b, *s, *t, c;
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++ unsigned long i, len;
++ int d, f, r, se, dt;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt (stream,msgno);
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), dirtype);
++ if(stat(tmp, &sbuf) == 0)
++ MDSIZE(elt) = sbuf.st_size;
++
++ maildir_get_date(stream, msgno);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&se, &dt);
++ elt->draft = d; elt->flagged = f; elt->answered = r; elt->seen = se;
++ elt->deleted = dt; elt->valid = T;
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd >= 0){
++ s = (char *) fs_get (MDSIZE(elt) + 1);
++ read (LOCAL->fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ t = s + strlen(s); /* make t point to the end of s */
++ for (i = 0L, b = s; b < t && !(i && (*b == '\n')); i = (*b++ == '\n'));
++ len = (*b ? ++b : b) - s;
++ elt->private.msg.header.text.size =
++ elt->private.msg.text.offset = len;
++ elt->private.msg.text.text.size = MDSIZE(elt) - len;
++ for (i = 0L, b = s, c = *b; b &&
++ ((c < '\016' && ((c == '\012' && ++i)
++ ||(c == '\015' && *(b+1) == '\012' && ++b && (i +=2))))
++ || b < t); i++, c= *++b);
++ elt->rfc822_size = i;
++ fs_give ((void **) &s);
++ close(LOCAL->fd); LOCAL->fd = -1;
++ }
++ return elt->rfc822_size;
++ }
++
++ int
++ maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno)
++ {
++ struct direct **names = NIL;
++ unsigned long i, nfiles, pos;
++ int d = 0, f = 0 , r = 0, s = 0, t = 0, in_list, scan_err;
++ MESSAGECACHE *elt;
++
++ maildir_scandir (LOCAL->path[Cur], &names, &nfiles, &scan_err, CCLIENT);
++
++ elt = mail_elt (stream,msgno);
++
++ in_list = nfiles > 0L
++ ? maildir_message_in_list(MDFILE(elt), names, 0L, nfiles - 1L, &pos)
++ : NIL;
++
++ if (in_list && pos >= 0L && pos < nfiles
++ && !strcmp(MDFILE(elt), names[pos]->d_name)){
++ in_list = NIL;
++ maildir_abort(stream);
++ }
++
++ if (in_list && pos >= 0L && pos < nfiles){
++ maildir_free_file_only((void **)&elt->private.spare.ptr);
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&s, &t);
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ MM_FLAGS(stream, msgno);
++ }
++ }
++ for (i = 0L; i < nfiles; i++)
++ fs_give((void **) &names[i]);
++ if (names)
++ fs_give((void **) &names);
++ return in_list ? 1 : -1;
++ }
++
++ /* Maildir fetch message header */
++
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags)
++ {
++ char tmp[MAILTMPLEN], *s;
++ MESSAGECACHE *elt;
++ static int try = 0;
++
++ if (length) *length = 0;
++ if (flags & FT_UID || !LOCAL) return ""; /* UID call "impossible" */
++ elt = mail_elt (stream,msgno);
++ if(elt->private.msg.header.text.size == 0)
++ maildir_parse_message(stream, msgno, MDLOC(elt));
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0)
++ LOCAL->fd = open (tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && errno == EACCES){
++ mm_log ("Message exists but can not be read. Envelope and body lost!",ERROR);
++ return NULL;
++ }
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_header(stream, msgno, length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ if (flags & FT_INTERNAL){
++ if(elt->private.msg.header.text.size > LOCAL->buflen){
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.header.text.size) + 1);
++ }
++ read (LOCAL->fd, (void *)LOCAL->buf, elt->private.msg.header.text.size);
++ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
++ }
++ else{
++ s = (char *) fs_get(elt->private.msg.header.text.size+1);
++ read (LOCAL->fd, (void *)s, elt->private.msg.header.text.size);
++ s[elt->private.msg.header.text.size] = '\0';
++ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
++ elt->private.msg.header.text.size);
++ fs_give ((void **) &s);
++ }
++ elt->private.msg.text.offset = elt->private.msg.header.text.size;
++ elt->private.msg.text.text.size = MDSIZE(elt) - elt->private.msg.text.offset;
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* Maildir find list of subscribed mailboxes
++ * Accepts: mail stream
++ * pattern to search
++ */
++
++ void maildir_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ char *s,test[MAILTMPLEN],file[MAILTMPLEN];
++ long i = 0L;
++
++ if((!pat || !*pat) && maildir_canonicalize (test,ref,"*")
++ && maildir_valid_name(test)){ /* there is a #md/ leading here */
++ for (i = 3L; test[i] && test[i] != '/'; i++);
++ if ((s = strchr (test+i+1,'/')) != NULL) *++s = '\0';
++ else test[0] = '\0';
++ mm_list (stream,'/',test, LATT_NOSELECT);
++ }
++ else if (maildir_canonicalize (test,ref,pat)) {
++ if (test[3] == '/') { /* looking down levels? */
++ /* yes, found any wildcards? */
++ if ((s = strpbrk (test,"%*")) != NULL){
++ /* yes, copy name up to that point */
++ strncpy (file,test+4,i = s - (test+4));
++ file[i] = '\0'; /* tie off */
++ }
++ else strcpy (file,test+4);/* use just that name then */
++ /* find directory name */
++ if ((s = strrchr (file, '/')) != NULL){
++ *s = '\0'; /* found, tie off at that point */
++ s = file;
++ }
++ /* do the work */
++ if(IS_COURIER(test))
++ courier_list_work (stream,s,test,0);
++ else
++ maildir_list_work (stream,s,test,0);
++ }
++ /* always an INBOX */
++ if (!compare_cstring (test,"#MD/INBOX"))
++ mm_list (stream,NIL,"#MD/INBOX",LATT_NOINFERIORS);
++ if (!compare_cstring (test,"#MC/INBOX"))
++ mm_list (stream,NIL,"#MC/INBOX",LATT_NOINFERIORS);
++ }
++ }
++
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ /* I am too lazy to do anything. Do you care to ask maildir list, please?
++ The real reason why this is a dummy function is because we do not want to
++ see the same folder listed twice.
++ */
++ }
++
++ /* For those that want to hide things, we give them a chance to do so */
++ void *maildir_parameters (long function, void *value)
++ {
++ void *ret = NIL;
++ switch ((int) function) {
++ case SET_MDINBOXPATH:
++ if(strlen((char *) value ) > 49)
++ strcpy(myMdInboxDir, "Maildir");
++ else
++ strcpy(myMdInboxDir, (char *) value);
++ case GET_MDINBOXPATH:
++ if (myMdInboxDir[0] == '\0') strcpy(myMdInboxDir,"Maildir");
++ ret = (void *) myMdInboxDir;
++ break;
++ case SET_COURIERSTYLE:
++ CourierStyle = (long) value;
++ case GET_COURIERSTYLE:
++ ret = (void *) CourierStyle;
++ break;
++ case GET_DIRFMTTEST:
++ ret = (void *) maildir_dirfmttest;
++ break;
++ default:
++ break;
++ }
++ return ret;
++ }
++
++ int maildir_create_folder(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ DirNamesType i;
++
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, mailbox, i);
++ if (mkdir(tmp, 0700) && errno != EEXIST){ /* try to make new dir */
++ snprintf (err, sizeof(err), "Can't create %s: %s", tmp, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++ return T;
++ }
++
++ int maildir_create_work(char *mailbox, int loop)
++ {
++ char *s, c, err[MAILTMPLEN], tmp[MAILTMPLEN], tmp2[MAILTMPLEN], mbx[MAILTMPLEN];
++ int fnlen, create_dir = 0, courier, mv;
++ struct stat sbuf;
++ long style = *(long *) maildir_parameters(GET_COURIERSTYLE, NIL);
++
++ courier = IS_COURIER(mailbox);
++ strcpy(mbx, mailbox);
++ mv = maildir_valid(mbx) ? 1 : 0;
++ maildir_file_path(mailbox, tmp, sizeof(tmp));
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ create_dir++;
++ mailbox[strlen(mailbox) - 1] = '\0';
++ }
++
++ if(!loop && courier){
++ if(mv){
++ if(create_dir){
++ if(style == CCLIENT)
++ strcpy (err,"Can not create directory: folder exists. Create subfolder");
++ else
++ strcpy(err,"Folder and Directory already exist");
++ }
++ else
++ strcpy (err, "Can't create mailbox: mailbox already exists");
++ }
++ else{
++ if(create_dir)
++ strcpy(err, "Can not create directory. Cread folder instead");
++ else
++ err[0] = '\0';
++ }
++ if(err[0]){
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++
++ fnlen = strlen(tmp);
++ if ((s = strrchr(mailbox,MDSEPARATOR(courier))) != NULL){
++ c = *++s;
++ *s = '\0';
++ if ((stat(tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
++ !maildir_create_work (mailbox, ++loop))
++ return NIL;
++ *s = c;
++ }
++ tmp[fnlen] = '\0';
++
++ if (mkdir(tmp,0700) && errno != EEXIST)
++ return NIL;
++
++ if (create_dir)
++ mailbox[fnlen] = '/';
++
++ if (create_dir){
++ if(style == CCLIENT){
++ if(!courier){
++ FILE *fp = NULL;
++ snprintf(tmp2, sizeof(tmp2), "%s%s", tmp, MDDIR);
++ if ((fp = fopen(tmp2,"w")) == NULL){
++ snprintf (err, sizeof(err), "Problem creating %s: %s", tmp2, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ fclose(fp);
++ }
++ }
++ return T;
++ }
++ else
++ return maildir_create_folder(tmp);
++ }
++
++ long maildir_create (MAILSTREAM *stream,char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ int rv, create_dir;
++
++ create_dir = mailbox ?
++ (mailbox[strlen(mailbox) - 1] ==
++ MDSEPARATOR(IS_COURIER(mailbox))) : 0;
++ maildir_file_path(mailbox, tmp, sizeof(tmp));
++ strcpy(tmp, mailbox);
++ rv = maildir_create_work(mailbox, 0);
++ strcpy(mailbox, tmp);
++ if (rv == 0){
++ snprintf (err, sizeof(err), "Can't create %s %s",
++ (create_dir ? "directory" : "mailbox"), mailbox);
++ mm_log (err,ERROR);
++ }
++ return rv ? LONGT : NIL;
++ }
++
++ #define MAXTRY 10000
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
++ {
++ char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN];
++ char *s;
++ int ren, try = 0;
++
++ if (elt->valid){
++ for (try = 1; try > 0 && try < MAXTRY; try++){
++ /* build the new filename */
++ snprintf (oldfile, sizeof(oldfile), "%s/%s",LOCAL->path[Cur], MDFILE(elt));
++ fn[0] = '\0';
++ if ((ren = maildir_message_exists(stream, MDFILE(elt), fn)) == 0){
++ errno = ENOENT;
++ try = MAXTRY;
++ }
++ if (*fn) /* new oldfile! */
++ snprintf (oldfile,sizeof(oldfile),"%s/%s", LOCAL->path[Cur], fn);
++ if ((s = strrchr (MDFILE(elt), FLAGSEP))) *s = '\0';
++ snprintf (fn, sizeof(fn), "%s%s%s%s%s%s%s", MDFILE(elt), MDSEP(2),
++ MDFLAG(Draft, elt->draft), MDFLAG(Flagged, elt->flagged),
++ MDFLAG(Replied, elt->answered), MDFLAG(Seen, elt->seen),
++ MDFLAG(Trashed, elt->deleted));
++ snprintf (newfile, sizeof(newfile), "%s/%s",LOCAL->path[Cur],fn);
++ if (ren != 0 && rename (oldfile,newfile) >= 0)
++ try = -1;
++ }
++
++ if (try > 0){
++ snprintf(oldfile, sizeof(oldfile), "Unable to write flags to disk: %s",
++ (errno == ENOENT) ? "message is gone!" : strerror (errno));
++ mm_log(oldfile,ERROR);
++ return;
++ }
++ #ifdef __CYGWIN__
++ utime(LOCAL->path[Cur], NIL); /* make sure next scan will catch the change */
++ #endif
++ maildir_free_file_only ((void **) &elt->private.spare.ptr);
++ MDFILE(elt) = cpystr (fn);
++ }
++ }
++
++ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options)
++ {
++ long ret;
++ MESSAGECACHE *elt;
++ unsigned long i, n = 0L;
++ unsigned long recent = stream->recent;
++ char tmp[MAILTMPLEN];
++
++ mm_critical (stream); /* go critical */
++ ret = sequence ? ((options & EX_UID) ?
++ mail_uid_sequence (stream,sequence) :
++ mail_sequence (stream,sequence)) : LONGT;
++ if(ret == 0L)
++ return 0L;
++ for (i = 1L; i <= stream->nmsgs;){
++ elt = mail_elt (stream,i);
++ if (elt->deleted && (sequence ? elt->sequence : T)){
++ snprintf (tmp, sizeof(tmp), "%s/%s", LOCAL->path[Cur], MDFILE(elt));
++ if (unlink (tmp) < 0) {/* try to delete the message */
++ snprintf (tmp, sizeof(tmp), "Expunge of message %ld failed, aborted: %s",i,
++ strerror (errno));
++ if (!stream->silent)
++ mm_log (tmp,WARN);
++ break;
++ }
++ if (elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++ if (elt->recent) --recent;/* if recent, note one less recent message */
++ mail_expunged (stream,i); /* notify upper levels */
++ n++; /* count up one more expunged message */
++ }
++ else i++;
++ }
++ if(n){ /* output the news if any expunged */
++ snprintf (tmp, sizeof(tmp), "Expunged %ld messages", n);
++ if (!stream->silent)
++ mm_log (tmp,(long) NIL);
++ }
++ else
++ if (!stream->silent)
++ mm_log ("No messages deleted, so no update needed",(long) NIL);
++ mm_nocritical (stream); /* release critical */
++ /* notify upper level of new mailbox size */
++ mail_exists (stream, stream->nmsgs);
++ mail_recent (stream, recent);
++ return ret;
++ }
++
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
++ {
++ STRING st;
++ MESSAGECACHE *elt;
++ unsigned long len;
++ int fd;
++ unsigned long i;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN], flags[MAILTMPLEN], path[MAILTMPLEN], *s;
++ /* copy the messages */
++ if ((options & CP_UID) ? mail_uid_sequence (stream, sequence) :
++ mail_sequence (stream,sequence))
++ for (i = 1L; i <= stream->nmsgs; i++)
++ if ((elt = mail_elt (stream,i))->sequence){
++ MSGPATH(path, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (((fd = open (path,O_RDONLY,NIL)) < 0)
++ ||((!elt->rfc822_size &&
++ ((stat(path, &sbuf) < 0) || !S_ISREG (sbuf.st_mode)))))
++ return NIL;
++ if(!elt->rfc822_size)
++ MDSIZE(elt) = sbuf.st_size;
++ s = (char *) fs_get(MDSIZE(elt) + 1);
++ read (fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ close (fd);
++ len = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen, s, MDSIZE(elt));
++ INIT (&st,mail_string, LOCAL->buf, len);
++ elt->rfc822_size = len;
++ fs_give ((void **)&s);
++
++ flags[0] = flags[1] = '\0';
++ if (elt->seen) strcat (flags," \\Seen");
++ if (elt->draft) strcat (flags," \\Draft");
++ if (elt->deleted) strcat (flags," \\Deleted");
++ if (elt->flagged) strcat (flags," \\Flagged");
++ if (elt->answered) strcat (flags," \\Answered");
++ flags[0] = '('; /* open list */
++ strcat (flags,")"); /* close list */
++ mail_date (tmp,elt); /* generate internal date */
++ if (!mail_append_full (NIL, mailbox, flags, tmp, &st))
++ return NIL;
++ if (options & CP_MOVE) elt->deleted = T;
++ }
++ return LONGT; /* return success */
++ }
++
++ long maildir_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
++ {
++ int fd, k, done, fail;
++ STRING *message;
++ char c,*s, *flags, *date;
++ char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN];
++ MESSAGECACHE elt;
++ long i, size = 0L, ret = LONGT, f;
++ unsigned long uf, ti;
++ static unsigned int transact = 0;
++ struct stat sbuf;
++
++ if (!maildir_valid(mailbox)) {
++ snprintf (tmp, sizeof(tmp), "Not a valid Maildir mailbox: %s", mailbox);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if (!*mdlocaldomain)
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain now! */
++
++ if (mypid == (pid_t) 0)
++ mypid = getpid();
++
++ if (!stream){
++ stream = &maildirproto;
++
++ for (k = 0; k < NUSERFLAGS && stream->user_flags[k]; ++k)
++ fs_give ((void **) &stream->user_flags[k]);
++ }
++
++ if (!(*af)(stream, data, &flags, &date, &message)) return NIL;
++
++ mm_critical (stream); /* go critical */
++ do {
++ fail = done = 0; /* we have not determined name of message file yet */
++ if (!SIZE (message)) { /* guard against zero-length */
++ mm_log ("Append of zero-length message", ERROR);
++ ret = NIL;
++ break;
++ }
++
++ if (date && !mail_parse_date(&elt,date)){
++ snprintf (tmp, sizeof(tmp), "Bad date in append: %.80s", date);
++ mm_log (tmp, ERROR);
++ ret = NIL;
++ break;
++ }
++
++ if(date){
++ struct tm tm;
++
++ tm.tm_sec = elt.seconds;
++ tm.tm_min = elt.minutes;
++ tm.tm_hour = elt.hours;
++ tm.tm_mday = elt.day;
++ tm.tm_mon = elt.month - 1;
++ tm.tm_year = BASEYEAR + elt.year - 1900;
++
++ ti = mktime(&tm);
++ } else ti = time(0);
++
++ f = mail_parse_flags (stream,flags,&uf);
++ do {
++ /* build file name we will use */
++ snprintf (file, sizeof(file), "%lu.%d_%09u.%s%s%s%s%s%s",
++ ti, mypid, transact++, mdlocaldomain, (f ? MDSEP(2) : ""),
++ MDFLAG(Draft, f&fDRAFT), MDFLAG(Flagged, f&fFLAGGED),
++ MDFLAG(Replied, f&fANSWERED), MDFLAG(Seen, f&fSEEN));
++ /* build tmp file name */
++ if (maildir_file_path(mailbox, tmp, sizeof(tmp))) /* copy in TMP */
++ MSGPATH(path1, tmp, file, Tmp);
++ /* build final filename to use */
++ if (maildir_file_path(mailbox, tmp, sizeof(tmp)))
++ MSGPATH(path2, tmp, file, New); /* copy in NEW */
++ if(stat(path1, &sbuf) < 0 && errno == ENOENT
++ && stat(path2, &sbuf) < 0 && errno == ENOENT)
++ done++;
++ else
++ fail++;
++ if(fail == 1000){
++ snprintf (tmp, sizeof(tmp), "Failure to create append message name");
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ } while (done == 0);
++
++ if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) {
++ snprintf (tmp, sizeof(tmp), "Can't open append mailbox: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ for (size = 0,i = SIZE (message),s = (char *) fs_get (i + 1); i; --i)
++ if ((c = SNX (message)) != '\015') s[size++] = c;
++ if ((write (fd, s, size) < 0) || fsync (fd)) {
++ unlink (path1); /* delete message */
++ snprintf (tmp, sizeof(tmp), "Message append failed: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ ret = NIL;
++ }
++ fs_give ((void **) &s); /* flush the buffer */
++ close (fd); /* close the file */
++
++ if (rename (path1,path2) < 0) {
++ snprintf (tmp, sizeof(tmp), "Message append failed: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ ret = NIL;
++ }
++ unlink (path1);
++ if(date){
++ time_t tp[2];
++ tp[0] = tp[1] = ti;
++ utime (path2,tp);
++ }
++
++ if (ret)
++ if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
++
++ } while (ret && message); /* write the data */
++ mm_nocritical (stream); /* release critical */
++ return ret;
++ }
++
++ long maildir_delete (MAILSTREAM *stream,char *mailbox)
++ {
++ DIR *dirp;
++ struct direct *d;
++ int i, remove_dir = 0, mddir = 0, rv, error = 0;
++ char tmp[MAILTMPLEN],tmp2[MAILTMPLEN], realname[MAILTMPLEN];
++ struct stat sbuf;
++ int courier = IS_COURIER(mailbox);
++
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ remove_dir++;
++ mailbox[strlen(mailbox) -1] = '\0';
++ }
++
++ if (!maildir_valid(mailbox)){
++ maildir_file_path(mailbox, tmp, sizeof(tmp));
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode)){
++ snprintf(tmp, sizeof(tmp), "Can not remove %s", mailbox);
++ error++;
++ }
++ }
++
++ if (!error && remove_dir && !maildir_dir_is_empty(mailbox)){
++ snprintf(tmp, sizeof(tmp), "Can not remove directory %s/: directory not empty", mailbox);
++ error++;
++ }
++
++ if(error){
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ maildir_close(stream,0); /* even if stream was NULL */
++
++ maildir_file_path(mailbox, realname, sizeof(realname));
++
++ if (remove_dir){
++ snprintf(tmp, sizeof(tmp), "%s/%s", realname, MDDIR);
++ if ((rv = stat (tmp,&sbuf)) == 0 && S_ISREG(sbuf.st_mode))
++ rv = unlink(tmp);
++ else if (errno == ENOENT)
++ rv = 0;
++ if (rv != 0){
++ snprintf(tmp, sizeof(tmp), "Can not remove %s/%s: %s", tmp2, MDDIR, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ if (!maildir_valid(realname) && rmdir(realname) != 0){
++ snprintf(tmp, sizeof(tmp), "Can not remove %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ return LONGT;
++ }
++ /* else remove just the folder. Remove all hidden files, except MDDIR */
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, realname, i);
++
++ if (!(dirp = opendir (tmp))){
++ snprintf(tmp, sizeof(tmp), "Can not read %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++
++ while ((d = readdir(dirp)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")){
++ snprintf(tmp2, sizeof(tmp2), "%s/%s", tmp, d->d_name);
++ if (unlink(tmp2) != 0){
++ snprintf(tmp2, sizeof(tmp2), "Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp2, ERROR);
++ return NIL;
++ }
++ }
++ }
++ closedir(dirp);
++ if (rmdir(tmp) != 0){
++ snprintf(tmp, sizeof(tmp), "Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ }
++ /*
++ * ok we have removed all subdirectories of the folder mailbox, Remove the
++ * hidden files.
++ */
++
++ if(!(dirp = opendir (realname))){
++ snprintf(tmp, sizeof(tmp), "Can not read %s/: %s", realname, strerror(errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++
++ while ((d = readdir(dirp)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && (!strcmp(d->d_name, MDDIR)
++ || !strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST))
++ || !strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)))){
++ if(strcmp(d->d_name, MDDIR) == 0)
++ mddir++;
++ snprintf(tmp, sizeof(tmp), "%s/%s", realname, d->d_name);
++ if (unlink(tmp) != 0)
++ error++;
++ }
++ }
++ closedir(dirp);
++ if (error ||
++ (maildir_dir_is_empty(mailbox) && mddir == 0 && rmdir(realname) < 0)){
++ snprintf(tmp, sizeof(tmp), "Can not remove folder %s: %s", mailbox, strerror(errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ return LONGT;
++ }
++
++ long maildir_rename (MAILSTREAM *stream, char *old, char *new)
++ {
++ char tmp[MAILTMPLEN], tmpnew[MAILTMPLEN], realold[MAILTMPLEN];
++ char realnew[MAILTMPLEN];
++ int courier = IS_COURIER(old) && IS_COURIER(new);
++ int i;
++ long rv = LONGT;
++ COURIER_S *cdir;
++
++ if((IS_COURIER(old) || IS_COURIER(new)) && !courier){
++ snprintf (tmp, sizeof(tmp), "Can't rename mailbox %s to %s", old, new);
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++
++ if (!maildir_valid(old)){
++ snprintf (tmp, sizeof(tmp), "Can't rename mailbox %s: folder not in maildir format",old);
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ maildir_file_path(old, realold, sizeof(realold));
++ if (!maildir_valid_name(new) && new[0] == '#'){
++ snprintf (tmp, sizeof(tmp), "Cannot rename mailbox %s: folder not in maildir format", new);
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ maildir_file_path(new, realnew, sizeof(realnew));
++ if (access(tmpnew,F_OK) == 0){ /* new mailbox name must not exist */
++ snprintf (tmp, sizeof(tmp), "Cannot rename to mailbox %s: destination already exists", new);
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++
++ if(!courier){
++ if (rename(realold, realnew)){ /* try to rename the directory */
++ snprintf(tmp, sizeof(tmp), "Can't rename mailbox %s to %s: %s", old, new,
++ strerror(errno));
++ mm_log(tmp,ERROR);
++ return NIL;
++ }
++ return LONGT; /* return success */
++ }
++
++ cdir = courier_list_dir(old);
++ for (i = 0; cdir && i < cdir->total; i++){
++ if(strstr(cdir->data[i]->name, old)){
++ snprintf(tmp, sizeof(tmp), "%s%s", new, cdir->data[i]->name+strlen(old));
++ maildir_file_path(cdir->data[i]->name, realold, sizeof(realold));
++ maildir_file_path(tmp, realnew, sizeof(realnew));
++ if (rename(realold, realnew)){
++ snprintf (tmp, sizeof(tmp), "Can't rename mailbox %s to %s: %s", old, new,
++ strerror(errno));
++ mm_log(tmp,ERROR);
++ rv = NIL;
++ }
++ }
++ }
++ courier_free_cdir(&cdir);
++ return rv;
++ }
++
++ long maildir_sub(MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_subscribe(mailbox);
++ }
++
++ long maildir_unsub(MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_unsubscribe(mailbox);
++ }
++
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat)
++ {
++ void *sdb = NIL;
++ char *s, test[MAILTMPLEN], tmp[MAILTMPLEN];
++ /* get canonical form of name */
++ if (maildir_canonicalize (test, ref, pat) && (s = sm_read (tmp, &sdb))) {
++ do if (pmatch_full (s, test, '/')) mm_lsub (stream, '/', s, NIL);
++ while ((s = sm_read (tmp, &sdb)) != NULL); /* until no more subscriptions */
++ }
++ }
++
++ long maildir_canonicalize (char *pattern,char *ref,char *pat)
++ {
++ if (ref && *ref) { /* have a reference */
++ strcpy (pattern,ref); /* copy reference to pattern */
++ /* # overrides mailbox field in reference */
++ if (*pat == '#') strcpy (pattern,pat);
++ /* pattern starts, reference ends, with / */
++ else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
++ strcat (pattern,pat + 1); /* append, omitting one of the period */
++
++ else strcat (pattern,pat); /* anything else is just appended */
++ }
++ else strcpy (pattern,pat); /* just have basic name */
++ return maildir_valid_name(pattern) ? LONGT : NIL;
++ }
++
++ void maildir_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
++ {
++ DIR *dp;
++ struct direct *d;
++ struct stat sbuf;
++ char curdir[MAILTMPLEN],name[MAILTMPLEN], tmp[MAILTMPLEN];
++ char realpat[MAILTMPLEN];
++ long i;
++ char *maildirpath = mdirpath();
++
++ snprintf(curdir, sizeof(curdir), "%s/%s/", myrootdir(pat), dir ? dir : maildirpath);
++ if ((dp = opendir (curdir)) != NULL){
++ if (dir) snprintf (name, sizeof(name), "%s%s/",MDPREFIX(CCLIENT),dir);
++ else strcpy (name, pat);
++
++ if (level == 0 && !strpbrk(pat,"%*")){
++ if(maildir_valid(pat)){
++ i = maildir_contains_folder(pat, NULL)
++ ? LATT_HASCHILDREN
++ : (maildir_is_dir(pat, NULL)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS);
++ maildir_file_path(pat, realpat, sizeof(realpat));
++ i += maildir_any_new_msgs(realpat)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'/', pat, i);
++ }
++ else
++ if(pat[strlen(pat) - 1] == '/')
++ mm_list (stream,'/', pat, LATT_NOSELECT);
++ }
++
++ while ((d = readdir (dp)) != NULL)
++ if(strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ if (dir) snprintf (tmp, sizeof(tmp), "%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++
++ if(pmatch_full (tmp, pat,'/')){
++ snprintf(tmp, sizeof(tmp), "%s/%s/%s", myrootdir(d->d_name),
++ (dir ? dir : maildirpath), d->d_name);
++ if(stat (tmp,&sbuf) == 0
++ && ((sbuf.st_mode & S_IFMT) == S_IFDIR)){
++ if (dir) snprintf (tmp, sizeof(tmp), "%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++ i = maildir_valid(tmp)
++ ? (maildir_contains_folder(dir, d->d_name)
++ ? LATT_HASCHILDREN
++ : (maildir_is_dir(dir, d->d_name)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS))
++ : LATT_NOSELECT;
++ i += maildir_any_new_msgs(tmp)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'/',tmp, i);
++ strcat (tmp, "/");
++ if(dmatch (tmp, pat,'/') &&
++ (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))){
++ snprintf(tmp, sizeof(tmp), "%s/%s",dir,d->d_name);
++ maildir_list_work (stream,tmp,pat,level+1);
++ }
++ }
++ }
++ }
++ closedir (dp);
++ }
++ }
++
++ void courier_list_work (MAILSTREAM *stream, char *dir, char *pat, long level)
++ {
++ char c, curdir[MAILTMPLEN], tmp[MAILTMPLEN];
++ char realname[MAILTMPLEN], realpat[MAILTMPLEN] = {'\0'};
++ int i, found;
++ long style = *(long *) maildir_parameters(GET_COURIERSTYLE, NIL), j;
++ char *maildirpath = mdirpath();
++ COURIER_S *cdir;
++
++ if(!strpbrk(pat,"%*")){ /* a mailbox */
++ maildir_file_path(pat, curdir, sizeof(curdir));
++ i = strlen(curdir) - 1;
++ if(curdir[i] == '/')
++ curdir[i] = '\0';
++ cdir = courier_list_dir(curdir);
++ if(cdir){
++ found = 0; j = 0L;
++ if(maildir_valid_name(pat)){
++ for(i = 0; !found && i < cdir->total; i++)
++ if(strstr(curdir, cdir->data[i]->name)){
++ if(strlen(curdir) < strlen(cdir->data[i]->name))
++ found += 2;
++ else if(strlen(curdir) == strlen(cdir->data[i]->name))
++ found -= 1;
++ }
++ if(found > 0)
++ j = LATT_HASCHILDREN;
++ else if(found == 0)
++ j = (style == COURIER) ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
++ }
++ else
++ j = LATT_NOSELECT;
++ j += maildir_any_new_msgs(curdir) ? LATT_MARKED : LATT_UNMARKED;
++ if (found)
++ mm_list (stream, '.', pat, j);
++ courier_free_cdir(&cdir);
++ }
++ return;
++ }
++
++ strcpy(tmp,pat + 4); /* a directory */
++ j = strlen(pat) - 1;
++ maildir_file_path(pat, realpat, sizeof(realpat));
++ c = pat[j];
++ pat[j] = '\0';
++ realname[0] = '\0';
++ if(dir)
++ maildir_file_path(dir, realname, sizeof(realname));
++ snprintf(curdir, sizeof(curdir), "%s%s%s/%s", (dir ? "" : myrootdir(pat)), (dir ? "" : "/"),
++ (dir ? realname : maildirpath), (dir ? "" : "."));
++ snprintf(tmp, sizeof(tmp), "%s%s/.", MDPREFIX(COURIER), dir ? dir : maildirpath);
++ if (level == 0 && tmp && pmatch_full (tmp, realpat, '.'))
++ mm_list (stream,'.', tmp, LATT_NOSELECT);
++
++ cdir = courier_list_dir(pat);
++ pat[j] = c;
++ for (i = 0; cdir && i < cdir->total; i++)
++ if(pmatch_full (cdir->data[i]->name, pat, '.')){
++ snprintf(tmp, sizeof(tmp), "%s.", cdir->data[i]->name);
++ courier_list_info(&cdir, tmp, i);
++ mm_list (stream,'.',cdir->data[i]->name, cdir->data[i]->attribute);
++ }
++ courier_free_cdir(&cdir);
++ }
++
++ int
++ same_maildir_file(char *name1, char *name2)
++ {
++ char tmp1[MAILTMPLEN], tmp2[MAILTMPLEN];
++ char *s;
++
++ strcpy(tmp1, name1 ? name1 : "");
++ strcpy(tmp2, name2 ? name2 : "");
++ if ((s = strrchr(tmp1, FLAGSEP)) != NULL)
++ *s = '\0';
++ if (((s = strrchr(tmp1, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
++ *s = '\0';
++ if ((s = strrchr(tmp2, FLAGSEP)) != NULL)
++ *s = '\0';
++ if (((s = strrchr(tmp2, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
++ *s = '\0';
++
++ return !strcmp(tmp1, tmp2);
++ }
++
++ unsigned long antoul(char *seed)
++ {
++ int i, error = 0;
++ unsigned long val = 0L, rv1 = 0L, t;
++ char c, *p;
++ if(!seed)
++ return 0L;
++ t = strtoul(seed, &p, 10);
++ if(p && (*p == '.' || *p == '_'))
++ return t;
++ /* else */
++ if((p = strchr(seed,'.')) != NULL)
++ *p = '\0';
++ error = (strlen(seed) > 6); /* too long */
++ for(i= strlen(seed)-1; error == 0 && i >= 0; i--){
++ c = seed[i];
++ if (c >= 'A' && c <= 'Z') val = c - 'A';
++ else if (c >= 'a' && c <= 'z') val = c - 'a' + 26;
++ else if (c >= '0' && c <= '9') val = c - '0' + 26 + 26;
++ else if (c == '-') val = c - '-' + 26 + 26 + 10;
++ else if (c == '_') val = c - '_' + 26 + 26 + 10 + 1;
++ else error++;
++ rv1 = val + (rv1 << 6);
++ }
++ if(p)
++ *p = '.';
++ return error ? 0L : rv1;
++ }
++
++ unsigned long mdfntoul (char *name)
++ {
++ unsigned long t;
++ char *r, last;
++
++ if((*name == '_') && ((r = strpbrk(name,".,%+")) != NULL)){ /* Grrr!!! */
++ last = *r;
++ *r = '\0';
++ t = antoul(r+1);
++ *r = last;
++ }
++ else
++ t = antoul(name);
++ return t;
++ }
++
++ int comp_maildir_file(char *name1, char *name2)
++ {
++ int uset1 = 1, uset2 = 1, i, j, cmp;
++ unsigned long t1, t2;
++ char *s1, *s2;
++
++ if (!(name1 && *name1))
++ return (name2 && *name2) ? (*name2 == FLAGSEP ? 0 : -1) : 0;
++
++ if (!(name2 && *name2))
++ return (name1 && *name1) ? (*name1 == FLAGSEP ? 0 : 1) : 0;
++
++ if((cmp = strcmp(name1,name2)) == 0)
++ return 0;
++
++ t1 = strtoul(name1, &s1, 10);
++ t2 = strtoul(name2, &s2, 10);
++
++ if(!s1 || *s1 != '.')
++ uset1 = 0;
++
++ if(!s2 || *s2 != '.')
++ uset2 = 0;
++
++ if(uset1 && uset2) /* normal sort order */
++ return (t1 < t2) ? -1 : (t1 > t2 ? 1 : (cmp < 0 ? -1 : 1));
++
++ /* If we make it here we say Grrrr.... first, then we try to figure out
++ * how to sort this mess.
++ * These are the rules.
++ * If there is a number at the beginning it is bigger than anything else.
++ * If there are digits, then the number of digits decides which one is bigger.
++ */
++
++ for(i = 0; isdigit(name1[i]); i++);
++ for(j = 0; isdigit(name2[j]); j++);
++
++ return(uset1 ? 1
++ : (uset2 ? -1
++ : (i < j ? -1 : (i > j ? 1 : (cmp < 0 ? -1 : 1)))));
++ }
++
++ void
++ maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t)
++ {
++ char tmp[MAILTMPLEN], *b;
++ int offset = 0;
++ int tmpd, tmpf, tmpr, tmps, tmpt;
++
++ if(d) *d = 0;
++ if(f) *f = 0;
++ if(r) *r = 0;
++ if(s) *s = 0;
++ if(t) *t = 0;
++
++ tmpd = tmpf = tmpr = tmps = tmpt = NIL; /* no flags set by default */
++ strcpy(tmp,name);
++ while ((b = strrchr(tmp+offset, FLAGSEP)) != NULL){
++ char flag,last;
++ int k;
++ if (!++b) break;
++ switch (*b){
++ case '1':
++ case '2':
++ case '3': flag = *b; b += 2;
++ for (k = 0; b[k] && b[k] != FLAGSEP && b[k] != ','; k++);
++ last = b[k];
++ b[k] = '\0';
++ if (flag == '2' || flag == '3'){
++ tmpd = strchr (b, MDFLAGC(Draft)) ? T : NIL;
++ tmpf = strchr (b, MDFLAGC(Flagged)) ? T : NIL;
++ tmpr = strchr (b, MDFLAGC(Replied)) ? T : NIL;
++ tmps = strchr (b, MDFLAGC(Seen)) ? T : NIL;
++ tmpt = strchr (b, MDFLAGC(Trashed)) ? T : NIL;
++ }
++ b[k] = last;
++ b += k;
++ for (; tmp[offset] && tmp[offset] != FLAGSEP; offset++);
++ offset++;
++ break;
++ default: break; /* Should we crash?... Nahhh */
++ }
++ }
++ if(d) *d = tmpd;
++ if(f) *f = tmpf;
++ if(r) *r = tmpr;
++ if(s) *s = tmps;
++ if(t) *t = tmpt;
++ }
++
++ int
++ maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos)
++ {
++ unsigned long middle = (bottom + top)/2;
++ int test;
++
++ if (!msgname)
++ return NIL;
++
++ if (pos) *pos = middle;
++
++ if (same_maildir_file(msgname, names[middle]->d_name))
++ return T;
++
++ if (middle == bottom){ /* 0 <= 0 < 1 */
++ int rv = NIL;
++ if (same_maildir_file(msgname, names[middle]->d_name)){
++ rv = T;
++ if (pos) *pos = middle;
++ }
++ else
++ if (same_maildir_file(msgname, names[top]->d_name)){
++ rv = T;
++ if (pos) *pos = top;
++ }
++ return rv;
++ }
++
++ test = comp_maildir_file(msgname, names[middle]->d_name);
++
++ if (top <= bottom)
++ return test ? NIL : T;
++
++ if (test < 0 ) /* bottom < msgname < middle */
++ return maildir_message_in_list(msgname, names, bottom, middle, pos);
++ else if (test > 0) /* middle < msgname < top */
++ return maildir_message_in_list(msgname, names, middle, top, pos);
++ else return T;
++ }
++
++ void
++ maildir_abort(MAILSTREAM *stream)
++ {
++ if (LOCAL){
++ DirNamesType i;
++
++ if(LOCAL->candouid)
++ maildir_read_uid(stream, NULL, &stream->uid_validity);
++ if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
++ for (i = Cur; i < EndDir; i++)
++ if(LOCAL->path[i]) fs_give ((void **) &LOCAL->path[i]);
++ fs_give ((void **) &LOCAL->path);
++ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
++ if(LOCAL->uidtempfile){
++ unlink(LOCAL->uidtempfile);
++ fs_give ((void **) &LOCAL->uidtempfile);
++ }
++ fs_give ((void **) &stream->local);
++ }
++ if (mdfpath) fs_give((void **)&mdfpath);
++ stream->dtb = NIL;
++ }
++
++ int
++ maildir_contains_folder(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
++ int rv = 0;
++ DIR *dir;
++ struct direct *d;
++
++ maildir_file_path(dirname, tmp2, sizeof(tmp2));
++ if(name){
++ strcat(tmp2,"/");
++ strcat(tmp2, name);
++ }
++
++ if (!(dir = opendir (tmp2)))
++ return NIL;
++
++ while ((d = readdir(dir)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ snprintf(tmp, sizeof(tmp), "%s/%s", tmp2, d->d_name);
++ if(maildir_valid(tmp)){
++ rv++;
++ break;
++ }
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ int
++ maildir_is_dir(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ maildir_file_path(dirname, tmp, sizeof(tmp));
++ if(name){
++ strcat(tmp, "/");
++ strcat(tmp, name);
++ }
++ strcat(tmp, "/");
++ strcat(tmp, MDDIR);
++
++ return ((stat(tmp, &sbuf) == 0) && S_ISREG (sbuf.st_mode)) ? 1 : 0;
++ }
++
++ int
++ maildir_dir_is_empty(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], tmp3[MAILTMPLEN],*s;
++ int rv = 1, courier = IS_COURIER(mailbox);
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ maildir_file_path(mailbox, tmp2, sizeof(tmp2));
++
++ if(courier){
++ strcpy(tmp3, tmp2);
++ if(s = strrchr(tmp2, '/'))
++ *s = '\0';
++ }
++
++ if (!(dir = opendir (tmp2)))
++ return rv;
++
++ if(courier){
++ while((d = readdir(dir)) != NULL){
++ snprintf(tmp, sizeof(tmp), "%s/%s", tmp2, d->d_name);
++ if(!strncmp(tmp, tmp3, strlen(tmp3))
++ && tmp[strlen(tmp3)] == '.'){
++ rv = 0;
++ break;
++ }
++ }
++ }
++ else
++ while ((d = readdir(dir)) != NULL){
++ snprintf(tmp, sizeof(tmp), "%s/%s", tmp2, d->d_name);
++ if (strcmp(d->d_name, ".")
++ && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))
++ && strcmp(d->d_name, MDDIR)
++ && strcmp(d->d_name, MDUIDVALIDITY)
++ && !(d->d_name[0] == '.'
++ && stat (tmp,&sbuf) == 0
++ && S_ISREG(sbuf.st_mode))){
++ rv = 0;
++ break;
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ void
++ maildir_get_file (MAILDIRFILE **mdfile)
++ {
++ MAILDIRFILE *md;
++
++ md = (MAILDIRFILE *) fs_get(sizeof(MAILDIRFILE));
++ memset(md, 0, sizeof(MAILDIRFILE));
++ *mdfile = md;
++ }
++
++ void
++ maildir_free_file (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md){
++ if (md->name) fs_give((void **)&md->name);
++ fs_give((void **)&md);
++ }
++ }
++
++ void
++ maildir_free_file_only (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md && md->name)
++ fs_give((void **)&md->name);
++ }
++
++ int
++ maildir_any_new_msgs(char *mailbox)
++ {
++ char tmp[MAILTMPLEN];
++ int rv = NIL;
++ DIR *dir;
++ struct direct *d;
++
++ MDFLD(tmp, mailbox, New);
++
++ if (!(dir = opendir (tmp)))
++ return rv;
++
++ while ((d = readdir(dir)) != NULL){
++ if (d->d_name[0] == '.')
++ continue;
++ rv = T;
++ break;
++ }
++ closedir(dir);
++ return rv;
++ }
++
++
++ void
++ maildir_get_date(MAILSTREAM *stream, unsigned long msgno)
++ {
++ MESSAGECACHE *elt;
++ struct tm *t;
++ time_t ti;
++ int i,k;
++
++ elt = mail_elt (stream,msgno);
++ if(elt && elt->year != 0)
++ return;
++ if ((ti = mdfntoul(MDFILE(elt))) > 0L && (t = gmtime(&ti))){
++ i = t->tm_hour * 60 + t->tm_min;
++ k = t->tm_yday;
++ t = localtime(&ti);
++ i = t->tm_hour * 60 + t->tm_min - i;
++ if((k = t->tm_yday - k) != 0)
++ i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
++ k = abs (i);
++ elt->hours = t->tm_hour;
++ elt->minutes = t->tm_min;
++ elt->seconds = t->tm_sec;
++ elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
++ elt->year = t->tm_year - (BASEYEAR - 1900);
++ elt->zoccident = (k == i) ? 0 : 1;
++ elt->zhours = k/60;
++ elt->zminutes = k % 60;
++ }
++ }
++
++ /* Support for Courier Style directories
++ When this code is complete there will be two types of support, which
++ will be configurable. The problem is the following: In Courier style
++ folder structure, a "folder" may have a subfolder called
++ "folder.subfolder", which is not natural in the file system in the
++ sense that I can not stat for "folder.subfolder" wihtout knowing what
++ "subfolder" is. It needs to be guessed. Because of this I need to look
++ in the list of folders if there is a folder with a name
++ "folder.subfolder", before I can say if the folder is dual or not. One
++ can avoid this annoyance if one ignores the problem by declaring that
++ every folder is dual. I will however code as the default the more
++ complicated idea of scaning the containing directory each time it is
++ modified and search for subfolders, and list the entries it found.
++ */
++
++ int courier_dir_select (const struct direct *name)
++ {
++ return name->d_name[0] == '.' && (strlen(name->d_name) > 2
++ || (strlen(name->d_name) == 2 && name->d_name[1] != '.'));
++ }
++
++ int courier_dir_sort (const struct direct **d1, const struct direct **d2)
++ {
++ const struct direct *e1 = *(const struct direct **) d1;
++ const struct direct *e2 = *(const struct direct **) d2;
++
++ return strcmp((char *) e1->d_name, (char *) e2->d_name);
++ }
++
++ void courier_free_cdir (COURIER_S **cdir)
++ {
++ int i;
++
++ if (!*cdir)
++ return;
++
++ if ((*cdir)->path) fs_give((void **)&((*cdir)->path));
++ for (i = 0; i < (*cdir)->total; i++)
++ if((*cdir)->data[i]->name) fs_give((void **)&((*cdir)->data[i]->name));
++ fs_give((void **)&((*cdir)->data));
++ fs_give((void **)&(*cdir));
++ }
++
++ COURIER_S *courier_get_cdir (int total)
++ {
++ COURIER_S *cdir;
++
++ cdir = (COURIER_S *)fs_get(sizeof(COURIER_S));
++ memset(cdir, 0, sizeof(COURIER_S));
++ cdir->data = (COURIERLOCAL **) fs_get(total*sizeof(COURIERLOCAL *));
++ memset(cdir->data, 0, sizeof(COURIERLOCAL *));
++ cdir->total = total;
++ return cdir;
++ }
++
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last)
++ {
++ int try = (first + last)/2;
++
++ if(!strstr(data[try]->name, name)){
++ if(first == try) /* first == last || first + 1 == last */
++ return strstr(data[last]->name, name) ? 1 : 0;
++ if(strcmp(data[try]->name, name) < 0) /*data[try] < name < data[end] */
++ return courier_search_list(data, name, try, last);
++ else /* data[begin] < name < data[try] */
++ return courier_search_list(data, name, first, try);
++ }
++ return 1;
++ }
++
++ /* Lists all directories that are subdirectories of a given directory */
++
++ COURIER_S *courier_list_dir(char *curdir)
++ {
++ struct direct **names = NIL;
++ struct stat sbuf;
++ unsigned long ndir;
++ COURIER_S *cdir = NULL;
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], pathname[MAILTMPLEN],
++ realname[MAILTMPLEN];
++ int i, j, scand, td;
++
++ /* There are two cases, either curdir is
++ #mc/INBOX. #mc/INBOX.foo
++ or
++ #mc/Maildir/. #mc/Maildir/.foo
++ */
++ strcpy(tmp,curdir + 4);
++ if(!strncmp(ucase(tmp), "INBOX", 5))
++ strcpy(tmp, "#mc/INBOX.");
++ else{
++ strcpy(tmp, curdir);
++ for (i = strlen(tmp) - 1; tmp[i] && tmp[i] != '/'; i--);
++ tmp[i+2] = '\0'; /* keep the last "." intact */
++ }
++ maildir_file_path(tmp, realname, sizeof(realname));
++ maildir_scandir (realname, &names, &ndir, &scand, COURIER);
++
++ if (scand > 0){
++ cdir = courier_get_cdir(ndir);
++ cdir->path = cpystr(realname);
++ for(i = 0, j = 0; i < ndir; i++){
++ td = realname[strlen(realname) - 1] == '.'
++ && *names[i]->d_name == '.';
++ snprintf(tmp2, sizeof(tmp2), "%s%s", tmp, names[i]->d_name+1);
++ snprintf(pathname, sizeof(pathname), "%s%s", realname, names[i]->d_name + td);
++ if(stat(pathname, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)){
++ cdir->data[j] = (COURIERLOCAL *) fs_get(sizeof(COURIERLOCAL));
++ cdir->data[j++]->name = cpystr(tmp2);
++ }
++ fs_give((void **)&names[i]);
++ }
++ cdir->total = j;
++ if(cdir->total == 0)
++ courier_free_cdir(&cdir);
++ }
++ if(names)
++ fs_give((void **) &names);
++ return cdir;
++ }
++
++ void
++ courier_list_info(COURIER_S **cdirp, char *data, int i)
++ {
++ long style = *(long *) maildir_parameters(GET_COURIERSTYLE, NIL);
++ COURIER_S *cdir = *cdirp;
++
++ if(maildir_valid(cdir->data[i]->name)){
++ if(courier_search_list(cdir->data, data, 0, cdir->total - 1))
++ cdir->data[i]->attribute = LATT_HASCHILDREN;
++ else
++ cdir->data[i]->attribute = (style == COURIER)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
++ }
++ else
++ cdir->data[i]->attribute = LATT_NOSELECT;
++ cdir->data[i]->attribute += maildir_any_new_msgs(cdir->data[i]->name)
++ ? LATT_MARKED : LATT_UNMARKED;
++ }
++
++ /* UID Support */
++ /* Yes, I know I procastinated a lot about this, but here it is finally */
++
++ /* return code:
++ bigger than zero: this session can assign uids
++ zero: this session will not assign uid
++ smaller than zero: this session temporarily suspends assigning uids
++ */
++ int
++ maildir_can_assign_uid (MAILSTREAM *stream)
++ {
++ unsigned int rv = 0;
++ int ownuid, existuid;
++ unsigned long t;
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], *p, *s;
++ DIR *dir;
++ struct direct *d;
++
++ if(!stream || stream->rdonly
++ || !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
++ return 0;
++
++ if(mypid == (pid_t) 0)
++ mypid = getpid();
++
++ snprintf(tmp, sizeof(tmp), "%s.%d", MDUIDTEMP, mypid);
++
++ ownuid = existuid = 0;
++ s = NULL;
++ while ((d = readdir(dir)) != NULL){
++ if(strncmp(d->d_name, tmp, strlen(tmp)) == 0){
++ existuid++; ownuid++;
++ if(ownuid > 1){
++ snprintf(tmp2, sizeof(tmp), "%s/%s", LOCAL->dir, d->d_name);
++ unlink(tmp2);
++ if(s){
++ snprintf(tmp2, sizeof(tmp2), "%s/%s", LOCAL->dir, s);
++ unlink(tmp2);
++ fs_give((void **)&s);
++ }
++ }
++ else
++ s = cpystr(d->d_name);
++ }
++ else if(strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)) == 0)
++ existuid++;
++ }
++
++ closedir(dir);
++ if(s)
++ fs_give((void **)&s);
++
++ if(ownuid == 1 && existuid == 1)
++ rv = 1;
++
++ if(ownuid == 0 && existuid == 0){ /* nobody owns the uid? */
++ FILE *fp;
++ snprintf(tmp, sizeof(tmp), "%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
++ if(fp = fopen(tmp, "w")){
++ fclose(fp);
++ if(LOCAL->uidtempfile)
++ fs_give((void **)&LOCAL->uidtempfile);
++ LOCAL->uidtempfile = cpystr(tmp);
++ }
++ rv = 1;
++ }
++
++ if(ownuid == 0 && existuid > 0) /* someone else owns uid assignment */
++ return 0;
++
++ /* if we own the uid, check that we do not own it more than once
++ * or that we share ownership. If any of these situations happens,
++ * give up the ownership until we can recover it
++ */
++
++ if(ownuid > 0){
++ if(ownuid > 1) /* impossible, two lock files for the same session */
++ return (-1)*ownuid;
++
++ if(ownuid != existuid){ /* lock files for different sessions */
++ if(LOCAL->uidtempfile){
++ unlink(LOCAL->uidtempfile);
++ fs_give((void **)&LOCAL->uidtempfile);
++ }
++ return (-1)*ownuid;
++ }
++ }
++
++ return rv;
++ }
++
++ void
++ maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last,
++ unsigned long *uid_validity)
++ {
++ int createuid, deleteuid = 0;
++ char tmp[MAILTMPLEN], *s = NULL;
++ DIR *dir;
++ struct direct *d;
++
++ if(uid_last) *uid_last = 0L;
++ if(uid_last && uid_validity) *uid_validity = time(0);
++ if(!stream || !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
++ return;
++
++ while ((d = readdir(dir)) != NULL){
++ if(!strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST)))
++ break;
++ }
++ createuid = d == NULL ? 1 : 0;
++ if(uid_last == NULL)
++ deleteuid++;
++ if(d){
++ if(uid_last){
++ s = d->d_name + strlen(MDUIDLAST) + 1;
++ *uid_last = strtoul(s, &s, 10);
++ if(!s || *s != '.'){
++ deleteuid++;
++ createuid++;
++ *uid_last = 0L;
++ }
++ }
++ if(s && *s == '.'){
++ if(uid_validity){
++ s++;
++ *uid_validity = strtoul(s, &s, 10);
++ if(s && *s != '\0'){
++ *uid_validity = time(0);
++ deleteuid++;
++ createuid++;
++ }
++ }
++ }
++ else{
++ deleteuid++;
++ createuid++;
++ }
++ }
++ if(deleteuid){
++ snprintf(tmp, sizeof(tmp), "%s/%s", LOCAL->dir, d->d_name);
++ unlink(tmp);
++ }
++ if(createuid)
++ maildir_write_uid(stream, (uid_last ? *uid_last : stream->uid_last),
++ uid_validity ? *uid_validity : time(0));
++ closedir(dir);
++ }
++
++ void
++ maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last,
++ unsigned long uid_validity)
++ {
++ char tmp[MAILTMPLEN];
++ FILE *fp;
++
++ if(!stream || stream->rdonly || !LOCAL || !LOCAL->dir)
++ return;
++
++ snprintf(tmp, sizeof(tmp), "%s/%s.%010lu.%010lu", LOCAL->dir, MDUIDLAST,
++ uid_last, uid_validity);
++ if(fp = fopen(tmp, "w"))
++ fclose(fp);
++ }
++
++ unsigned long
++ maildir_get_uid(char *name)
++ {
++ char *s;
++ unsigned long rv = 0L;
++
++ if(!name || (s = strstr(name,MDUIDSEP)) == NULL)
++ return rv;
++
++ s += strlen(MDUIDSEP);
++ rv = strtoul(s, NULL, 10);
++ return rv;
++ }
++
++
++ void
++ maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno)
++ {
++ char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt(stream, msgno);
++ if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
++ return;
++
++ snprintf(old, sizeof(old), "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
++ t = MDFILE(elt);
++ if(s = strstr(MDFILE(elt), MDUIDSEP)){
++ *s = '\0';
++ s += strlen(MDUIDSEP);
++ strtoul(s, &s, 10);
++ snprintf(new, sizeof(new), "%s/%s/%s%s", LOCAL->dir, MDNAME(Cur), t, s);
++ if(rename(old, new) == 0){
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ s = strrchr(new, '/');
++ MDFILE(elt) = cpystr(s+1);
++ }
++ elt->private.uid = 0L;
++ }
++ }
++
++ void
++ maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid)
++ {
++ int createuid, deleteuid = 0;
++ char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt(stream, msgno);
++ if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
++ return;
++
++ maildir_delete_uid(stream, msgno);
++ snprintf(old, sizeof(old), "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
++ t = MDFILE(elt);
++ if((s = strrchr(MDFILE(elt),FLAGSEP)) != NULL){
++ *s++ = '\0';
++ snprintf(new, sizeof(new), "%s/%s/%s%s%lu%c%s",
++ LOCAL->dir, MDNAME(Cur), t, MDUIDSEP, uid, FLAGSEP, s);
++ if(rename(old, new) == 0){
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ s = strrchr(new, '/');
++ MDFILE(elt) = cpystr(s+1);
++ stream->uid_validity = time(0);
++ }
++ elt->private.uid = uid;
++ }
++ }
++
++ void
++ maildir_uid_renew_tempfile(MAILSTREAM *stream)
++ {
++ char tmp[MAILTMPLEN];
++
++ if(!stream || stream->rdonly
++ || !LOCAL || !LOCAL->candouid || !LOCAL->dir || !LOCAL->uidtempfile)
++ return;
++
++ if(mypid == (pid_t) 0)
++ mypid = getpid();
++
++ snprintf(tmp, sizeof(tmp), "%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
++ if(rename(LOCAL->uidtempfile, tmp) == 0){
++ fs_give((void **)&LOCAL->uidtempfile);
++ LOCAL->uidtempfile = cpystr(tmp);
++ }
++ }
+diff -rc alpine-2.24/imap/src/osdep/unix/maildir.h alpine-2.24.maildir/imap/src/osdep/unix/maildir.h
+*** alpine-2.24/imap/src/osdep/unix/maildir.h 2020-10-10 00:26:50.012168504 -0600
+--- alpine-2.24.maildir/imap/src/osdep/unix/maildir.h 2020-10-10 00:26:49.972167485 -0600
+***************
+*** 0 ****
+--- 1,226 ----
++ /*
++ * A few definitions that try to make this module portable to other
++ * platforms (e.g. Cygwin). This module is based on the information from
++ * http://cr.yp.to/proto/maildir.html
++ */
++
++ /* First we deal with the separator character */
++ #ifndef FLAGSEP
++ #define FLAGSEP ':'
++ #endif
++ #define SIZESEP ','
++
++ const char sep1[] = {FLAGSEP, '1', ',', '\0'}; /* experimental semantics*/
++ const char sep2[] = {FLAGSEP, '2', ',', '\0'}; /* Flags Information */
++ const char sep3[] = {FLAGSEP, '3', ',', '\0'}; /* Grrrr.... */
++
++ const char *sep[] = { sep1, sep2, sep3, NULL};
++
++ #define MDSEP(i) sep[((i) - 1)]
++
++ /* Now we deal with flags. Woohoo! */
++ typedef enum {Draft, Flagged, Passed, Replied, Seen, Trashed,
++ EmptyFlag, EndFlags} MdFlagNamesType;
++ const int mdimapflags[] = {Draft, Flagged, Replied, Seen, Trashed, EmptyFlag, EndFlags};
++ const int mdkwdflags[] = {Passed, EmptyFlag, EndFlags};
++
++ /* this array lists the codes for mdflgnms (maildir flag names) above */
++ const char *mdflags[] = { "D", "F", "P", "R", "S", "T", "", NULL};
++ /* and as characters too */
++ const char cmdflags[] = { 'D', 'F', 'P', 'R', 'S', 'T', '0', '\0'};
++
++ /* MDFLAG(Seen, elt->seen) */
++ #define MDFLAG(i,j) mdflags[j ? (i) : EmptyFlag]
++ /* MDFLAGC(Seen) */
++ #define MDFLAGC(i) cmdflags[(i)]
++
++ /* Now we deal with the directory structure */
++ typedef enum {Cur, Tmp, New, EndDir} DirNamesType;
++ char *mdstruct[] = {"cur", "tmp", "new", NULL};
++ #define MDNAME(i) mdstruct[(i)]
++ #define MDFLD(tmp, dir, i) sprintf((tmp),"%s/%s", (dir), mdstruct[(i)])
++ #define MSGPATH(tmp, dir, msg,i) sprintf((tmp),"%s/%s/%s", (dir), mdstruct[(i)],(msg))
++
++ /* Files associated to a maildir directory */
++
++ #define MDUIDVALIDITY ".uidvalidity" /* support for old maildirs */
++ #define MDDIR ".mdir" /* this folder is a directory */
++ #define MDUIDLAST ".uidlast" /* last assigned uid */
++ #define MDUIDTEMP ".uidtemp" /* We assign uid's no one else */
++
++
++
++ /* Support of Courier Structure */
++ #define CCLIENT 0
++ #define COURIER 1
++ #define IS_CCLIENT(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'd' || (t)[2] == 'D')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++
++ #define IS_COURIER(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'c' || (t)[2] == 'C')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++ #define MDPREFIX(s) ((s) ? "#mc/" : "#md/")
++ #define MDSEPARATOR(s) ((s) ? '.' : '/')
++
++ /* UID Support */
++
++ #define MAXTEMPUID (unsigned long) 180L
++ const char mduid[] = {',','u','=','\0'};
++ #define MDUIDSEP mduid
++
++
++ /* Now we deal with messages filenames */
++ char mdlocaldomain[MAILTMPLEN+1] = {'\0'};
++ pid_t mypid = (pid_t) 0;
++ static char *mdfpath = NULL;
++ static char myMdInboxDir[50] = { '\0' };/* Location of the Maildir INBOX */
++ static long CourierStyle = CCLIENT;
++
++ #define CHUNK 16384 /* from unix.h */
++
++ typedef struct courier_local {
++ char *name; /* name of directory/folder */
++ int attribute; /* attributes (children/marked/etc) */
++ } COURIERLOCAL;
++
++ typedef struct courier {
++ char *path; /* Path to collection */
++ time_t scantime; /* time at which information was generated */
++ int total; /* total number of elements in data */
++ COURIERLOCAL **data;
++ } COURIER_S;
++
++ /* In gdb this is the *(struct maildir_local *)stream->local structure */
++ typedef struct maildir_local {
++ unsigned int dirty : 1; /* diskcopy needs updating */
++ unsigned int courier : 1; /* It is Courier style file system */
++ unsigned int link : 1; /* There is a symbolic link */
++ int candouid; /* we can assign uids and no one else */
++ char *uidtempfile; /* path to uid temp file */
++ int fd; /* fd of open message */
++ char *dir; /* mail directory name */
++ char **path; /* path to directories cur, new and tmp */
++ unsigned char *buf; /* temporary buffer */
++ unsigned long buflen; /* current size of temporary buffer */
++ time_t scantime; /* last time directory scanned */
++ } MAILDIRLOCAL;
++
++ /* Convenient access to local data */
++ #define LOCAL ((MAILDIRLOCAL *) stream->local)
++
++ typedef struct maildir_file_info {
++ char *name; /* name of the file */
++ DirNamesType loc; /* location of this file */
++ unsigned long pos; /* place in list where this file is listed */
++ off_t size; /* size in bytes, on disk */
++ time_t atime; /* last access time */
++ time_t mtime; /* last modified time */
++ time_t ctime; /* last changed time */
++ } MAILDIRFILE;
++
++ #define MDFILE(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->name)
++ #define MDLOC(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->loc)
++ #define MDPOS(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->pos)
++ #define MDSIZE(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->size)
++ #define MDATIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->atime)
++ #define MDMTIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->mtime)
++ #define MDCTIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->ctime)
++
++ /* Function prototypes */
++
++ DRIVER *maildir_valid (char *name);
++ MAILSTREAM *maildir_open (MAILSTREAM *stream);
++ void maildir_close (MAILSTREAM *stream, long options);
++ long maildir_ping (MAILSTREAM *stream);
++ void maildir_check (MAILSTREAM *stream);
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags);
++ void maildir_list (MAILSTREAM *stream,char *ref,char *pat);
++ void *maildir_parameters (long function,void *value);
++ int maildir_create_folder (char *mailbox);
++ long maildir_create (MAILSTREAM *stream,char *mailbox);
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); /*check */
++ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options);
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
++ long maildir_append (MAILSTREAM *stream,char *mailbox, append_t af, void *data);
++ long maildir_delete (MAILSTREAM *stream,char *mailbox);
++ long maildir_rename (MAILSTREAM *stream,char *old,char *new);
++ long maildir_sub (MAILSTREAM *stream,char *mailbox);
++ long maildir_unsub (MAILSTREAM *stream,char *mailbox);
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat);
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat);
++
++ /* utility functions */
++ void courier_realname (char *name, char *realname);
++ long maildir_dirfmttest (char *name);
++ char *maildir_file (char *dst,char *name);
++ int maildir_select (const struct direct *name);
++ int maildir_namesort (const struct direct **d1, const struct direct **d2);
++ unsigned long antoul (char *seed);
++ unsigned long mdfntoul (char *name);
++ int courier_dir_select (const struct direct *name);
++ int courier_dir_sort (const struct direct **d1, const struct direct **d2);
++ long maildir_canonicalize (char *pattern,char *ref,char *pat);
++ void maildir_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ void courier_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ int maildir_file_path(char *name, char *tmp, size_t sizeoftmp);
++ int maildir_valid_name (char *name);
++ int maildir_valid_dir (char *name);
++ int is_valid_maildir (char **name);
++ int maildir_message_exists(MAILSTREAM *stream,char *name, char *tmp);
++ char *maildir_remove_root(char *name);
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags);
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype);
++ int maildir_eliminate_duplicate (char *name, struct direct ***flist,
++ unsigned long *nfiles);
++ int maildir_doscandir (char *name, struct direct ***flist, int flag);
++ unsigned long maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag);
++ void maildir_parse_folder (MAILSTREAM *stream, int full);
++ void md_domain_name (void);
++ char *myrootdir (char *name);
++ char *mdirpath (void);
++ int maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype);
++ unsigned long maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, struct direct **names, unsigned long nfiles, int full);
++ int same_maildir_file(char *name1, char *name2);
++ int comp_maildir_file(char *name1, char *name2);
++ int maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos);
++ void maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t);
++ int maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_abort (MAILSTREAM *stream);
++ int maildir_contains_folder(char *dirname, char *name);
++ int maildir_is_dir(char *dirname, char *name);
++ int maildir_dir_is_empty(char *mailbox);
++ int maildir_create_work (char *mailbox, int loop);
++ void maildir_get_file (MAILDIRFILE **mdfile);
++ void maildir_free_file (void **mdfile);
++ void maildir_free_file_only (void **mdfile);
++ int maildir_any_new_msgs(char *mailbox);
++ void maildir_get_date(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags);
++
++ /* Courier server support */
++ void courier_free_cdir (COURIER_S **cdir);
++ COURIER_S *courier_get_cdir (int total);
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last);
++ COURIER_S *courier_list_dir(char *curdir);
++ void courier_list_info(COURIER_S **cdirp, char *data, int i);
++
++ /* UID Support */
++ int maildir_can_assign_uid (MAILSTREAM *stream);
++ void maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last,
++ unsigned long *uid_validity);
++ void maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last,
++ unsigned long uid_validity);
++ unsigned long maildir_get_uid(char *name);
++ void maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid);
++ void maildir_uid_renew_tempfile(MAILSTREAM *stream);
++
+diff -rc alpine-2.24/imap/src/osdep/unix/Makefile alpine-2.24.maildir/imap/src/osdep/unix/Makefile
+*** alpine-2.24/imap/src/osdep/unix/Makefile 2020-10-10 00:24:28.196554399 -0600
+--- alpine-2.24.maildir/imap/src/osdep/unix/Makefile 2020-10-10 00:26:49.976167588 -0600
+***************
+*** 146,152 ****
+ # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
+ # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
+ #
+! DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+ CHUNKSIZE=65536
+
+ # Normally no need to change any of these
+--- 146,152 ----
+ # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
+ # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
+ #
+! DEFAULTDRIVERS=maildir courier imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+ CHUNKSIZE=65536
+
+ # Normally no need to change any of these
+***************
+*** 155,161 ****
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o http.o json.o pop3.o \
+! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
+ CFLAGS=-g
+
+ CAT=cat
+--- 155,161 ----
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o http.o json.o pop3.o \
+! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o maildir.o
+ CFLAGS=-g
+
+ CAT=cat
+***************
+*** 292,298 ****
+
+ cyg: # Cygwin - note that most local file drivers don't work!!
+ $(BUILD) `$(CAT) SPECIALS` OS=$@ \
+! DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \
+ SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
+ SPOOLDIR=/var \
+ ACTIVEFILE=/usr/local/news/lib/active \
+--- 292,298 ----
+
+ cyg: # Cygwin - note that most local file drivers don't work!!
+ $(BUILD) `$(CAT) SPECIALS` OS=$@ \
+! DEFAULTDRIVERS="imap nntp pop3 mbx unix maildir phile" \
+ SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
+ SPOOLDIR=/var \
+ ACTIVEFILE=/usr/local/news/lib/active \
+***************
+*** 921,926 ****
+--- 921,927 ----
+ utf8aux.o: mail.h misc.h osdep.h utf8.h
+ json.o: mail.h misc.h osdep.h utf8.h json.h
+ http.o: mail.h misc.h osdep.h utf8.h http.h json.h
++ maildir.o: mail.h misc.h osdep.h maildir.h dummy.h
+
+ # OS-dependent
+
+diff -rc alpine-2.24/imap/src/osdep/unix/os_cyg.h alpine-2.24.maildir/imap/src/osdep/unix/os_cyg.h
+*** alpine-2.24/imap/src/osdep/unix/os_cyg.h 2020-10-10 00:24:28.192554297 -0600
+--- alpine-2.24.maildir/imap/src/osdep/unix/os_cyg.h 2020-10-10 00:26:49.976167588 -0600
+***************
+*** 47,52 ****
+--- 47,53 ----
+ #define setpgrp setpgid
+
+ #define SYSTEMUID 18 /* Cygwin returns this for SYSTEM */
++ #define FLAGSEP ';'
+ #define geteuid Geteuid
+ uid_t Geteuid (void);
+
+diff -rc alpine-2.24/pith/conf.c alpine-2.24.maildir/pith/conf.c
+*** alpine-2.24/pith/conf.c 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/conf.c 2020-10-10 00:26:49.976167588 -0600
+***************
+*** 453,458 ****
+--- 453,461 ----
+
+ CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file";
+
++ #ifndef _WINDOWS
++ CONF_TXT_T cf_text_maildir_location[] = "Location relative to your HOME directory of the directory where your INBOX\n# for the maildir format is located. Default value is \"Maildir\". If your\n# inbox is located at \"~/Maildir\" you do not need to change this value.\n# A common value is also \".maildir\"";
++ #endif
+
+ /*----------------------------------------------------------------------
+ These are the variables that control a number of pine functions. They
+***************
+*** 657,662 ****
+--- 660,669 ----
+ NULL, cf_text_news_active},
+ {"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_news_spooldir},
++ #ifndef _WINDOWS
++ {"maildir-location", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
++ "Maildir Location", cf_text_maildir_location},
++ #endif
+ {"upload-command", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_upload_cmd},
+ {"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+***************
+*** 2392,2397 ****
+--- 2399,2410 ----
+ mail_parameters(NULL, SET_NEWSSPOOL,
+ (void *)VAR_NEWS_SPOOL_DIR);
+
++ #ifndef _WINDOWS
++ set_current_val(&vars[V_MAILDIR_LOCATION], TRUE, TRUE);
++ if(VAR_MAILDIR_LOCATION && VAR_MAILDIR_LOCATION[0])
++ mail_parameters(NULL, SET_MDINBOXPATH, (void *)VAR_MAILDIR_LOCATION);
++ #endif
++
+ /* guarantee a save default */
+ set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE);
+ if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0])
+***************
+*** 3030,3035 ****
+--- 3043,3052 ----
+ F_SORT_DEFAULT_SAVE_ALPHA, h_config_sort_save_alpha, PREF_FLDR, 0},
+ {"vertical-folder-list", "Use Vertical Folder List",
+ F_VERTICAL_FOLDER_LIST, h_config_vertical_list, PREF_FLDR, 0},
++ #ifndef _WINDOWS
++ {"use-courier-folder-list", "Courier Style Folder List",
++ F_COURIER_FOLDER_LIST, h_config_courier_list, PREF_FLDR, 0},
++ #endif
+
+ /* Addr book */
+ {"combined-addrbook-display", "Combined Address Book Display",
+***************
+*** 7209,7215 ****
+ int just_flip_value, EditWhich ew)
+ {
+ char **vp, *p, **lval, ***alval;
+! int og, on_before, was_set;
+ char *err;
+ long l;
+
+--- 7226,7232 ----
+ int just_flip_value, EditWhich ew)
+ {
+ char **vp, *p, **lval, ***alval;
+! int og, on_before, was_set, i;
+ char *err;
+ long l;
+
+***************
+*** 7262,7267 ****
+--- 7279,7291 ----
+
+ break;
+
++ #ifndef _WINDOWS
++ case F_COURIER_FOLDER_LIST:
++ i = F_ON(f->id ,ps) ? 1 : 0;
++ mail_parameters(NULL,SET_COURIERSTYLE, (void *) &i);
++ break; /* COURIER == 1, CCLIENT == 0, see maildir.h */
++ #endif
++
+ case F_COLOR_LINE_IMPORTANT :
+ case F_DATES_TO_LOCAL :
+ clear_index_cache(ps->mail_stream, 0);
+***************
+*** 8062,8067 ****
+--- 8086,8095 ----
+ return(h_config_newmailwidth);
+ case V_NEWSRC_PATH :
+ return(h_config_newsrc_path);
++ #ifndef _WINDOWS
++ case V_MAILDIR_LOCATION :
++ return(h_config_maildir_location);
++ #endif
+ case V_BROWSER :
+ return(h_config_browser);
+ case V_HISTORY :
+diff -rc alpine-2.24/pith/conf.h alpine-2.24.maildir/pith/conf.h
+*** alpine-2.24/pith/conf.h 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/conf.h 2020-10-10 00:26:49.976167588 -0600
+***************
+*** 264,269 ****
+--- 264,273 ----
+ #define GLO_NEWS_ACTIVE_PATH vars[V_NEWS_ACTIVE_PATH].global_val.p
+ #define VAR_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].current_val.p
+ #define GLO_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].global_val.p
++ #ifndef _WINDOWS
++ #define VAR_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].current_val.p
++ #define GLO_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].global_val.p
++ #endif
+ #define VAR_DISABLE_DRIVERS vars[V_DISABLE_DRIVERS].current_val.l
+ #define VAR_DISABLE_AUTHS vars[V_DISABLE_AUTHS].current_val.l
+ #define VAR_REMOTE_ABOOK_METADATA vars[V_REMOTE_ABOOK_METADATA].current_val.p
+diff -rc alpine-2.24/pith/conftype.h alpine-2.24.maildir/pith/conftype.h
+*** alpine-2.24/pith/conftype.h 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/conftype.h 2020-10-10 00:26:49.980167690 -0600
+***************
+*** 118,123 ****
+--- 118,126 ----
+ , V_NEWSRC_PATH
+ , V_NEWS_ACTIVE_PATH
+ , V_NEWS_SPOOL_DIR
++ #ifndef _WINDOWS
++ , V_MAILDIR_LOCATION
++ #endif
+ , V_UPLOAD_CMD
+ , V_UPLOAD_CMD_PREFIX
+ , V_DOWNLOAD_CMD
+***************
+*** 406,411 ****
+--- 409,417 ----
+ F_PASS_C1_CONTROL_CHARS,
+ F_SINGLE_FOLDER_LIST,
+ F_VERTICAL_FOLDER_LIST,
++ #ifndef _WINDOWS
++ F_COURIER_FOLDER_LIST,
++ #endif
+ F_TAB_CHK_RECENT,
+ F_AUTO_REPLY_TO,
+ F_VERBOSE_POST,
+diff -rc alpine-2.24/pith/init.c alpine-2.24.maildir/pith/init.c
+*** alpine-2.24/pith/init.c 2020-10-10 00:24:28.208554703 -0600
+--- alpine-2.24.maildir/pith/init.c 2020-10-10 00:26:49.980167690 -0600
+***************
+*** 408,413 ****
+--- 408,416 ----
+ && stricmp(filename, folder_base)){
+ #else
+ if(strncmp(filename, folder_base, folder_base_len) == 0
++ #ifndef _WINDOWS
++ && filename[folder_base_len] != list_cntxt->dir->delim
++ #endif
+ && strcmp(filename, folder_base)){
+ #endif
+ #endif
+diff -rc alpine-2.24/pith/pattern.c alpine-2.24.maildir/pith/pattern.c
+*** alpine-2.24/pith/pattern.c 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/pattern.c 2020-10-10 00:26:49.984167792 -0600
+***************
+*** 49,55 ****
+ #include "../pith/icache.h"
+ #include "../pith/ablookup.h"
+ #include "../pith/keyword.h"
+!
+
+ /*
+ * Internal prototypes
+--- 49,57 ----
+ #include "../pith/icache.h"
+ #include "../pith/ablookup.h"
+ #include "../pith/keyword.h"
+! #ifndef _WINDOWS
+! int maildir_file_path(char *name, char *tmp, size_t sizeoftmp);
+! #endif /* _WINDOWS */
+
+ /*
+ * Internal prototypes
+***************
+*** 5485,5490 ****
+--- 5487,5501 ----
+ break;
+
+ case '#':
++ #ifndef _WINDOWS
++ if(!struncmp(patfolder, "#md/", 4)
++ || !struncmp(patfolder, "#mc/", 4)){
++ maildir_file_path(patfolder, tmp1, sizeof(tmp1));
++ if(!strcmp(tmp1, stream->mailbox))
++ match++;
++ break;
++ }
++ #endif
+ if(!strcmp(patfolder, stream->mailbox))
+ match++;
+
+***************
+*** 7905,7911 ****
+ int we_cancel = 0, width;
+ CONTEXT_S *save_context = NULL;
+ char buf[MAX_SCREEN_COLS+1], sbuf[MAX_SCREEN_COLS+1];
+! char *save_ref = NULL;
+ #define FILTMSG_MAX 30
+
+ if(!stream)
+--- 7916,7922 ----
+ int we_cancel = 0, width;
+ CONTEXT_S *save_context = NULL;
+ char buf[MAX_SCREEN_COLS+1], sbuf[MAX_SCREEN_COLS+1];
+! char *save_ref = NULL, *save_dstfldr = NULL, *save_dstfldr2 = NULL;
+ #define FILTMSG_MAX 30
+
+ if(!stream)
+***************
+*** 7939,7944 ****
+--- 7950,7965 ----
+ if(F_OFF(F_QUELL_FILTER_MSGS, ps_global))
+ we_cancel = busy_cue(buf, NULL, 0);
+
++ #ifndef _WINDOWS
++ if(!struncmp(dstfldr, "#md/", 4) || !struncmp(dstfldr, "#mc/", 4)){
++ char tmp1[MAILTMPLEN];
++ maildir_file_path(dstfldr, tmp1, sizeof(tmp1));
++ save_dstfldr2 = dstfldr;
++ save_dstfldr = cpystr(tmp1);
++ dstfldr = save_dstfldr;
++ }
++ #endif
++
+ if(!is_absolute_path(dstfldr)
+ && !(save_context = default_save_context(ps_global->context_list)))
+ save_context = ps_global->context_list;
+***************
+*** 8002,8007 ****
+--- 8023,8033 ----
+ if(we_cancel)
+ cancel_busy_cue(buf[0] ? 0 : -1);
+
++ if(save_dstfldr){
++ fs_give((void **)&save_dstfldr);
++ dstfldr = save_dstfldr2;
++ }
++
+ return(buf[0] != '\0');
+ }
+
+diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.maildir/pith/pine.hlp
+*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/pine.hlp 2020-10-10 00:26:49.996168098 -0600
+***************
+*** 23452,23457 ****
+--- 23452,23553 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_maildir_location ======
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_maildir-location"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_maildir-location"--></H1>
++
++ <P>
++ This option should be used only if you have a Maildir folder which you
++ want to use as your INBOX. If this is not your case (or don't know what
++ this is), you can safely ignore this option.
++
++ <P>
++ This option overrides the default directory Pine uses to find the location of
++ your INBOX, in case this is in Maildir format. The default value of this
++ option is "Maildir", but in some systems, this directory could have been
++ renamed (e.g. to ".maildir"). If this is your case use this option to change
++ the default.
++
++ <P>
++ The value of this option is prefixed with the "~/" string to determine the
++ full path to your INBOX.
++
++ <P>
++ You should probably <A HREF="h_config_maildir">read</A> a few tips that
++ teach you how to configure your maildir for optimal performance. This
++ version also has <A HREF="h_config_courier_list">support</A> for the
++ Courier style file system when a maildir collection is accessed locally.
++
++ <P><UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL>
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_maildir =====
++ <HTML>
++ <HEAD>
++ <TITLE>Maildir Support</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>Maildir Support</H1>
++
++ This version of Alpine has been enhanced with Maildir support. This text is
++ intended to be a reference on its support.
++ <P>
++
++ A Maildir folder is a directory that contains three directories called
++ cur, tmp and new. A program that delivers mail (e.g. postfix) will put new
++ mail in the new directory. A program that reads mail will look for for old
++ messages in the cur directory, while it will look for new mail in the new
++ directory.
++ <P>
++
++ In order to use maildir support it is better to set your inbox-path to the
++ value &quot;#md/inbox&quot; (without quotes). This assumes that your mail
++ delivery agent is delivering new mail to ~/Maildir/new. If the directory
++ where new mail is being delivered is not called "Maildir", you can set the
++ name of the subdirectory of home where it is being delivered in the <A
++ HREF="h_config_maildir_location"><!--#echo var="VAR_maildir-location"--></A> configuration
++ variable. Most of the time you will not have to worry about the
++ <!--#echo var="VAR_maildirlocation"--> variable, because it will probably be set by your
++ administrator in the pine.conf configuration file.
++ <P>
++
++ One of the advantages of the Maildir support of this version of Alpine is
++ that you do not have to stop using folders in another styles (mbox, mbx,
++ etc.). This is desirable since the usage of a specific mail storage system
++ is a personal decision. Folders in the maildir format that are part of the
++ Mail collection will be recognized without any extra configuration of your
++ part. If your mail/ collection is located under the mail/ directory, then
++ creating a new maildir folder in this collection is done by pressing "A"
++ and entering the string "#driver.md/mail/newfolder". Observe that adding a
++ new folder as "newfolder" may not create such folder in maildir format.
++
++ <P>
++ If you would like to have all folders created in the maildir format by
++ default, you do so by adding a Maildir Collection. In order to convert
++ your current mail/ collection into a maildir collection, edit the
++ collection and change the path variable from &quot;mail/&quot; to
++ &quot;#md/mail&quot;. In a maildir collection folders of any other format
++ are ignored.
++
++ <P> Finally, This version also has
++ <A HREF="h_config_courier_list">support</A> for the Courier style file system
++ when a maildir collection is accessed locally.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_literal_sig =====
+ <HTML>
+ <HEAD>
+***************
+*** 31683,31688 ****
+--- 31779,31827 ----
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
++ </HTML>
++ ====== h_config_courier_list =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_courier-folder-list"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_courier-folder-list"--></H1>
++
++ In a maildir collection, a folder could be used as a directory to store
++ folders. In the Courier server if you create a folder, then a directory
++ with the same name is created. If you use this patch to access a
++ collection created by the Courier server, then the display of such
++ collection will look confusing. The best way to access a maildir
++ collection created by the Courier server is by using the &quot;#mc/&quot;
++ prefix instead of the &quot;#md/&quot; prefix. If you use this alternate
++ prefix, then this feature applies to you, otherwise you can safely ignore
++ the text that follows.
++ <P>
++ Depending on if you have enabled the option
++ <a href="h_config_separate_fold_dir_view"><!--#echo var="FEAT_separate-folder-and-directory-entries"--></a>
++ a folder may be listed as &quot;folder[.]&quot;, or as two entries in the
++ list by &quot;folder&quot; and &quot;folder.&quot;.
++ <P>
++ If this option is disabled, Pine will list local folders that are in Courier
++ style format, as &quot;folder&quot;, and those that are also directories as
++ &quot;folder[.]&quot;. This makes the default display cleaner.
++ <P>
++ If this feature is enabled then creating folders in a maildir collection
++ will create a directory with the same name. If this feature is disabled, then
++ a folder is considered a directory only if it contains subfolders, so you can
++ not create a directory with the same name as an exisiting folder unless
++ you create a subfolder of that folder first (e.g. if you have a folder
++ called &quot;foo&quot; simply add &quot;foo.bar&quot; directly. This will
++ create the directory &quot;foo&quot; and the subfolder &quot;bar&quot; of it).
++ <P>
++ Observe that this feature works only for maildir collections that are accessed
++ locally. If a collection is accessed remotely then this feature has no value,
++ as the report is created in a server, and Pine only reports what received
++ from the server in this case.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
+ </HTML>
+ ====== h_config_verbose_post =====
+ <HTML>
+diff -rc alpine-2.24/pith/send.c alpine-2.24.maildir/pith/send.c
+*** alpine-2.24/pith/send.c 2020-10-10 00:24:28.204554602 -0600
+--- alpine-2.24.maildir/pith/send.c 2020-10-10 00:26:49.996168098 -0600
+***************
+*** 47,52 ****
+--- 47,55 ----
+
+ #include "../c-client/smtp.h"
+ #include "../c-client/nntp.h"
++ #ifndef _WINDOWS
++ int maildir_file_path(char *name, char *tmp, size_t sizeoftmp);
++ #endif /* _WINDOWS */
+
+
+ /* this is used in pine_send and pine_simple_send */
+***************
+*** 250,255 ****
+--- 253,265 ----
+
+ if(exists & FEX_ISFILE){
+ context_apply(tmp, p_cntxt, mbox, sizeof(tmp));
++ #ifndef _WINDOWS
++ if (!struncmp(tmp, "#md/",4) || !struncmp(tmp, "#mc/", 4)){
++ char tmp2[MAILTMPLEN];
++ maildir_file_path(tmp, tmp2, sizeof(tmp2));
++ strcpy(tmp, tmp2);
++ }
++ #endif
+ if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
+ /*
+ * The mbox is relative to the home directory.
+diff -rc alpine-2.24/README.maildir alpine-2.24.maildir/README.maildir
+*** alpine-2.24/README.maildir 2020-10-10 00:26:50.012168504 -0600
+--- alpine-2.24.maildir/README.maildir 2020-10-10 00:26:49.996168098 -0600
+***************
+*** 0 ****
+--- 1,149 ----
++ ---------------------------------------
++
++ Maildir Driver for Alpine 2.0
++ By Eduardo Chappa
++ <alpine.chappa@gmx.com>
++
++ ---------------------------------------
++ 1. General Information About This Patch
++ ---------------------------------------
++
++ This patch adds support for the maildir format to Alpine. We take the
++ approach that this patch is one more driver among the number of formats
++ supported by Alpine (more generally c-client). This approach differs from
++ older versions of similar patches, in that once a maildir patch was
++ applied, it was assumed that all your folders would be created in the
++ maildir format.
++
++ This patch does not assume that maildir is a preferred format, instead
++ puts maildir in equal footing with other formats (mbox, mbx, mix, etc),
++ and so a maildir folder in the mail/ collection is treated in the same way
++ as any other folder in any other format. In other words, just by reading
++ the name of a folder, or opening it, or doing any operation with it, you
++ can not know in which format the folder is.
++
++ This implies that if you want to add a folder in the maildir format to the
++ mail/ collection, then you must add by pressing "A" in the folder list
++ collection and enter "#driver.md/mail/name_maildir_folder".
++
++ If you only want to use maildir, however, you can do so too. In this case,
++ you must create a maildir collection. In that collection, only maildir
++ folders will be listed. If there is any folder in any other format, that
++ folder will be ignored. In another words, any folder listed there is in
++ maildir format and can be accessed through that collection, conversely,
++ any folder not listed there is not in maildir format and there is no way
++ to access it using this collection.
++
++ In order to create a maildir collection, you could press M S L, and "A" to
++ add a collection. Fill in the required fields as follows:
++
++ Nickname : Anything
++ Server :
++ Path : #md/relative/path/to/maildir/collection/
++ View :
++
++ For example, if "path" is set to "#md/mail/", then Alpine will look for your
++ maildir folders that are in ~/mail/.
++
++ The code in this patch is mostly based in code for the unix driver plus
++ some combinations of the mh, mbx and nntp drivers for the c-client
++ library. Those drivers were designed by Mark Crispin, and bugs in this
++ code are not his bugs, but my own.
++
++ I got all the specification for this patch from
++ http://cr.yp.to/proto/maildir.html. If you know of a place with a better
++ specification for maildir format please let me know. The method this patch
++ uses to create a unique filename for a message is one of the "old
++ fashioned" methods. I realize that this is old fashioned, but it is
++ portable, and portability is the main reason why I decided to use an old
++ fashioned method (most methods are not portable. See the word
++ "Unfortunately" in that document).
++
++ --------------
++ 2. Other Goals
++ --------------
++
++ It is intended that this code will work well with any application
++ written using the c-client library. Of paramount importance is to make the
++ associated imap server work well when the server accesses a folder in
++ Maildir format. The program mailutil should also work flawlessly with this
++ implemetation of the driver.
++
++ It is intended that this driver be fast and stable. We intend not to
++ patch Alpine to make this driver do its work, unless such patching is for
++ fixing bugs in Alpine or to pass parameters to the driver.
++
++ ------------------------------------------------------------------------
++ 3. What are the known bugs of this implementation of the Maildir driver?
++ ------------------------------------------------------------------------
++
++ I don't know any at this time. There have been bugs before, though, but
++ I try to fix bugs as soon as they are reported.
++
++ ----------
++ 4. On UIDs
++ ----------
++
++ This patch keeps uids in the name of the file that contains the message,
++ by adding a ",u=" string to the file name to save the uid of a message. A
++ file is kept between sessions to save information on the last uid assigned
++ and its time of validity. Only one session with writing access can write
++ uids, all others must wait for the other session to assign them. The
++ session assigning uids creates a ".uidtemp" file which other sessions must
++ not disturb.
++
++ Uid support appeared in Alpine 1.00 (snapshot 925), and is experimental,
++ please report any problems.
++
++ ----------------------------------------------
++ 5. Configuring Alpine and Setting up a Maildir
++ ----------------------------------------------
++
++ Once this approach was chosen, it implied the following:
++
++ * This patch assumes that your INBOX is located at "$HOME/Maildir".
++ This is a directory which should have three subdirectories "cur",
++ "tmp" and "new". Mail is delivered to 'new' and read from 'cur'. I
++ have added a configuration option "maildir-location" which can be
++ used to tell Alpine where your Maildir inbox is, in case your system
++ does not use the above directory (e.g. your system may use
++ "~/.maildir"). In this case define that variable to be the name of
++ the directory where your e-mail is being delivered (e.g.
++ ".maildir").
++
++ * If you want to use the above configuration as your inbox, you must
++ define your inbox-path as "#md/inbox" (no quotes). You can define
++ the inbox-path like above even if you have changed the
++ maildir-location variable. That's the whole point of that variable.
++
++ -------------------------------------------
++ 6. What about Courier/Dovecot file systems?
++ -------------------------------------------
++
++ In a courier file system all folders are subfolders of a root folder
++ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are
++ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a
++ subfolder of INBOX and is accessed with the nickname "INBOX.Trash".
++
++ You can not access folders in this way unless you preceed them with the
++ string "#mc/". The purpose of the string "#mc/" is to warn Alpine that a
++ collection in the Courier format is going to be accessed. Therefore, you
++ can SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash"
++
++ You can access a collection through a server, but if you want to access a
++ collection of folders created using the Courier server, you MUST edit your
++ ".pinerc" file and enter the definition of the collection as follows:
++
++ folder-collections="Anything you want" #mc/INBOX.[]
++
++ You can replace the string "#mc/INBOX." by something different, for example
++ "#mc/Courier/." will make Alpine search for your collection in ~/Courier.
++
++ You can not add this setting directly into Alpine because Alpine fails to
++ accept this value from its input, but it takes it correctly when it is
++ added through the ".pinerc" file.
++
++ You can access your inbox as "#mc/INBOX" or "#md/INBOX". Both definitions
++ point to the same place.
++
++ Last Updated May 28, 2011