        For applying thich patch use (on directory where Configure is)

                patch -p1 < {this-file}

------------------------------------------------------------------------
Index: elmME+.2.5.alpha64-cvs/hdrs/patchlevel.h
Prereq:  1735000000
*** elmME+.2.5.alpha63/hdrs/patchlevel.h	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/hdrs/patchlevel.h	Sat Jun 29 11:16:36 2024
***************
*** 1,12 ****
! #define PATCHLEVEL        "alpha63"
  /* Used by Configure:
! SHAREDTAG: .1.1.63
  */
! #define LAST_REPORT_TIME  1735000000
  #define BUG_REPORT_ADDR   "Kari Hurtta <elm@elmme-mailer.org>"
! #define VERS_DATE	  "Jan 2024"	/* for elm -v option */
  #define WHAT_STRING	\
! 	"@(#) Version ME+ 2.5, released Jan 2024"
  
  /*
   * Local Variables:
--- 1,12 ----
! #define PATCHLEVEL        "alpha64"
  /* Used by Configure:
! SHAREDTAG: .1.1.64
  */
! #define LAST_REPORT_TIME  1750000000
  #define BUG_REPORT_ADDR   "Kari Hurtta <elm@elmme-mailer.org>"
! #define VERS_DATE	  "Jul 2024"	/* for elm -v option */
  #define WHAT_STRING	\
! 	"@(#) Version ME+ 2.5, released Jul 2024"
  
  /*
   * Local Variables:
Index: elmME+.2.5.alpha64-cvs/README.ME+
*** elmME+.2.5.alpha63/README.ME+	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/README.ME+	Sat Jun 29 12:22:40 2024
***************
*** 1,6 ****
! $Header: /home/users/hurtta/cvsroot/mail/elmme+/README.ME+,v 2.1094 2024/01/01 19:05:58 hurtta Exp $
! 
! $Header: /home/users/hurtta/cvsroot/mail/elmme+/README.ME+,v 2.1094 2024/01/01 19:05:58 hurtta Exp $
  
  Version Elm2.4ME+ PL0 (25) is based on version Elm2.4 PL24 ME8b+.
  Version Elm2.4 PL24 ME8b+ is based on version Elm2.4 PL24 ME8b.
--- 1,4 ----
! $Header: /home/users/hurtta/cvsroot/mail/elmme+/README.ME+,v 2.1107 2024/06/29 09:22:40 hurtta Exp $
  
  Version Elm2.4ME+ PL0 (25) is based on version Elm2.4 PL24 ME8b+.
  Version Elm2.4 PL24 ME8b+ is based on version Elm2.4 PL24 ME8b.
***************
*** 21,31 ****
  ===================================================================
  * Changelog of Elm ME+ 2.5
  
  Changes on Elm ME+ 2.5 PLalpha63 compared with Elm ME+ 2.5 PLalpha62
  --------------------------------------------------------------------
  
          SUMMARY: This release includes tagfilter module for
!                  filtering text/enrcinhed and text/html
                   tags. This release adds "editor-tfent-propline"
                   and "page-tagfilter" elmrc options and
                   new tool "elmtagfilterents". This release
--- 19,132 ----
  ===================================================================
  * Changelog of Elm ME+ 2.5
  
+ Changes on Elm ME+ 2.5 PLalpha64 compared with Elm ME+ 2.5 PLalpha63
+ --------------------------------------------------------------------
+ 
+         SUMMARY: This release last read timestamps file for
+                  used for folder browser when  access time of
+                  folders are not updated when read. "Eu" -command
+                  (show mail quota usage) now rereads IMAP quota
+                  before displaying. New elmrc
+                  options are "use-last-read-file" and
+                  "last-read-fallback-locking". Also some bug
+                  fixes and other changes are included.
+                  
+         - Added file .elm-last-read-{uid} on directory (when
+           directory is writable) or file ~/.elm/last.read,
+           when mailbox is on mailhome directory, to
+           keep track last read time of folder.
+ 	* This helps situation where access time of
+ 	  mail folders or mailboxes are not updated
+ 	  when they are read and therefore N (new mail)
+ 	  indicator is shown on folder browser although mail folder
+ 	  or mailbox is read after it was updated.
+         - Added "use-last-read-file" elmrc option.
+           Values are:
+                  no                     Do not read or update
+                                         .elm-last-read-{uid} file
+                  yes                    Create, use and update
+                                         .elm-last-read-{uid} file
+                  auto                   Use and update existing
+                                         .elm-last-read-{uid} file.
+                                         Create file if access
+                                         time is not updated.
+                  existing               Use and update existing
+                                         .elm-last-read-{uid} file
+            This elmrc option is also used for
+             ~/.elm/last.read update.
+         - Added "last-read-fallback-locking" elmrc option.
+            This lock option knows following keywords
+                 none                    None of values are selected
+                                         (use value none to disable locking)
+                 flock                   Use flock() locking. flock() 
+                                         does not lock files over NFS.
+                 fcntl                   Use fcntl() locking.  
+                 prefer                  Prefer this option instead of
+                                         folder-locking or mailbox-locking
+         - ~/.elm/last.read file uses conf-merge-locking.
+         - .elm-last-read-{uid} file uses either folder-locking,
+           mailbox-locking, or last-read-fallback-locking.
+ 
+         - Exported
+               char * MAILBOX_LOCKING[]
+           from lib/read_rc.c to hdrs/rc_imp.h and added "prefer"
+           value to it.
+ 
+         - Change for fbrowser_selection_is_mbox()
+ 
+         - Small change of home[] initialization on user_init()
+ 
+         - Moved struct file_changes from lib/alias/aliases.c
+           to lib/addr/file_changes.c and from hdrs/aliaslib.h
+           to hdrs/addrlib.h 
+ 
+         - Possible fix for malloc_gets()
+ 
+         - Added  cat_dir_entry() to lib/mox/localmbx.c and
+           lib/mbox/def_mbox.c
+         - Changed write_conf() on lib/misc/conf_write.c
+         - Changed insert_commentfile() on lib/misc/commentfile.c
+         - Changed most of ino_t and dev_t output to use (unsigned long)
+           and %lu format.
+ 
+ 	- Added copy_num_messages_folder() to lib/mbox/mbox.c
+           and hdrs/mboxlib.h
+ 	- Added mbx_give_message_count_folder() to  hdrs/mbx_imp.h
+ 	- Added mbx_give_message_count_default() to lib/mbox/mbox_generic.c
+           and lib/mbox/def_mbox.h
+ 	- Added number of messages to 
+ 	  	Reading in XXX message: xxx
+ 	  counter if available and there is enough space.
+ 	- Changed width calculations on
+ 	  	Reading in XXX message: xxx
+ 	  counter text.
+ 
+ 	- Possible fix on quota_display_add_qlist() on src/quotadisp.c
+ 	- Possible fix on ref_mqr_imap() on lib/mbox/imap_quota.c
+ 	- "Eu" -command ("E)xtended command" - "show mail quota u)sage")
+ 	  now reloads IMAP QUOTA information.
+ 	* Changed prototype of mbx_give_imap_quotar_list()
+ 	* Added quotaroot_list_set_refresh() to  lib/mbox/quota.c
+ 	  and  hdrs/mboxlib.h
+ 
+ 	- Changed cs_streamclip_from_unknown() on lib/cs_unknown.c
+ 	- Possible fix for lookup_static_host_sentry() on lib/static-hosts.c
+ 	- Possible fix for compare_threads_1_revsentd() on src/thread.c
+ 
+ 	New file:
+             lib/mbox/last_read.c
+             lib/addr/file_changes.c
+             doc/elmlastread-info
+ 
+         New elmrc options:
+             use-last-read-file
+             last-read-fallback-locking
+ 
  Changes on Elm ME+ 2.5 PLalpha63 compared with Elm ME+ 2.5 PLalpha62
  --------------------------------------------------------------------
  
          SUMMARY: This release includes tagfilter module for
!                  filtering text/enriched and text/html
                   tags. This release adds "editor-tfent-propline"
                   and "page-tagfilter" elmrc options and
                   new tool "elmtagfilterents". This release
***************
*** 6426,6432 ****
                   crypt() is different for [encode] 
                   (type application/X-ELM-encode). So old
                   messages can not decoded (easily). And format 
!                  does not tell is crypt() used for encryption
                   key. But same difficulty is also between
                   different machines.
          - Used more $rmlist on Configure
--- 6527,6533 ----
                   crypt() is different for [encode] 
                   (type application/X-ELM-encode). So old
                   messages can not decoded (easily). And format 
!                  does not tell if crypt() used for encryption
                   key. But same difficulty is also between
                   different machines.
          - Used more $rmlist on Configure
***************
*** 27214,27220 ****
          subscript           CSI 74 m           CSI 75 m
  
  Tagfilter entities listing
! -------------------------
  
          Files libdir/elm.tagfilter.entities and ~/.elm/.elm/tagfilter.entities
          handles named character references regognized by
--- 27315,27321 ----
          subscript           CSI 74 m           CSI 75 m
  
  Tagfilter entities listing
! --------------------------
  
          Files libdir/elm.tagfilter.entities and ~/.elm/.elm/tagfilter.entities
          handles named character references regognized by
***************
*** 28156,28161 ****
--- 28257,28263 ----
          generate-message-id                     -
          imap-idle-alive-interval                IMAP
          ipv6-scope-id                           SYSTEM
+         last-read-fallback-locking              SYSTEM
          local-lockfile-pidcheck                 -       (also introduced on  
                                                           Elm 2.4ME+ PL126 (25))
          mail-menu-time                          -
***************
*** 28186,28191 ****
--- 28288,28294 ----
          use-char-set-header-field-hack          -
          use-content-type-charset-for-8bit-subject-hack  -
          use-config-library                      -
+         use-last-read-file                      SYSTEM
          use-tls                                 -
          user-conf-rewrite                       -
          user-map-dir                            -
***************
*** 28366,28392 ****
  Options which now takes enumerated values
  -----------------------------------------
  
          auto-attachment         none, application, non-text     
          browser-wildcard-matching     off, on, file browser
          default-folder-status   Read, Old, new
          editor-elmrc-propline   auto, emacs, ignore
          editor-ms-propline      auto, emacs, ignore
          env-from-source         forward-from, from, return-path
          fragment-handling       none, manual, auto
          header-phrase-display-mode    plain, quoted
          local-lockfile-pidcheck no, yes, hostname, ignore-hostname, 
                                  require-hostname
          local-sessionlock-use-home    never, spool, always, non-spool
          message-hide-hack       none, FOLDER INTERNAL DATA
          mime-parameters         plain, encoded, plain-and-encoded
          noencoding              pass-7bit, pass-8bit, pass-binary
          pager-header-display-mode          pain, bold
          pgp-encrypt-type        application/pgp, text/plain, text/x-pgp
          pgp-sign-type           application/pgp, text/plain, text/x-pgp
          pgp-version             default, pgp2, pgp5, gpg
          show-header-errors      OFF, ON, store
          userlevel               beginner, intermediate, expert
! 
  Warnings
  -------- 
  
--- 28469,28508 ----
  Options which now takes enumerated values
  -----------------------------------------
  
+         add-sender              no, yes, auto
+         address-lookup          normal, shared, gethostbyaddr, getnameinfo
          auto-attachment         none, application, non-text     
          browser-wildcard-matching     off, on, file browser
+         convert-cr-to-newline-hack    off, on-with-error, on-silent
          default-folder-status   Read, Old, new
+         editor-al-propline      auto, emacs, ignore
          editor-elmrc-propline   auto, emacs, ignore
          editor-ms-propline      auto, emacs, ignore
+         editor-usermap-propline auto, emacs, ignore
          env-from-source         forward-from, from, return-path
          fragment-handling       none, manual, auto
          header-phrase-display-mode    plain, quoted
          local-lockfile-pidcheck no, yes, hostname, ignore-hostname, 
                                  require-hostname
          local-sessionlock-use-home    never, spool, always, non-spool
+         mail-services-lookup    hostname, shared,  gethostbyname, getaddrinfo
          message-hide-hack       none, FOLDER INTERNAL DATA
          mime-parameters         plain, encoded, plain-and-encoded
+         mimeforward             off, on, auto
+         name-lookup-cancel      disabled, enabled, auto
          noencoding              pass-7bit, pass-8bit, pass-binary
          pager-header-display-mode          pain, bold
+         pager-time-display      legacy, default, ...
+         pagerelated              no, yes, single-part
          pgp-encrypt-type        application/pgp, text/plain, text/x-pgp
          pgp-sign-type           application/pgp, text/plain, text/x-pgp
          pgp-version             default, pgp2, pgp5, gpg
          show-header-errors      OFF, ON, store
+         show-mail-quota         off, on-open
          userlevel               beginner, intermediate, expert
!         verify-domain           no, yes, hostname, shared
!         verify-local-domain     no, yes, if-remote-mailer
!         
  Warnings
  -------- 
  
Index: elmME+.2.5.alpha64-cvs/MANIFEST
*** elmME+.2.5.alpha63/MANIFEST	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/MANIFEST	Mon Jun 10 21:05:33 2024
***************
*** 713,715 ****
--- 713,718 ----
  melib/tagfilter_html.c
  hdrs/pg_params_imp.h
  lib/string_alt.c
+ lib/mbox/last_read.c
+ lib/addr/file_changes.c
+ doc/elmlastread-info
Index: elmME+.2.5.alpha64-cvs/doc/Makefile.SH
*** elmME+.2.5.alpha63/doc/Makefile.SH	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/doc/Makefile.SH	Mon Jun 10 21:05:34 2024
***************
*** 37,43 ****
  cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.26 2023/12/13 16:55:32 hurtta Exp $
  #
  # Modified by Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
  #	       	      (was hurtta+elm@posti.FMI.FI)
--- 37,43 ----
  cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.27 2024/06/10 18:05:34 hurtta Exp $
  #
  # Modified by Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
  #	       	      (was hurtta+elm@posti.FMI.FI)
***************
*** 221,227 ****
    $(LIB)/elmterminalinfo-info $(LIB)/elmmimecharsets-info \
    $(LIB)/elmmailinglists-info $(LIB)/elmmailservices-info \
    $(LIB)/elmiso2022sets-info $(LIB)/elmhashmarks-info \
!   $(LIB)/elmtagfilent-info
  
  # List of files installed in LIB directory
  
--- 221,227 ----
    $(LIB)/elmterminalinfo-info $(LIB)/elmmimecharsets-info \
    $(LIB)/elmmailinglists-info $(LIB)/elmmailservices-info \
    $(LIB)/elmiso2022sets-info $(LIB)/elmhashmarks-info \
!   $(LIB)/elmtagfilent-info  $(LIB)/elmlastread-info
  
  # List of files installed in LIB directory
  
***************
*** 543,548 ****
--- 543,553 ----
  $(LIB)/elmtagfilent-info:	elmtagfilent-info
  				$(REG) copy -m 444 $? $@
  
+ $(LIB)/elmlastread-info:	elmlastread-info
+ 				$(REG) copy -m 444 $? $@
+ 
+ 
+ 
  info-list: $(INFO_LIST)
  
  #	Dependencies and rules for installing catman
Index: elmME+.2.5.alpha64-cvs/doc/elmlastread-info
*** /tmp/5689-very-long-file-name/NULL-5689-comes-in-here--XXXXXXXXX	Sat Jun 29 18:42:35 2024
--- elmME+.2.5.alpha64-cvs/doc/elmlastread-info	Tue Jun 11 19:13:17 2024
***************
*** 0 ****
--- 1,17 ----
+ # This file stores read time for folder/mailbox files if reading
+ # does not update access time of folder/mailbox files.
+ #
+ # Relative names refers folder/mailbox files on same directory than
+ # this file. It is used when this is .elm-last-read-{uid} file
+ # on same directory than folder/mailbox files.
+ #
+ # Absolute names refer folder/mailbox files on other directory
+ # than where this file is. It is used when this file is
+ # user's ~/.elm/last.read file and is used for last read time
+ # for maildir directory (incoming mailboxes).
+ #
+ # Access time or last read time is used for folder browser
+ # to show N letter for folder/mailbox files which have unread
+ # mails.
+ #
+ # This file usage is controlled by  "use-last-read-file" elmrc option.
\ No newline at end of file
Index: elmME+.2.5.alpha64-cvs/doc/elmrc-info
*** elmME+.2.5.alpha63/doc/elmrc-info	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/doc/elmrc-info	Mon Jun 10 21:05:34 2024
***************
*** 1,4 ****
! #@(#)$Id: elmrc-info,v 2.91 2023/12/13 16:55:32 hurtta Exp $
  # Elm Version ME+ 2.5
  #
  #$HDR - magic line to mark comments to put at top of user's elmrc file.
--- 1,4 ----
! #@(#)$Id: elmrc-info,v 2.92 2024/06/10 18:05:34 hurtta Exp $
  # Elm Version ME+ 2.5
  #
  #$HDR - magic line to mark comments to put at top of user's elmrc file.
***************
*** 1382,1387 ****
--- 1382,1420 ----
  #
  # See also: extra-mailbox-dir, mailbox-locking
  
+ last-read-fallback-locking
+ # What locking to use for .elm-last-read-{uid} file when
+ # use-last-read enables it.
+ #
+ # ~/.elm/last.read file uses conf-merge-locking
+ #
+ #  .elm-last-read-{uid} file uses either
+ #  			folder-locking,
+ #			mailbox-locking, or
+ #                  this last-read-fallback-locking
+ #
+ # This option includes list of keywords:
+ #       flock                  Use flock() locking. 
+ #                              flock() does not lock files over NFS
+ #       fcntl                  Use fcntl() locking. 
+ #       prefer                 Prefer this option
+ #			       instead of folder-locking or
+ #			       mailbox-locking
+ #
+ # If value is "none" or "prefer" alone, then locking is disabled.
+ #
+ # This option accepts two forms:
+ #    - Absolute form where used options are listed
+ #    - Additive form where changes from compile
+ #      time default (or changes from global elm.rc) 
+ #      are listed:
+ #               +flock          -flock
+ #               +fcntl          -fcntl
+ #		+prefer		-prefer
+ #
+ #  See also: mailbox-locking, folder-locking, use-last-read-file,
+ #            extra-mailbox-dir
+ 
  local-dir-sortby
  # How to sort local files and folders on folder and file browser?
  # Possible values: none
***************
*** 1578,1583 ****
--- 1611,1636 ----
  #
  # See also: sortby, thread-sortby
  
+ use-last-read-file
+ # This option controls use of per directory .elm-last-read-{uid}
+ # file and use of user's ~/.elm/last.read file.
+ #
+ # A last read stores read time for folder/mailbox files if reading
+ # does not update access time of folder/mailbox files.
+ #
+ #	  Values are:
+ #	  	 no			Do not read or update
+ #		 			.elm-last-read-{uid} file
+ #	  	 yes			Create, use and update
+ #		 			.elm-last-read-{uid} file
+ #	  	 auto			Use and update existing
+ #		 			.elm-last-read-{uid} file.
+ #					Create file if access
+ #					time is not updated.
+ #	  	 existing		Use and update existing
+ #		 			.elm-last-read-{uid} file
+ # See also: last-read-fallback-locking
+ 
  $usersection
  #-----------------------------------------------------------------------
  #
Index: elmME+.2.5.alpha64-cvs/doc/elmrc.samp
*** elmME+.2.5.alpha63/doc/elmrc.samp	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/doc/elmrc.samp	Sat Jun 29 11:16:36 2024
***************
*** 3,9 ****
  #
  # Character set used on this file
  @charset = UTF-8
! # Saved automatically by ELM ME+ 2.5 PLalpha63 for Kari Hurtta
  #
  
  #
--- 3,9 ----
  #
  # Character set used on this file
  @charset = UTF-8
! # Saved automatically by ELM ME+ 2.5 PLalpha64 for Kari Hurtta
  #
  
  #
***************
*** 1365,1370 ****
--- 1365,1403 ----
  # See also: extra-mailbox-dir, mailbox-locking
  ### incomingfolders = 
  
+ # What locking to use for .elm-last-read-{uid} file when
+ # use-last-read enables it.
+ #
+ # ~/.elm/last.read file uses conf-merge-locking
+ #
+ #  .elm-last-read-{uid} file uses either
+ #  			folder-locking,
+ #			mailbox-locking, or
+ #                  this last-read-fallback-locking
+ #
+ # This option includes list of keywords:
+ #       flock                  Use flock() locking. 
+ #                              flock() does not lock files over NFS
+ #       fcntl                  Use fcntl() locking. 
+ #       prefer                 Prefer this option
+ #			       instead of folder-locking or
+ #			       mailbox-locking
+ #
+ # If value is "none" or "prefer" alone, then locking is disabled.
+ #
+ # This option accepts two forms:
+ #    - Absolute form where used options are listed
+ #    - Additive form where changes from compile
+ #      time default (or changes from global elm.rc) 
+ #      are listed:
+ #               +flock          -flock
+ #               +fcntl          -fcntl
+ #		+prefer		-prefer
+ #
+ #  See also: mailbox-locking, folder-locking, use-last-read-file,
+ #            extra-mailbox-dir
+ ### last-read-fallback-locking = flock fcntl
+ 
  # How to sort local files and folders on folder and file browser?
  # Possible values: none
  #                  name, reverse-name
***************
*** 1492,1497 ****
--- 1525,1550 ----
  # See also: sortby, thread-sortby
  ### unstable-reverse-thread = OFF
  
+ # This option controls use of per directory .elm-last-read-{uid}
+ # file and use of user's ~/.elm/last.read file.
+ #
+ # A last read stores read time for folder/mailbox files if reading
+ # does not update access time of folder/mailbox files.
+ #
+ #	  Values are:
+ #	  	 no			Do not read or update
+ #		 			.elm-last-read-{uid} file
+ #	  	 yes			Create, use and update
+ #		 			.elm-last-read-{uid} file
+ #	  	 auto			Use and update existing
+ #		 			.elm-last-read-{uid} file.
+ #					Create file if access
+ #					time is not updated.
+ #	  	 existing		Use and update existing
+ #		 			.elm-last-read-{uid} file
+ # See also: last-read-fallback-locking
+ ### use-last-read-file = auto
+ 
  #-----------------------------------------------------------------------
  #
  # Section 9:  MIME and Character Set Options
Index: elmME+.2.5.alpha64-cvs/hdrs/addrlib.h
*** elmME+.2.5.alpha63/hdrs/addrlib.h	Fri Sep  2 20:38:19 2022
--- elmME+.2.5.alpha64-cvs/hdrs/addrlib.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* $Id: addrlib.h,v 2.41 2022/08/06 08:01:51 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.41 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: addrlib.h,v 2.42 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.42 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 13,18 ****
--- 13,19 ----
  #define E_(x)
  #endif
  
+ 
  /* init.c */
  
  extern void init_addrlib P_((int read_flags /* READ_FLAG_IGNORE_MISSING */));
***************
*** 952,957 ****
--- 953,999 ----
  extern       struct digest_proc      * digest_proc_md5 P_((void));
  
  
+ /* file_changes.c ----------------------------------------------------- */
+ 
+ #define FILE_CHANGES_magic	0xF612
+ 
+ extern const struct file_changes {
+     unsigned short magic;     /* FILE_CHANGES_magic */
+ 
+     size_t    self_size;      /* Size of struct file_changes */
+     
+     /* copy some stat information */
+         
+     dev_t     dev;	   /* ID of device containing file */
+     ino_t     ino;         /* inode number */
+     off_t     size;        /* total size, in bytes */
+     time_t    mtime;	   /* time of last modification */
+     
+     unsigned int valid:1;
+ } NULL_file_changes;
+ 
+ #define FILE_CHANGES_INIT     {			\
+ 	    FILE_CHANGES_magic,			\
+ 	    sizeof (struct file_changes),	\
+ 	    0,					\
+ 	    0,					\
+ 	    0,					\
+ 	    0,					\
+ 						\
+ 	    0  /* No valid information */	\
+  }
+ 
+ 
+ extern enum file_changes_result {
+     file_changes_error = -1,
+ 	no_file_changes    = 0,
+ 	have_file_changes } test_file_changes P_((const char *filename,
+ 						  const struct file_changes *old_file,
+ 						  int *errno_res));
+ 
+ extern void stat_to_file_changes P_((const struct stat *st,
+ 				     struct file_changes *file_information));
+ 
  
  /*
   * Local Variables:
Index: elmME+.2.5.alpha64-cvs/hdrs/aliaslib.h
*** elmME+.2.5.alpha63/hdrs/aliaslib.h	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/hdrs/aliaslib.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* $Id: aliaslib.h,v 2.12 2021/07/14 07:19:22 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.12 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: aliaslib.h,v 2.13 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.13 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 12,55 ****
  struct address_alias;
  #endif
  
- /* file chnage information ------------------------------------------------- */
- 
- #define FILE_CHANGES_magic	0xF612
- 
- extern const struct file_changes {
-     unsigned short magic;     /* FILE_CHANGES_magic */
- 
-     size_t    self_size;      /* Size of struct file_changes */
-     
-     /* copy some stat information */
-         
-     dev_t     dev;	   /* ID of device containing file */
-     ino_t     ino;         /* inode number */
-     off_t     size;        /* total size, in bytes */
-     time_t    mtime;	   /* time of last modification */
-     
-     unsigned int valid:1;
- } NULL_file_changes;
- 
- #define FILE_CHANGES_INIT     {			\
- 	    FILE_CHANGES_magic,			\
- 	    sizeof (struct file_changes),	\
- 	    0,					\
- 	    0,					\
- 	    0,					\
- 	    0,					\
- 						\
- 	    0  /* No valid information */	\
-  }
- 
- 
- extern enum file_changes_result {
-     file_changes_error = -1,
- 	no_file_changes    = 0,
- 	have_file_changes } test_file_changes P_((const char *filename,
- 						  const struct file_changes *old_file,
- 						  int *errno_res));
- 
  /* ------------------------------------------------------------------------- */
  
  /* init.c */
--- 12,17 ----
Index: elmME+.2.5.alpha64-cvs/hdrs/elmlib.h
*** elmME+.2.5.alpha63/hdrs/elmlib.h	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/hdrs/elmlib.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* $Id: elmlib.h,v 2.175 2023/12/13 16:55:32 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.175 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! /* $Id: elmlib.h,v 2.176 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.176 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 482,487 ****
--- 482,489 ----
      struct thread_name      * thread_name;
      struct entity_sort_item * entity;
      struct tagfilter_cmd    * tf_cmd;
+     struct last_read_cache  * last_read_cache;
+     struct last_read_entry  * last_read_entry;
  };
  
  union sort_key {
***************
*** 496,501 ****
--- 498,505 ----
      const struct uidl_entry_def   * uidl;
      const struct aliases_node_def * aliases;
      const struct tf_cmd_def       * tf_cmd;
+     const struct last_read_cache_def * last_read_cache;
+     const struct last_read_entry_def * last_read_entry;
  };
  
  typedef void alloc_sort_item_f P_((union sort_item             * res,
***************
*** 1350,1355 ****
--- 1354,1362 ----
  extern char user_hash_marks[SLEN];    /* .elm/hash.marks         */
  extern char user_tagfilter_entfile[SLEN]; /* .elm/tagfilter.entities */ 
  
+ extern char user_last_read_def[SLEN]; /* .elm/last.read    */
+ extern char user_last_read_dot[SLEN]; /* .elm-last-read-{uid}  */
+ 
  extern ESTR calendar_file_e;	/* name of file for clndr       */
  
  #define defaultfile_KW_MAIL        0x0001
***************
*** 1552,1557 ****
--- 1559,1565 ----
      lock_lockfile_flag,                    /* not used on folder locking */
      lock_flock_flag,
      lock_fcntl_flag,
+     lock_prefer_flag,                      /* Not used for locking       */
      NUM_mailbox_locking_v
  };
  extern FLAGS folder_locking;
Index: elmME+.2.5.alpha64-cvs/hdrs/mboxlib.h
*** elmME+.2.5.alpha63/hdrs/mboxlib.h	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/hdrs/mboxlib.h	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! /* $Id: mboxlib.h,v 2.45 2021/07/13 07:58:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.45 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: mboxlib.h,v 2.48 2024/06/23 07:38:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.48 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 17,26 ****
--- 17,35 ----
  
  /* init.c ------------------------------------------------------------------ */
  
+ enum use_lastread_v {
+     use_lastread_no,
+     use_lastread_yes,
+     use_lastread_auto,
+     use_lastread_existing,
+     NUM_use_lastread
+ };
+ 
  extern ENUMERATE editor_hm_propline;
  #if USERMAP_PROPLINE
  extern ENUMERATE editor_usermap_propline;
  #endif
+ extern ENUMERATE use_last_read_file;
  extern ESTR      user_map_dir_e;
  
  extern charset_t                   system_hash_marks_cs;
***************
*** 304,309 ****
--- 313,322 ----
  					    READ_STATE read_state_ptr));
  extern long copy_fbytes_folder P_((struct folder_info *folder,
  				   READ_STATE read_state_ptr));
+ 
+ /* -1 if not available (local mail) */
+ extern int copy_num_messages_folder P_((struct folder_info *folder));
+ 
  extern int copy_lines_folder P_((struct folder_info *folder,
  				   READ_STATE read_state_ptr));
  extern void copy_skipcount_folder P_((struct folder_info *folder,
***************
*** 421,432 ****
                                                P_((struct folder_info *folder));
   
  /* Increments refcount */
  extern struct mail_quotaroot_list * give_folder_quotaroot_l
                                             P_((struct folder_info *folder,
  					       struct cancel_data  * cd
  					       /* Allow cancelation (Ctrl-C)
! 						  on remote mailbox
! 					       */));
  
  /* Increments refcount */
  extern struct mail_quota * have_folder_quota P_((struct folder_info *folder));
--- 434,451 ----
                                                P_((struct folder_info *folder));
   
  /* Increments refcount */
+ 
+ enum quota_mode { quotam_normal = 0,
+ 		  quotam_refresh };
+ 
  extern struct mail_quotaroot_list * give_folder_quotaroot_l
                                             P_((struct folder_info *folder,
  					       struct cancel_data  * cd
  					       /* Allow cancelation (Ctrl-C)
! 						  on remote mailbox.
! 					       */,
! 					       enum quota_mode refresh
! 					       ));
  
  /* Increments refcount */
  extern struct mail_quota * have_folder_quota P_((struct folder_info *folder));
***************
*** 509,514 ****
--- 528,535 ----
  				  size_t idx,
  				  struct cancel_data  * cd
  				  ));
+ extern void quotaroot_list_set_refresh P_((struct mail_quotaroot_list *quota_list,
+ 					   enum quota_mode refresh));
  
  /* Increments refcount 
     Returns NULL if  associated struct mail_quota is deallocated */
Index: elmME+.2.5.alpha64-cvs/hdrs/mbx_imp.h
*** elmME+.2.5.alpha63/hdrs/mbx_imp.h	Thu May 26 11:16:29 2022
--- elmME+.2.5.alpha64-cvs/hdrs/mbx_imp.h	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! /* $Id: mbx_imp.h,v 2.34 2022/02/12 14:00:06 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.34 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! /* $Id: mbx_imp.h,v 2.37 2024/06/23 07:38:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.37 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 170,181 ****
  typedef struct mail_quotaroot_list * mbx_give_folder_quotar_list
      P_((struct folder_info * folder,
  	struct mail_quota  * mq,
! 	struct cancel_data * cd /* Allow cancelation (Ctrl-C) on remote mailbox */));
  
  typedef int mbx_give_message_msize_folder P_((struct folder_info * folder,
  					      struct header_rec  * entry,
  					      unsigned long      * ret_size));
  
  #define FOLDER_TYPE_magic	0xFA01
  
  struct folder_type {
--- 170,185 ----
  typedef struct mail_quotaroot_list * mbx_give_folder_quotar_list
      P_((struct folder_info * folder,
  	struct mail_quota  * mq,
! 	struct cancel_data * cd /* Allow cancelation (Ctrl-C) on remote mailbox */,
! 	enum quota_mode      refresh));
  
  typedef int mbx_give_message_msize_folder P_((struct folder_info * folder,
  					      struct header_rec  * entry,
  					      unsigned long      * ret_size));
  
+ /* Return -1 if not available (local mail) */
+ typedef int mbx_give_message_count_folder P_((struct folder_info * folder));
+ 
  #define FOLDER_TYPE_magic	0xFA01
  
  struct folder_type {
***************
*** 217,222 ****
--- 221,227 ----
      mbx_have_folder_quota        * have_it_quota;
      mbx_give_folder_quotar_list  * mbx_give_it_quotar_list;
      mbx_give_message_msize_folder * mbx_give_message_msize_it;
+     mbx_give_message_count_folder * mbx_give_message_count_it;
  };
  
  extern int mbx_copy_line_to_temp P_((struct folder_info *folder,
***************
*** 322,338 ****
  
  #define PRIVATE_DATA_magic	0xFA03
  
  extern struct private_data {
      unsigned short magic;           /* PRIVATE_DATA_magic */
  
      FILE *fh_temp;		   /* current folder 	     */
      FILE *fh_folder;               /* current folder 	     */
  
- #define FLAG1_CHECKNEW            0x01
-     int   flags1;                  /* Set by sessionlock_folder() */
  
      struct dt_flags_info  * lock_info;
  
      union {
  	int dummy;
  	struct SPOOL {
--- 327,359 ----
  
  #define PRIVATE_DATA_magic	0xFA03
  
+ enum FLAG1_bits {
+     FLAG1_bit_CHECKNEW = 0,
+     FLAG1_bit_have_ostat,
+ 
+     FLAG1_bit_count
+ };
+ 
+ #define FLAG1_CHECKNEW		(1 << FLAG1_bit_CHECKNEW)
+ #define FLAG1_have_ostat	(1 << FLAG1_bit_have_ostat)
+     
  extern struct private_data {
      unsigned short magic;           /* PRIVATE_DATA_magic */
  
      FILE *fh_temp;		   /* current folder 	     */
      FILE *fh_folder;               /* current folder 	     */
  
  
+     unsigned   flags1 :  FLAG1_bit_count;                 /* Set by sessionlock_folder() */
+ 
+     /* Only used for local folder / mailbox */
+     struct stat        ostat; 
+ 
+     
      struct dt_flags_info  * lock_info;
  
+ 
+     
      union {
  	int dummy;
  	struct SPOOL {
Index: elmME+.2.5.alpha64-cvs/hdrs/mbximap_imp.h
*** elmME+.2.5.alpha63/hdrs/mbximap_imp.h	Sat Jan 18 22:07:40 2020
--- elmME+.2.5.alpha64-cvs/hdrs/mbximap_imp.h	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! /* $Id: mbximap_imp.h,v 2.7 2020/01/18 20:07:40 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.7 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                  (was hurtta+elm@posti.FMI.FI)  
--- 1,7 ----
! /* $Id: mbximap_imp.h,v 2.9 2024/06/23 07:38:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.9 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                  (was hurtta+elm@posti.FMI.FI)  
***************
*** 12,25 ****
  
  /* capability_bits */
  
! #define CAPA_IMAP4rev1           1
! #define CAPA_UNSELECT            2
! #define CAPA_QUOTA		 4
  
  
  struct IMAP_CON {
  	    
!     long                     capability_bits;
  #ifdef USE_DLOPEN
      struct IMAP_capa_libs   *capability_libs;
      int                      capability_lib_count;
--- 12,32 ----
  
  /* capability_bits */
  
! enum CAPA_bits {
!     CAPA_bit_IMAP4rev1 = 0,
!     CAPA_bit_UNSELECT,
!     CAPA_bit_QUOTA,	       
  
+     NUM_CAPA_bits
+ };
+ 
+ #define CAPA_IMAP4rev1       (1 << CAPA_bit_IMAP4rev1)
+ #define CAPA_UNSELECT        (1 << CAPA_bit_UNSELECT)
+ #define CAPA_QUOTA	     (1 << CAPA_bit_QUOTA)
  
  struct IMAP_CON {
  	    
!     unsigned int             capability_bits : NUM_CAPA_bits;
  #ifdef USE_DLOPEN
      struct IMAP_capa_libs   *capability_libs;
      int                      capability_lib_count;
***************
*** 191,197 ****
  E_(mbx_give_folder_quotar_list mbx_give_imap_quotar_list)
  extern struct mail_quotaroot_list * mbx_give_imap_quotar_list P_((struct folder_info * folder,
  								  struct mail_quota  * mq,
! 		    struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */));
  
  
  /*
--- 198,206 ----
  E_(mbx_give_folder_quotar_list mbx_give_imap_quotar_list)
  extern struct mail_quotaroot_list * mbx_give_imap_quotar_list P_((struct folder_info * folder,
  								  struct mail_quota  * mq,
! 		  struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */,
! 								  enum quota_mode      refresh
! 								  ));
  
  
  /*
Index: elmME+.2.5.alpha64-cvs/hdrs/mbxlocal_imp.h
*** elmME+.2.5.alpha63/hdrs/mbxlocal_imp.h	Wed May  3 22:34:21 2017
--- elmME+.2.5.alpha64-cvs/hdrs/mbxlocal_imp.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* $Id: mbxlocal_imp.h,v 2.9 2017/05/03 19:34:21 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.9 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: mbxlocal_imp.h,v 2.10 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.10 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 65,72 ****
  				   char **refname, int *iscopy,
  				   int is_text));
  
! 
! extern int local_stat_flags P_((const char * pathname,struct stat * buf));
  
  
  /*
--- 65,74 ----
  				   char **refname, int *iscopy,
  				   int is_text));
  
! extern int local_stat_flags P_((const char * pathname,struct stat * buf	,			
! 				/* upgrade_last_read() is assumed to be called */
! 				struct last_read_cache * this_last_read
! 				));
  
  
  /*
Index: elmME+.2.5.alpha64-cvs/hdrs/quota_imp.h
*** elmME+.2.5.alpha63/hdrs/quota_imp.h	Sat Jan 18 22:07:40 2020
--- elmME+.2.5.alpha64-cvs/hdrs/quota_imp.h	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! /* $Id: quota_imp.h,v 2.1 2020/01/18 20:07:40 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.1 $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *       or Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: quota_imp.h,v 2.2 2024/06/23 07:38:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.2 $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *       or Kari Hurtta <elm@elmme-mailer.org>
***************
*** 30,35 ****
--- 30,39 ----
  							    struct cancel_data  * cd
  							    ));
  
+ typedef void mq_quotarootl_refresh  P_((struct mail_quota *mq,
+ 					struct mail_quotaroot_list *mqrl,
+ 					enum quota_mode refresh));
+ 
  typedef void mq_init_mail_quotaroot P_((struct mail_quota *mq,
  					struct mail_quotaroot *mqr));
  typedef void mq_disc_mail_quotaroot P_((struct mail_quota *mq,
***************
*** 81,86 ****
--- 85,91 ----
  
      mq_quotarootl_list_len  * mq_listlen_mqrl_it;
      mq_quotarootl_list_item * mq_listitem_mqrl_it;
+     mq_quotarootl_refresh   * mq_refresh_mqrl_it;
  
      /* struct mail_quotaroot */
  
***************
*** 149,155 ****
  	void              * dummy;
  	struct mqrl_imap  * imap;
      } p;
!         
  } * malloc_mail_quotaroot_list P_((struct mail_quota *mail_quota));
  
  #define MAIL_QUOTAROOT_magic	0xF52D
--- 154,160 ----
  	void              * dummy;
  	struct mqrl_imap  * imap;
      } p;
!     
  } * malloc_mail_quotaroot_list P_((struct mail_quota *mail_quota));
  
  #define MAIL_QUOTAROOT_magic	0xF52D
Index: elmME+.2.5.alpha64-cvs/hdrs/rc_imp.h
*** elmME+.2.5.alpha63/hdrs/rc_imp.h	Fri Dec 21 13:21:42 2018
--- elmME+.2.5.alpha64-cvs/hdrs/rc_imp.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* $Id: rc_imp.h,v 2.25 2018/12/21 11:21:42 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.25 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! /* $Id: rc_imp.h,v 2.26 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.26 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 270,275 ****
--- 270,277 ----
  				 enum rec_line_mode line_mode,
  				 int read_flags /* READ_FLAG_IGNORE_MISSING */));
  
+ /* exported for lib/mbox/init.c */
+ extern char * MAILBOX_LOCKING[NUM_mailbox_locking_v+1];
  
  /* rc_handle.c */
  
Index: elmME+.2.5.alpha64-cvs/hdrs/s_me.h
*** elmME+.2.5.alpha63/hdrs/s_me.h	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/hdrs/s_me.h	Mon Jun 10 21:05:34 2024
***************
*** 1047,1049 ****
--- 1047,1060 ----
  #define MeTagFUnsupTagsFilterList	0x45f
  #define MeTagFilteredTags	0x460
  #define MeUnknownTerminalAttribute	0x461
+ #define MeFolderStatError	0x462
+ #define MeLastReadWaitingFail	0x463
+ #define MeLastReadWaitingOK	0x464
+ #define MeLastReadWaiting	0x465
+ #define MeLastReadWaitingError	0x466
+ #define MeLastReadWriteTempFail	0x467
+ #define MeLastReadCreatTempFail	0x468
+ #define MeLastReadCheckTempFail	0x469
+ #define MeLastReadRenameFail	0x46a
+ #define MeDefaultLastReadW	0x474
+ #define MeSavedAutoWrite2	0x475
Index: elmME+.2.5.alpha64-cvs/hdrs/save_opts.h
*** elmME+.2.5.alpha63/hdrs/save_opts.h	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/hdrs/save_opts.h	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! /* @(#)$Id: save_opts.h,v 2.69 2023/12/13 16:55:32 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.69 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! /* @(#)$Id: save_opts.h,v 2.71 2024/06/10 18:05:34 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.71 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 554,559 ****
--- 554,561 ----
      {"keepempty",		ZZZ_DT_BOL(&keep_empty_files),          ZZZ_TAIL },
      {"keeppassfor",             ZZZ_DT_NUM(&pgp_keeppassfor), 0,        TAILCOND_INT(&use_PGP) },
      {"keypad",	                ZZZ_DT_OBS0,                            ZZZ_TAIL },
+     
+     {"last-read-fallback-locking",       ZZZ_DT_DELAY,                  ZZZ_TAIL }, 
      {"local-dir-sortby",        ZZZ_DT_SORT(&local_dir_sortby),         ZZZ_TAIL },
      {"local-fast-lookup",       ZZZ_DT_BOL(&local_fast_lookup),         ZZZ_TAIL },
      {"local-fs-charset",        ZZZ_DT_STR(raw_local_fs_charset), 
***************
*** 575,580 ****
--- 577,583 ----
      {"lock-in-copy",            ZZZ_DT_BOL(&lock_in_copy),              ZZZ_TAIL },
  #endif
      {"long-encoded-headers",    ZZZ_DT_BOL(&long_encoded_headers),      ZZZ_TAIL },
+     
      {"mail-menu-time",          ZZZ_DT_FLAGS(&mail_menu_time),          ZZZ_TAIL },
      {"mail-services-lookup",    ZZZ_DT_ENUM_(FL_SHOWSYS,
  					     &mail_services_lookup),    ZZZ_TAIL },
***************
*** 724,729 ****
--- 727,733 ----
      {"use-connect-library",     ZZZ_DT_SHARED(&use_shared_connect), 	ZZZ_TAIL },
  #endif
      {"use-content-type-charset-for-8bit-subject-hack", ZZZ_DT_BOL(&use_ct_cs_for_subj_hack), ZZZ_TAIL },
+     {"use-last-read-file",       ZZZ_DT_DELAY,                          ZZZ_TAIL }, 
  #ifdef USE_DLOPEN
      {"use-library",             ZZZ_DT_SHARED(&use_shared_all), 	ZZZ_TAIL }, 
      {"use-mailer-library",      ZZZ_DT_DELAYSHARED, 			ZZZ_TAIL },
***************
*** 737,743 ****
      {"usetite",		        ZZZ_DT_BOL_(FL_AND,&use_tite), 		ZZZ_TAIL },
      {"utf7-encode-optional",    ZZZ_DT_BOL(&utf7_encode_optional), 	ZZZ_TAIL },
      {"valid-domains",           ZZZ_DT_DELAY, 				ZZZ_TAIL },
!     {"valid-msg-id-domains",     ZZZ_DT_DELAY, 				ZZZ_TAIL },
      {"verify-alias-domain",     ZZZ_DT_BOL(&verify_alias_domain), 	ZZZ_TAIL },
      {"verify-domain",           ZZZ_DT_ENUM(&verify_domain), 		ZZZ_TAIL },
      {"verify-local-address",    ZZZ_DT_BOL(&verify_local_address), 	ZZZ_TAIL },
--- 741,747 ----
      {"usetite",		        ZZZ_DT_BOL_(FL_AND,&use_tite), 		ZZZ_TAIL },
      {"utf7-encode-optional",    ZZZ_DT_BOL(&utf7_encode_optional), 	ZZZ_TAIL },
      {"valid-domains",           ZZZ_DT_DELAY, 				ZZZ_TAIL },
!     {"valid-msg-id-domains",    ZZZ_DT_DELAY, 				ZZZ_TAIL },
      {"verify-alias-domain",     ZZZ_DT_BOL(&verify_alias_domain), 	ZZZ_TAIL },
      {"verify-domain",           ZZZ_DT_ENUM(&verify_domain), 		ZZZ_TAIL },
      {"verify-local-address",    ZZZ_DT_BOL(&verify_local_address), 	ZZZ_TAIL },
Index: elmME+.2.5.alpha64-cvs/hdrs/sysdefs.SH
*** elmME+.2.5.alpha63/hdrs/sysdefs.SH	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/hdrs/sysdefs.SH	Mon Jun 10 21:05:34 2024
***************
*** 39,48 ****
  
  echo "Extracting hdrs/sysdefs.h (with variable substitutions)"
  sed <<!GROK!THIS! >sysdefs.h -e 's!^#undef!/\*#undef!'
! /* $Id: sysdefs.SH,v 2.17 2023/12/13 16:55:32 hurtta Exp $ */
  
  /*****************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.17 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
--- 39,48 ----
  
  echo "Extracting hdrs/sysdefs.h (with variable substitutions)"
  sed <<!GROK!THIS! >sysdefs.h -e 's!^#undef!/\*#undef!'
! /* $Id: sysdefs.SH,v 2.18 2024/06/10 18:05:34 hurtta Exp $ */
  
  /*****************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.18 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
***************
*** 101,107 ****
  #define USER_MAIL_SERVICES      ".elm/mail.services"
  #define USER_MLIST_FILE         ".elm/mailing.lists"
  #define USER_HASHMARK_FILE      ".elm/hash.marks"
! #define USER_TAGFILTER_ENTFILE  ".elm/tagfilter.entities"    
  
  #define HOSTDOMFILE             "$etc/domain"
  
--- 101,108 ----
  #define USER_MAIL_SERVICES      ".elm/mail.services"
  #define USER_MLIST_FILE         ".elm/mailing.lists"
  #define USER_HASHMARK_FILE      ".elm/hash.marks"
! #define USER_TAGFILTER_ENTFILE  ".elm/tagfilter.entities"
! #define USER_LAST_READ          ".elm/last.read"
  
  #define HOSTDOMFILE             "$etc/domain"
  
***************
*** 145,151 ****
  #define ELMISO2022SETS_INFO   "$lib/elmiso2022sets-info"
  #define ELMHASHMARKS_INFO     "$lib/elmhashmarks-info"
  #define ELMTAGFILENT_INFO     "$lib/elmtagfilent-info"
!     
      
  #define VERSIONTAG            "$d_sharedtag"
  #ifdef SHARED_LIBS
--- 146,152 ----
  #define ELMISO2022SETS_INFO   "$lib/elmiso2022sets-info"
  #define ELMHASHMARKS_INFO     "$lib/elmhashmarks-info"
  #define ELMTAGFILENT_INFO     "$lib/elmtagfilent-info"
! #define ELMLASTREAD_INFO      "$lib/elmlastread-info"
      
  #define VERSIONTAG            "$d_sharedtag"
  #ifdef SHARED_LIBS
Index: elmME+.2.5.alpha64-cvs/lib/MAGIC
*** elmME+.2.5.alpha63/lib/MAGIC	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/MAGIC	Mon Jun 10 21:05:34 2024
***************
*** 219,224 ****
--- 219,229 ----
  #define CPPREV_RS_magic		0xFA07
  #define UIDL_ENTRY_magic	0xFA08
  #define UIDL_ENTRY_DEF_magic	0xFA09
+ #define LAST_READ_CACHE_magic	0xFA0A
+ #define LAST_READ_ENTRY_magic	0xFA0B
+ #define LAST_READ_CACHE_DEF_magic	0xFA0C
+ #define LAST_READ_ENTRY_DEF_magic	0xFA0D
+ #define LAST_READ_OPEN_magic 	0xFA0E
  #define UNIDATA_magic           0xFB00
  #define BINDATA_magic           0xFB01
  #define UNIDATA21_magic         0xFB02
Index: elmME+.2.5.alpha64-cvs/lib/addr/Makefile.SH
*** elmME+.2.5.alpha63/lib/addr/Makefile.SH	Tue May 12 21:18:18 2020
--- elmME+.2.5.alpha64-cvs/lib/addr/Makefile.SH	Mon Jun 10 21:05:34 2024
***************
*** 31,37 ****
  $cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.16 2020/05/12 18:18:18 hurtta Exp $
  #
  #  Makefile for the ELM (ME+) mail program.
  #
--- 31,37 ----
  $cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.17 2024/06/10 18:05:34 hurtta Exp $
  #
  #  Makefile for the ELM (ME+) mail program.
  #
***************
*** 91,97 ****
   dispaddr.o mailer.o headers.o outheaders.o write_hdr.o okay_addr.o \
   error.o parsestring.o getid.o message-id.o references.o outexpires.o \
   date.o parsarpdat.o getword.o split_addr.o duplicate.o md5c.o md5_wrapper.o \
!  digest.o outdate.o
  
  all:	Makefile ../../libs/libelmme-addr.a $(SOTARG)
  install_s: all $(INSTLIB)
--- 91,97 ----
   dispaddr.o mailer.o headers.o outheaders.o write_hdr.o okay_addr.o \
   error.o parsestring.o getid.o message-id.o references.o outexpires.o \
   date.o parsarpdat.o getword.o split_addr.o duplicate.o md5c.o md5_wrapper.o \
!  digest.o outdate.o file_changes.o
  
  all:	Makefile ../../libs/libelmme-addr.a $(SOTARG)
  install_s: all $(INSTLIB)
***************
*** 134,139 ****
--- 134,140 ----
  digest.o:    def_addr.h
  duplicate.o: def_addr.h 
  get_addr.o:  def_addr.h 
+ file_changes.o: def_addr.h
  mlist.o:     def_addr.h $(INCLDIR)/mlist_imp.h $(INCLDIR)/mlist_common.h
  md5c.o:		def_addr.h md5_global.h md5.h
  md5_wrapper.o:	def_addr.h md5_global.h md5.h $(INCLDIR)/digest_imp.h
Index: elmME+.2.5.alpha64-cvs/lib/addr/file_changes.c
*** /tmp/5689-very-long-file-name/NULL-5689-comes-in-here--XXXXXXXXX	Sat Jun 29 18:42:35 2024
--- elmME+.2.5.alpha64-cvs/lib/addr/file_changes.c	Mon Jun 10 21:05:34 2024
***************
*** 0 ****
--- 1,155 ----
+ static char rcsid[] = "@(#)$Id: file_changes.c,v 2.1 2024/06/10 18:05:34 hurtta Exp $";
+ 
+ /******************************************************************************
+  *  The Elm (ME+) Mail System  -  $Revision: 2.1 $   $State: Exp $
+  *
+  *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
+  *      or  Kari Hurtta <elm@elmme-mailer.org>
+  *****************************************************************************/
+ 
+ 
+ #include "def_addr.h"
+ 
+ DEBUG_VAR(Debug,__FILE__,"addr");
+ 
+ const struct file_changes NULL_file_changes = FILE_CHANGES_INIT;
+ 
+ /* st == NULL resets file_information */
+ 
+ void stat_to_file_changes(st,file_information)
+      const struct stat *st;
+      struct file_changes *file_information;
+ {
+     if (FILE_CHANGES_magic != file_information->magic)
+ 	panic("ALIASES PANIC",__FILE__,__LINE__,"stat_to_file_changes",
+ 	      "Bad magic number (file_changes)",0);
+ 
+     if (sizeof (*file_information) != file_information->self_size) {
+ 	    
+ 	DPRINT(Debug,1,(&Debug,
+ 			"stat_to_file_changes: size mismatch file_changes size %zu != self size %zu\n",
+ 			sizeof (*file_information),file_information->self_size));
+ 
+ 	return;
+     }
+     
+     *file_information = NULL_file_changes;
+     
+     if (st) {
+ 	file_information->dev   = st->st_dev;
+ 	file_information->ino   = st->st_ino;
+ 	file_information->size  = st->st_size;
+ 	file_information->mtime = st->st_mtime;
+ 	file_information->valid = 1;
+     }    
+ }
+ 
+ enum file_changes_result test_file_changes(filename,old_file,errno_res)
+      const char                * filename;
+      const struct file_changes * old_file;
+      int                       * errno_res;
+ {
+     enum file_changes_result ret = file_changes_error;
+     
+     struct stat filename_stat;
+     int have_filename_stat = 0;
+     enum syscall_status  r;
+ 
+     
+     if (FILE_CHANGES_magic != old_file->magic)
+ 	panic("ALIASES PANIC",__FILE__,__LINE__,"test_file_changes",
+ 	      "Bad magic number (file_changes)",0);
+     
+     if (errno_res)
+ 	* errno_res = 0;
+ 
+     if (sizeof (*old_file) != old_file->self_size) {
+ 	
+ 	DPRINT(Debug,1,(&Debug,
+ 			"test_file_changes: size mismatch file_changes size %zu != self size %zu\n",
+ 			sizeof (*old_file),old_file->self_size));
+ 	ret = file_changes_error;
+ 	goto fail;
+     }
+     
+     r = stat(filename,&filename_stat);
+     switch (r) {
+ 	char *X;
+ 	int err;
+     case syscall_success:
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "test_file_changes: stat %s succeed: dev %ld ino %ld size %ld modified %ld",
+ 			 filename,
+ 			 (long)filename_stat.st_dev,
+ 			 (long)filename_stat.st_ino,
+ 			 (long)filename_stat.st_size,
+ 			 (long)filename_stat.st_mtime));
+ 	X = ctime(& (filename_stat.st_mtime));
+ 	if (X) { /* ctime() includes newline */
+ 	    DPRINT(Debug,14,(&Debug," -- %s",X));
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,"\n"));
+ 	}
+ 	
+ 	have_filename_stat = 1;
+ 	
+ 	break;
+     case syscall_error:
+ 	err = errno;
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "test_file_changes: stat %s: %s\n",
+ 			 filename,strerror(err)));
+ 
+ 	ret = file_changes_error;
+ 	if (errno_res)
+ 	    * errno_res = err;
+ 	    
+ 	goto fail;
+     }
+ 
+     if (! old_file->valid || !	have_filename_stat) {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "test_file_changes: %s: no information -- assumed changed\n", filename));
+ 	ret = have_file_changes;
+     } else if (filename_stat.st_dev   == old_file->dev  &&
+ 	       filename_stat.st_ino   == old_file->ino  &&
+ 	       filename_stat.st_size  == old_file->size &&
+ 	       filename_stat.st_mtime == old_file->mtime) {
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "test_file_changes: %s: No changes\n",
+ 			 filename));
+ 	ret = 	no_file_changes;
+     } else {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "test_file_changes: %s changed.\n",
+ 			 filename));
+ 	ret = have_file_changes;
+     }
+ 
+  fail:
+     DPRINT(Debug,14,(&Debug,
+ 		     "test_file_changes=%d",ret));
+     switch (ret) {
+     case file_changes_error: DPRINT(Debug,14,(&Debug," file_changes_error")); break;
+     case no_file_changes:    DPRINT(Debug,14,(&Debug," no_file_changes"));    break;
+     case have_file_changes:  DPRINT(Debug,14,(&Debug," have_file_changes"));  break;
+     }
+     if (errno_res && * errno_res) {
+ 	DPRINT(Debug,14,(&Debug,"; error %s",
+ 			 strerror(* errno_res)));
+     }
+     
+     DPRINT(Debug,14,(&Debug,"\n"));
+     
+     return ret;
+ }
+ 
+ /*
+  * Local Variables:
+  *  mode:c
+  *  c-basic-offset:4
+  *  buffer-file-coding-system: iso-8859-1
+  * End:
+  */
Index: elmME+.2.5.alpha64-cvs/lib/alias/aliases.c
*** elmME+.2.5.alpha63/lib/alias/aliases.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/alias/aliases.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: aliases.c,v 1.20 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 1.20 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: aliases.c,v 1.21 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 1.21 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 658,664 ****
  	    int err UNUSED_VAROK;
  	    
  	case syscall_success:
! 	DPRINT(Debug,14,(&Debug,
  			 "read_aliases_map: Reading again from offset %ld at %s\n",
  			 pos,filename));
  	break;
--- 658,664 ----
  	    int err UNUSED_VAROK;
  	    
  	case syscall_success:
! 	    DPRINT(Debug,14,(&Debug,
  			 "read_aliases_map: Reading again from offset %ld at %s\n",
  			 pos,filename));
  	break;
***************
*** 1177,1206 ****
      return 1;    
  }
  
- const struct file_changes NULL_file_changes = FILE_CHANGES_INIT;
  
- /* st == NULL resets file_information */
  
- static void stat_to_file_changes P_((const struct stat *st,
- 				     struct file_changes *file_information));
- static void stat_to_file_changes(st,file_information)
-      const struct stat *st;
-      struct file_changes *file_information;
- {
-     if (FILE_CHANGES_magic != file_information->magic)
- 	panic("ALIASES PANIC",__FILE__,__LINE__,"stat_to_file_changes",
- 	      "Bad magic number (file_changes)",0);
-    
-     *file_information = NULL_file_changes;
-     
-     if (st) {
- 	file_information->dev   = st->st_dev;
- 	file_information->ino   = st->st_ino;
- 	file_information->size  = st->st_size;
- 	file_information->mtime = st->st_mtime;
- 	file_information->valid    = 1;
-     }    
- }
  
  
  
--- 1177,1184 ----
***************
*** 1295,1303 ****
  	    char *X;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "load_aliases_map: fstat %d: %s succeed: dev %d ino %d size %ld modified %ld",
  			     file_fd,filename,
! 			     file_fd_stat.st_dev,file_fd_stat.st_ino,
  			     (long)file_fd_stat.st_size,
  			     (long)file_fd_stat.st_mtime));
  
--- 1273,1282 ----
  	    char *X;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "load_aliases_map: fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
  			     file_fd,filename,
! 			     (unsigned long)file_fd_stat.st_dev,
! 			     (unsigned long)file_fd_stat.st_ino,
  			     (long)file_fd_stat.st_size,
  			     (long)file_fd_stat.st_mtime));
  
***************
*** 1385,1394 ****
  	    char *X;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "load_aliases_map: stat %s succeed: dev %ld ino %ld size %ld modified %ld",
  			     filename,
! 			     (long)filename_stat.st_dev,
! 			     (long)filename_stat.st_ino,
  			     (long)filename_stat.st_size,
  			     (long)filename_stat.st_mtime));
  	    X = ctime(& (filename_stat.st_mtime));
--- 1364,1373 ----
  	    char *X;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "load_aliases_map: stat %s succeed: dev %lu ino %lu size %ld modified %ld",
  			     filename,
! 			     (unsigned long)filename_stat.st_dev,
! 			     (unsigned long)filename_stat.st_ino,
  			     (long)filename_stat.st_size,
  			     (long)filename_stat.st_mtime));
  	    X = ctime(& (filename_stat.st_mtime));
***************
*** 1425,1433 ****
  	    goto quit_locking_loop;
  	    
  	} else if (filename_stat.st_dev   == file_fd_stat.st_dev  &&
! 	    filename_stat.st_ino   == file_fd_stat.st_ino  &&
! 	    filename_stat.st_size  == file_fd_stat.st_size &&
! 	    filename_stat.st_mtime == file_fd_stat.st_mtime) {
  
  	    DPRINT(Debug,14,(&Debug,
  			     "load_aliases_map: file %s not changed (since open)\n",
--- 1404,1412 ----
  	    goto quit_locking_loop;
  	    
  	} else if (filename_stat.st_dev   == file_fd_stat.st_dev  &&
! 		   filename_stat.st_ino   == file_fd_stat.st_ino  &&
! 		   filename_stat.st_size  == file_fd_stat.st_size &&
! 		   filename_stat.st_mtime == file_fd_stat.st_mtime) {
  
  	    DPRINT(Debug,14,(&Debug,
  			     "load_aliases_map: file %s not changed (since open)\n",
***************
*** 1731,1740 ****
  	    int err;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "merge_aliases_map: fstat %d: %s succeed: dev %ld ino %ld size %ld modified %ld",
  			     file_fd,filename,
! 			     (long)file_fd_stat.st_dev,
! 			     (long)file_fd_stat.st_ino,
  			     (long)file_fd_stat.st_size,
  			     (long)file_fd_stat.st_mtime));
  	    
--- 1710,1719 ----
  	    int err;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
! 			     "merge_aliases_map: fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
  			     file_fd,filename,
! 			     (unsigned long)file_fd_stat.st_dev,
! 			     (unsigned long)file_fd_stat.st_ino,
  			     (long)file_fd_stat.st_size,
  			     (long)file_fd_stat.st_mtime));
  	    
***************
*** 2167,2174 ****
  			    
  			}
  			DPRINT(Debug,14,(&Debug,"\n"));
! 		    	
! 			free_aliases_map_node(& (res.aliases));
  		    }
  		    if (i > 0)
  			i--;
--- 2146,2154 ----
  			    
  			}
  			DPRINT(Debug,14,(&Debug,"\n"));
! 
! 			if (res.aliases)
! 			    free_aliases_map_node(& (res.aliases));
  		    }
  		    if (i > 0)
  			i--;
***************
*** 2204,2213 ****
  		char *X;
  	    case syscall_success:
  		DPRINT(Debug,14,(&Debug,
! 				 "dump_aliases_map: fstat %d: succeed: dev %ld ino %ld size %ld modified %ld",
  				 file_fd,
! 				 (long)file_fd_stat.st_dev,
! 				 (long)file_fd_stat.st_ino,
  				 (long)file_fd_stat.st_size,
  				 (long)file_fd_stat.st_mtime));
  		
--- 2184,2193 ----
  		char *X;
  	    case syscall_success:
  		DPRINT(Debug,14,(&Debug,
! 				 "dump_aliases_map: fstat %d: succeed: dev %lu ino %lu size %ld modified %ld",
  				 file_fd,
! 				 (unsigned long)file_fd_stat.st_dev,
! 				 (unsigned long)file_fd_stat.st_ino,
  				 (long)file_fd_stat.st_size,
  				 (long)file_fd_stat.st_mtime));
  		
***************
*** 2247,2253 ****
      if (file_information) {
  
  	if (FILE_CHANGES_magic != file_information->magic)
! 	    panic("ALIASES PANIC",__FILE__,__LINE__,"merge_aliases_map",
  		  "Bad magic number (file_changes)",0);
  	
  	if (sizeof (*file_information) != file_information->self_size) {	    
--- 2227,2233 ----
      if (file_information) {
  
  	if (FILE_CHANGES_magic != file_information->magic)
! 	    panic("ALIASES PANIC",__FILE__,__LINE__,"dump_aliases_map",
  		  "Bad magic number (file_changes)",0);
  	
  	if (sizeof (*file_information) != file_information->self_size) {	    
***************
*** 2272,2378 ****
      return ret;
  }
  
- enum file_changes_result test_file_changes(filename,old_file,errno_res)
-      const char                * filename;
-      const struct file_changes * old_file;
-      int                       * errno_res;
- {
-     enum file_changes_result ret = file_changes_error;
-     
-     struct stat filename_stat;
-     int have_filename_stat = 0;
-     enum syscall_status  r;
- 
-     
-     if (FILE_CHANGES_magic != old_file->magic)
- 	panic("ALIASES PANIC",__FILE__,__LINE__,"test_file_changes",
- 	      "Bad magic number (file_changes)",0);
-     
-     if (errno_res)
- 	* errno_res = 0;
- 
-     if (sizeof (*old_file) != old_file->self_size) {
- 	
- 	DPRINT(Debug,1,(&Debug,
- 			"test_file_changes: size mismatch file_changes size %zu != self size %zu\n",
- 			sizeof (*old_file),old_file->self_size));
- 	ret = file_changes_error;
- 	goto fail;
-     }
-     
-     r = stat(filename,&filename_stat);
-     switch (r) {
- 	char *X;
- 	int err;
-     case syscall_success:
- 	DPRINT(Debug,14,(&Debug,
- 			 "test_file_changes: stat %s succeed: dev %ld ino %ld size %ld modified %ld",
- 			 filename,
- 			 (long)filename_stat.st_dev,
- 			 (long)filename_stat.st_ino,
- 			 (long)filename_stat.st_size,
- 			 (long)filename_stat.st_mtime));
- 	X = ctime(& (filename_stat.st_mtime));
- 	if (X) { /* ctime() includes newline */
- 	    DPRINT(Debug,14,(&Debug," -- %s",X));
- 	} else {
- 	    DPRINT(Debug,14,(&Debug,"\n"));
- 	}
- 	
- 	have_filename_stat = 1;
- 	
- 	break;
-     case syscall_error:
- 	err = errno;
- 	
- 	DPRINT(Debug,14,(&Debug,
- 			 "test_file_changes: stat %s: %s\n",
- 			 filename,strerror(err)));
- 
- 	ret = file_changes_error;
- 	if (errno_res)
- 	    * errno_res = err;
- 	    
- 	goto fail;
-     }
- 
-     if (! old_file->valid || !	have_filename_stat) {
- 	DPRINT(Debug,14,(&Debug,
- 			 "test_file_changes: %s: no information -- assumed changed\n", filename));
- 	ret = have_file_changes;
-     } else if (filename_stat.st_dev   == old_file->dev  &&
- 	       filename_stat.st_ino   == old_file->ino  &&
- 	       filename_stat.st_size  == old_file->size &&
- 	       filename_stat.st_mtime == old_file->mtime) {
- 
- 	DPRINT(Debug,14,(&Debug,
- 			 "test_file_changes: %s: No changes\n",
- 			 filename));
- 	ret = 	no_file_changes;
-     } else {
- 	DPRINT(Debug,14,(&Debug,
- 			 "test_file_changes: %s changed.\n",
- 			 filename));
- 	ret = have_file_changes;
-     }
- 
-  fail:
-     DPRINT(Debug,14,(&Debug,
- 		     "test_file_changes=%d",ret));
-     switch (ret) {
-     case file_changes_error: DPRINT(Debug,14,(&Debug," file_changes_error")); break;
-     case no_file_changes:    DPRINT(Debug,14,(&Debug," no_file_changes"));    break;
-     case have_file_changes:  DPRINT(Debug,14,(&Debug," have_file_changes"));  break;
-     }
-     if (errno_res && * errno_res) {
- 	DPRINT(Debug,14,(&Debug,"; error %s",
- 			 strerror(* errno_res)));
-     }
-     
-     DPRINT(Debug,14,(&Debug,"\n"));
-     
-     return ret;
- }
  
  const struct address_alias * aliases_map_get_alias(map,idx,key)
       const struct aliases_map *map;
--- 2252,2257 ----
Index: elmME+.2.5.alpha64-cvs/lib/cs_unknown.c
*** elmME+.2.5.alpha63/lib/cs_unknown.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/cs_unknown.c	Sun Jun 23 19:12:01 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: cs_unknown.c,v 2.21 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.21 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: cs_unknown.c,v 2.23 2024/06/23 16:12:01 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.23 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 1258,1263 ****
--- 1258,1264 ----
  	    /* return value r includes possible \0 character */
  
  	    if ((size_t)(-1) == r) {
+ 		int err = errno;
  		
  		if (L'?' == c)
  		    panic("STRING PANIC",__FILE__,__LINE__,
***************
*** 1270,1276 ****
  		
  		DPRINT(Debug,61,(&Debug,
  				 "cs_stream_from_unknown: Failed to convert 0x%04x at %d: errno = %d\n",
! 				 (int)c,i,errno));
  
  		c = L'?';
  		goto retry;
--- 1271,1277 ----
  		
  		DPRINT(Debug,61,(&Debug,
  				 "cs_stream_from_unknown: Failed to convert 0x%04x at %d: errno = %d\n",
! 				 (int)c,i,err));
  
  		c = L'?';
  		goto retry;
***************
*** 1421,1432 ****
  
  #ifdef WCHAR
  	int alloced;
! 	int l;
  	mbstate_t State;
- 	wchar_t  * tmp;
- 	const wchar_t  *ctmp, *src;
  	int i;
! 	
  
  	/* If str->p->private_flag is set, charset is 
  	 * locale charset
--- 1422,1431 ----
  
  #ifdef WCHAR
  	int alloced;
! 	int retlen = 0;
  	mbstate_t State;
  	int i;
! 	size_t r;
  
  	/* If str->p->private_flag is set, charset is 
  	 * locale charset
***************
*** 1441,1448 ****
  
  	/* NOTE:  str->p->a.wchars is not NUL terminated        
  	 *
! 	 * ! ! !    NOTE!   this do not convert strings including \0
! 	 *                  characters
  	 */
  
  	if (len > str->p->len)
--- 1440,1449 ----
  
  	/* NOTE:  str->p->a.wchars is not NUL terminated        
  	 *
! 	 	 * Assumed that wcrtomb() do not produce more than MB_CUR_MAX
! 	 * bytes at once
! 	 *
! 	 * wcrtomb() is not constant (value depends on locale)
  	 */
  
  	if (len > str->p->len)
***************
*** 1450,1457 ****
  
  	if (len <= 0) 
  	    goto done;
  
! 	tmp = safe_malloc((len + 1) * sizeof (tmp[0]));	
  
  	for (i = 0; i < len && *pos < str->p->len; i++, (*pos)++) {
  	    wchar_t c = str->p->a.wchars[*pos];
--- 1451,1462 ----
  
  	if (len <= 0) 
  	    goto done;
+       
+ 	memset(&State, 0, sizeof(State));
  
! 	alloced = len + MB_CUR_MAX + 1;
!      
! 	ret = safe_malloc(alloced);
  
  	for (i = 0; i < len && *pos < str->p->len; i++, (*pos)++) {
  	    wchar_t c = str->p->a.wchars[*pos];
***************
*** 1476,1546 ****
  #endif
  	    }
  
  
! 	    tmp[i] = c;       
! 	}
! 	tmp[i] = L'\0';
! 
! 	ctmp = (const wchar_t  *) tmp;
! 	
! 	memset(&State, 0, sizeof(State));
  
! 	alloced = len+1;
!      
! 	ret = safe_malloc(alloced);
  
! 	for (src = ctmp, l = 0; src; ) {
! 	    int left = alloced - l;
! 	    size_t r = wcsrtombs(us2s(ret+l),&src,left,&State);
  
  	    if ((size_t)(-1) == r) {
! 		int pos = src-ctmp;
! 		if (L'?' == *src)
  		    panic("STRING PANIC",__FILE__,__LINE__,
  			  "cs_streamclip_from_unknown",
  			  "? not convertible",0);
! 		if (L'\0' == *src)
  		    panic("STRING PANIC",__FILE__,__LINE__,
  			  "cs_streamclip_from_unknown",
  			  "Ooops",0);
! 		    
  		DPRINT(Debug,61,(&Debug,
! 				 "*cs_streamclip_from_unknown: Failed to convert 0x%04x at %d: errno = %d\n",
! 				 (int)*src,pos,errno));
  
  
! 		tmp[pos] = L'?';
  		
! 	    } else {
! 
! 		if (r >= 0)
! 		    l += r;
! 		else
  		    panic("STRING PANIC",__FILE__,__LINE__,
! 			  "cs_stream_from_unknown",
! 			  "Unexpected return from wcsrtombs()",0);
  
! 		if (src) {
! 		    int x;
! 		    
! 		    x = len - (src-ctmp);
  
! 		    alloced += x + MB_CUR_MAX;
  
! 		    ret = safe_realloc(ret,alloced);		
! 		}
! 	    }	   
  	}
  
! 	if ('\0' != ret[l])
  	    panic("STRING PANIC",__FILE__,__LINE__,
  		  "cs_stream_from_unknown",
  		  "\\0 not written",0);	   
  
- 	free(tmp); tmp = NULL;
- 	
  #else
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_add_streambytes_to_binary",
  	      "No wchar_t support",0);
  #endif
  
--- 1481,1579 ----
  #endif
  	    }
  
+ 	    if (alloced < retlen + MB_CUR_MAX + 1) {
+ 		int left = len - i;
+ 		
+ 		if (left > 64)
+ 		    left = 64;
  
! 		alloced = retlen + left * MB_CUR_MAX + 1;
  
! 		ret = safe_realloc(ret,alloced);		
! 	    }
!   
! 	retry:
! 	    r = wcrtomb(us2s(ret+retlen),c,&State);
  
! 	    /* return value r includes possible \0 character */
  
  	    if ((size_t)(-1) == r) {
! 		int err = errno;
! 		
! 		if (L'?' == c)
  		    panic("STRING PANIC",__FILE__,__LINE__,
  			  "cs_streamclip_from_unknown",
  			  "? not convertible",0);
! 		if (L'\0' == c)
  		    panic("STRING PANIC",__FILE__,__LINE__,
  			  "cs_streamclip_from_unknown",
  			  "Ooops",0);
! 		
  		DPRINT(Debug,61,(&Debug,
! 				 "cs_streamclip_from_unknown: Failed to convert 0x%04x at %d: errno = %d\n",
! 				 (int)c,i,err));
! 
! 		c = L'?';
! 		goto retry;
  
+ 	    } else if (r >= 0) {
  
! 		retlen += r;
  		
! 		if (retlen > alloced)
  		    panic("STRING PANIC",__FILE__,__LINE__,
! 			  "cs_streamclip_from_unknown",
! 			  "Overflow",0);
  
! 	    } else 
! 		panic("STRING PANIC",__FILE__,__LINE__,
! 		      "cs_streamclip_from_unknown",
! 		      "Unexpected return from wcrtomb()",0);
! 
! 	    if (0 == r) {
! 		DPRINT(Debug,61,(&Debug,
! 				 "cs_streamclip_from_unknown: Character 0x%04x at %d produces nothing\n",
! 				 (int)c,i));
! 	    }	    
! 	}
  
! 	
! 	/* And end of string */
! 	
! 	if (alloced < retlen + MB_CUR_MAX + 1) {
! 	    alloced = retlen + MB_CUR_MAX + 1;
  
! 	    ret = safe_realloc(ret,alloced);		
  	}
  
! 	/* Resets state */
! 	r = wcrtomb(us2s(ret+retlen),L'\0',&State);
! 	
! 	if ((size_t)(-1) == r) {
! 	    panic("STRING PANIC",__FILE__,__LINE__,
! 		  "cs_streamclip_from_unknown",
! 		  "Ooops",0);
! 		    
! 	} else if (r > 0) {  /* Must produce \0 at least */
! 
! 	    retlen += r -1;    /* DO not count final \0 */
! 	    
! 	    if (retlen > alloced)
! 		panic("STRING PANIC",__FILE__,__LINE__,
! 		      "cs_streamclip_from_unknown",
! 		      "Overflow",0);
! 	} else 
  	    panic("STRING PANIC",__FILE__,__LINE__,
  		  "cs_stream_from_unknown",
+ 		  "Unexpected return from wcrtomb()",0);	
+ 	    
+ 	if ('\0' != ret[retlen])
+ 	    panic("STRING PANIC",__FILE__,__LINE__,
+ 		  "cs_streamclip_from_unknown",
  		  "\\0 not written",0);	   
  
  #else
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_streamclip_from_unknown",
  	      "No wchar_t support",0);
  #endif
  
***************
*** 1612,1626 ****
  
      if (ret->string_type->charset_type !=
  	str->string_type->charset_type) 
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_binary",
  	      "String type mismatch",0);
  
      if (*pos < 0)
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_binary",
  	      "Index out of array",0);
  
      if (len < 0)
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_binary",
  	      "Negative size",0);
  
      cs_free_unknown(ret);
--- 1645,1659 ----
  
      if (ret->string_type->charset_type !=
  	str->string_type->charset_type) 
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_unknown",
  	      "String type mismatch",0);
  
      if (*pos < 0)
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_unknown",
  	      "Index out of array",0);
  
      if (len < 0)
! 	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_unknown",
  	      "Negative size",0);
  
      cs_free_unknown(ret);
***************
*** 1706,1712 ****
  	    uint16 val;
  
  	    /* wctob returns unsigned char if character is representable
! 	     * as byte or EOF otehrwise 
  	     */
  
  	    if (EOF == c1)
--- 1739,1745 ----
  	    uint16 val;
  
  	    /* wctob returns unsigned char if character is representable
! 	     * as byte or EOF otherwise 
  	     */
  
  	    if (EOF == c1)
Index: elmME+.2.5.alpha64-cvs/lib/delay_unlink.c
*** elmME+.2.5.alpha63/lib/delay_unlink.c	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/lib/delay_unlink.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: delay_unlink.c,v 2.3 2021/08/20 18:11:57 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.3 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: delay_unlink.c,v 2.4 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.4 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 381,390 ****
  
  	    ret->have_st_dev_ino = 1;
  
! 	    DPRINT(Debug,11,(&Debug,"alloc_delay_unlink: ret=%p: fstat %d: file %s: dev/ino = %ld/%ld\n",
  			     ret,fd,name,
! 			     (long)stat_buffer.st_dev,
! 			     (long)stat_buffer.st_ino));
  	}	
      }
      
--- 381,390 ----
  
  	    ret->have_st_dev_ino = 1;
  
! 	    DPRINT(Debug,11,(&Debug,"alloc_delay_unlink: ret=%p: fstat %d: file %s: dev/ino = %lu/%lu\n",
  			     ret,fd,name,
! 			     (unsigned long)stat_buffer.st_dev,
! 			     (unsigned long)stat_buffer.st_ino));
  	}	
      }
      
***************
*** 407,416 ****
  	
      } else if (0 == r) {
  
! 	DPRINT(Debug,11,(&Debug,"alloc_delay_unlink: ret=%p: stat %s: dev/ino = %ld/%ld\n",
  			 ret,name,
! 			 (long)stat_buffer.st_dev,
! 			 (long)stat_buffer.st_ino));
  	
  	if (0 == ret->have_st_dev_ino) {
  
--- 407,416 ----
  	
      } else if (0 == r) {
  
! 	DPRINT(Debug,11,(&Debug,"alloc_delay_unlink: ret=%p: stat %s: dev/ino = %lu/%lu\n",
  			 ret,name,
! 			 (unsigned long)stat_buffer.st_dev,
! 			 (unsigned long)stat_buffer.st_ino));
  	
  	if (0 == ret->have_st_dev_ino) {
  
Index: elmME+.2.5.alpha64-cvs/lib/mail_gets.c
*** elmME+.2.5.alpha63/lib/mail_gets.c	Sat Dec 30 13:44:59 2017
--- elmME+.2.5.alpha64-cvs/lib/mail_gets.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: mail_gets.c,v 2.6 2017/12/30 11:44:59 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.6 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: mail_gets.c,v 2.7 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.7 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 108,114 ****
  
  	if (line_bytes+1 > alloced) {
  	    size_t n = alloced + 100;
! 	    if (n > (size_t)limit && limit > line_bytes)
  		n = limit;
  
  	    buf = safe_realloc(buf,n);
--- 108,114 ----
  
  	if (line_bytes+1 > alloced) {
  	    size_t n = alloced + 100;
! 	    if (limit > 0 && n > (size_t)limit && limit > line_bytes)
  		n = limit;
  
  	    buf = safe_realloc(buf,n);
***************
*** 134,140 ****
      
      *buffer = buf;
  
!     if (line_bytes >= limit ||
  	line_bytes == INT_MAX)
  	return -1;
      
--- 134,140 ----
      
      *buffer = buf;
  
!     if ((limit > 0 && line_bytes >= limit) ||
  	line_bytes == INT_MAX)
  	return -1;
      
Index: elmME+.2.5.alpha64-cvs/lib/mbox/Makefile.SH
*** elmME+.2.5.alpha63/lib/mbox/Makefile.SH	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/Makefile.SH	Mon Jun 10 21:05:34 2024
***************
*** 38,44 ****
  $cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.17 2021/07/13 07:58:36 hurtta Exp $
  #
  #  Makefile for the ELM (ME+) mail program.
  #
--- 38,44 ----
  $cat >Makefile <<!GROK!THIS!
  #!$make
  #
! # $Id: Makefile.SH,v 2.18 2024/06/10 18:05:34 hurtta Exp $
  #
  #  Makefile for the ELM (ME+) mail program.
  #
***************
*** 110,116 ****
   mbox_generic.o common_local.o remote_server.o connection.o \
   con_imap.o hashmark.o commentfile.o hashmark_local.o \
   hashmark_remote.o hashmark_browser.o hashmark_helper.o \
!  quota.o imap_quota.o utime_util.o filelock.o
  
  all:	Makefile ../../libs/libelmme-mbox.a $(SOTARG)
  install_s: all $(INSTLIB)
--- 110,116 ----
   mbox_generic.o common_local.o remote_server.o connection.o \
   con_imap.o hashmark.o commentfile.o hashmark_local.o \
   hashmark_remote.o hashmark_browser.o hashmark_helper.o \
!  quota.o imap_quota.o utime_util.o filelock.o last_read.o
  
  all:	Makefile ../../libs/libelmme-mbox.a $(SOTARG)
  install_s: all $(INSTLIB)
***************
*** 204,209 ****
--- 204,211 ----
  connection.o: def_mbox.h $(INCLDIR)/ss_imp.h 
  quota.o: def_mbox.h $(INCLDIR)/quota_imp.h
  utime_util.o: def_mbox.h
+ last_read.o: def_mbox.h $(INCLDIR)/mbxlocal_imp.h $(INCLDIR)/s_me.h \
+  $(INCLDIR)/filelock.h $(INCLDIR)/commentfile.h
  
  ../../libs/libelmme-mbox.a: $(OBJS)
  	$(AR) r $@ $?
Index: elmME+.2.5.alpha64-cvs/lib/mbox/common_local.c
*** elmME+.2.5.alpha63/lib/mbox/common_local.c	Fri Dec 10 20:18:48 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/common_local.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: common_local.c,v 2.25 2021/09/22 17:50:58 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.25 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: common_local.c,v 2.26 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.26 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 33,38 ****
--- 33,40 ----
      return (char *)str;
  }
  
+ 
+ 
  /* rel_itemname is relative to type -- not include user@hostname 
  
     rel_itemname is NULL is idicating that selection is on
***************
*** 49,61 ****
      char          * str  = NULL;
      int F = 0;
      int idx;
      
      idx = browser_select_generic(dir,dir->dirname,
  				 rel_itemname,relative,&Lstr,&str,'/',
  				 local_fs_charset);
- 		
  
!     F = local_selection_stat(str);
  
      if (idx >= 0) {
   	DPRINT(Debug,11,(&Debug,
--- 51,70 ----
      char          * str  = NULL;
      int F = 0;
      int idx;
+ 
+     if (FOLDER_BROWSER_magic != dir->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"real_select_local",
+ 	      "Bad magic type (folder_browser)",0);
      
      idx = browser_select_generic(dir,dir->dirname,
  				 rel_itemname,relative,&Lstr,&str,'/',
  				 local_fs_charset);
  
!     /* dir can be dummy_browser */
!     
! 
!     F = local_selection_stat(str,
! 			     browser_local_last_read(dir));
  
      if (idx >= 0) {
   	DPRINT(Debug,11,(&Debug,
***************
*** 145,155 ****
  	    /* Incoming mailbox (may also be IMAP mailbox) */
  	    
  	    /* Explicite disallow $MAIL to be interpreted as remote mailbox */
! 	    if (0 != (defaultfile_cmask & FOLDER_is_local_file)) {
  		
  		enum folder_place place;
  		
! 		DPRINT(Debug,10,(&Debug,"real_folder_from_local: FOLDER_is_local_file is set for value\n"));
  		
  		res = mbx_new_folder();
  		
--- 154,165 ----
  	    /* Incoming mailbox (may also be IMAP mailbox) */
  	    
  	    /* Explicite disallow $MAIL to be interpreted as remote mailbox */
! 	    if (ison(defaultfile_cmask,FOLDER_is_local_file)) {
  		
  		enum folder_place place;
  		
! 		DPRINT(Debug,10,(&Debug,
! 				 "real_folder_from_local: FOLDER_is_local_file is set for value\n"));
  		
  		res = mbx_new_folder();
  		
***************
*** 1008,1016 ****
  }
  
  
! int local_stat_flags(pathname,buf) 
       const char * pathname;
       struct stat * buf;
  {
  
      int flags = 0;
--- 1018,1028 ----
  }
  
  
! int local_stat_flags(pathname,buf,this_last_read) 
       const char * pathname;
       struct stat * buf;
+      /* upgrade_last_read() is assumed to be called */
+      struct last_read_cache * this_last_read;
  {
  
      int flags = 0;
***************
*** 1041,1053 ****
  			 "local_stat_flags : %s: not on folder (file)\n",pathname));
  	
  
!     } else
! 	if (buf->st_mtime > buf->st_atime) {
  	    DPRINT(Debug,13,(&Debug,
! 			     "local_stat_flags : %s: mtime=%d > atime=%d -- new mail?\n",
! 			     pathname,buf->st_mtime,buf->st_atime));
! 	    flags |= BROWSER_MARKED;
  	}
      
      if ((BROWSER_NOFOLDER|BROWSER_NODIR) == flags) {
  	DPRINT(Debug,13,(&Debug,
--- 1053,1090 ----
  			 "local_stat_flags : %s: not on folder (file)\n",pathname));
  	
  
!     } else {
! 	time_t atime          = buf->st_atime;
! 	time_t last_read_time = buf->st_atime;
! 	int found_last_read = 0;
! 	char * X UNUSED_VAROK = "";
! 	
! 	if (this_last_read) {
! 	    found_last_read = have_last_read(this_last_read,
! 					     pathname,buf,
! 					     &last_read_time);
! 	    if (found_last_read &&
! 		last_read_time > atime) {
! 
! 		DPRINT(Debug,13,(&Debug,
! 				 "local_stat_flags : %s: updating atime %d -> last_read %d\n",
! 				 pathname,atime,last_read_time));
! 
! 		atime = last_read_time;
! 	    } else {
! 		X = found_last_read ? "old last_read entry" : "No last_read entry";
! 	    }
! 	} else {
! 	    X = "last_read not enabled or updated";
! 	}
! 	    
! 	if (buf->st_mtime > atime) {
  	    DPRINT(Debug,13,(&Debug,
! 			     "local_stat_flags : %s: mtime=%d > atime=%d -- new mail? %s\n",
! 			     pathname,buf->st_mtime,atime,X));
! 	    setit(flags,BROWSER_MARKED);
  	}
+     }
      
      if ((BROWSER_NOFOLDER|BROWSER_NODIR) == flags) {
  	DPRINT(Debug,13,(&Debug,
***************
*** 1058,1068 ****
      return flags;
  }
  
! int local_selection_stat(str)
       const char * str;
  {
      int F = 0;
      struct stat    bufX;	 /* stat command  */
      
      /* give_dt_estr_as_str adds / to end */
      const char * folders_val = give_dt_estr_as_str(&folders_e,"maildir",NULL,NULL);
--- 1095,1108 ----
      return flags;
  }
  
! int local_selection_stat(str,dir_last_read)
       const char * str;
+      struct last_read_cache * dir_last_read;
  {
      int F = 0;
      struct stat    bufX;	 /* stat command  */
+ 
+     enum syscall_status r_stat;
      
      /* give_dt_estr_as_str adds / to end */
      const char * folders_val = give_dt_estr_as_str(&folders_e,"maildir",NULL,NULL);
***************
*** 1073,1079 ****
  						    "mailhome-dir",
  						    NULL,NULL);
  
!     if (0 == stat(str,&bufX)) {
  	DPRINT(Debug,11,(&Debug,
  		    "local_selection_stat: %s exists\n",
  		    str));
--- 1113,1126 ----
  						    "mailhome-dir",
  						    NULL,NULL);
  
!     r_stat = stat(str,&bufX);
!     switch (r_stat) {
!     case syscall_success /* 0 */: {
! 	
! 	struct last_read_cache * this_last_read =
! 	    upgrade_last_read(dir_last_read,
! 			      str,&bufX);
! 	
  	DPRINT(Debug,11,(&Debug,
  		    "local_selection_stat: %s exists\n",
  		    str));
***************
*** 1094,1101 ****
  	    F |= BROWSER_DIRPREFIX;
  	}
  
! 	F |= local_stat_flags(str,&bufX);
! 
  
  	if (0 == (F & BROWSER_NOFOLDER)) {
  
--- 1141,1147 ----
  	    F |= BROWSER_DIRPREFIX;
  	}
  
! 	F |= local_stat_flags(str,&bufX,this_last_read);
  
  	if (0 == (F & BROWSER_NOFOLDER)) {
  
***************
*** 1110,1123 ****
  		F |= BROWSER_MAILFILE;
  	}
  
!     } else {
  	DPRINT(Debug,11,(&Debug,
! 		    "local_selection_stat: %s : stat fail\n",
! 		    str));
  
  	F |= BROWSER_NOFOLDER|BROWSER_NODIR;
      }
! 	
  
      return F;
  
--- 1156,1177 ----
  		F |= BROWSER_MAILFILE;
  	}
  
! 	/* Decrements refcount */
! 	if (this_last_read)
! 	    free_last_read_cache(&this_last_read);
!     }
! 	break;
!     case syscall_error /* -1 */: {
! 	int err UNUSED_VAROK = errno;
! 	
  	DPRINT(Debug,11,(&Debug,
! 			 "local_selection_stat: %s : stat failed: %s\n",
! 			 str,strerror(err)));
  
  	F |= BROWSER_NOFOLDER|BROWSER_NODIR;
      }
! 	break;
!     }
  
      return F;
  
Index: elmME+.2.5.alpha64-cvs/lib/mbox/def_mbox.h
*** elmME+.2.5.alpha63/lib/mbox/def_mbox.h	Thu May 26 11:16:29 2022
--- elmME+.2.5.alpha64-cvs/lib/mbox/def_mbox.h	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! /* $Id: def_mbox.h,v 2.21 2022/02/20 13:46:55 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.21 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! /* $Id: def_mbox.h,v 2.24 2024/06/23 07:38:36 hurtta Exp $ */
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.24 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 22,29 ****
--- 22,32 ----
  extern SHAREDLIB use_shared_mbox;
  #endif
  
+ extern FLAGS last_read_fbck_locking;
+ 
  extern struct out_state_type state_out_dir;
  
+ 
  extern void remote_server_dec_dir P_((struct folder_browser *browser));
  extern void remote_server_inc_dir P_((struct folder_browser *browser,
  				      const struct remote_server *server));
***************
*** 197,209 ****
  E_(mbx_give_folder_quotar_list mbx_give_default_quotar_list)
  extern struct mail_quotaroot_list * mbx_give_default_quotar_list P_((struct folder_info * folder,
  								     struct mail_quota   * mq,
! 		    struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */));
  
  E_(mbx_give_message_msize_folder  mbx_give_message_msize_default)
  extern int mbx_give_message_msize_default P_((struct folder_info * folder,
  					  struct header_rec  * entry,
  					  unsigned long      * ret_size));
  
  
  
  extern int sessionlock_create_tempfolder P_((struct folder_info *folder,
--- 200,218 ----
  E_(mbx_give_folder_quotar_list mbx_give_default_quotar_list)
  extern struct mail_quotaroot_list * mbx_give_default_quotar_list P_((struct folder_info * folder,
  								     struct mail_quota   * mq,
! 	      struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */,
! 								     enum quota_mode refresh
! 
! 								     ));
  
  E_(mbx_give_message_msize_folder  mbx_give_message_msize_default)
  extern int mbx_give_message_msize_default P_((struct folder_info * folder,
  					  struct header_rec  * entry,
  					  unsigned long      * ret_size));
  
+ /* Return -1 if not available (local mail) */
+ E_(mbx_give_message_count_folder mbx_give_message_count_default)
+ int mbx_give_message_count_default P_((struct folder_info * folder));
  
  
  extern int sessionlock_create_tempfolder P_((struct folder_info *folder,
***************
*** 215,223 ****
  
  extern int imap_handle_greeting P_((struct connection_cache *con));
  
  /* common_local.c */
  
! extern int local_selection_stat P_((const char * str));
  
  /* localmbx.c */
  
--- 224,297 ----
  
  extern int imap_handle_greeting P_((struct connection_cache *con));
  
+ /* last_read.c */
+ 
+ /* Increments refcount - may change or open new cache 
+    does not reload cache if directory is corrent 
+ */
+ extern struct last_read_cache * upgrade_last_read P_((struct last_read_cache * dir_last_read,
+ 						      const char        * stat_file,
+ 						      struct stat * stat_buf));
+ 
+ /* Decrements refcount */
+ extern void free_last_read_cache P_((struct last_read_cache ** dir_last_read));
+ 
+ /* Cache assumed to point correct directory */
+ extern int have_last_read P_((struct last_read_cache * this_last_read,
+ 			      const char             * pathname,
+ 			      struct stat            * file_stat,
+ 			      time_t                 * last_read_time));
+ 
+ /* Posible allocates new, decrement old refcount if name is changed */
+ extern int update_last_read P_((struct last_read_cache ** dir_last_read,
+ 				 const char * sys_dir));
+ 
+ /* Write struct last_read_cache if modified */
+ extern void flush_last_read P_((struct last_read_cache * dir_last_read));
+ 
+ /* Flag local entries and matching with sys_dir prefix */
+ extern void flag_last_read P_((struct last_read_cache * dir_last_read,
+ 			       const char * sys_dir,
+ 			       const char * entryname));
+ 
+ /* deletes not flagged local entries (and absolute path entries
+    matchig with sys_dir prefix) */
+ extern void purge_last_read P_((struct last_read_cache * dir_last_read,
+ 				const char * sys_dir
+ 				));
+ 
+ 
+ /* Increments refcount */
+ extern struct last_read_cache * last_read_enabled
+   P_((enum use_lastread_v use_lastread,
+       char             * cur_folder_sys,
+       struct stat      * oldstat,
+       struct stat      * curstat));
+ 
+ 
+ E_(free_rc_hook free_last_read)
+ extern void free_last_read P_((void));
+ 
+ /* system init hook */
+ E_(init_default_hook init_last_read_defaults)
+ extern void init_last_read_defaults P_((int *errors));
+ 
+ 
+ /* User init hook */
+ E_(init_default_hook last_read_rc_file)
+ extern void last_read_rc_file P_((int *errors));
+ 
+ /* Writes cache */
+ 
+ extern void mark_last_read P_((struct last_read_cache * cache,
+ 			       char                   * cur_folder_sys,
+ 			       struct stat            * curstat));
+ 
  /* common_local.c */
  
! extern int local_selection_stat P_((const char * str,
! 				    struct last_read_cache * dir_last_read));
! 
  
  /* localmbx.c */
  
***************
*** 227,232 ****
--- 301,312 ----
  extern void zero_FILE_rs P_((struct FILE_rs *rs));
  extern void clear_FILE_rs P_((struct FILE_rs *rs));
  
+ /* result is malloced */
+ extern char * cat_dir_entry P_((const char *sys_dir,const char *entryname));
+ 
+ /* dir->a.local_browser->this_last_read */
+ extern struct last_read_cache *browser_local_last_read P_((struct folder_browser *dir));
+ 
  /* remote_mbx.c */
  
  extern int same_remote_account_host_user P_((const struct remote_account *ra1,
Index: elmME+.2.5.alpha64-cvs/lib/mbox/hashmark.c
*** elmME+.2.5.alpha63/lib/mbox/hashmark.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/mbox/hashmark.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: hashmark.c,v 2.8 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.8 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: hashmark.c,v 2.9 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.9 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
***************
*** 555,561 ****
      return 0;
  }
  
- 
  static int hashtype_parse_kw_none(filename,lineno,rest_S,item,kw,rc,now)
       const char *filename;
       int lineno;
--- 555,560 ----
Index: elmME+.2.5.alpha64-cvs/lib/mbox/hashmark_local.c
*** elmME+.2.5.alpha63/lib/mbox/hashmark_local.c	Thu May 26 11:16:29 2022
--- elmME+.2.5.alpha64-cvs/lib/mbox/hashmark_local.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: hashmark_local.c,v 2.6 2022/02/12 14:00:06 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.6 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: hashmark_local.c,v 2.7 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.7 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
***************
*** 996,1002 ****
  
      if (item_d->expanded_dir && item_d->directory) {
  
! 	int F = local_selection_stat(item_d->expanded_dir);
  	struct string * X = NULL;
  	
  	if (0 == (F & BROWSER_NOFOLDER)) {
--- 996,1004 ----
  
      if (item_d->expanded_dir && item_d->directory) {
  
! 	int F = local_selection_stat(item_d->expanded_dir,
! 				     /* Is this correct? */
! 				     browser_local_last_read(dir));
  	struct string * X = NULL;
  	
  	if (0 == (F & BROWSER_NOFOLDER)) {
Index: elmME+.2.5.alpha64-cvs/lib/mbox/imap.c
*** elmME+.2.5.alpha63/lib/mbox/imap.c	Tue Apr 20 20:32:06 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/imap.c	Thu Jun 13 20:36:55 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: imap.c,v 2.51 2021/01/10 15:47:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.51 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: imap.c,v 2.52 2024/06/13 17:36:55 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.52 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 5607,5612 ****
--- 5607,5642 ----
      return ret;
  }
  
+ /* Return -1 if not available (local mail) */
+ S_(mbx_give_message_count_folder mbx_give_message_count_imap)
+ static int mbx_give_message_count_imap P_((struct folder_info * folder));
+ static int mbx_give_message_count_imap(folder)
+      struct folder_info * folder;
+ {
+     struct connection_cache *con;
+     int ret = -1;
+     
+     DPRINT(Debug,11,(&Debug,
+ 		     "mbx_give_message_count_imap: folder=%p (%s)\n",
+ 		     folder,folder->cur_folder_sys));
+         
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_message_count_imap",
+ 	      "Bad magic number (private_data)",0);
+ 
+     con = folder->p->a.imap_mbx.Ch;
+     if (con->type != &IMAP_connection) {
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_message_count_imap",
+ 	      "Wrong type connection attached to folder",0);
+     }
+ 
+     ret = folder -> p->a.imap_mbx.reference_count-1;
+ 
+     DPRINT(Debug,11,(&Debug,
+ 		     "mbx_give_message_count_imap=%d\n",ret));
+ 
+     return ret;
+ }
  
  
  struct folder_type imap_mbx = {
***************
*** 5646,5652 ****
  				mbx_update_prev_hdr_imap,
  				mbx_have_imap_quota,
  				mbx_give_imap_quotar_list,
! 				mbx_give_message_msize_imap
  };
  
  
--- 5676,5683 ----
  				mbx_update_prev_hdr_imap,
  				mbx_have_imap_quota,
  				mbx_give_imap_quotar_list,
! 				mbx_give_message_msize_imap,
! 				mbx_give_message_count_imap
  };
  
  
Index: elmME+.2.5.alpha64-cvs/lib/mbox/imap_quota.c
*** elmME+.2.5.alpha63/lib/mbox/imap_quota.c	Wed Jun 16 20:17:54 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/imap_quota.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: imap_quota.c,v 2.2 2021/06/13 16:13:58 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.2 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: imap_quota.c,v 2.3 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.3 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
***************
*** 137,142 ****
--- 137,143 ----
      struct quotaroot_name {
  	struct string     * name;
  	char              * given_name;
+ 	enum quota_mode     refresh;
      }              * quotaroot_name_list;
      size_t           quotaroot_name_count;   
      
***************
*** 280,286 ****
  {
      struct mail_quotaroot *ret = NULL;
      const char * given_name = NULL;
! 
      
      DPRINT(Debug,15,(&Debug, 
                       "mq_listitem_mqrl_imap: mq=%p, mqrl=%p, idx=%zu, cd=%p\n",
--- 281,287 ----
  {
      struct mail_quotaroot *ret = NULL;
      const char * given_name = NULL;
!     enum quota_mode refresh UNUSED_VAROK = quotam_normal; 
      
      DPRINT(Debug,15,(&Debug, 
                       "mq_listitem_mqrl_imap: mq=%p, mqrl=%p, idx=%zu, cd=%p\n",
***************
*** 296,360 ****
  
      given_name = mqrl->p.imap->quotaroot_name_list[idx].given_name;
  
!     if (given_name) {
      
! 	ret = ref_mail_quotaroot(mq,given_name);
  
! 	if (ret)
! 	    inc_mail_quotaroot_refcount(ret);
! 	else {
! 	    struct connection_cache *con;
! 	    
! 	    if (MQUOTA_IMAP_magic != mq->p.imap->magic)
! 		panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 		      "Bad magic number (mquota_imap)",0);
! 	    
! 	    con = mq->p.imap->con;
  	    
! 	    if (con) {
! 		
! 		if (con->type != &IMAP_connection) {
! 		    panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 			  "Wrong type connection attached to folder",0);
! 		}
! 		
! 		if (mq != con->quota)
! 		    panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 			  "mail_quota mismatch",0);
  		
! 		if (start_imap_command_c(con,"GETQUOTA",cd)) {
! 		    imap_states res;
  		    
! 		    imap_command_push_astring(con,given_name);
! 
! 		    end_imap_command(con);
! 		    if (imap_command_ok_c(con,&res,NULL,cd)) {
! 			
! 			ret = ref_mail_quotaroot(mq,given_name);
  			
! 			if (ret)
! 			    inc_mail_quotaroot_refcount(ret);
! 			else {
! 			    DPRINT(Debug,15,(&Debug, 
! 					     "mq_listitem_mqrl_imap: GETQUOTA did not returned quota root resources?\n"));
  			}
! 		    } else {
! 			DPRINT(Debug,15,(&Debug, 
! 					 "mq_listitem_mqrl_imap: GETQUOTA failed ot canceled?\n"));
! 		    }
! 		    
! 		}
  		
! 		if (!imap_clear_command_c(con,cd)) {
! 		    DPRINT(Debug,11,(&Debug,
! 				     "mq_listitem_mqrl_imap: OOPS failure on clear command (canceled?)\n"));
! 		}
! 	    }	 
  	}
      }
      
      DPRINT(Debug,15,(&Debug, 
!                      "mq_listitem_mqrl_imap=\n"));
      if (ret) {
  	DPRINT(Debug,15,(&Debug,"%p",ret));
      } else {
--- 297,386 ----
  
      given_name = mqrl->p.imap->quotaroot_name_list[idx].given_name;
  
!     refresh    = mqrl->p.imap->quotaroot_name_list[idx].refresh;
!     /* Refresh only once */
!     mqrl->p.imap->quotaroot_name_list[idx].refresh = quotam_normal;
      
!     if (given_name) {
  
! 	DPRINT(Debug,15,(&Debug, 
! 			 "mq_listitem_mqrl_imap: given_name=%s refresh=%d",
! 			 given_name,refresh));
! 	switch (refresh) {
! 	case quotam_normal:     DPRINT(Debug,15,(&Debug," quotam_normal"));  break;
! 	case quotam_refresh:    DPRINT(Debug,15,(&Debug," quotam_refresh")); break;
! 	}
! 	DPRINT(Debug,15,(&Debug,"\n"));
! 
! 	switch (refresh) {
! 	case quotam_normal: 
! 
! 	    /* does not increment refcount */
! 	    ret = ref_mail_quotaroot(mq,given_name);
  	    
! 	    if (ret)
! 		inc_mail_quotaroot_refcount(ret);
! 	    else {
! 		struct connection_cache *con;
  		
! 		case quotam_refresh: 
  		    
! 		    if (MQUOTA_IMAP_magic != mq->p.imap->magic)
! 			panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 			      "Bad magic number (mquota_imap)",0);
! 		    
! 		    con = mq->p.imap->con;
! 		    
! 		    if (con) {
  			
! 			if (con->type != &IMAP_connection) {
! 			    panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 				  "Wrong type connection attached to folder",0);
  			}
! 			
! 			if (mq != con->quota)
! 			    panic("MBX PANIC",__FILE__,__LINE__,"mq_listitem_mqrl_imap",
! 				  "mail_quota mismatch",0);
  		
! 			if (start_imap_command_c(con,"GETQUOTA",cd)) {
! 			    imap_states res;
! 			    
! 			    imap_command_push_astring(con,given_name);
! 			    
! 			    end_imap_command(con);
! 			    if (imap_command_ok_c(con,&res,NULL,cd)) {
! 
! 				/* does not increment refcount */
! 				ret = ref_mail_quotaroot(mq,given_name);
! 				
! 				if (ret)
! 				    inc_mail_quotaroot_refcount(ret);
! 				else {
! 				    DPRINT(Debug,15,(&Debug, 
! 						     "mq_listitem_mqrl_imap: GETQUOTA did not returned quota root resources?\n"));
! 				}
! 			    } else {
! 				DPRINT(Debug,15,(&Debug, 
! 					 "mq_listitem_mqrl_imap: GETQUOTA failed ot canceled?\n"));
! 			    }
! 			    
! 			}
! 			
! 			if (!imap_clear_command_c(con,cd)) {
! 			    DPRINT(Debug,11,(&Debug,
! 					     "mq_listitem_mqrl_imap: OOPS failure on clear command (canceled?)\n"));
! 			}
! 		    }	 
! 	    }
! 	    break;
  	}
+     } else {
+ 	DPRINT(Debug,15,(&Debug, 
+ 			 "mq_listitem_mqrl_imap: No given_nane\n"));
      }
      
      DPRINT(Debug,15,(&Debug, 
!                      "mq_listitem_mqrl_imap="));
      if (ret) {
  	DPRINT(Debug,15,(&Debug,"%p",ret));
      } else {
***************
*** 365,370 ****
--- 391,426 ----
      return ret;
  }
  
+ S_(mq_quotarootl_refresh mq_refresh_mqrl_imap)
+ static void mq_refresh_mqrl_imap  P_((struct mail_quota *mq,
+ 				      struct mail_quotaroot_list *mqrl,
+ 				      enum quota_mode refresh));
+ static void mq_refresh_mqrl_imap(mq,mqrl,refresh)
+      struct mail_quota *mq;
+      struct mail_quotaroot_list *mqrl;
+      enum quota_mode refresh;
+ {
+     size_t idx;
+     
+     DPRINT(Debug,15,(&Debug, 
+                      "mq_refresh_mqrl_imap: mq=%p, mqrl=%p, refresh=%d",
+ 		     mq,mqrl,refresh));
+     
+     switch (refresh) {
+     case quotam_normal:     DPRINT(Debug,15,(&Debug," quotam_normal"));  break;
+     case quotam_refresh:    DPRINT(Debug,15,(&Debug," quotam_refresh")); break;
+     }
+     DPRINT(Debug,15,(&Debug,"\n"));
+     
+     if (MQRL_IMAP_magic != mqrl->p.imap->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mq_refresh_mqrl_imap",
+ 	      "Bad magic number (mqrl_imap)",0);
+ 
+     for (idx = 0; idx < mqrl->p.imap->quotaroot_name_count; idx++) {
+ 	mqrl->p.imap->quotaroot_name_list[idx].refresh = refresh;
+     }
+ }
+ 
  #define MQR_IMAP_magic		0xF531
  
  struct mqr_imap {
***************
*** 737,742 ****
--- 793,799 ----
  
      mq_listlen_mqrl_imap,
      mq_listitem_mqrl_imap,
+     mq_refresh_mqrl_imap,
  
      /* struct mail_quotaroot */
  
***************
*** 759,765 ****
      mq_unlink_con_imap
  };
  
! /* given_name may be NULL */
  static struct mail_quotaroot *ref_mail_quotaroot(mq,given_name)
       struct mail_quota * mq;
       const char * given_name;
--- 816,822 ----
      mq_unlink_con_imap
  };
  
! /* given_name may be NULL -- does not increment refcount */
  static struct mail_quotaroot *ref_mail_quotaroot(mq,given_name)
       struct mail_quota * mq;
       const char * given_name;
***************
*** 964,969 ****
--- 1021,1028 ----
  		ret->p.imap->quotaroot_name_list[t].name       = NULL;
  		ret->p.imap->quotaroot_name_list[t].given_name = NULL;
  	    }
+ 	    ret->p.imap->quotaroot_name_list[t].refresh = quotam_normal;
+ 
  	}
  	ret->p.imap->quotaroot_name_count = t;	   
      }   
***************
*** 1083,1093 ****
  	panic("MBX PANIC",__FILE__,__LINE__,"ref_mqr_imap",
  	      "Bad magic number (mail_quota)",0);
      
!     /* Allow NULL name->str */
      quotaroot = ref_mail_quotaroot(mq,name->str);
  
      if (quotaroot) {
! 
  	if (MAIL_QUOTAROOT_magic != quotaroot->magic)
  	    panic("MBX PANIC",__FILE__,__LINE__,"ref_mqr_imap",
  		  "Bad magic number (mail_quotaroot)",0);
--- 1142,1153 ----
  	panic("MBX PANIC",__FILE__,__LINE__,"ref_mqr_imap",
  	      "Bad magic number (mail_quota)",0);
      
!     /* Allow NULL name->str --  does not increment refcount */
      quotaroot = ref_mail_quotaroot(mq,name->str);
  
      if (quotaroot) {
! 	inc_mail_quotaroot_refcount(quotaroot);
! 	
  	if (MAIL_QUOTAROOT_magic != quotaroot->magic)
  	    panic("MBX PANIC",__FILE__,__LINE__,"ref_mqr_imap",
  		  "Bad magic number (mail_quotaroot)",0);
***************
*** 1155,1166 ****
  	if (quotaroot->name)
  	    DPRINT(Debug,20,(&Debug,"; name=%S",
  			     quotaroot->name));
! 
  	free_mail_quotaroot(&quotaroot);
      }
      
-     DPRINT(Debug,20,(&Debug,"\n"));
-     
      return ret;
  }
  
--- 1215,1227 ----
  	if (quotaroot->name)
  	    DPRINT(Debug,20,(&Debug,"; name=%S",
  			     quotaroot->name));
! 	DPRINT(Debug,20,(&Debug,"\n"));
! 	
  	free_mail_quotaroot(&quotaroot);
+     } else {    
+ 	DPRINT(Debug,20,(&Debug,"\n"));
      }
      
      return ret;
  }
  
***************
*** 1311,1323 ****
  	}
      }
  
      qrlist = give_quotaroot_list(quota,&(quotaroot_params[1]),quotaroot_param_count-1);
  
      folqroot =  ref_folder_quotaroot(mquota,&(quotaroot_params[0]));
  
!     if (folqroot->quotaroot_list)
  	free_mail_quotaroot_list(&  (folqroot->quotaroot_list));
! 
      folqroot->quotaroot_list = qrlist;
  
   cleanup: ;
--- 1372,1388 ----
  	}
      }
  
+     /* Increments refcount */
      qrlist = give_quotaroot_list(quota,&(quotaroot_params[1]),quotaroot_param_count-1);
  
      folqroot =  ref_folder_quotaroot(mquota,&(quotaroot_params[0]));
  
!     if (folqroot->quotaroot_list) {
! 		    
  	free_mail_quotaroot_list(&  (folqroot->quotaroot_list));
! 	
!     }
! 	
      folqroot->quotaroot_list = qrlist;
  
   cleanup: ;
***************
*** 1664,1681 ****
  
  
  E_(mbx_give_folder_quotar_list mbx_give_imap_quotar_list)
! struct mail_quotaroot_list * mbx_give_imap_quotar_list(folder,mq,cd)
       struct folder_info  * folder;
       struct mail_quota   * mq; 
       struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
  {
      struct mail_quotaroot_list * ret = NULL;
      struct string              * folder_name = NULL;
  
      DPRINT(Debug,11,(&Debug, 
! 		     "mbx_give_imap_quotar_list: folder=%p (%s)\n",
  		     folder,folder->cur_folder_sys));
!     
      if (PRIVATE_DATA_magic != folder->p->magic) 
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_imap_quotar_list",
  	      "Bad magic number (private_data)",0);
--- 1729,1755 ----
  
  
  E_(mbx_give_folder_quotar_list mbx_give_imap_quotar_list)
! struct mail_quotaroot_list * mbx_give_imap_quotar_list(folder,mq,cd,refresh)
       struct folder_info  * folder;
       struct mail_quota   * mq; 
       struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
+      enum quota_mode      refresh;
  {
      struct mail_quotaroot_list * ret = NULL;
      struct string              * folder_name = NULL;
  
      DPRINT(Debug,11,(&Debug, 
! 		     "mbx_give_imap_quotar_list: folder=%p (%s)",
  		     folder,folder->cur_folder_sys));
! 
!     DPRINT(Debug,11,(&Debug,
! 		     "; refresh=%d",refresh));
!     switch (refresh) {
!     case quotam_normal:     DPRINT(Debug,11,(&Debug," quotam_normal"));  break;
!     case quotam_refresh:    DPRINT(Debug,11,(&Debug," quotam_refresh")); break;
!     }
!     DPRINT(Debug,11,(&Debug,"\n"));
! 
      if (PRIVATE_DATA_magic != folder->p->magic) 
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_imap_quotar_list",
  	      "Bad magic number (private_data)",0);
***************
*** 1708,1749 ****
  	folder_name = conv_from_imap_name(folder->p->a.imap_mbx.folder);
      }
  
!     ret = folder_name_to_quote_root_list( mq->p.imap,folder_name);
!     if (ret) {
! 	inc_mail_quotaroot_list_refcount(ret);
!     } else {
! 	struct connection_cache *con =  folder->p->a.imap_mbx.Ch;
! 
! 	if (con->type != &IMAP_connection) {
! 	    panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_imap_quotar_list",
! 		  "Wrong type connection attached to folder",0);
! 	}
! 
! 	if (start_imap_command_c(con,"GETQUOTAROOT",cd)) {
! 	    imap_states res;
  	    
! 	    imap_command_push_astring(con,folder->p->a.imap_mbx.folder);
! 
! 	    end_imap_command(con);
! 	    if (imap_command_ok_c(con,&res,NULL,cd)) {
! 
! 		ret = folder_name_to_quote_root_list( mq->p.imap,folder_name);
! 		if (ret) {
! 		    inc_mail_quotaroot_list_refcount(ret);
! 		} else {
! 		    DPRINT(Debug,11,(&Debug, 
! 				     "mbx_give_imap_quotar_list: GETQUOTAROOT did not returned quota root list?\n"));
! 		}		
! 	    } else {
! 		DPRINT(Debug,11,(&Debug, 
! 				 "mbx_give_imap_quotar_list: GETQUOTAROOT failed or canceled\n"));
! 	    }
! 	}
  
! 	if (!imap_clear_command_c(con,cd)) {
! 	    DPRINT(Debug,11,(&Debug,
! 			     "mbx_give_imap_quotar_list: OOPS failure on clear command (canceled?)\n"));
  	}
      }
  	    
      free_string(&folder_name);
--- 1782,1831 ----
  	folder_name = conv_from_imap_name(folder->p->a.imap_mbx.folder);
      }
  
!     switch (refresh) {
!     case quotam_normal: 
!         ret = folder_name_to_quote_root_list( mq->p.imap,folder_name);
! 	if (ret) {
! 	    inc_mail_quotaroot_list_refcount(ret);
! 	} else {
! 	    struct connection_cache *con;
  	    
! 	    case quotam_refresh: 
! 		con =  folder->p->a.imap_mbx.Ch;
! 		
! 		if (con->type != &IMAP_connection) {
! 		    panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_imap_quotar_list",
! 			  "Wrong type connection attached to folder",0);
! 		}
! 		
! 		if (start_imap_command_c(con,"GETQUOTAROOT",cd)) {
! 		    imap_states res;
! 		    
! 		    imap_command_push_astring(con,folder->p->a.imap_mbx.folder);
! 		    
! 		    end_imap_command(con);
! 		    if (imap_command_ok_c(con,&res,NULL,cd)) {
! 			
! 			ret = folder_name_to_quote_root_list( mq->p.imap,folder_name);
! 			if (ret) {
! 			    inc_mail_quotaroot_list_refcount(ret);
! 			    
! 			} else {
! 			    DPRINT(Debug,11,(&Debug, 
! 					     "mbx_give_imap_quotar_list: GETQUOTAROOT did not returned quota root list?\n"));
! 			}		
! 		    } else {
! 			DPRINT(Debug,11,(&Debug, 
! 					 "mbx_give_imap_quotar_list: GETQUOTAROOT failed or canceled\n"));
! 		    }
! 		}
  
! 		if (!imap_clear_command_c(con,cd)) {
! 		    DPRINT(Debug,11,(&Debug,
! 				     "mbx_give_imap_quotar_list: OOPS failure on clear command (canceled?)\n"));
! 		}
  	}
+ 	break;
      }
  	    
      free_string(&folder_name);
Index: elmME+.2.5.alpha64-cvs/lib/mbox/init.c
*** elmME+.2.5.alpha63/lib/mbox/init.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/mbox/init.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: init.c,v 2.12 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.12 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: init.c,v 2.13 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.13 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 51,56 ****
--- 51,74 ----
  };
  #endif
  
+ static char *USE_LASTREAD[NUM_use_lastread+1] = {
+     "no",
+     "yes",
+     "auto",
+     "existing",
+     NULL
+ };
+ 
+ ENUMERATE use_last_read_file = {
+     use_lastread_auto,
+     NUM_use_lastread,
+     &(USE_LASTREAD[0]),
+     NULL,
+     1		/* allow boolean ON, OFF, TRUE, FALSE, YES and NO */,
+     NULL        /* not delayed */,
+     NULL
+ };
+ 
  ESTR user_map_dir_e = {            
      ESTR_meta|ESTR_slash,
      NULL,
***************
*** 65,70 ****
--- 83,112 ----
  struct editor_propline    * user_hash_marks_pl;
  struct hash_marks_conf    * user_hash_marks_conf;
  
+ FLAGS last_read_fbck_locking = {
+     /* Current value */
+     0L 
+ #ifdef USE_FLOCK_LOCKING
+     | FLAGVAL(lock_flock_flag)
+ #endif
+ #ifdef USE_FCNTL_LOCKING
+     | FLAGVAL(lock_fcntl_flag)
+ #endif
+     ,0L,0L,
+     NUM_mailbox_locking_v,&(MAILBOX_LOCKING[0]),
+ 
+     /* Allowed values */
+     FLAGVAL(lock_prefer_flag)
+ #ifdef COMPILE_FLOCK_LOCKING
+     | FLAGVAL(lock_flock_flag)
+ #endif
+ #ifdef COMPILE_FCNTL_LOCKING
+     | FLAGVAL(lock_fcntl_flag)
+ #endif
+     , 1,NULL
+ };
+ 
+ 
  static ZZZ_SAVE_TYPE mbox_info_data[] = {
  	
      {"editor-hm-propline",   ZZZ_DT_ENUM(&editor_hm_propline), ZZZ_TAIL },
***************
*** 73,78 ****
--- 115,124 ----
      {"editor-usermap-propline",   ZZZ_DT_ENUM(&editor_usermap_propline), ZZZ_TAIL },
  #endif
  
+     {"last-read-fallback-locking",ZZZ_DT_FLAGS(&last_read_fbck_locking),  ZZZ_TAIL },
+     
+     {"use-last-read-file",   ZZZ_DT_ENUM(&use_last_read_file), ZZZ_TAIL },
+     
  #if 0	/* NOT USED -- use register_hidden_library() instead */
  #ifdef USE_DLOPEN
      {"use-mbox-library",    ZZZ_DT_SHARED(&use_shared_mbox), 0 },
***************
*** 183,191 ****
--- 229,248 ----
      register_list(&use_shared_mbox);
  #endif
  
+     /* System files */
+     
      add_init_default_hook(&init_hashmark_defaults);
+     add_init_default_hook(&init_last_read_defaults);
+ 
+     /* User files */
+     
      add_read_rc_file_hook(&hashmark_read_rc_file);
+     add_read_rc_file_hook(&last_read_rc_file);
+ 
+     /* cleanup */
+     
      add_free_rc_hook(&free_hashmark_rc_file);
+     add_free_rc_hook(&free_last_read);
  }
  
  
Index: elmME+.2.5.alpha64-cvs/lib/mbox/last_read.c
*** /tmp/5689-very-long-file-name/NULL-5689-comes-in-here--XXXXXXXXX	Sat Jun 29 18:42:35 2024
--- elmME+.2.5.alpha64-cvs/lib/mbox/last_read.c	Mon Jun 10 21:05:34 2024
***************
*** 0 ****
--- 1,5493 ----
+ static char rcsid[] = "@(#)$Id: last_read.c,v 2.1 2024/06/10 18:05:34 hurtta Exp $";
+ 
+ /************************************************************************
+  *  The Elm (ME+) Mail System  -  $Revision: 2.1 $   $State: Exp $
+  *
+  *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
+  *      or  Kari Hurtta <elm@elmme-mailer.org>
+  ************************************************************************/
+ 
+ #include "def_mbox.h"
+ #include "mbxlocal_imp.h"
+ #include "s_me.h"
+ 
+ #include "commentfile.h"
+ #include "filelock.h"
+ 
+ DEBUG_VAR(Debug,__FILE__,"file");
+ 
+ #if ANSI_C
+ #define S_(x) static x;
+ #else
+ #define S_(x)
+ #endif
+ 
+ static const unsigned char * cs2us P_((const char *str));
+ static const unsigned char * cs2us(str)
+      const char *str;
+ {
+     return (unsigned char *)str;
+ }
+ 
+ #define LAST_READ_CACHE_magic	0xFA0A
+ 
+ /*  File .elm-last-read-{uid} */
+ static struct last_read_cache {
+     unsigned short               magic;   /* LAST_READ_CACHE_magic */
+ 
+     int                       refcount;
+     
+     char * sys_dir;             /* NULL, if fallback file
+ 				   ~/.elm/last.read
+ 				*/
+ 
+     struct string_sort * cached_name; /* helper for sortlist functions */
+ 
+     
+     char * cache_file_name;  
+     
+     /* Store only inode number if st_dev is same than on cache 
+        cache_file.dev is implied
+      */
+     struct file_changes      cache_file;
+     
+     struct sortlist * entries;
+ 
+ 
+     unsigned modified:    1; /* Need write when
+ 				flush_last_read()
+ 				is called 
+ 			     */
+     unsigned read:    1;    /* Read from file */
+ 
+ } * malloc_last_read_cache P_((const char                 * sys_dir,
+ 			       const struct stat          * st,
+ 			       size_t                       prealloc,
+ 			       const struct file_changes  * fchanges,
+ 			       const char                 * filename
+ 			       ));
+ 
+ static void inc_last_read_cache_refcount P_((struct last_read_cache * cache));
+ 
+ #define LAST_READ_CACHE_DEF_magic	0xFA0C
+ 
+ static const struct last_read_cache_def {
+     unsigned short   magic; /* LAST_READ_CACHE_DEF_magic */
+     
+     const struct stat         * st;
+     size_t                      prealloc;
+     const struct file_changes * fchanges;
+     const char                * cache_file_name;
+ } NULL_last_read_cache_def = {
+     LAST_READ_CACHE_DEF_magic,
+     NULL,
+     0,
+     NULL,
+     NULL
+ };
+ 
+ 
+ #define LAST_READ_ENTRY_magic	0xFA0B
+ 
+ enum LAST_READ_bits {
+     LAST_READ_bit_have_st_ino,  /* Have inode number */
+     LAST_READ_bit_modified,     /* entry modified - do no read
+ 				 from .elm-last-read-{uid}
+ 			        */
+     LAST_READ_bit_flag,         /* entry flagged - found
+ 				   from directory listing
+ 				*/
+     LAST_READ_bit_delete,       /* entry marked for delete -
+ 				   not written -
+ 				   deleted after write
+ 				*/
+ 
+     LAST_READ_bit_old,
+ 
+     LAST_READ_bit_valid,        /* if not set, entry not set yet */
+ 
+     
+     LAST_READ_bit_purge,        /* entry marked for delete
+ 				   after read -- unmarked
+ 				   if seen on read
+ 				*/
+ 
+     LAST_READ_bit_memonly,      /* Not saved to disk */
+     
+     LAST_READ_bit_count
+ };
+ 
+ #define LAST_READ_have_st_ino  (1 << LAST_READ_bit_have_st_ino)  
+ #define LAST_READ_modified     (1 << LAST_READ_bit_modified)
+ #define LAST_READ_flag         (1 << LAST_READ_bit_flag)
+ #define LAST_READ_delete       (1 << LAST_READ_bit_delete)
+ #define LAST_READ_old          (1 << LAST_READ_bit_old)
+ #define LAST_READ_valid        (1 << LAST_READ_bit_valid)
+ #define LAST_READ_purge        (1 << LAST_READ_bit_purge)
+ #define LAST_READ_memonly      (1 << LAST_READ_bit_memonly)
+ 
+ 
+ #define LAST_READ_ENTRY_DEF_magic	0xFA0D
+ 
+ struct last_read_entry_def {
+     unsigned short               magic;   /* LAST_READ_ENTRY_DEF_magic */
+ 
+     unsigned entry_flags : LAST_READ_bit_count;
+ };
+ 
+ static struct last_read_entry {
+ 
+     unsigned short               magic; /* LAST_READ_ENTRY_magic */
+ 
+     int                       refcount;
+     
+     time_t   last_read;       /* Last read timestamp */
+     
+     /* Does not include path
+        if on same directory than
+        .elm-last-read-{uid} file
+     */
+     char               * folder_sys;
+     
+     struct string_sort * cached_name; /* helper for sortlist functions */
+     
+     ino_t     st_ino;         /* Inode number of folder */
+ 
+     unsigned entry_flags : LAST_READ_bit_count;
+ } * malloc_last_read_entry P_((const char                   * folder_sys,
+ 			       const struct last_read_entry_def * def
+ 			       ));
+ 
+ static struct last_read_entry * malloc_last_read_entry(folder_sys,def)
+      const char                       * folder_sys;
+      const struct last_read_entry_def * def;
+ {
+     struct last_read_entry * ret =
+ 	safe_zero_alloc(sizeof (*ret));
+ 
+     ret -> magic       =  LAST_READ_ENTRY_magic;
+ 
+     ret -> refcount    = 1;
+ 
+     ret -> last_read   = 0;
+ 
+     ret -> folder_sys  = safe_strdup(folder_sys);
+     ret -> cached_name = NULL;  /* Filled later */
+     
+     ret -> st_ino      = 0;
+ 
+     ret -> entry_flags = 0;
+ 
+     if (def) {
+ 	if (LAST_READ_ENTRY_DEF_magic != def->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "malloc_last_read_entry",
+ 		  "Bad magic number (last_read_entry_def)",0);
+ 
+ 	ret -> entry_flags = def->entry_flags;
+     }
+     
+     return ret;
+ }
+ 
+ 
+ static void free_last_read_entry P_((struct last_read_entry ** entry));
+ static void free_last_read_entry(entry)
+      struct last_read_entry ** entry;
+ {
+     if (LAST_READ_ENTRY_magic != (*entry)->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_entry",
+               "Bad magic type (last_read_entry)",0);
+ 
+     if ((*entry)->refcount < 1)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_entry",
+               "Bad refcount",0);
+ 
+     (*entry)->refcount--;
+ 
+     if ((*entry)->refcount > 0) {
+ 	(*entry) = NULL;
+ 
+ 	return;
+     }
+ 
+     if ((*entry)->folder_sys) {
+ 	free((*entry)->folder_sys);
+ 
+ 	(*entry)->folder_sys = NULL;	
+     }
+ 
+     if ((*entry)->cached_name)
+ 	free_string_sort(& ((*entry)->cached_name));
+ 
+     (*entry)->magic = 0; /* invalidate */
+     free(*entry);
+ 
+     *entry = NULL;
+ }
+ 
+ static void inc_last_read_entry_refcount P_((struct last_read_entry * entry));
+ static void inc_last_read_entry_refcount(entry)
+      struct last_read_entry * entry;
+ {
+     if (LAST_READ_ENTRY_magic != entry->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"inc_last_read_entry_refcount",
+               "Bad magic type (last_read_entry)",0);
+     
+     entry->refcount++;
+ }
+ 
+     
+ 
+ /* ------------------------------------------------------------------ */
+ 
+ S_(alloc_sort_item_f alloc_read_entry)
+ static void alloc_read_entry P_((union sort_item             * res,
+ 				 const union sort_key          key,
+ 				 const union sort_item_default def));
+ static void alloc_read_entry(res,key,def)
+      union sort_item             * res;
+      const union sort_key          key;
+      const union sort_item_default def;
+ {
+     res->last_read_entry =  malloc_last_read_entry(key.str,
+ 						   def.last_read_entry);     
+ }
+ 
+ S_(free_sort_item_f free_read_entry)
+ static void free_read_entry  P_((union sort_item      * ptr)); /* Decrements refcount */
+ static void free_read_entry(ptr)
+      union sort_item      * ptr;
+ {
+     free_last_read_entry(& (ptr->last_read_entry));     
+ }
+ 
+ S_(inc_sort_item_refcount_f inc_read_entry_refcount)
+ static void inc_read_entry_refcount P_((union sort_item item));
+ static void inc_read_entry_refcount(item)
+      union sort_item item;
+ {
+     inc_last_read_entry_refcount(item.last_read_entry);
+ }
+ 
+ S_(sort_item_debug_name_f read_entry_name)
+ static struct string * read_entry_name P_((const union sort_item item));
+ static struct string * read_entry_name(item)
+      const union sort_item item;
+ {
+     struct string          * ret   = NULL;
+     struct last_read_entry * entry = item.last_read_entry;
+     
+     if (LAST_READ_ENTRY_magic != entry->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"read_entry_name",
+               "Bad magic type (last_read_entry)",0);
+ 
+     if (entry->cached_name) {
+ 	/* Increments refcount */
+ 	ret = give_string_from_string_sort(entry->cached_name);
+     } else {
+ 	ret = new_string2(local_fs_charset,cs2us(entry->folder_sys));
+ 
+ 	/* Cache reference of string (increments refcount) */
+ 	entry->cached_name = new_string_sort(ret);
+     }
+ 
+     return ret;
+ }
+ 
+ S_(compare_sort_key_to_item_f cmp_key_read_entry)
+ static int cmp_key_read_entry P_((const union sort_key key,
+ 				  const union sort_item item));
+ static int cmp_key_read_entry(key,item)
+      const union sort_key key;
+      const union sort_item item;
+ {
+     int ret;
+ 
+     struct last_read_entry * entry = item.last_read_entry;
+ 
+     if (LAST_READ_ENTRY_magic != entry->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"cmp_key_read_entry",
+               "Bad magic type (last_read_entry)",0);
+ 
+     ret = strcmp(key.str,entry->folder_sys);
+ 
+     return ret;
+ }
+ 
+ S_(sort_key_debug_name_f read_entry_key_name)
+ static struct string * read_entry_key_name  P_((const union sort_key key));
+ static struct string * read_entry_key_name(key)
+      const union sort_key key;
+ {
+     struct string          * ret   = new_string2(local_fs_charset,
+ 						 cs2us(key.str));
+ 
+     return ret;
+ }
+ 
+ static  struct sort_operation last_read_entry_op = {
+     SORT_OPERATION_magic,
+ 
+     alloc_read_entry,
+     free_read_entry,
+     inc_read_entry_refcount,
+     read_entry_name,
+ 
+     cmp_key_read_entry,
+ 
+     read_entry_key_name
+ };
+ 
+ 
+ 
+ /* ------------------------------------------------------------------ */
+ 
+ S_(alloc_sort_item_f alloc_read_cache)
+ static void alloc_read_cache P_((union sort_item             * res,
+ 				 const union sort_key          key,
+ 				 const union sort_item_default def));
+ static void alloc_read_cache(res,key,def)
+      union sort_item             * res;
+      const union sort_key          key;
+      const union sort_item_default def;
+ {
+     const struct last_read_cache_def * X = def.last_read_cache;
+ 
+     if (LAST_READ_CACHE_DEF_magic != X->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"alloc_read_cache",
+               "Bad magic type (last_read_cache_def)",0);
+     
+     res->last_read_cache = malloc_last_read_cache(key.str,
+ 						  X->st,
+ 						  X->prealloc,
+ 						  X->fchanges,
+ 						  X->cache_file_name);
+ }
+ 
+ S_(free_sort_item_f free_read_cache)
+ static void free_read_cache  P_((union sort_item      * ptr)); /* Decrements refcount */
+ static void free_read_cache(ptr)
+      union sort_item      * ptr;
+ {
+     free_last_read_cache(& (ptr->last_read_cache));
+ }
+ 
+ S_(inc_sort_item_refcount_f inc_read_cache_refcount)
+ static void inc_read_cache_refcount P_((union sort_item item));
+ static void inc_read_cache_refcount(item)
+      union sort_item item;
+ {   
+     inc_last_read_cache_refcount(item.last_read_cache);
+ }
+ 
+ S_(sort_item_debug_name_f read_cache_name)
+ static struct string * read_cache_name P_((const union sort_item item));
+ static struct string * read_cache_name(item)
+      const union sort_item item;
+ {
+     struct string          * ret   = NULL;
+     struct last_read_cache * cache = item.last_read_cache;
+ 
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"read_cache_name",
+               "Bad magic type (last_read_cache)",0);
+ 
+     if (cache->cached_name) {
+ 	/* Increments refcount */
+ 	ret = give_string_from_string_sort(cache->cached_name);
+     } else {
+ 	ret = new_string2(local_fs_charset,cs2us(cache->sys_dir));
+ 
+ 	/* Cache reference of string (increments refcount) */
+ 	cache->cached_name = new_string_sort(ret);
+     }
+ 
+     return ret;
+ }
+ 
+ S_(compare_sort_key_to_item_f cmp_key_read_cache)
+ static int cmp_key_read_cache P_((const union sort_key key,
+ 				  const union sort_item item));
+ static int cmp_key_read_cache(key,item)
+      const union sort_key key;
+      const union sort_item item;
+ {
+     int ret;
+     
+     struct last_read_cache * cache = item.last_read_cache;
+ 
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__," cmp_key_read_cache",
+               "Bad magic type (last_read_cache)",0);
+ 
+     ret = strcmp(key.str,cache->sys_dir);
+ 
+     return ret;
+ }
+ 
+ S_(sort_key_debug_name_f read_cache_key_name)
+ static struct string * read_cache_key_name  P_((const union sort_key key));
+ static struct string * read_cache_key_name(key)
+      const union sort_key key;
+ {
+     struct string          * ret   = new_string2(local_fs_charset,
+ 						 cs2us(key.str));
+ 
+     return ret;
+ }
+ 
+ static  struct sort_operation last_read_cache_op = { 
+     SORT_OPERATION_magic,
+ 
+     alloc_read_cache,
+     free_read_cache,
+     inc_read_cache_refcount,
+     read_cache_name,
+ 
+     cmp_key_read_cache,
+ 
+     read_cache_key_name
+ };
+ 
+ 
+ /* ------------------------------------------------------------------ */
+ 
+ 
+ static const char LAST_READ_HEADER[] = "ELMME+ READ\n";
+ static const size_t LAST_READ_HEADER_len = (sizeof LAST_READ_HEADER) - 1;
+ 
+ #define NAME_LIMIT 2048
+ 
+ static int parse_last_read_cache P_((const char          * filename,
+ 				     FILE                * f,
+ 				     struct file_changes * cache_file,
+ 				     struct sortlist    ** cache_entries,
+ 				     int                 * errors,
+ 			 const struct last_read_entry_def * entry_default,
+ 				     int                 * suggest_rewrite
+ 				     ));
+ 
+ #if DEBUG
+ /* Returns pointer to static storage */
+ static char * give_entry_flags P_((unsigned entry_flags));
+ static char * give_entry_flags(entry_flags)
+      unsigned entry_flags;
+ {
+     static char buffer[25*LAST_READ_bit_count];
+ 
+     enum LAST_READ_bits b;
+ 
+     if (!entry_flags)
+ 	return "none";
+ 
+     buffer[0] = '\0';
+     buffer[1] = '\0'; /* In case there is unknown bits set */
+ 
+     for (b = 0; b < LAST_READ_bit_count; b++) {
+ 	if (ison(entry_flags,(1 << b))) {
+ 	    switch (b) {
+ 	    case LAST_READ_bit_have_st_ino:
+ 		strfcat(buffer," LAST_READ_have_st_ino", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_modified:
+ 		strfcat(buffer," LAST_READ_modified", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_flag:
+ 		strfcat(buffer," LAST_READ_flag", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_delete:
+ 		strfcat(buffer," LAST_READ_delete", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_old:
+ 		strfcat(buffer," LAST_READ_old", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_valid:
+ 		strfcat(buffer," LAST_READ_valid", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_purge:
+ 		strfcat(buffer," LAST_READ_purge", sizeof buffer);
+ 		break;
+ 	    case LAST_READ_bit_memonly:
+ 		strfcat(buffer," LAST_READ_memonly", sizeof buffer);
+ 		break;
+ 	    case  LAST_READ_bit_count:
+ 		break;
+ 	    }
+ 	}
+     }
+     
+     return buffer+1;
+ }
+ #endif
+ 
+ static int stat_last_read_cache P_((const char          * filename,
+ 				    FILE                * f,
+ 				    struct file_changes * cache_file));
+ 
+ static int stat_last_read_cache(filename,f,cache_file)
+      const char          * filename;
+      FILE                * f;
+      struct file_changes * cache_file;
+ {
+     int ret = 1;
+     
+     enum syscall_status  r_stat;
+     struct stat          stat_buffer;
+     int            fd = fileno(f);
+     
+     r_stat = fstat(fileno(f),&stat_buffer);
+     switch (r_stat) {
+ 	int err UNUSED_VAROK;
+ 	char *X;
+     case syscall_success:
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "stat_last_read_cache: fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
+ 			 fd,filename,
+ 			 (unsigned long)stat_buffer.st_dev,
+ 			 (unsigned long)stat_buffer.st_ino,
+ 			 (long)stat_buffer.st_size,
+ 			 (long)stat_buffer.st_mtime));
+ 	X = ctime(& (stat_buffer.st_mtime));
+ 	if (X) { /* ctime() includes newline */
+ 	    DPRINT(Debug,14,(&Debug," -- %s",X));
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,"\n"));
+ 	}
+ 	
+ 	stat_to_file_changes(&stat_buffer,cache_file);
+ 	break;
+     case syscall_error:
+ 	err = errno;
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "stat_last_read_cache: fstat %d: %s failed: %s\n",
+ 			 fd,filename,strerror(err)));
+ 	ret = 0;
+ 	break;
+     }		
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "stat_last_read_cache=%d; filename %s, fileno %d\n",
+ 		     ret,filename,fd));
+ 
+     return ret;
+ }
+ 
+ static int parse_last_read_cache(filename,f,cache_file,
+ 				cache_entries,errors,entry_default,
+ 				suggest_rewrite)
+      const char          * filename;
+      FILE                * f;
+      struct file_changes * cache_file;
+      struct sortlist    ** cache_entries;
+      int                 * errors;
+      const struct last_read_entry_def * entry_default;
+      int                 * suggest_rewrite;
+ {
+     
+     char buffer[100];
+     int lineno = 1;
+     int c;
+     int corrupt_note = 0;
+     size_t idx = 0;  /* append mode position */
+     size_t cache_len = 0;
+ 
+     char * entry_name = NULL;
+     size_t entry_name_alloced = 0;
+     int ret = 0;
+     long pos = 0;
+ 
+     /* Assumed to be unsigned */
+     ino_t MAX_ino     = ~(ino_t)0;
+     time_t now = time(NULL);
+     
+     
+     if (((time_t) -1) == now) {
+ 	int err UNUSED_VAROK = errno;
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: time() failed: %s\n",
+ 			 strerror(err)));
+ 
+     }
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "parse_last_read_cache:  MAX_ino = %lu (unsigned assumed)\n",
+ 		     (unsigned long)MAX_ino));
+ 
+     
+     
+     if ((ret = mail_gets(buffer, sizeof buffer,f)) > 0) {
+ 	if (ret != LAST_READ_HEADER_len || 0 != memcmp(buffer,LAST_READ_HEADER,
+ 						       LAST_READ_HEADER_len)) {
+ 	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
+ 			      "File %s is corrupted."),
+ 		      filename);
+ 	    
+ 	    if (errors)
+ 		(* errors)++;
+ 	    
+ 	    return 0;
+ 	}
+ 	lineno++;  /* mail_gets() reads whole line */
+     }
+ 
+ 
+ 
+     /* skip comment block */
+     pos = ftell(f);
+     c = fgetc(f);
+     if (EOF != c) {
+ 
+ 	if ('#' == c || '\n' == c) {
+ 
+ 	    int lines = 0;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: Skipping comment block from offset %ld at %s\n",
+ 			     pos,filename));
+ 	
+ 	    while ('#' == c || '\n' == c) {
+ 		lines++;
+ 		
+ 		while (EOF != c && '\n' != c) {
+ 		    c = fgetc(f);
+ 		}
+ 		
+ 		if ('\n' == c) {
+ 		    lineno++;
+ 
+ 		    pos = ftell(f);
+ 		    c = fgetc(f);
+ 		} else
+ 		    break;
+ 	    }
+ 
+ 	    if (lines) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: Skipped %d lines (last line offset %ld)\n",
+ 				 filename,lines,pos));
+ 	    }
+ 	    
+ 	}
+ 
+ 	if (EOF != c)
+ 	    ungetc(c,f);	
+     }
+ 
+     if (EOF == c) {
+ 	pos = ftell(f);
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: File %s do not have entries, offset %ld\n",
+ 			 filename,pos));
+     }
+ 
+     if (* cache_entries) {
+ 	size_t i;
+ 	
+ 	cache_len = sort_list_len(* cache_entries);
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: %zu items on cache_entries already\n",
+ 			 cache_len));
+ 
+ 	for (i = 0; i < cache_len; i++) {
+ 
+ 	    union sort_item res;
+ 
+ 	    res.last_read_entry = NULL;
+ 
+ 	    /* Increments refcount */
+ 	    get_sort_list_item(* cache_entries,sort_list_get_normal,i,
+ 			       &res);
+ 
+ 	    if (res.last_read_entry) {
+ 		struct last_read_entry * entry;
+ 		
+ 		if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,
+ 			  "parse_last_read_cache",
+ 			  "Bad magic type (last_read_entry)",0);
+ 
+ 		entry = res.last_read_entry;
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: entry %zu = %Q",
+ 				 i,entry->folder_sys));
+ 
+ 		if (ison(entry->entry_flags,LAST_READ_have_st_ino)) {
+ 
+ 		    DPRINT(Debug,14,(&Debug,", st_ino=%lu",
+ 				     (unsigned long)(entry->st_ino)));
+ 		}
+ 
+ 		if (entry->entry_flags) {
+ 		    DPRINT(Debug,14,(&Debug,", entry_flags=%u %s",
+ 				     entry->entry_flags,
+ 				     give_entry_flags(entry->entry_flags)
+ 				     ));
+ 
+ 		}
+ 
+ 		/* Delete if not seen on read */
+ 		
+ 		if (isoff(entry->entry_flags,LAST_READ_delete) &&
+ 		    isoff(entry->entry_flags,LAST_READ_modified) &&
+ 		    isoff(entry->entry_flags,LAST_READ_memonly))
+ 		    setit(entry->entry_flags,LAST_READ_purge);
+ 		
+ 		if (entry->last_read > 0) {
+ 		    char * X;
+ 		    
+ 		    DPRINT(Debug,14,(&Debug,", last_read=%ld",
+ 				     (long)(entry->last_read)));
+ 
+ 		    X = ctime(&(entry->last_read));
+ 
+ 		    /* ctime() includes newline \n to result */
+ 		    if (X) {
+ 			DPRINT(Debug,14,(&Debug," %s",
+ 					 X));
+ 		    } else {
+ 			DPRINT(Debug,14,(&Debug,"\n"));
+ 		    }		    
+ 		} else {
+ 			DPRINT(Debug,14,(&Debug,"\n"));
+ 		}
+ 		
+ 		free_last_read_entry(& res.last_read_entry);
+ 	    }	   
+ 	}
+     } else {
+ 	size_t count = 0;
+ 	int last_c = '\n';
+ 	enum syscall_status r;
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: Creating cache_entries, counting entries from offset %ld at %s\n",
+ 			 pos,filename));
+ 	
+ 	while (EOF != (c = fgetc(f))) {
+ 	    if (c == '\n')
+ 		count++;
+ 	    last_c = c;
+ 	}
+ 
+ 	if ('\n' != last_c) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: Last character was not newline\n"));
+ 	    count ++;
+ 	}
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: Creating cache_entries, count=%zu of %s\n",
+ 			 count,filename));
+ 
+ 	* cache_entries = alloc_sort_list(&last_read_entry_op,count);
+ 
+ 	r = fseek(f,pos,SEEK_SET);
+ 	switch (r) {
+ 	    int err UNUSED_VAROK;
+ 	case syscall_success:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: Reading again from offset %ld at %s\n",
+ 			     pos,filename));
+ 	    break;
+ 	case syscall_error:
+ 	    err = errno;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: Failed to seek to offset %ld at %s: %s\n",
+ 			     pos,filename,strerror(err)));
+ 
+ 	    if (errors)
+ 		(* errors)++;
+ 
+ 	    return 0;
+ 	}
+     }
+ 
+ 
+     entry_name_alloced = SLEN;
+     entry_name = safe_malloc(entry_name_alloced);
+     
+     while (EOF != (c = fgetc(f))) {
+ 
+ 	size_t entry_name_len = 0;
+ 	int q = 0;
+ 
+ 	union sort_key            key;
+ 	union sort_item           res;
+ 	union sort_item_default   def;
+ 
+ 	key.str             = NULL;  
+ 	def.last_read_entry = entry_default;
+ 	res.dummy           = NULL;
+ 	
+ 	if ('\n' == c) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: empty line\n",
+ 			     filename,lineno));
+ 
+ 	    lineno++;
+ 
+ 	    if (suggest_rewrite)
+ 		(*suggest_rewrite)++;
+ 	    
+ 	    break;
+ 	}
+ 
+ 	if (!c) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: NUL not allowed\n",
+ 			     filename,lineno));
+ 
+ 	    if (!corrupt_note) {
+ 	    
+ 		lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
+ 				  "File %s is corrupted."),
+ 			  filename);
+ 
+ 		if (errors)
+ 		    (* errors)++;
+ 		
+ 		corrupt_note = 1;
+ 	    }
+ 	    
+ 	    goto fail_line;
+ 	}
+ 
+ 	/* space or TAB */
+ 	if (whitespace(c)) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: no filename\n",
+ 			     filename,lineno));
+ 
+ 	    goto fail_line;
+ 	}
+ 
+ 	if ('#' == c) {  /* Ignore lines starting with # */
+ 
+ 	    
+ 	    goto end_line;
+ 	}
+ 	
+ 	if ('"' == c) {
+ 	    /*  " and \   are quoted -- filename with NL \n is not allowed 
+ 		end with "
+ 	    */
+ 
+ 	    q = 1;
+ 	} else {
+ 	    /* Filename but \  " or  NL \n is not allowed 
+ 	       end with whitespace
+ 	     */
+ 
+ 	    q = 0;
+ 
+ 	    entry_name[0]  = c;
+ 	    entry_name_len = 1;
+ 	}
+ 
+ 	while (EOF != c) {
+ 	    c = fgetc(f);
+ 	    
+ 	    if ('"' == c) {
+ 		if (q)
+ 		    break;
+ 
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: %c is not allowed\n",
+ 				 filename,lineno,c));
+ 		goto fail_line;
+ 	    }
+ 	    
+ 	    if (whitespace(c)) {
+ 		if (!q) {
+ 		    break;
+ 		}		
+ 	    }
+ 	    
+ 	    if ('\\' == c) {
+ 
+ 		if (q) {
+ 		    c = fgetc(f);
+ 
+ 		    if (EOF == c)
+ 			goto fail_line;
+ 		    
+ 		} else {
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "parse_last_read_cache: %s: %d: %c is not allowed\n",
+ 				     filename,lineno,c));
+ 		    goto fail_line;
+ 		}
+ 	    }
+ 
+ 	    if (!c) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: NUL not allowed\n",
+ 				 filename,lineno));
+ 		
+ 		if (!corrupt_note) {
+ 		    
+ 		    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
+ 				      "File %s is corrupted."),
+ 			      filename);
+ 		    
+ 		    if (errors)
+ 			(* errors)++;
+ 		    
+ 		    corrupt_note = 1;
+ 		}
+ 		
+ 		goto fail_line;
+ 	    } 
+ 
+ 	    if (entry_name_len > 0 &&
+ 		'/' == c && '/' != entry_name[0]) {
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: / is only allowed on absolute paths\n",
+ 				 filename,lineno));
+ 
+ 		goto fail_line;
+ 	    }
+ 			    
+ 	    if ('\n' == c) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: Unexpected NL\n",
+ 				 filename,lineno));
+ 		goto fail_line;
+ 	    }
+ 
+ 	    if (entry_name_len+1 >= entry_name_alloced &&
+ 		entry_name_alloced < (size_t)(NAME_LIMIT+1)) {
+ 
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: Expanding name buffer %zu => %d\n",
+ 				 filename,lineno,entry_name_alloced,NAME_LIMIT+1));
+ 		
+ 		entry_name_alloced = NAME_LIMIT+1;
+ 		entry_name = safe_realloc(entry_name,entry_name_alloced);
+ 	    }
+ 	    
+ 	    if (entry_name_len+1 >= entry_name_alloced) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: Too long name\n",
+ 				 filename,lineno));
+ 		goto fail_line;
+ 	    }
+ 	    entry_name[entry_name_len++] = c;
+ 	}
+ 
+ 	if (0 == entry_name_len) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: No name\n",
+ 			     filename,lineno));
+ 	    goto fail_line;
+ 	} else if (entry_name_len < entry_name_alloced) {
+ 	    entry_name[entry_name_len] = '\0';
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: Too long name\n",
+ 			     filename,lineno));
+ 	    goto fail_line;
+ 	}
+ 
+ 	if (q) {
+ 	    if ('"' != c) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: \" expected\n",
+ 				 filename,lineno));
+ 		goto fail_line;		 
+ 	    }
+ 	    c = fgetc(f);	    
+ 	}
+ 	
+ 	if (EOF == c)
+ 	    goto fail_line;
+ 
+ 	/* Not space or TAB */
+ 	if (! whitespace(c)) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: %Q: whitespace expected\n",
+ 			     filename,lineno,entry_name));
+ 	    goto fail_line;	
+ 	}
+ 	
+ 	key.str             = entry_name;
+ 	def.last_read_entry = entry_default;
+ 	res.dummy       = NULL;
+ 
+ 	/* Increments refcount, returns 1 if found or created */
+ 	if (search_sort_list_item(* cache_entries,
+ 				  sort_list_insert_hint /* append mode */,
+ 				  key,def,&res,&idx,
+ 				  suggest_rewrite)) {
+ 
+ 
+ 	    if (res.last_read_entry) {
+ 		struct last_read_entry * entry = res.last_read_entry;
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: %Q: found or created item %zu\n",
+ 				 filename,lineno,entry_name, idx));
+ 		
+ 
+ 		       				 
+ 		if (LAST_READ_ENTRY_magic != entry->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,"parse_last_read_cache",
+ 			  "Bad magic type (last_read_entry)",0);
+ 
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: #%zu folder_sys=%s",
+ 				 idx,entry->folder_sys));
+ 
+ 		if (entry->entry_flags) {		    
+ 		    DPRINT(Debug,14,(&Debug,", entry_flags=%u %s",
+ 				     entry->entry_flags,
+ 				     give_entry_flags(entry->entry_flags)
+ 				     ));
+ 		}
+ 
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 
+ 		/* Seen - do not delete after read */
+ 		clearit(entry->entry_flags,LAST_READ_purge);
+ 		
+ 		/* Format:
+ 
+ 		   filename ino time
+ 		*/
+ 
+ 		if (isoff(entry->entry_flags,LAST_READ_delete)) {
+ 
+ 		    unsigned entry_flags = 0;
+ 		    
+ 		    ino_t     st_ino     = 0;
+ 		    time_t    last_read  = 0;
+ 
+ 		    char comment[SLEN];
+ 		    int comment_len = 0;
+ 		    
+ 		    /* space or TAB */
+ 		    while (whitespace(c))
+ 			c = fgetc(f);
+ 
+ 		    /* - means no inode */
+ 		    
+ 		    if ('-' == c) {
+ 			
+ 			c = fgetc(f);
+ 			if ('0' <= c && c <= '9') {
+ 
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: %s: %d: %Q: %c is not allowed (negative inode)\n",
+ 					     filename,lineno,entry_name,c));
+ 			    
+ 			    if (suggest_rewrite)
+ 				(*suggest_rewrite)++;
+ 			    
+ 			    goto skip_line;
+ 
+ 			}
+   
+ 			
+ 		    } else if ('0' <= c && c <= '9') {
+ 			
+ 			while ('0' <= c && c <= '9') {
+ 
+ 			    /* st_ino assumed to be unsigned */
+ 			    
+ 			    if (st_ino >= MAX_ino/10 &&
+ 				MAX_ino > 0) {
+ 				DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: %s: %d: %Q: possible ino overflow\n",
+ 					     filename,lineno,entry_name));
+ 			    
+ 				if (suggest_rewrite)
+ 				    (*suggest_rewrite)++;
+ 				
+ 				goto skip_line;	
+ 			    }
+ 			    
+ 			    st_ino = st_ino * 10 + (c - '0');
+ 			    c = fgetc(f);	    
+ 			}
+ 
+ 			setit(entry_flags,LAST_READ_have_st_ino);
+ 			
+ 		    } else if (!c) {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "parse_last_read_cache: %s: %d: %Q: NUL not allowed\n",
+ 					 filename,lineno,entry_name));
+ 			
+ 			if (!corrupt_note) {
+ 			    
+ 			    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
+ 					      "File %s is corrupted."),
+ 			      filename);
+ 			    
+ 			    if (errors)
+ 				(* errors)++;
+ 			    
+ 			    corrupt_note = 1;
+ 			}
+ 
+ 			goto skip_line;
+ 		    } else {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "parse_last_read_cache: %s: %d: %Q: %c is not allowed\n",
+ 					 filename,lineno,entry_name,c));
+ 
+ 			if (suggest_rewrite)
+ 			    (*suggest_rewrite)++;
+ 			
+ 			goto skip_line;
+ 		    }
+ 
+ 		    /* then time - must be positive */
+ 
+ 		    if (! whitespace(c)) {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "parse_last_read_cache: %s: %d: %Q: whitespace expected\n",
+ 					 filename,lineno,entry_name));
+ 
+ 			if (suggest_rewrite)
+ 			    (*suggest_rewrite)++;
+ 			
+ 			goto skip_line;	
+ 		    }
+ 
+ 		    while (EOF != c && whitespace(c))
+ 			c = fgetc(f);
+ 
+ 		    while ('0' <= c && c <= '9') {
+ 			if (last_read >= time_MAX/10) {
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: %s: %d: %Q: possible time overflow\n",
+ 					     filename,lineno,entry_name));
+ 			    
+ 			    if (suggest_rewrite)
+ 				(*suggest_rewrite)++;
+ 			    
+ 			    goto skip_line;	
+ 			}
+ 
+ 			last_read = last_read * 10 + (c - '0');
+ 			c = fgetc(f);			
+ 		    }
+ 		    
+ 		    /* space or TAB */
+ 		    
+ 		    while (whitespace(c))
+ 			c = fgetc(f);
+ 		    
+ 		    if ('#' == c) {
+ 		        /* Ignore comment (#) on end of line */
+ 		    
+ 		        while (EOF != c && '\n' != c) {
+ 			    c = fgetc(f);
+ 
+ 			    if (comment_len+1 < sizeof comment) {
+ 				comment[comment_len++] = c;
+ 			    }
+ 			    
+ 			}
+ 		    }
+ 		    
+ 		    if ('\n' == c) {
+ 
+ 			int entry_same_file = 0;
+ 			
+ 			setit(entry_flags,LAST_READ_valid);
+ 			setit(entry_flags,LAST_READ_old);
+ 		       	
+ 			if (ison(entry->entry_flags,LAST_READ_valid)) {
+ 			    entry_same_file =
+ 				( isoff(entry->entry_flags,LAST_READ_have_st_ino) &&
+ 				  isoff(entry_flags,LAST_READ_have_st_ino) )
+ 				||
+ 				( ison(entry->entry_flags,LAST_READ_have_st_ino) &&
+ 				  ison(entry_flags,LAST_READ_have_st_ino) &&
+ 				  st_ino == entry->st_ino );			    
+ 			}
+ 
+ 			if ((time_t) -1 != now && last_read > now) {
+ 			    DPRINT(Debug,14,(&Debug,
+ 					    "parse_last_read_cache: %s: %d: %Q: %zu -- timestamp in future, last_read = %d > now = %d\n",
+ 					    filename,lineno,entry_name, idx,
+ 					    last_read,now));
+ 			    
+ 		        } else if (ison(entry->entry_flags,LAST_READ_old) ||
+ 				   isoff(entry->entry_flags,LAST_READ_valid) ||
+ 				   
+ 				   ( entry_same_file &&
+ 				     entry->last_read < last_read) ||
+ 				   
+ 				   ( isoff(entry->entry_flags,LAST_READ_modified) &&
+ 				     entry->last_read < last_read)
+ 				   ) {
+ 			    
+ 			    /* Update from disk */
+ 			    
+ 			    entry->entry_flags = entry_flags |
+ 				(  entry->entry_flags &
+ 				   LAST_READ_flag );
+ 
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: %s: %d: %Q: %zu -- %s",
+ 					     filename,lineno,entry_name, idx,
+ 					     ison(entry->entry_flags,LAST_READ_valid) ?
+ 					     "updating" : "setting"));
+ 
+ 			    if (ison(entry->entry_flags,LAST_READ_valid)) {
+ 				if (entry->last_read != last_read) {
+ 				    DPRINT(Debug,14,(&Debug, " last read = %d -> %d",
+ 						     entry->last_read,last_read));
+ 				}
+ 				
+ 				if (ison(entry_flags,LAST_READ_have_st_ino) &&
+ 				    entry->st_ino != st_ino) {
+ 				    DPRINT(Debug,14,(&Debug, " st_ino = %lu -> %lu",
+ 						     (unsigned long)entry->st_ino,
+ 						     (unsigned long)st_ino));
+ 				}
+ 			    } else {
+ 				DPRINT(Debug,14,(&Debug, " last read = %d",
+ 						 last_read));
+ 
+ 				if (ison(entry_flags,LAST_READ_have_st_ino)) {
+ 				    DPRINT(Debug,14,(&Debug, " st_ino = %lu",
+ 						     (unsigned long)st_ino));
+ 				}
+ 			    }
+ 
+ 			    if (comment_len > 0) {
+ 				comment[comment_len] = '\0';
+ 
+ 				DPRINT(Debug,14,(&Debug, " comment = %.*s",
+ 						 comment_len,comment));
+ 			    }
+ 			    
+ 			    DPRINT(Debug,14,(&Debug,"\n"));
+ 			    
+ 			    entry->last_read = last_read;
+ 			    entry->st_ino    = st_ino;
+ 			    
+ 			} else {
+ 			    
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: %s: %d: %Q: %zu -- skipping update from disk, %s\n",
+ 					     filename,lineno,entry_name, idx,
+ 					     entry_same_file ? "is same file" : "not same file"));
+ 			}
+ 				
+ 			/* lineno is incremented later */
+ 		    } else {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "parse_last_read_cache: %s: %d: %Q: newline expected\n",
+ 					 filename,lineno,entry_name));
+ 			
+ 			if (suggest_rewrite)
+ 			    (*suggest_rewrite)++;
+ 			
+ 			goto skip_line;	
+ 		    }
+ 		    		
+ 		} else {
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "parse_last_read_cache:  %s: %d: %Q: Skipping line\n",
+ 				     filename,lineno,entry_name));
+ 
+ 		skip_line:
+ 		    
+ 		    while (EOF != c && '\n' != c)
+ 			c = fgetc(f);
+ 
+ 		}
+ 		
+ 		/* Decrements refcount */
+ 		free_last_read_entry(& res.last_read_entry);
+ 		
+ 
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: %Q: search_sort_list_item did not set last_read_entry\n",
+ 				 filename,lineno,entry_name));
+ 		goto fail_line;
+ 	    }
+ 			    
+ 	} else {
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %d: %Q: search_sort_list_item failed to create item\n",
+ 			     filename,lineno,entry_name));
+ 			     
+ 	fail_line:
+ 	    if (suggest_rewrite)
+ 		(*suggest_rewrite)++;
+ 
+ 	end_line:
+ 	    while (EOF != c && '\n' != c)
+ 		c = fgetc(f);
+ 	}
+ 	    
+ 	switch (c) {
+ 	case EOF:
+ 	    
+ 	    if (feof(f)) {		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: Unexpect end of file\n",
+ 				 filename,lineno));
+ 	    }
+ 	    
+ 	    if (ferror(f)) {
+ 		int err UNUSED_VAROK = errno;
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "parse_last_read_cache: %s: %d: %s\n",
+ 				 filename,lineno,strerror(err)));		    
+ 	    }
+ 	    break;
+ 	    
+ 	case '\n':
+ 	    lineno++;
+ 	    break;
+ 	}	    
+     }
+     
+     if (entry_name) {
+ 	free(entry_name);
+ 	entry_name = NULL;
+     }
+     entry_name_alloced = 0;
+ 
+     if (cache_file) {
+ 
+ 	if (! stat_last_read_cache(filename,f,cache_file)) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: stat %s failed\n",
+ 			     filename));
+ 	    ret = 0;
+ 	    goto fail;
+ 	}	
+     }
+ 
+     cache_len = sort_list_len(* cache_entries);
+     
+     if (feof(f)) {
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: %s: %zu items\n",
+ 			 filename,cache_len));
+ 
+ 	if (cache_len > 0) {
+ 	    size_t i = cache_len -1;
+ 	    size_t deleted  = 0;
+ 	    size_t valid    = 0;
+ 	    size_t purge    = 0;
+ 	    size_t modified = 0;
+ 	    
+ 	    while (1) {
+ 		union sort_item res;
+ 
+ 		res.last_read_entry = NULL;
+ 		
+ 		/* Increments refcount */
+ 		get_sort_list_item(* cache_entries,sort_list_get_normal,i,
+ 				   &res);
+ 		
+ 		if (res.last_read_entry) {
+ 		    struct last_read_entry * entry;
+ 		    
+ 		    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 			panic("MBX PANIC",__FILE__,__LINE__,
+ 			      "parse_last_read_cache",
+ 			      "Bad magic type (last_read_entry)",0);
+ 		    
+ 		    entry = res.last_read_entry;
+ 
+ 		    if (ison(entry->entry_flags,LAST_READ_purge))
+ 			purge++;
+ 		    if (ison(entry->entry_flags,LAST_READ_valid))
+ 			valid++;
+ 		    if (ison(entry->entry_flags,LAST_READ_modified))
+ 			modified++;
+ 
+ 		    if (isoff(entry->entry_flags,LAST_READ_valid) ||
+ 			(ison(entry->entry_flags,LAST_READ_purge) &&
+ 			 isoff(entry->entry_flags,LAST_READ_modified))) {
+ 
+ 			free_last_read_entry(& res.last_read_entry);
+ 
+ 			/* Increments refcount */
+ 			get_sort_list_item(* cache_entries,sort_list_get_remove,i,
+ 					   &res);
+ 
+ 			if (res.last_read_entry) {
+ 			    struct last_read_entry * entry;
+ 			    
+ 			    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 				panic("MBX PANIC",__FILE__,__LINE__,
+ 				      "parse_last_read_cache",
+ 				      "Bad magic type (last_read_entry)",0);
+ 
+ 			    entry = res.last_read_entry;
+ 			    
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "parse_last_read_cache: #%zu folder_sys=%s - deleted\n",
+ 					     i,entry->folder_sys));
+ 			    
+ 			    
+ 			    deleted++;
+ 			}
+ 
+ 
+ 			
+ 		    } else
+ 			clearit(entry->entry_flags,LAST_READ_purge);
+ 		    
+ 		    if (res.last_read_entry) 
+ 			free_last_read_entry(& res.last_read_entry);
+ 		}	   
+ 
+ 		if (i > 0)
+ 		    i--;
+ 		else
+ 		    break;
+ 	    }
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "parse_last_read_cache: %s: %zu valid, %zu flagged purge, %zu modified items - %zu deleted.\n",
+ 			     filename,valid,purge,modified,deleted));	    
+ 	}
+ 	
+ 	ret = 1;
+     } else {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "parse_last_read_cache: %s: All items not readed\n",
+ 			 filename));
+     }
+ 
+  fail:
+     DPRINT(Debug,14,(&Debug,
+ 		     "parse_last_read_cache=%d\n",
+ 		     ret));
+     
+     return ret;
+ }
+ 
+ 
+ 
+ static enum quote_name_res {
+     quote_name_bad = -1   /* Bad name */,
+     quote_name_no  =  0   /* do not quote */,
+     quote_name_needed
+ 
+ } quote_name P_((const char *folder_sys));
+ static enum quote_name_res  quote_name(folder_sys)
+      const char *folder_sys;
+ {
+     const char * c;
+ 
+     enum quote_name_res ret = quote_name_no;
+     
+     
+     if (! folder_sys[0])
+ 	return quote_name_bad;
+ 
+     if ('#' == folder_sys[0])
+ 	ret = quote_name_needed;
+     
+     for (c = folder_sys; *c; c++) {
+ 
+ 	switch (*c) {
+ 
+ 	case '\n':
+ 	    return quote_name_bad;
+ 
+ 	case '"':
+ 	case '\\':
+ 	    ret = quote_name_needed;
+ 	    break;
+ 	   	    
+ 	case '\r':
+ 	    return quote_name_bad;
+ 
+ 	case '/':
+ 
+ 	    /* / is only allowed on absolute paths */
+ 	    
+ 	    if ('/' != folder_sys[0])
+ 		return quote_name_bad;
+ 
+ 	    break;
+ 	    
+ 	default:
+ 	    if (whitespace(*c))
+ 		ret = quote_name_needed;
+ 		
+ 	    break;	    
+ 	}
+ 
+ 	if (c - folder_sys >= NAME_LIMIT)
+ 	    return quote_name_bad;
+     }
+         
+     return ret;
+ }
+ 
+ 
+ /* This is written to temporary file */
+ static int dump_last_read_cache P_((FILE *f,
+ 				    const char          * filename /* temp file name */,
+ 				    struct file_changes * cache_file,
+ 				    struct sortlist     * cache_entries,
+ 				    int                 * errno_res,
+ 
+ 				    /* May be NULL */
+ 				    FILE *commentfile, 
+ 				    const char *actor,
+ 				    char *version_buff
+ 				    )); 
+ static int dump_last_read_cache(f,filename,cache_file,cache_entries,errno_res,
+ 				commentfile,actor,version_buff)
+      FILE *f;
+      const char          * filename /* temp file name */;
+      struct file_changes * cache_file;
+      struct sortlist     * cache_entries;
+      int                 * errno_res;
+      
+      /* May be NULL */
+      FILE                * commentfile; 
+      const char          * actor;
+      char                * version_buff;     
+ {
+     int ret = 0;
+     size_t cache_len = 0;
+     int r;
+     size_t z1;
+ 
+     static char actor1[SLEN]   = "";
+     static char version1[SLEN] = "";
+ 
+     if (actor && version_buff) {
+ 	strfcpy(actor1,actor,sizeof actor1);
+ 	strfcpy(version1,version_buff,sizeof version1);
+     } else if (actor1[0]) {   /* Sticky */
+ 	actor        = &(actor1[0]);
+ 	version_buff = &(version1[0]);
+     } 
+         
+     if (! cache_entries) {
+ 	ret = 0;
+ 
+ 	goto fail;
+     }
+     
+     cache_len = sort_list_len(cache_entries);
+     
+     if ((z1=fwrite(LAST_READ_HEADER,1, LAST_READ_HEADER_len,f)) <
+ 	LAST_READ_HEADER_len) {
+ 
+ 	if (ferror(f)) {
+ 	    int err = errno;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: fwrite failed: %s\n",
+ 			     filename,strerror(err)));
+ 	    
+ 	    lib_error(CATGETS(elm_msg_cat, MeSet,
+ 			      MeLastReadWriteTempFail,
+ 			      "Write failed for last-read temp file %s: %s"),
+ 		      filename,strerror(err));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: short fwrite = %zu < %zu\n",
+ 			     filename,z1,LAST_READ_HEADER_len));
+ 	}
+ 	
+ 	ret = 0;
+ 
+ 	goto fail;
+     }
+ 
+     /* commentfile,actor,version_buff may be NULL */
+     insert_commentfile(f,ELMLASTREAD_INFO,commentfile,
+ 		       actor,version_buff);
+     
+     if (cache_len > 0) {
+ 	size_t i;
+ 
+ 	size_t need_delete = 0;
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "dump_last_read_cache: %s: cache_len=%zu\n",
+ 			 filename,cache_len));
+ 	
+ 	for (i = 0; i < cache_len; i++) {
+ 	    
+ 	    union sort_item res;
+ 	    
+ 	    res.last_read_entry = NULL;
+ 	    
+ 	    /* Increments refcount */
+ 	    get_sort_list_item(cache_entries,sort_list_get_normal,i,
+ 			       &res);
+ 	    
+ 	    if (res.last_read_entry) {
+ 		struct last_read_entry * entry;
+ 		enum quote_name_res      q;
+ 		char * X;
+ 		
+ 		if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,
+ 			  "dump_last_read_cache",
+ 			  "Bad magic type (last_read_entry)",0);
+ 		
+ 		entry = res.last_read_entry;
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "dump_last_read_cache: entry %zu = %Q",
+ 				 i,entry->folder_sys));
+ 		
+ 		DPRINT(Debug,14,(&Debug,", entry_flags=%u %s",
+ 				 entry->entry_flags,
+ 				 give_entry_flags(entry->entry_flags)
+ 				 ));
+ 
+ 		if (ison(entry->entry_flags,
+ 			 LAST_READ_delete)) {
+ 		    need_delete++;
+ 		    
+ 		    DPRINT(Debug,14,(&Debug," -- delete, skipping\n"));
+ 		    goto skip_this_entry;
+ 		}
+ 				
+ 		if (isoff(entry->entry_flags,
+ 			  LAST_READ_valid)) {
+ 		    DPRINT(Debug,14,(&Debug," -- not valid, skipping\n"));
+ 		    goto skip_this_entry;
+ 		}
+ 		
+ 		if (ison(entry->entry_flags,
+ 			 LAST_READ_memonly)) {
+ 		    DPRINT(Debug,14,(&Debug," -- mem only, skipping\n"));
+ 		    goto skip_this_entry;
+ 		}
+ 		
+ 		q = quote_name(entry->folder_sys);
+ 		DPRINT(Debug,14,(&Debug," quote name = %d",
+ 				 q));
+ 		switch (q) {
+ 		case quote_name_bad:
+ 		    DPRINT(Debug,14,(&Debug," quote_name_bad"));    break;
+ 		case quote_name_no:
+ 		    DPRINT(Debug,14,(&Debug," quote_name_no"));     break;
+ 		case quote_name_needed:
+ 		    DPRINT(Debug,14,(&Debug," quote_name_needed")); break;
+ 		}
+ 		
+ 		if (q <= quote_name_bad) {
+ 		    DPRINT(Debug,14,(&Debug,", skipping\n"));
+ 		    setit(entry->entry_flags,LAST_READ_memonly);
+ 		    goto skip_this_entry;
+ 		} else if (q > quote_name_no) {
+ 		    DPRINT(Debug,14,(&Debug,", quoting\n"));
+ 		    
+ 		    elm_fprintf(f,FRM("%Q"),entry->folder_sys);
+ 		} else {
+ 		    DPRINT(Debug,14,(&Debug,"\n"));
+ 		    
+ 		    fputs(entry->folder_sys,f);
+ 		}
+ 		
+ 		/* Both space and TAB allowed */
+ 		putc('\t',f);
+ 		
+ 		if (ison(entry->entry_flags,
+ 			 LAST_READ_have_st_ino)) {
+ 		    
+ 		    fprintf(f,"%lu",(unsigned long)(entry->st_ino));
+ 		    
+ 		} else
+ 		    putc('-',f);  /* Placeholder */
+ 		
+ 		/* Both space and TAB allowed */
+ 		putc('\t',f);
+ 		
+ 		fprintf(f,"%ld",(long)(entry->last_read));
+ 		
+ 		X = ctime(&(entry->last_read));
+ 		
+ 		/* ctime() includes newline \n to result */
+ 		if (X) {
+ 		    fprintf(f,"\t# %s",
+ 			    X);
+ 		    
+ 		} else
+ 		    putc('\n',f);
+ 		
+ 	    skip_this_entry:
+ 		free_last_read_entry(& res.last_read_entry);
+ 		
+ 	    }
+ 	}
+ 
+ 
+ 	if (ferror(f)) {
+ 	    int err = errno;
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: write failed: %s\n",
+ 			     filename,strerror(err)));
+ 
+ 	    lib_error(CATGETS(elm_msg_cat, MeSet,
+ 			      MeLastReadWriteTempFail,
+ 			      "Write failed for last-read temp file %s: %s"),
+ 		      filename,strerror(err));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    ret = 0;
+ 	    goto fail;
+ 	}
+ 	
+ 	r = fflush(f);
+ 	switch(r) {
+ 	    int err;
+ 	case 0:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: written\n",
+ 			     filename));
+ 	    ret = 1;
+ 	    break;
+ 	case EOF:
+ 	    err = errno;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: flush failed: %s\n",
+ 			     filename,strerror(err)));
+ 
+ 	    lib_error(CATGETS(elm_msg_cat, MeSet,
+ 			      MeLastReadWriteTempFail,
+ 			      "Write failed for last-read temp file %s: %s"),
+ 		      filename,strerror(err));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    ret = 0;
+ 	    goto fail;
+ 	}
+ 
+ 	if (cache_file) {
+ 	    if (! stat_last_read_cache(filename,f,cache_file)) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "dump_last_read_cache: stat %s failed\n",
+ 				 filename));
+ 		ret = 0;
+ 		goto fail;
+ 	    }				 
+ 	}
+ 
+ 	if (need_delete > 0) {
+ 
+ 	    size_t i = cache_len -1;
+ 	    size_t deleted  = 0;
+ 	    size_t valid    = 0;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: %zu entries marked for delete\n",
+ 			     filename,need_delete));
+ 
+ 	    while (1) {
+ 		union sort_item res;
+ 
+ 		res.last_read_entry = NULL;
+ 		
+ 		/* Increments refcount */
+ 		get_sort_list_item(cache_entries,sort_list_get_normal,i,
+ 				   &res);
+ 		
+ 		if (res.last_read_entry) {
+ 		    struct last_read_entry * entry;
+ 		    
+ 		    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 			panic("MBX PANIC",__FILE__,__LINE__,
+ 			      "dump_last_read_cache",
+ 			      "Bad magic type (last_read_entry)",0);
+ 		    
+ 		    entry = res.last_read_entry;
+ 
+ 		    if (ison(entry->entry_flags,LAST_READ_valid))
+ 			valid++;
+ 
+ 		    if (ison(entry->entry_flags,LAST_READ_delete)) {
+ 
+ 			free_last_read_entry(& res.last_read_entry);
+ 			
+ 			/* Increments refcount */
+ 			get_sort_list_item(cache_entries,sort_list_get_remove,i,
+ 					   &res);
+ 
+ 			if (res.last_read_entry) {
+ 			    struct last_read_entry * entry;
+ 			    
+ 			    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 				panic("MBX PANIC",__FILE__,__LINE__,
+ 				      "dump_last_read_cache",
+ 				      "Bad magic type (last_read_entry)",0);
+ 
+ 			    entry = res.last_read_entry;
+ 			    
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "dump_last_read_cache: #%zu folder_sys=%s - deleted\n",
+ 					     i,entry->folder_sys));
+ 			    
+ 			    
+ 			    deleted++;
+ 			}
+ 		    }
+ 
+ 		    if (res.last_read_entry) 
+ 			free_last_read_entry(& res.last_read_entry);
+ 		}	   
+ 		
+ 		if (i > 0)
+ 		    i--;
+ 		else
+ 		    break;
+ 	    }
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "dump_last_read_cache: %s: %zu valid, %zu deleted.\n",
+ 			     filename,valid,deleted));
+ 	}
+ 
+     } else {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "dump_last_read_cache: %s: No entries\n",
+ 			 filename
+ 			 ));
+     }
+ 
+     
+     
+  fail:
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "dump_last_read_cache=%d%s; filename=%s\n",
+ 		     ret,
+ 		     ret ? " (succeed)" : "",
+ 		     filename));
+     return ret;
+ }
+ 
+ 
+ 
+ static struct last_read_cache *malloc_last_read_cache(sys_dir,st,
+ 						      prealloc,fchanges,
+ 						      filename)
+      const char                 * sys_dir;
+      const struct stat          * st;
+      size_t                       prealloc;
+      const struct file_changes  * fchanges;
+      const char                 * filename;
+ {
+     struct last_read_cache * ret = 
+ 	safe_zero_alloc(sizeof (*ret));
+ 
+     ret -> magic = LAST_READ_CACHE_magic;
+ 
+     ret -> refcount = 1;
+     
+     ret -> sys_dir = sys_dir ? safe_strdup(sys_dir) : NULL;
+     ret -> cached_name = NULL;
+     
+ 
+     if (filename) {
+ 	ret -> cache_file_name = safe_strdup(filename);
+     } else
+ 	ret -> cache_file_name = NULL;   /* Filled later */
+ 	
+     ret->cache_file = NULL_file_changes;
+ 
+     if (fchanges)
+ 	ret->cache_file = *fchanges;
+     
+     if (st)
+ 	stat_to_file_changes(st,& (ret->cache_file));
+ 
+     ret->entries = alloc_sort_list(&last_read_entry_op,
+ 				   prealloc);
+     
+     ret->modified  = 0;
+     ret->read      = 0;
+     
+     return ret;
+ }
+ 
+ enum last_read_mode {
+     last_read_read_only = 0,
+     last_read_check,
+     last_read_read_update  /* opended for rewrite */,
+     last_read_create  /* Create for locking        */
+ };
+ 
+ 
+ enum LREAD_OPEN_bits {
+     LREAD_OPEN_bit_SUGGEST_REWRITE,
+     LREAD_OPEN_bit_FILE_FD_LOCKED,
+     LREAD_OPEN_bit_WRITTEN,
+     
+     LREAD_OPEN_bit_count
+ };
+ 
+ #define LREAD_OPEN_SUGGEST_REWRITE   (1 << LREAD_OPEN_bit_SUGGEST_REWRITE)
+ #define LREAD_OPEN_FILE_FD_LOCKED    (1 << LREAD_OPEN_bit_FILE_FD_LOCKED)
+ #define LREAD_OPEN_WRITTEN           (1 << LREAD_OPEN_bit_WRITTEN)
+ 
+ 
+ #define LAST_READ_OPEN_magic 	0xFA0E
+ 
+ static struct last_read_open {
+     unsigned short               magic; 	/* LAST_READ_OPEN_magic */
+ 
+     int    file_fd;
+     FILE * fh;
+ 
+     const char           * filename;
+     struct dt_flags_info * locking_flags;
+ 
+     enum last_read_mode    is_update;
+ 
+     unsigned int  lread_open_flags :  LREAD_OPEN_bit_count;
+     
+ } * open_last_read_cache P_((const char           * filename,
+ 			     struct dt_flags_info * locking_flags,
+ 			     enum last_read_mode    is_update,
+ 			     struct file_changes  * file_information,
+ 			     int                  * errno_res
+ 			     )); 
+ 
+ static struct last_read_open * open_last_read_cache(filename,
+ 						    locking_flags,
+ 						    is_update,
+ 						    file_information,
+ 						    errno_res)
+      const char           * filename;
+      struct dt_flags_info * locking_flags;
+      enum last_read_mode    is_update;
+      struct file_changes  * file_information;
+      int                  * errno_res;
+ {
+     struct last_read_open * ret = NULL;
+     
+     enum FLOCKING_mode fm = FLOCKING_exclusive;
+     char *          openm = "r+";
+     int              accm = O_RDWR;
+     mode_t         creatm = 0600;   /* Supposed to be read only
+ 				       by user */
+     
+     int file_fd = -1;
+     int file_fd_locked = 0;
+     int loop_count = 0;
+     int loop_message_printed = 0;
+ 
+     FILE * f = NULL;
+     
+     struct stat file_fd_stat;
+     struct stat filename_stat;
+     
+     int have_file_fd_stat = 0;
+     int have_filename_stat = 0;
+     int have_creat_retry   = 0;
+     
+     
+     DPRINT(Debug,10,(&Debug,
+ 		     "open_last_read_cache: is_update=%d",
+ 		     is_update));
+ 
+     switch (is_update) {
+     case last_read_read_only:
+ 	DPRINT(Debug,10,(&Debug," last_read_read_only"));
+ 	fm     = FLOCKING_shared;
+ 	openm  = "r";
+ 	accm   = O_RDONLY;
+ 
+ 	break;
+ 
+     case last_read_check:
+ 	DPRINT(Debug,10,(&Debug," last_read_check"));
+ 
+ 	if (0) {
+ 	case last_read_read_update:
+ 	    DPRINT(Debug,10,(&Debug," last_read_read_update"));
+ 	}
+ 	fm = FLOCKING_exclusive;
+ 	openm = "r+";
+ 	accm = O_RDWR;
+ 	break;
+ 	    	
+     case last_read_create:
+ 	DPRINT(Debug,10,(&Debug," last_read_create"));
+ 	fm = FLOCKING_exclusive;
+ 	openm = "r+";
+ 	accm = O_RDWR;
+ 	break;
+     }
+     DPRINT(Debug,10,(&Debug," filename=%Q\n",
+ 		     filename));
+     
+     while (-1 == file_fd) {
+ 	enum syscall_status  r;
+ 	enum FLOCKING_status r1;
+ 	
+ 	int err = can_open(filename,openm);
+ 	int creatf = 0;
+ 
+ 	file_fd_locked = 0;
+ 
+ 	if (err) {
+ 	    DPRINT(Debug,2,(&Debug,
+ 			    "open_last_read_cache: %s: %s (can_open)\n",
+ 			    filename,strerror(err)));
+ 	    
+ 	    if (EINTR == err) {
+ 		continue;
+ 	    }
+ 
+ 	    if (ENOENT == err &&
+ 		last_read_create == is_update &&
+ 		! have_creat_retry) {
+ 
+ 		DPRINT(Debug,10,(&Debug,
+ 				 "open_last_read_cache: %s: Trying create file\n",
+ 				 filename));
+ 		
+ 		creatf = O_CREAT|O_EXCL;		
+ 	    } else {
+ 		if (loop_message_printed) {
+ 		    lib_transient(CATGETS(elm_msg_cat, MeSet,
+ 					  MeLastReadWaitingFail,
+ 					  "Waiting last-read file %s to be updated... Fail: %s"),
+ 				  filename,strerror(err));
+ 		}
+ 
+ 		if (errno_res)
+ 		    *errno_res = err;
+ 		
+ 		return NULL;
+ 	    }
+ 	    	    
+ 	} else {
+ 	    have_creat_retry = 0;
+ 	}
+ 
+ 	file_fd = open(filename,accm|creatf,creatm);
+ 	
+ 	if (-1 == file_fd) {
+ 	    err = errno;
+ 
+ 	    DPRINT(Debug,10,(&Debug,"open_last_read_cache: %s: %s\n",
+ 			     filename,strerror(err)));
+ 
+ 	     if (EINTR == err) {
+ 		 continue;
+ 	     }
+ 
+ 	     if (EEXIST == err) {
+ 		 /* Must have create failure 
+ 		    -- retry with canopen()
+ 		 */
+ 
+ 		 DPRINT(Debug,10,(&Debug,
+ 				  "open_last_read_cache: %s: Trying open file\n",
+ 				  filename));
+ 		 
+ 		 have_creat_retry = 1;
+ 		 continue;
+ 	     }
+ 
+ 	     if (loop_message_printed) {
+ 		 lib_transient(CATGETS(elm_msg_cat, MeSet,
+ 				       MeLastReadWaitingFail,
+ 				       "Waiting last-read file %s to be updated... Fail: %s"),
+ 			       filename,strerror(err));
+ 	     }
+ 
+ 	     if (errno_res)
+ 		 *errno_res = err;
+ 	     
+ 	     return NULL;
+ 	}
+ 
+ 	r = fstat(file_fd,&file_fd_stat);
+ 	switch (r) {
+ 	    char *X;
+ 	case syscall_success:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
+ 			     file_fd,filename,
+ 			     (unsigned long)file_fd_stat.st_dev,
+ 			     (unsigned long)file_fd_stat.st_ino,
+ 			     (long)file_fd_stat.st_size,
+ 			     (long)file_fd_stat.st_mtime));
+ 
+ 	    X = ctime(& (file_fd_stat.st_mtime));
+ 	    if (X) { /* ctime() includes newline */
+ 		DPRINT(Debug,14,(&Debug," -- %s",X));
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 	    }
+ 
+ 	    have_file_fd_stat = 1;
+ 	    
+ 	    break;
+ 	case syscall_error:
+ 	    err = errno;
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: fstat %d: %s failed: %s\n",
+ 			     file_fd,filename,strerror(err)));
+ 
+ 	    if (EINTR == err) {
+ 		goto oops;
+ 	    }
+ 	    
+ 	    /* Just read old file ? */
+ 	    goto quit_locking_loop;
+ 	}
+ 
+ 	/* <last_read> is locked with exclusive lock
+ 	   when new file <last_read>.N is written
+ 	   and then renamed to <last_read>
+ 
+ 	*/
+ 
+ 	r1 = filelock_fd(file_fd,fm,
+ 			 locking_flags,
+ 			 filename,
+ 			 FLOCKING_non_block,
+ 			 &err);
+ 
+ 	switch (r1) {
+ 	case FLOCKING_FAIL:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: filelock_fd %d: %s locking failed: %s\n",
+ 			     file_fd,filename,strerror(err)));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 		/* Just read old file ? */
+ 	    goto quit_locking_loop;
+ 	case FLOCKING_OK:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: filelock_fd %d: %s locked\n",
+ 			     file_fd,filename));
+ 	    file_fd_locked = 1;
+ 	    break;
+ 	case FLOCKING_RETRY:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: filelock_fd %d: %s locking failed (retry)",
+ 			     file_fd,filename));
+ 	    if (err) {
+ 		DPRINT(Debug,14,(&Debug,": %s",
+ 				 strerror(err)));
+ 	    }
+ 	    DPRINT(Debug,14,(&Debug,"\n"));
+ 	    
+ 	    if (EINTR == err) {
+ 		goto oops;
+ 	    }
+ 	    	    
+ 	    goto wait_to_change;
+ 	case FLOCKING_UNSUPPORTED:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: filelock_fd %d: %s locking not supported\n",
+ 			     file_fd,filename));
+ 	    /* Just read old file ? */
+ 	    goto quit_locking_loop;
+ 	}
+ 
+ 	r = stat(filename,&filename_stat);
+ 	switch (r) {
+ 	    char *X;
+ 	case syscall_success:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: stat %s succeed: dev %lu ino %lu size %ld modified %ld",
+ 			     filename,
+ 			     (unsigned long)filename_stat.st_dev,
+ 			     (unsigned long)filename_stat.st_ino,
+ 			     (long)filename_stat.st_size,
+ 			     (long)filename_stat.st_mtime));
+ 	    X = ctime(& (filename_stat.st_mtime));
+ 	    if (X) { /* ctime() includes newline */
+ 		DPRINT(Debug,14,(&Debug," -- %s",X));
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 	    }
+ 	    
+ 	    have_filename_stat = 1;
+ 	    
+ 	    break;
+ 	case syscall_error:
+ 	    err = errno;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: stat %s: %s\n",
+ 			     filename,strerror(err)));
+ 	    if (EINTR == err) {
+ 		goto oops;
+ 	    }
+ 	    
+ 	    /* Just read old file ? */
+ 	    goto quit_locking_loop;
+ 	}
+ 	
+ 	if (!have_filename_stat || !have_file_fd_stat) {
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: file %s - no stat?\n",
+ 			     filename));
+ 
+ 	    goto quit_locking_loop;
+ 	    
+ 	} else if (filename_stat.st_dev   == file_fd_stat.st_dev  &&
+ 		   filename_stat.st_ino   == file_fd_stat.st_ino  &&
+ 		   filename_stat.st_size  == file_fd_stat.st_size &&
+ 		   filename_stat.st_mtime == file_fd_stat.st_mtime) {
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: file %s not changed (since open)\n",
+ 			     filename));
+ 
+ 	    if (loop_message_printed) {
+ 		lib_transient(CATGETS(elm_msg_cat, MeSet,
+ 				      MeLastReadWaitingOK,
+ 				      "Waiting last-read file %s to be updated... OK"),
+ 			      filename);
+ 		loop_message_printed = 0;
+ 	    }
+ 	    
+ 	    goto quit_locking_loop;
+ 
+ 	} else {
+ 	    int wait_it;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "open_last_read_cache: file %s changed after open\n",
+ 			     filename));
+ 	    
+ 	oops:
+ 	    wait_it = 0;
+ 	    
+ 	    if (0) {
+ 	    wait_to_change:
+ 		wait_it = 1;
+ 	    }
+ 	    
+ 	    if (loop_count++ > 10) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "open_last_read_cache: file %s - try #%d -- quiting\n",
+ 				 filename,loop_count));
+ 		goto quit_locking_loop;
+ 	    }
+ 
+ 	    if (wait_it) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "open_last_read_cache: file %s - try #%d -- waiting\n",
+ 				 filename,loop_count));
+ 
+ 		if (!loop_message_printed) {
+ 		    lib_transient(CATGETS(elm_msg_cat, MeSet,
+ 					  MeLastReadWaiting,
+ 					  "Waiting last-read file %s to be updated..."),
+ 				  filename);
+ 		    loop_message_printed = 1;		    
+ 		}
+ 
+ 		if (POLL_method)
+ 		    wait_for_timeout(5);
+ 		else
+ 		    sleep(5);
+ 		
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "open_last_read_cache: file %s - try #%d -- looping\n",
+ 				 filename,loop_count));
+ 	    }
+ 
+ 	    if (file_fd_locked) { /* Just ignore error --
+ 				     close() should release this anyway
+ 				  */
+ 		filelock_fd(file_fd,FLOCKING_release,locking_flags,
+ 			    filename,FLOCKING_non_block,NULL);
+ 	    }
+ 	    
+ 	    close(file_fd);  /* Result ignored */
+ 	    file_fd = -1;	    
+ 	}	
+     }
+ 
+  quit_locking_loop:
+ 
+     if (loop_message_printed) {
+ 	lib_transient(CATGETS(elm_msg_cat, MeSet,
+ 			      MeLastReadWaitingError,
+ 			      "Waiting last-read file %s to be updated... Error"),
+ 		      filename);
+     }			      
+ 
+     if (file_information) {
+ 	if (FILE_CHANGES_magic != file_information->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"open_last_read_cache",
+ 		  "Bad magic number (file_changes)",0);
+ 
+ 	if (sizeof (*file_information) != file_information->self_size) {
+ 	    
+ 	    DPRINT(Debug,1,(&Debug,
+ 			    "open_last_read_cache: size mismatch file_changes size %zu != self size %zu\n",
+ 			    sizeof (*file_information),file_information->self_size));
+ 	    	    
+ 	} else {
+ 	    stat_to_file_changes(have_file_fd_stat ? &file_fd_stat : NULL,
+ 				 file_information);
+ 	}
+     }
+ 
+     f = fdopen(file_fd,openm);
+     if (!f) {
+  	int err = errno;
+ 	DPRINT(Debug,10,(&Debug,
+ 			 "open_last_read_cache: fdopen %d: %s: %s\n",
+ 			 file_fd,filename,strerror(err)));
+ 	
+ 	if (file_fd_locked) { /* Just ignore error --
+ 				 close() should release this anyway
+ 			      */
+ 	    filelock_fd(file_fd,FLOCKING_release,locking_flags,
+ 			filename,FLOCKING_non_block,NULL);
+ 	}
+ 	
+ 	close(file_fd);  /* Result ignored */
+ 
+ 	if (errno_res)
+ 	    *errno_res = err;
+ 	
+ 	return NULL;
+     }
+ 
+ 
+     ret = safe_zero_alloc(sizeof (*ret));
+ 
+     ret->magic    = LAST_READ_OPEN_magic;
+     ret->file_fd  = file_fd;
+     ret->fh       = f;
+     ret->filename = filename;   /* shared */
+     ret->locking_flags = locking_flags;
+     ret->is_update     = is_update;
+ 
+ #define IFSET(var,flag) (var ? flag : 0)
+     
+     ret->lread_open_flags =
+ 	IFSET(file_fd_locked,LREAD_OPEN_FILE_FD_LOCKED);
+    
+     DPRINT(Debug,10,(&Debug,
+ 		     "open_last_read_cache: %s open%s\n",
+ 		     filename,
+ 		     file_fd_locked ? ", file_fd locked" : ""));
+ 
+     return ret;
+ }
+ 
+ static void close_last_read_open P_((struct last_read_open *ptr));
+ 
+ /* Closes ptr->fh if not update */
+ static int read_last_read_cache P_((struct last_read_open *ptr,
+ 				    struct file_changes * cache_file,
+ 				    struct sortlist    ** cache_entries,
+ 				    int                 * errors,
+ 				    const struct last_read_entry_def * entry_default));
+ static int read_last_read_cache(ptr,cache_file,cache_entries,errors,entry_default)
+      struct last_read_open *ptr;
+      struct file_changes * cache_file;
+      struct sortlist    ** cache_entries;
+      int                 * errors;
+      const struct last_read_entry_def * entry_default;
+ {
+     int ret = 0;
+     int suggest_rewrite = 0;
+ 
+     
+     if (LAST_READ_OPEN_magic != ptr->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,
+ 	      "read_last_read_cache",
+ 	      "Bad magic number (last_read_open)",0);
+ 
+     if (! ptr->fh) {
+ 	ret = 0;
+ 	goto fail;
+     }
+ 	
+     rewind(ptr->fh);
+ 
+     ret = parse_last_read_cache(ptr->filename,
+ 				ptr->fh,
+ 				cache_file,
+ 				cache_entries,
+ 				errors,
+ 				entry_default,
+ 				&suggest_rewrite);
+ 
+     if (ptr -> is_update < last_read_check ||
+ 	(last_read_check == ptr -> is_update &&
+ 	 ! suggest_rewrite)) {
+ 	close_last_read_open(ptr);	
+     }
+ 
+     if (suggest_rewrite)
+ 	setit(ptr->lread_open_flags,
+ 	      LREAD_OPEN_SUGGEST_REWRITE);
+     
+  fail:
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "read_last_read_cache=%d; filename=%s\n",
+ 		     ret,ptr->filename));
+ 
+     
+     return ret;
+     
+ }
+ 					  	
+ static void close_last_read_open(ptr)
+     struct last_read_open *ptr;
+ {
+     if ( LAST_READ_OPEN_magic != ptr->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,
+ 	      "close_last_read_entry",
+ 	      "Bad magic number (last_read_open)",0);
+     
+     if (-1 != ptr->file_fd) {
+ 	if (ison(ptr->lread_open_flags,
+ 		 LREAD_OPEN_FILE_FD_LOCKED) &&
+ 	    ptr->locking_flags) {
+ 	    /* Just ignore error --
+ 	       close() should release this anyway
+ 	    */
+ 	    
+ 	    filelock_fd(ptr->file_fd,FLOCKING_release,
+ 			ptr->locking_flags,
+ 			ptr->filename,
+ 			FLOCKING_non_block,NULL);
+ 
+ 	    clearit(ptr->lread_open_flags,
+ 		    LREAD_OPEN_FILE_FD_LOCKED);
+ 	}
+ 	
+ 	if (! ptr->fh ||
+ 	    fileno(ptr->fh) != ptr->file_fd) {
+ 
+ 	    close(ptr->file_fd);
+ 	}
+ 	ptr->file_fd = -1;
+     }
+ 
+     if (ptr->fh) {
+ 	int r = fclose(ptr->fh);
+ 	switch (r) {
+ 	    int err UNUSED_VAROK;
+ 	case 0:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "close_last_read_open: %s: closed\n",
+ 			     ptr->filename));
+ 	    break;
+ 			
+ 	case EOF:
+ 	    err = errno;
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "close_last_read_open: %s: close failed: %s\n",
+ 			     ptr->filename,strerror(err)));
+ 	    break;
+ 	}
+ 	ptr->fh = NULL;
+     }
+ 
+ }
+ 	
+ static void free_last_read_open P_((struct last_read_open **ptr)); 
+ static void free_last_read_open(ptr)
+      struct last_read_open **ptr;
+ {
+     if (LAST_READ_OPEN_magic != (*ptr)->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "free_last_read_open",
+ 		  "Bad magic number (last_read_open)",0);
+ 
+     if ((*ptr)->filename) {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "free_last_read_open: Freeing %s\n",
+ 			 (*ptr)->filename));
+     }
+ 
+     
+     close_last_read_open(*ptr);
+ 
+     (*ptr)->magic = 0; /* Invalidate */
+     free(*ptr);
+     *ptr = NULL;
+ }
+ 
+     
+ /* Ignores / on end */
+ int same_dir_str P_((const char * dir1, const char * dir2));
+ int same_dir_str(dir1,dir2)
+      const char * dir1;
+      const char * dir2;
+ {
+     int r = 0;
+     
+     size_t l1 = strlen(dir1);
+     size_t l2 = strlen(dir2);
+ 
+     if (l1 > 1 && '/' == dir1[l1-1])
+ 	l1--;
+     if (l2 > 1 && '/' == dir2[l2-1])
+ 	l2--;
+ 	
+     if (l1 == l2) {
+ 	r = 0 == strncmp(dir1,dir2,l1);
+ 	
+     } else {
+ 	r = 0;
+     }
+ 	
+     return r;
+ }
+ 
+ static int same_dir_stat P_((const char  * dir1,
+ 		      struct stat * buf_dir1,
+ 		      const char  * dir2));
+ static int same_dir_stat(dir1,buf_dir1,dir2)
+      const char * dir1;
+      struct stat * buf_dir1;
+      const char * dir2;
+ {
+     struct stat buf2;
+     enum syscall_status  r = stat(dir2, &buf2);
+     
+     switch (r) {
+     case syscall_error /* -1 */: {
+ 	int err UNUSED_VAROK = errno;
+ 
+ 	DPRINT(Debug,10,(&Debug,
+ 			 "same_dir_stat: stat %s failed %s (errno=%d)\n",
+ 			 dir2,strerror(err), err));
+ 		
+     }
+ 	break;
+     case syscall_success /* 0 */:
+ 	
+ 	DPRINT(Debug,10,(&Debug,
+ 			 "same_dir_stat: stat %s succeed\n",
+ 			 dir2));
+ 	
+ 	if (buf_dir1->st_ino == buf2.st_ino && buf_dir1->st_dev == buf2.st_dev) {
+ 
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "same_dir_stat: Same dir %s and %s\n",
+ 			     dir1,dir2));
+ 	    return 1;
+ 	}
+ 	break;
+     }
+     
+     return 0;
+ }
+ 
+ /* Is sys_dir is relative, may return read_loc_none */
+ 
+ static enum last_read_location {
+     read_loc_none = 0,
+     read_loc_dir,
+     read_loc_def } last_read_dir_to_loc P_((const char * sys_dir,
+ 					    const char **res_dir));
+ 
+ static enum last_read_location last_read_dir_to_loc(sys_dir,
+ 						    res_dir)
+      const char * sys_dir;
+      const char **res_dir;
+ {
+     enum last_read_location ret = read_loc_none;
+ 
+     enum syscall_status  r_sys_dir = syscall_error;
+     struct stat        buf_sys_dir;
+     
+     /* give_dt_estr_as_str adds / to end */
+     const char * mailhome_val =
+ 	give_dt_estr_as_str(&mailhome_dir_e,
+ 			    "mailhome-dir",
+ 			    NULL,NULL);   /* XXXX */
+ 
+     const char * mbx_dir =
+ 	give_dt_estr_as_str(&extra_mailbox_dir_e,
+ 			    "extra-mailbox-dir",
+ 			    NULL,NULL);
+     
+     const char * folder_dir =
+ 	give_dt_estr_as_str(&folders_e,
+ 			    "maildir",
+ 			    NULL,NULL);
+     
+     if (res_dir)
+ 	*res_dir = NULL;
+     
+     if (mailhome_val) {
+ 	if (same_dir_str(mailhome_val,sys_dir)) {
+ 	    ret =  read_loc_def;
+ 	    if (res_dir)
+ 		*res_dir = mailhome_val;
+ 	}
+     }
+ 
+     if (read_loc_none == ret && mbx_dir) {	
+ 	if (same_dir_str(mbx_dir,sys_dir)) {
+ 	    ret =  read_loc_dir;
+ 	    if (res_dir)
+ 		*res_dir = mbx_dir;
+ 	}	
+     }
+ 
+     if (read_loc_none == ret && folder_dir) {	
+ 	if (same_dir_str(folder_dir,sys_dir)) {
+ 	    ret =  read_loc_dir;
+ 	    if (res_dir)
+ 		*res_dir = folder_dir;
+ 	}	
+     }
+ 
+     if (read_loc_none == ret) {	
+ 	if (same_dir_str(home,sys_dir)) {
+ 	    ret =  read_loc_dir;
+ 	    if (res_dir)
+ 		*res_dir = home;
+ 	}	
+     }
+     
+     if (read_loc_none == ret) {
+ 	char * pwd_val = getenv("PWD");
+ 	
+ 	r_sys_dir = stat(sys_dir,&buf_sys_dir);
+ 
+ 	switch (r_sys_dir) {
+ 	case syscall_error /* -1 */: {
+ 	    int err UNUSED_VAROK = errno;
+ 	    
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "last_read_dir_to_loc: stat %s failed %s (errno=%d)\n",
+ 			     sys_dir,strerror(err), err));
+ 	}
+ 	    break;
+ 	case syscall_success /* 0 */:
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "last_read_dir_to_loc: stat %s succeed\n",
+ 			     sys_dir));
+ 
+ 	    if (mailhome_val) {
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  mailhome_val)) {
+ 		    
+ 		    ret =  read_loc_def;
+ 		    if (res_dir)
+ 			*res_dir = mailhome_val;
+ 		    
+ 		}	    
+ 	    }
+ 
+ 	    if (read_loc_none == ret && mbx_dir) {	
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  mbx_dir)) {
+ 		    ret =  read_loc_dir;
+ 		    if (res_dir)
+ 			*res_dir = mbx_dir;
+ 		}	
+ 	    }
+ 	    
+ 	    if (read_loc_none == ret && folder_dir) {
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  folder_dir)) {
+ 		    ret =  read_loc_dir;
+ 		    if (res_dir)
+ 			*res_dir = folder_dir;
+ 		}	
+ 	    }
+ 	    
+ 	    if (read_loc_none == ret && folder_dir) {
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  folder_dir)) {
+ 		    ret =  read_loc_dir;
+ 		    if (res_dir)
+ 			*res_dir = folder_dir;
+ 		}	
+ 	    }
+ 	    
+ 	    if (read_loc_none == ret) {
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  home)) {
+ 		    ret =  read_loc_dir;
+ 		    if (res_dir)
+ 			*res_dir = home;
+ 		}	
+ 	    }
+ 	    
+ 	    if (read_loc_none == ret && pwd_val && '/' == pwd_val[0]) {
+ 		
+ 		if (same_dir_stat(sys_dir,&buf_sys_dir,
+ 				  pwd_val)) {
+ 		    ret =  read_loc_dir;
+ 		    if (res_dir)
+ 			*res_dir = pwd_val;
+ 		}	
+ 	    }
+ 
+ 	    break;
+ 	}
+ 
+ 	if (read_loc_none == ret && '/' == sys_dir[0]) {
+ 	    ret =  read_loc_dir;
+ 	    if (res_dir)
+ 		*res_dir = sys_dir;
+ 	}
+     }
+ 
+     
+     DPRINT(Debug,10,(&Debug,
+ 		     "last_read_dir_to_loc=%d",
+ 		     ret));
+ 
+     switch (ret) {
+     case read_loc_none: DPRINT(Debug,10,(&Debug, " read_loc_none")); break;
+     case read_loc_dir:  DPRINT(Debug,10,(&Debug, " read_loc_dir"));  break;
+     case read_loc_def:  DPRINT(Debug,10,(&Debug, " read_loc_def")); break;
+     }
+     DPRINT(Debug,10,(&Debug," sys_dir=%Q",sys_dir));
+     if (res_dir && *res_dir) {
+ 	DPRINT(Debug,10,(&Debug,"; *res_dir=%Q",*res_dir));
+     }
+     DPRINT(Debug,10,(&Debug,"\n"));
+     
+     return ret;
+ }
+ 
+ /* Replaces file */
+ static int write_last_read_cache P_((struct last_read_open  * H,
+ 				     struct last_read_cache * cache,
+ 				     struct dt_flags_info   * locking_flags,
+ 				     int                    * errno_res,
+ 
+ 				     /* May be NULL */
+ 				     FILE *commentfile, 
+ 				     const char *actor,
+ 				     char *version_buff
+ 				     ));
+ static int write_last_read_cache(H,cache,locking_flags,errno_res,
+ 				 commentfile,actor,version_buff
+ 				 )
+      struct last_read_open  * H;
+      struct last_read_cache * cache;
+      struct dt_flags_info   * locking_flags;
+      int                    * errno_res;
+ 
+      /* May be NULL */
+      FILE                * commentfile; 
+      const char          * actor;
+      char                * version_buff;     
+      
+ {
+     int ret = 0;
+     
+     if (LAST_READ_OPEN_magic != H->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,
+ 	      "write_last_read_cache",
+ 	      "Bad magic number (last_read_open)",0);
+ 
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"write_last_read_cache",
+               "Bad magic type (last_read_cache)",0);
+ 
+     
+     if (H->filename) {  /* shared pointer */
+         char          * temp_filename = NULL;
+ 	int             unlink_temp   = 0;
+ 	
+ 	int             temp_file_fd  = -1;
+ 	int             file_fd_locked = 0;
+ 
+ 	FILE          * temp_fh       = NULL;
+ 	
+ 	int err;
+ 	enum FLOCKING_status r2;
+ 		
+ 
+ 	temp_filename =
+ 	    elm_message(FRM("%s.N"),
+ 			H->filename);
+ 
+ 	err = can_open(temp_filename,"r+");
+ 
+ 	if (err) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: %s canopen: %s\n",
+ 			     temp_filename,strerror(err)));
+ 
+ 	    if (ENOENT != err) {
+ 	    
+ 		lib_error(CATGETS(elm_msg_cat, MeSet,
+ 				  MeLastReadCheckTempFail,
+ 				  "Failed to check last-read temp file %s: %s"),
+ 			  temp_filename,strerror(err));
+ 
+ 		if (errno_res)
+ 		    *errno_res = err;
+ 		
+ 		goto fail;
+ 	    }
+ 	}
+ 
+ 	temp_file_fd = open(temp_filename,O_CREAT|O_EXCL|O_RDWR,
+ 			    0600   /* Supposed to be read only
+ 				      by user */);
+ 
+ 	if (-1 == temp_file_fd) {
+ 	    err = errno;
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: %s open: %s\n",
+ 			     temp_filename,strerror(err)));
+ 
+  	    lib_error(CATGETS(elm_msg_cat, MeSet,
+ 			      MeLastReadCreatTempFail,
+ 			      "Failed to create last-read temp file %s: %s"),
+ 		      temp_filename,strerror(err));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    goto fail;
+ 	}
+ 	
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "write_last_read_cache: %s created\n",
+ 			 temp_filename));
+ 
+ 
+ 	/* Lock this, because this is moved to  struct last_read_open */
+ 	
+ 	r2 = filelock_fd(temp_file_fd,FLOCKING_exclusive,locking_flags,
+ 			 temp_filename,FLOCKING_non_block,
+ 			 &err);
+ 
+ 	switch (r2) {
+ 	case FLOCKING_FAIL:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: filelock_fd %d: %s locking failed: %s\n",
+ 			     temp_file_fd, temp_filename,strerror(err)));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    unlink_temp = 1;
+ 	    goto fail;
+ 	case FLOCKING_OK:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: filelock_fd %d: %s locked\n",
+ 			     temp_file_fd, temp_filename));
+ 	    file_fd_locked = 1;
+ 	    break;
+ 	case FLOCKING_RETRY:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: filelock_fd %d: %s locking failed (retry)",
+ 			     temp_file_fd, temp_filename));
+ 	    if (err) {
+ 		DPRINT(Debug,14,(&Debug,": %s",
+ 				 strerror(err)));
+ 	    }
+ 	    DPRINT(Debug,14,(&Debug,"\n"));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    unlink_temp = 1;
+ 	    goto fail;
+ 	case FLOCKING_UNSUPPORTED:
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: filelock_fd %d: %s locking not supported\n",
+ 			     temp_file_fd, temp_filename));
+ 	    break;
+ 	}
+ 
+ 	temp_fh = fdopen(temp_file_fd,"w+");
+ 	if (temp_fh) {
+ 	    struct file_changes      cache_file = cache->cache_file;
+ 
+ 	    if (dump_last_read_cache(temp_fh,
+ 				     temp_filename,
+ 				     &cache_file,
+ 				     cache->entries,
+ 				     errno_res,
+ 
+ 				     /* commentfile,actor,version_buff
+ 					may be NULL
+ 				     */
+ 				     commentfile,actor,version_buff
+ 				     )) {
+ 		enum syscall_status  r_rename =
+ 		    rename(temp_filename,
+ 			   H->filename);
+ 
+ 		switch (r_rename) {
+ 		case syscall_success:
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "write_last_read_cache: %s renamed to %s\n",
+ 				     temp_filename,
+ 				     H->filename));
+ 			   
+ 		    close_last_read_open(H);
+ 		    
+ 		    cache->cache_file_name = strmcpy(cache->cache_file_name,
+ 						     H->filename);
+ 		    cache->cache_file = cache_file;
+ 		    cache->modified   = 0;
+ 		    
+ 		    H->filename = cache->cache_file_name;
+ 		    H->file_fd  = temp_file_fd; temp_file_fd = -1;
+ 		    H->fh       = 	temp_fh; temp_fh = NULL;
+ 		    H->lread_open_flags =
+ 			LREAD_OPEN_WRITTEN |
+ 			(file_fd_locked ? LREAD_OPEN_FILE_FD_LOCKED : 0);
+ 
+ 		    ret = 1;
+ 
+ 
+ 		    
+ 		    break;
+ 
+ 		case syscall_error /* -1 */:
+ 		    err = errno;
+ 
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "write_last_read_cache: %s rename to %s failed: %s\n",
+ 				     temp_filename,
+ 				     H->filename,
+ 				     strerror(err)));
+ 
+ 		    lib_error(CATGETS(elm_msg_cat, MeSet,
+ 				      MeLastReadRenameFail,
+ 				      "Failed to rename last-read file to %s: %s"),
+ 			      H->filename,strerror(err));
+ 
+ 		    if (errno_res)
+ 			*errno_res = err;
+ 		    
+ 		    unlink_temp = 1;
+ 		    break;
+ 		}
+ 	    } else {
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "write_last_read_cache: Failed to write last-read temp file %s\n",
+ 				 temp_filename));
+ 
+ 		unlink_temp = 1;
+ 	    }
+ 		
+ 	} else {
+ 	    err = errno;
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: fdopen %d: %s open failed: %s\n",
+ 			     temp_file_fd, temp_filename,strerror(err)));
+ 
+ 	    if (errno_res)
+ 		*errno_res = err;
+ 	    
+ 	    unlink_temp = 1;
+ 	}
+ 		
+     fail:
+ 	if (temp_file_fd != -1) {
+ 	    
+ 	    if (temp_file_fd != H->file_fd) {
+ 		if (file_fd_locked) {
+ 		    /* Just ignore error --
+ 		       close() should release this anyway
+ 		    */
+ 		    
+ 		    filelock_fd(temp_file_fd,FLOCKING_release,locking_flags,
+ 				temp_filename,FLOCKING_non_block,
+ 				NULL);
+ 		}
+ 		
+ 		if (! temp_fh || temp_file_fd != fileno(temp_fh)) {
+ 
+ 		    unlink_temp = 1;
+ 		    close(temp_file_fd);
+ 		}
+ 	    }
+ 	    temp_file_fd = -1;
+ 	}
+ 	
+ 	if (temp_fh) {
+ 	    if (temp_fh != H->fh) {
+ 		
+ 		unlink_temp = 1;
+ 		fclose(temp_fh);
+ 	    }
+ 	    temp_fh = NULL;
+ 	}
+ 	
+ 	if (temp_filename) {
+ 	    
+ 	    if (unlink_temp) {
+ 		enum syscall_status r1 = unlink(temp_filename);
+ 		switch (r1) {
+ 		case syscall_success:
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "write_last_read_cache: %s unlinked\n",
+ 				     temp_filename));
+ 		    break;
+ 		case syscall_error:
+ 		    err = errno;
+ 		    DPRINT(Debug,14,(&Debug,
+ 				     "write_last_read_cache: %s unlink: %s\n",
+ 				     temp_filename,strerror(err)));
+ 
+ 		    if (errno_res)
+ 			*errno_res = err;
+ 		    
+ 		    break;
+ 		}
+ 	    }
+ 	    
+ 	    free(temp_filename);
+ 	    temp_filename = NULL;
+ 	}
+     } else {
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "write_last_read_cache: No filename\n"));
+     }
+ 
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "write_last_read_cache=%d%s\n",
+ 		     ret,
+ 		     ret ? " (succeed)" : ""));
+     
+     return ret;
+ }
+ 
+ static struct last_read_cache * load_last_read_cache
+                 P_((const char * filename,
+ 		    const char * sys_dir /* may be NULL */,
+ 		    struct last_read_open  **hdl,
+ 		    int *errors,
+ 		    struct dt_flags_info * locking_flags,
+ 		    enum last_read_mode    is_update
+ 		    ));
+ 
+ static void reload_last_read_cache P_((struct last_read_cache *cache,
+ 				       struct last_read_open  **hdl,
+ 				       int *errors,
+ 				       struct dt_flags_info * locking_flags,
+ 				       enum last_read_mode    is_update,
+ 				       int                  * errno_res));
+ 
+ static void reload_last_read_cache(cache,
+ 				   hdl,errors,locking_flags,
+ 				   is_update,errno_res)
+      struct last_read_cache *cache;
+      struct last_read_open  **hdl;
+      int *errors;
+      struct dt_flags_info * locking_flags;
+      enum last_read_mode    is_update;
+      int                  * errno_res;
+ {
+ 
+     const char * filename                 = NULL;
+ 
+     struct last_read_open  * H = NULL;
+ 
+     struct file_changes    fchanges = NULL_file_changes;
+ 
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"reload_last_read_cache",
+               "Bad magic type (last_read_cache)",0);
+ 
+     filename = cache->cache_file_name;
+         
+     if (hdl && *hdl) 
+ 	free_last_read_open(hdl);
+        
+     H = open_last_read_cache(filename,locking_flags,
+ 			     is_update,
+ 			     &fchanges,
+ 			     errno_res);
+ 
+     if (H) {
+ 
+ 	static struct last_read_entry_def def = {
+ 	    LAST_READ_ENTRY_DEF_magic,
+ 
+ 	    
+ 	    LAST_READ_old /* Is this needed ? */
+ 	};
+ 
+ 	if (LAST_READ_OPEN_magic != H->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "reload_last_read_cache",
+ 		  "Bad magic number (last_read_open)",0);
+ 
+ 	if (H->fh) {
+ 	    
+ 	    if (read_last_read_cache(H,
+ 				     & (cache->cache_file),
+ 				     & (cache->entries),
+ 				     errors,
+ 				     &def)) {
+ 
+ 		/* Update file information */
+ 		cache->cache_file = fchanges; 
+ 		cache->read       = 1;  /* Mark that read once */
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "reload_last_read_cache: %s: load succeed\n",
+ 				 filename));
+ 		
+ 		if (H->fh &&
+ 		    ison(H->lread_open_flags,
+ 			 LREAD_OPEN_SUGGEST_REWRITE) &&
+ 		    (is_update == last_read_read_update ||
+ 		     !hdl)) {
+ 		    
+ 		    /* Write_update */
+ 		    
+ 		    if (write_last_read_cache(H,cache,locking_flags,
+ 					      NULL /* errno_res */,
+ 					      
+ 					      /* commentfile,actor,version_buff */
+ 					      NULL,NULL,NULL
+ 					      )) {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "reload_last_read_cache: %s: updated\n",
+ 					 filename));
+ 		    }
+ 		}
+ 	    }
+ 
+ 	    
+ 	    if (H->fh && is_update < last_read_read_update)
+ 		close_last_read_open(H);
+ 	    
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "reload_last_read_cache: %s: No file handle\n",
+ 			     filename));
+ 	}
+     
+     	if (hdl) {
+ 	    *hdl = H;
+ 	    H = NULL;
+ 	} else
+ 	    free_last_read_open(&H);
+     }
+ }
+ 				       
+ /* For loading new cache */
+ struct last_read_cache * load_last_read_cache(filename,
+ 					      sys_dir,
+ 					      hdl,
+ 					      errors,locking_flags,is_update)
+      const char * filename;
+      const char * sys_dir /* may be NULL */;
+      struct last_read_open  **hdl;
+      int *errors;
+      struct dt_flags_info * locking_flags;
+      enum last_read_mode    is_update;
+ {
+     struct last_read_open  * H = NULL;
+     struct last_read_cache * ret = NULL;
+ 
+     struct file_changes    fchanges = NULL_file_changes;
+     
+     if (hdl && *hdl) 
+ 	free_last_read_open(hdl);
+     
+     H = open_last_read_cache(filename,locking_flags,is_update,
+ 			     &fchanges,
+ 			     NULL /* errno_res */);
+ 
+     if (H) {
+ 
+ 	static struct last_read_entry_def def = {
+ 	    LAST_READ_ENTRY_DEF_magic,
+ 
+ 	    
+ 	    LAST_READ_old /* Is this needed ? */
+ 	};
+ 
+ 	if (LAST_READ_OPEN_magic != H->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "load_last_read_cache",
+ 		  "Bad magic number (last_read_open)",0);
+ 
+ 	if (H->fh) {
+ 	    int c = '\0';
+ 	    
+ 	    size_t prealloc = 0;
+ 	    int last_c = '\0';  /* ignore first line
+ 				   (header) on prealloc
+ 				   counting
+ 				*/
+ 	    
+ 	    while (EOF != (c = getc(H->fh))) {
+ 		if ('\n' == last_c &&
+ 		    '#'  != c && '\n' != c)
+ 		    prealloc++;
+ 		last_c = c;
+ 	    }
+ 	
+ 	    if (ferror(H->fh)) {
+ 		int err UNUSED_VAROK = errno;
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "load_last_read_cache: %s: read failed: %s\n",
+ 				 filename,strerror(err)));
+ 	    }
+ 
+ 	    if (feof(H->fh)) {
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "load_last_read_cache: %s: prealloc %zu entries\n",
+ 				 filename,prealloc));	       
+ 	    }
+ 
+ 	    rewind(H->fh);
+ 
+ 	    ret = malloc_last_read_cache(sys_dir,NULL,prealloc,
+ 					 &fchanges,filename);
+ 	    
+ 	    if (read_last_read_cache(H,
+ 				     & (ret->cache_file),
+ 				     & (ret->entries),
+ 				     errors,
+ 				     &def)) {
+ 
+ 		/* Update file information */
+ 		ret->cache_file = fchanges; 
+ 		ret->read       = 1;  /* Mark that read once */
+ 		
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "load_last_read_cache: %s: load succeed\n",
+ 				 filename));
+ 
+ 		if (H->fh &&
+ 		    ison(H->lread_open_flags,
+ 			 LREAD_OPEN_SUGGEST_REWRITE) &&
+ 		    (is_update == last_read_read_update ||
+ 		     !hdl)) {
+ 		    
+ 		    /* Write_update */
+ 
+ 		    if (write_last_read_cache(H,ret,locking_flags,
+ 					      NULL /* errno_res */,
+ 
+ 					      /* commentfile,actor,version_buff */
+ 					      NULL,NULL,NULL
+ 					      )) {
+ 			DPRINT(Debug,14,(&Debug,
+ 					 "load_last_read_cache: %s: updated\n",
+ 					 filename));
+ 		    }
+ 		    
+ 		}
+ 	    }
+ 
+ 	    if (H->fh && is_update < last_read_read_update)
+ 		close_last_read_open(H);
+ 	    
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "load_last_read_cache: %s: No file handle\n",
+ 			     filename));
+ 	}
+     
+ 	if (hdl) {
+ 	    *hdl = H;
+ 	    H = NULL;
+ 	} else
+ 	    free_last_read_open(&H);
+ 
+     }
+     
+     DPRINT(Debug,14,(&Debug,
+ 		     "load_last_read_cache"));
+ 
+     if (ret) {
+ 	DPRINT(Debug,14,(&Debug,"=%p (succeed)\n",
+ 			 ret));
+     } else {
+ 	DPRINT(Debug,14,(&Debug,"=NULL\n"));
+     }
+ 
+     return ret;
+ }
+ 
+ static struct last_read_cache * last_read_def_cache    = NULL;
+ static int                      last_read_def_rewrite  = 0; /* not used */
+ static struct file_changes      last_read_def_fchanges = FILE_CHANGES_INIT;
+ 
+ /* write_conf() lib/misc/conf_writer.c does locking */
+ S_(merge_conf_map_f merge_user_last_read)
+ static int merge_user_last_read  P_((const char  * fname,
+ 				     FILE        * f));
+ static int merge_user_last_read(fname,f)
+      const char  * fname;
+      FILE        * f;
+ {
+     int r = 0;
+ 
+ 	static struct last_read_entry_def def = {
+ 	    LAST_READ_ENTRY_DEF_magic,
+ 
+ 	    
+ 	    LAST_READ_old /* Is this needed ? */
+ 	};
+ 
+     
+     if (! last_read_def_cache) {
+ 	int c = '\0';	    
+ 	size_t prealloc = 0;
+ 	
+ 	while (EOF != (c = getc(f))) {
+ 	    if ('\n' == c)
+ 		prealloc++;
+ 	}
+ 	
+ 	if (ferror(f)) {
+ 	    int err UNUSED_VAROK = errno;
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "merge_user_last_read: %s: read failed: %s\n",
+ 			     fname,strerror(err)));
+ 	}
+ 	
+ 	if (feof(f)) {
+ 	    /* This may give one line too much (header) */
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "merge_user_last_read: %s: prealloc %zu entries\n",
+ 			     fname,prealloc));	       
+ 	}
+ 	
+ 	rewind(f);
+ 
+ 	last_read_def_cache = malloc_last_read_cache(NULL /* sys_dir */,
+ 						     NULL /* struct stat */,
+ 						     prealloc,
+ 						     &last_read_def_fchanges,
+ 						     fname);
+     }
+ 
+     if (LAST_READ_CACHE_magic != last_read_def_cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"merge_user_last_read",
+               "Bad magic type (last_read_cache)",0);
+ 
+     r =  parse_last_read_cache(fname,f,&last_read_def_fchanges,
+ 			       & (last_read_def_cache->entries),
+ 			       NULL /* Errors */,
+ 			       &def,
+ 			       &last_read_def_rewrite);
+ 				   
+     DPRINT(Debug,14,(&Debug,
+ 		     "merge_user_last_read=%d%s\n",
+ 		     r,
+ 		     r ? " (succeed)" : ""));
+     
+     return r;				   
+ }
+ 
+ 
+ /* write_conf() lib/misc/conf_writer.c does locking */
+ S_(dump_conf_map_f dump_user_last_read)
+ static int dump_user_last_read P_((FILE *f,const char *actor,
+ 				   char *version_buff,
+ 				   int * errno_res));
+ static int dump_user_last_read(f,actor,version_buff,errno_res) 
+      FILE *f;
+      const char *actor;
+      char *version_buff;
+      int * errno_res;
+ {
+     int r = 0;
+     
+     if (last_read_def_cache) {
+ 
+ 	if (LAST_READ_CACHE_magic != last_read_def_cache->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"dump_user_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	if (last_read_def_cache->entries) {
+ 	
+ 	    r = dump_last_read_cache(f,user_last_read_def,
+ 				     &last_read_def_fchanges,
+ 				     last_read_def_cache->entries,
+ 				     errno_res,
+ 
+ 				     NULL /* commentfile */,
+ 				     actor,version_buff);
+ 	    
+ 	    if (r) {
+ 		DPRINT(Debug,14,(&Debug,
+ 				 "dump_user_last_read: %s written\n",
+ 				 user_last_read_def));
+ 		
+ 		last_read_def_rewrite  = 0;
+ 	    }
+ 	}
+     }
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "dump_user_last_read=%d%s",
+ 		     r,
+ 		     r ? " (succeed)" : ""));
+     if (errno_res) {
+ 	DPRINT(Debug,14,(&Debug,"; *errno_res=%d",
+ 			 *errno_res));
+ 
+ 	if (*errno_res) {
+ 	    DPRINT(Debug,14,(&Debug,": %s",
+ 			     strerror(*errno_res)));
+ 	}
+     }    
+     DPRINT(Debug,14,(&Debug,"\n"));
+     
+     return r;
+ }
+ 
+ S_(dump_message_f user_last_read_written)
+ static void user_last_read_written P_((char *fname));
+ static void user_last_read_written(fname)
+      char *fname;
+ {
+     lib_error(CATGETS(elm_msg_cat, MeSet, 
+ 		      MeDefaultLastReadW,
+ 		      "Default last read file %s written."),
+ 	      fname);
+ }
+ 
+ 
+ /* system init hook */
+ void init_last_read_defaults(errors)
+      int *errors;
+ {
+ 
+     DPRINT(Debug,10,(&Debug,"init_last_read_defaults: starting\n"));
+ 
+     register_conf_write(USER_LAST_READ,
+ 			user_last_read_def,
+ 			dump_user_last_read,
+ 			user_last_read_written,
+ 			&last_read_def_rewrite, /* not used */
+ 			merge_user_last_read);
+ 
+     DPRINT(Debug,10,(&Debug,"init_last_read_defaults: done\n"));
+ }
+ 
+ static struct sortlist        * last_read_dir_cache = NULL;       
+ 
+ 
+ /* User init hook */
+ void last_read_rc_file(errors)
+      int *errors;
+ {
+     enum use_lastread_v use_lastread =
+ 	give_dt_enumerate_as_int(&use_last_read_file);
+     
+     if (use_lastread > use_lastread_no) {
+ 	struct last_read_open  * last_read_hdl_cache = NULL;
+ 
+ 	/* Also give_last_read() can set last_read_dir_cache */
+ 	
+ 	if (last_read_dir_cache) {
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "last_read_rc_file: last_read_dir_cache already set\n"));
+ 	} else
+ 	    last_read_dir_cache = alloc_sort_list(& last_read_cache_op,2);
+ 
+ 	/* Also give_last_read() can set last_read_def_cache */
+ 
+ 	if (last_read_def_cache) {
+ 
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "last_read_rc_file: default cache %s already set\n",
+ 			     user_last_read_def));
+ 	    
+ 	} else
+ 	    last_read_def_cache =
+ 		load_last_read_cache(user_last_read_def,
+ 				     NULL /* user default file */,
+ 				     &last_read_hdl_cache,
+ 				     errors,
+ 				     &conf_merge_locking,
+ 				     last_read_check
+ 				     );
+ 
+ 	if (last_read_hdl_cache) {
+ 
+ 	    if (LAST_READ_OPEN_magic != last_read_hdl_cache->magic)
+ 		panic("MBX PANIC",__FILE__,__LINE__,
+ 		      "last_read_rc_file",
+ 		      "Bad magic number (last_read_open)",0);
+ 
+ 	    last_read_def_rewrite = ison(last_read_hdl_cache->lread_open_flags,
+ 					 LREAD_OPEN_SUGGEST_REWRITE);
+ 	    
+ 	    free_last_read_open(& last_read_hdl_cache);
+ 	}
+     }
+ }
+ 
+ static char * give_cache_file_name P_((const char       * sys_dir,
+ 				       enum last_read_location last_read_loc));
+ static char * give_cache_file_name(sys_dir,last_read_loc)
+      const char       * sys_dir;
+      enum last_read_location last_read_loc;
+ {
+     static char * ret = NULL;
+ 
+     switch (last_read_loc) {
+     case read_loc_none:
+ 	ret = NULL;
+ 	break;
+     case read_loc_dir:
+ 	if (sys_dir) {
+ 	    int L;
+ 
+ 	    char temp[STRING];
+ 
+ 	    elm_sfprintf(temp,sizeof temp,
+ 			 FRM(".elm-last-read-%04x"),
+ 			 userid);
+ 	    
+ 	    ret = safe_strdup(sys_dir);
+ 	    L = strlen(ret);
+ 	    if (L > 0 && ret[L-1] != '/') {
+ 		ret = strmcat(ret,"/");
+ 	    }
+ 	    ret = strmcat(ret,temp);
+ 	}
+ 	break;
+     case read_loc_def:
+ 	ret = safe_strdup(user_last_read_def);
+ 	break;
+     }
+ 
+     if (ret) {
+ 	DPRINT(Debug,13,(&Debug,"give_cache_file_name=%Q",
+ 			 ret));
+     } else {
+ 	DPRINT(Debug,13,(&Debug,"give_cache_file_name=NULL"));
+     }
+     DPRINT(Debug,13,(&Debug,"; last_read_loc=%d",last_read_loc));
+     switch (last_read_loc) {
+     case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none"));  break;
+     case read_loc_dir:  DPRINT(Debug,13,(&Debug," read_loc_dir"));   break;
+     case read_loc_def:  DPRINT(Debug,13,(&Debug," read_loc_def"));   break;
+     }
+     if (sys_dir) {
+ 	DPRINT(Debug,13,(&Debug," sys_dir=%Q",sys_dir));
+     }
+     DPRINT(Debug,13,(&Debug,"\n"));
+     
+     return ret;
+ }
+ 
+ 
+ void free_last_read()
+ {
+     if (last_read_def_cache)
+ 	free_last_read_cache(& last_read_def_cache);
+ 
+     if (last_read_dir_cache)
+ 	free_sort_list(& last_read_dir_cache);
+ }
+ 
+ static struct dt_flags_info * cache_guess_locking
+    P_((struct last_read_cache * dir_last_read));
+ static struct dt_flags_info * cache_guess_locking(dir_last_read)
+      struct last_read_cache * dir_last_read;
+ {
+     struct dt_flags_info *ret = &folder_locking;
+     
+     const char * mbx_dir =
+ 	give_dt_estr_as_str(&extra_mailbox_dir_e,
+ 			    "extra-mailbox-dir",
+ 			    NULL,NULL);
+ 
+     
+     if (LAST_READ_CACHE_magic != dir_last_read->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"cache_guess_locking",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     if (! dir_last_read->sys_dir) {
+ 	/*  NULL, if fallback file
+ 	    ~/.elm/last.read
+ 	*/
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "cache_guess_locking=&conf_merge_locking; file %s\n",
+ 			 dir_last_read->cache_file_name));
+ 	
+ 	return &conf_merge_locking;
+     }
+ 
+     if (dt_flag_is_set(&last_read_fbck_locking, lock_prefer_flag)) {
+ 
+ 	ret =  &last_read_fbck_locking;
+ 
+ 	DPRINT(Debug,14,(&Debug,
+ 			 "cache_guess_locking: last-read-fallback-locking preferred\n"));
+ 	
+     } else {
+ 	int ok = 0;
+ 	
+ 	if (mbx_dir && same_dir_str(dir_last_read->sys_dir,
+ 				    mbx_dir)) {    
+ 	    ret =  &mailbox_locking;
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "cache_guess_locking: %s on extra-mailbox-dir, suggest mailbox-locking\n",
+ 			     dir_last_read->sys_dir));
+ 	    
+ 	}
+ 
+ 	if (dt_flag_is_set(ret,lock_flock_flag)) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "cache_guess_locking: flock locking set\n"));
+ 	    ok = 1;
+ 	}
+ 	
+ 	if (dt_flag_is_set(ret,lock_fcntl_flag)) {
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "cache_guess_locking: fcntl locking set\n"));
+ 	    ok = 1;
+ 	}
+ 
+ 	if (!ok) {
+ 		
+ 	    ret =  &last_read_fbck_locking;
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "cache_guess_locking: falling to last-read-fallback-locking\n"));
+ 	    
+ 	}
+     }
+ 
+     DPRINT(Debug,14,(&Debug,
+ 		     "cache_guess_locking=%p",ret));
+ 
+     if ( &folder_locking == ret) {
+ 	DPRINT(Debug,14,(&Debug," &folder_locking"));
+     }
+     if (&mailbox_locking == ret) {
+ 	DPRINT(Debug,14,(&Debug," &mailbox_locking"));
+     }
+     if (&last_read_fbck_locking == ret) {
+ 	DPRINT(Debug,14,(&Debug," (&last_read_fbck_locking"));
+     }    
+     DPRINT(Debug,14,(&Debug,"; dir %s, file %s\n",
+ 		     dir_last_read->sys_dir,
+ 		     dir_last_read->cache_file_name));
+ 	
+     return ret;
+ }
+ 
+ 
+ /* Write struct last_read_cache if modified */
+ void flush_last_read(dir_last_read)
+      struct last_read_cache * dir_last_read;
+ {
+ 
+     if (dir_last_read) {
+ 	
+ 	if (LAST_READ_CACHE_magic != dir_last_read->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"flush_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	if (dir_last_read->modified) {
+ 
+ 	    struct dt_flags_info   * locking =
+ 		cache_guess_locking(dir_last_read);
+ 	    struct last_read_open  * H = NULL;
+ 
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "write_last_read_cache: %s: %s need update\n",
+ 			     dir_last_read->sys_dir ?
+ 			     dir_last_read->sys_dir : "fallback file",
+ 			     dir_last_read->cache_file_name));
+ 	    
+ 	    /* Need read and lock */
+ 
+ 	    reload_last_read_cache(dir_last_read,&H,
+ 				   NULL /* errors */,
+ 				   locking,
+ 				   last_read_read_update,
+ 				   NULL /* errno_res */);
+ 
+ 	    if (H) {
+ 
+ 		if (LAST_READ_OPEN_magic != H->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,
+ 			  "write_last_read_cache",
+ 			  "Bad magic number (last_read_open)",0);
+ 		
+ 		if (last_read_def_cache == dir_last_read) {
+ 		    last_read_def_rewrite = ison(H->lread_open_flags,
+ 						 LREAD_OPEN_SUGGEST_REWRITE);
+ 		}
+ 
+ 
+ 		if (write_last_read_cache(H,
+ 					  dir_last_read,
+ 					  locking,
+ 					  NULL /* errno_res */,
+ 
+ 					  /* commentfile,actor,version_buff */
+ 					  NULL,NULL,NULL
+ 					  )) {
+ 		    
+ 		     DPRINT(Debug,14,(&Debug,
+ 				      "write_last_read_cache: %s: %s updated\n",
+ 				      dir_last_read->sys_dir ?
+ 				      dir_last_read->sys_dir : "fallback file",
+ 				      dir_last_read->cache_file_name));
+ 
+ 		     if (last_read_def_cache == dir_last_read) {
+ 			 last_read_def_rewrite = 0;
+ 		     }
+ 		     
+ 		}
+ 
+ 		free_last_read_open(&H);
+ 	    }
+ 	}
+     }
+ 	
+ }
+ 
+ enum last_read_default { last_read_def_existing = 0,
+ 			 last_read_def_create };
+ 
+ static  struct last_read_cache * give_last_read P_((const char       * sys_dir,
+ 						    enum last_read_location last_read_loc,
+ 						    const char * res_dir,
+ 						    enum last_read_default default_create
+ 						    ));
+ 						    
+ static  struct last_read_cache * give_last_read(sys_dir,last_read_loc,res_dir,
+ 						default_create)
+      const char            * sys_dir;
+      enum last_read_location last_read_loc;
+      const char            * res_dir;
+      enum last_read_default  default_create;
+ {
+     struct last_read_cache * ret   = NULL;
+     char                   * fname = NULL;
+ 
+     DPRINT(Debug,13,(&Debug,"give_last_read: sys_dir=%s last_read_loc=%d",sys_dir,last_read_loc));
+     switch (last_read_loc) {
+     case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none"));     break;
+     case read_loc_dir:  DPRINT(Debug,13,(&Debug," read_loc_dir"));      break;
+     case read_loc_def:  DPRINT(Debug,13,(&Debug," read_loc_def"));      break;	
+     }
+     if (res_dir) {
+ 	DPRINT(Debug,13,(&Debug," res_dir=%s",res_dir));
+     }
+     DPRINT(Debug,13,(&Debug," default_create=%d",default_create));
+     switch (default_create) {
+     case last_read_def_existing:  DPRINT(Debug,13,(&Debug," last_read_def_existing")); break;
+     case last_read_def_create:    DPRINT(Debug,13,(&Debug," last_read_def_create"));   break;
+     }
+     DPRINT(Debug,13,(&Debug,"\n"));
+     
+     fname = give_cache_file_name(sys_dir,last_read_loc);
+ 
+     if (fname) {	    
+ 	enum sort_list_search_op op = sort_list_search_normal;
+ 	enum use_lastread_v use_lastread =
+ 	    give_dt_enumerate_as_int(&use_last_read_file);
+ 	
+ 	
+ 	switch (use_lastread) {
+ 	case use_lastread_no:
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "give_last_read: %s - use-last-read disabled\n",
+ 			     sys_dir));
+ 	    goto fail;
+ 	    
+ 	case use_lastread_yes:
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "give_last_read: %s - use-last-read enabled\n",
+ 			     sys_dir));
+ 	    op = sort_list_search_create;
+ 	    break;
+ 	case use_lastread_auto:
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "give_last_read: %s - use-last-read auto\n",
+ 			     sys_dir));
+ 
+ 	    if (0) {
+ 	    case use_lastread_existing:
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "give_last_read: %s - use-last-read existing\n",
+ 				 sys_dir));	    	    
+ 	    }
+ 
+ 	    switch (default_create) {
+ 	    case last_read_def_create:
+ 		op = sort_list_search_create;
+ 		break;
+ 	    case last_read_def_existing: {
+ 		enum syscall_status  r_access =
+ 		    access(fname, ACCESS_EXISTS);
+ 		
+ 		switch ( r_access) {
+ 		    int err UNUSED_VAROK;
+ 		case syscall_success:
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s - %s exists\n",
+ 				     sys_dir,fname));
+ 		    op = sort_list_search_create;
+ 		    break;
+ 		case syscall_error:
+ 		    err = errno;
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s - %s gives: %s\n",
+ 				     sys_dir,fname,
+ 				     strerror(err)));
+ 		    break;
+ 		}		    						
+ 	    }
+ 		break;
+ 	    }
+ 		    
+ 	    break;
+ 	case NUM_use_lastread:
+ 	    break;
+ 	}
+ 		 	    
+ 	switch (last_read_loc) {
+ 	    
+ 	case read_loc_none:
+ 	    break;
+ 	case read_loc_dir:
+ 	    
+ 	    if (res_dir) {
+ 		struct last_read_cache_def def = NULL_last_read_cache_def;
+ 		union sort_item_default    def0;
+ 		union sort_item            res;
+ 		size_t                     idx;
+ 		union sort_key             key;
+ 		
+ 		if (! last_read_dir_cache) {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s -- setting last_read_dir_cache\n",
+ 				     sys_dir));
+ 		    
+ 		    last_read_dir_cache = alloc_sort_list(& last_read_cache_op,2);
+ 		}
+ 		
+ 		def.st              = NULL;
+ 		def.prealloc        = 5;
+ 		def.fchanges        = NULL;
+ 		
+ 		def0.last_read_cache = &def;
+ 		def.cache_file_name = fname;
+ 		
+ 		res.last_read_cache  = NULL;
+ 		key.str = res_dir;
+ 		idx = 0;
+ 		
+ 		/* Increments refcount */;
+ 		if (search_sort_list_item(last_read_dir_cache,
+ 					  op,
+ 					  key,def0,&res,&idx,NULL)) {
+ 		    
+ 		    if (res.last_read_cache) {
+ 			if (LAST_READ_CACHE_magic != res.last_read_cache->magic)
+ 			    panic("MBX PANIC",__FILE__,__LINE__,"give_last_read",
+ 				  "Bad magic type (last_read_cache)",0);
+ 				    			
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s -- last read %Q: idx #%zu found\n",
+ 					 sys_dir,res_dir,idx));
+ 			
+ 			ret = res.last_read_cache;
+ 
+ 			if (! ret->read) {
+ 			    DPRINT(Debug,13,(&Debug,
+ 					     "give_last_read: %s -- need initial read\n",
+ 					     sys_dir));
+ 			    
+ 			    reload_last_read_cache(ret,NULL,NULL,
+ 						   cache_guess_locking(ret),
+ 						   last_read_check,
+ 						   NULL /* errno_res */);
+ 			} else {
+ 			    int err = 0;
+ 			    enum file_changes_result change_status
+ 				= test_file_changes(fname,
+ 						    & ret->cache_file,
+ 						    & err);
+ 
+ 			    switch (change_status) {
+ 			    case no_file_changes:
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "give_last_read: %s last_read %s not changed\n",
+ 						 sys_dir,fname));
+ 				break;
+ 			    case file_changes_error:
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "give_last_read: %s last_read %s not available %s\n",
+ 						 sys_dir,fname,strerror(err)));
+ 				break;
+ 			    case have_file_changes:
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "give_last_read: %s last_read %s need reload\n",
+ 						 sys_dir,fname));
+ 				
+ 				reload_last_read_cache(ret,NULL,NULL,
+ 						       cache_guess_locking(ret),
+ 						       last_read_check,
+ 						       NULL /* errno res */);
+ 				break;
+ 			    }
+ 			}
+ 			    						
+ 		    } else {
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s -- last read for %Q: search_sort_list_item did not set last_read_cache, idx #%zu\n",
+ 					 sys_dir,res_dir,idx));
+ 		    }
+ 		    
+ 		} else {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s -- last read for %Q not found or created\n",
+ 				     sys_dir,res_dir));
+ 		}
+ 	    } else {
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "give_last_read: %s -- target dir not set\n",
+ 				 sys_dir));
+ 	    }
+ 	    break;
+ 	case read_loc_def: {
+ 	    struct last_read_open  * H = NULL;
+ 	    
+ 	    if (last_read_def_cache) {
+ 		
+ 		ret = last_read_def_cache;
+ 		inc_last_read_cache_refcount(ret);
+ 
+ 		if (! ret->read) {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s -- need initial read for default cache %s\n",
+ 				     sys_dir,fname));
+ 		    
+ 		    reload_last_read_cache(ret,&H,NULL,
+ 					   &conf_merge_locking,
+ 					   last_read_check,
+ 					   NULL /* errno_res */);
+ 		} else {
+ 
+ 		    int err = 0;
+ 		    enum file_changes_result change_status
+ 			= test_file_changes(fname,
+ 					    & ret->cache_file,
+ 					    & err);
+ 		    
+ 		    switch (change_status) {
+ 		    case no_file_changes:
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s last_read %s not changed\n",
+ 					 sys_dir,fname));
+ 			break;
+ 		    case file_changes_error:
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s last_read %s not available %s\n",
+ 					 sys_dir,fname,strerror(err)));
+ 			break;
+ 		    case have_file_changes:
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s last_read %s need reload\n",
+ 					 sys_dir,fname));
+ 			
+ 			reload_last_read_cache(ret,&H,NULL,
+ 					       &conf_merge_locking,
+ 					       last_read_check,
+ 					       NULL /* errno_res */);
+ 			break;
+ 		    }
+ 		}
+ 		    
+ 	    } else {
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "give_last_read: %s -- default cache %s not read\n",
+ 				 sys_dir,fname));
+ 
+ 		last_read_def_cache =
+ 		    load_last_read_cache(user_last_read_def,NULL,
+ 					 &H,NULL, &conf_merge_locking,
+ 					 last_read_check);
+ 
+ 		if (last_read_def_cache) {
+ 		    ret = last_read_def_cache;
+ 		    inc_last_read_cache_refcount(ret);
+ 
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "give_last_read: %s -- succeed to read default cache %s\n",
+ 				     sys_dir,fname)); 
+ 		} else {
+ 		    switch (default_create) {
+ 		    case last_read_def_create:
+ 			last_read_def_cache = malloc_last_read_cache(NULL /* sys_dir */,
+ 								     NULL /* struct stat */,
+ 								     1,
+ 								     &last_read_def_fchanges,
+ 								     fname);
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "give_last_read: %s - created dummy default cache %s\n",
+ 					 sys_dir,fname));
+ 
+ 			ret = last_read_def_cache;
+ 			inc_last_read_cache_refcount(ret);
+ 			
+ 			break;
+ 		    case last_read_def_existing:
+ 			break;
+ 		    }
+ 		}
+ 	    }
+ 
+ 	    if (H) {
+ 		
+ 		if (LAST_READ_OPEN_magic != H->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,
+ 			  "write_last_read_cache",
+ 			  "Bad magic number (last_read_open)",0);
+ 		
+ 		if (last_read_def_cache) {
+ 		    last_read_def_rewrite = ison(H->lread_open_flags,
+ 						 LREAD_OPEN_SUGGEST_REWRITE);
+ 		}
+ 
+ 		free_last_read_open(&H);
+ 	    }
+ 	    
+ 	}
+ 	    break;
+ 	}
+ 	    
+     fail:
+ 	free(fname);
+ 	fname = NULL;       	    
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "give_last_read: %s -- cache file name not set\n",
+ 			 sys_dir));
+     }
+     
+     if (ret) {
+ 	if (LAST_READ_CACHE_magic != ret->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"give_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "give_last_read=%p",ret));
+ 	if (ret->sys_dir) {
+ 	    DPRINT(Debug,13,(&Debug," sys_dir=%s",ret->sys_dir));
+ 	}
+ 	if (ret->cache_file_name) {
+ 	    DPRINT(Debug,13,(&Debug," cache_file_name=%s",ret->cache_file_name));
+ 	}	
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "give_last_read=NULL"));
+     }
+ 
+     DPRINT(Debug,13,(&Debug,"; requested sys_dir=%s",sys_dir));
+     if (res_dir) {
+ 	DPRINT(Debug,13,(&Debug," res_dir=%s",res_dir));
+     }
+     DPRINT(Debug,13,(&Debug,"\n"));
+     
+     return ret;
+ }
+ 					     
+ /* Result is malloced if *free_sys_dir is set */
+ static char * stat_file_to_sys_dir P_((const char   * stat_file,
+ 				       int          * free_sys_dir_p
+ 				       ));
+ static char * stat_file_to_sys_dir (stat_file,free_sys_dir_p)
+      const char   * stat_file;
+      int          * free_sys_dir_p;
+ {
+      char       * sys_dir  = NULL;
+      int          free_sys_dir = * free_sys_dir_p;
+ 
+      const char * p        = strrchr(stat_file,'/');
+     
+      if (p) {
+ 	 size_t len = (p - stat_file);
+ 	 	 
+ 	 sys_dir = safe_malloc(len+1);
+ 	 free_sys_dir = 1;
+ 	 strnfcpy(sys_dir,stat_file,len,len+1,NULL);	
+ 	
+      } else {
+ 	 sys_dir      = ".";
+ 	 free_sys_dir = 0;
+      }
+      
+      
+      DPRINT(Debug,14,(&Debug,
+ 		      "stat_file_to_sys_dir=%s; stat_file=%s\n",
+ 		     sys_dir,
+ 		     stat_file));
+     
+      * free_sys_dir_p = free_sys_dir;
+      return sys_dir;
+ }
+ 
+ /* Increments refcount - may change or open new cache 
+    does not reload cache if directory is corrent 
+ */
+ struct last_read_cache * upgrade_last_read(dir_last_read,
+ 					   stat_file,
+  					   stat_buf)
+      struct last_read_cache * dir_last_read;
+      const char             * stat_file;
+      struct stat            * stat_buf;
+ {
+     struct last_read_cache *ret = NULL;
+     int need_upgrade    = 0;
+ 
+     int          free_sys_dir = 0;
+     char       * sys_dir      =  stat_file_to_sys_dir(stat_file,
+ 						      &free_sys_dir);
+     const char * res_dir = NULL;
+     
+     enum last_read_location last_read_loc =  read_loc_none;
+ 
+     
+     DPRINT(Debug,13,(&Debug,
+ 		     "upgrade_last_read: %s => sys_dir=%Q\n",
+ 		     stat_file,sys_dir));
+ 
+     last_read_loc = last_read_dir_to_loc(sys_dir,&res_dir);
+ 
+     DPRINT(Debug,13,(&Debug,
+ 		     "upgrade_last_read: %s => location %d",
+ 		     stat_file,
+ 		     last_read_loc));
+ 
+     switch (last_read_loc) {
+     case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none"));
+ 	break;
+     case read_loc_dir:  DPRINT(Debug,13,(&Debug," read_loc_dir"));
+ 	break;
+     case read_loc_def:  DPRINT(Debug,13,(&Debug," read_loc_def"));
+ 	break;
+     }
+     
+     if (res_dir) {
+ 	DPRINT(Debug,13,(&Debug," res_dir=%Q",res_dir));
+     }
+     DPRINT(Debug,13,(&Debug,"\n"));
+     
+     if (dir_last_read) {
+ 
+ 	if (LAST_READ_CACHE_magic != dir_last_read->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "upgrade_last_read: %s dir_last_read=%p",
+ 			 stat_file,dir_last_read));
+ 	if (dir_last_read->sys_dir) {
+ 	    DPRINT(Debug,13,(&Debug," sys_dir=%s",dir_last_read->sys_dir));
+ 	}
+ 	if (dir_last_read->cache_file_name) {
+ 	    DPRINT(Debug,13,(&Debug," cache_file_name=%s",
+ 			     dir_last_read->cache_file_name));
+ 	}	
+ 	DPRINT(Debug,13,(&Debug,"\n"));
+ 	
+ 	switch (last_read_loc) {
+ 	case read_loc_none: need_upgrade = 1;  break;
+ 	case read_loc_dir:
+ 	    if (res_dir && dir_last_read->sys_dir &&
+ 		same_dir_str(res_dir,dir_last_read->sys_dir)) {
+ 
+ 		if (FILE_CHANGES_magic != dir_last_read->cache_file.magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
+ 			  "Bad magic type (file_changes)",0);
+ 
+ 		if (stat_buf &&
+ 		    dir_last_read->cache_file.dev != stat_buf->st_dev) {
+ 
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "upgrade_last_read: %s -- last_read dev %ld does not match %Q dev %ld\n",
+ 				     stat_file,
+ 				     (long)(dir_last_read->cache_file.dev),
+ 				     res_dir,
+ 				     (long)(stat_buf->st_dev)));
+ 		    need_upgrade = 1;
+ 		}
+ 		
+ 	    } else {
+ 		need_upgrade = 1;
+ 		if (res_dir && dir_last_read->sys_dir) {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "upgrade_last_read: %s -- last_read %Q does not match to %Q\n",
+ 				     stat_file,dir_last_read->sys_dir,
+ 				     res_dir));
+ 				     
+ 		}
+ 	    }
+ 	    break;
+ 	case read_loc_def:
+ 	    if (last_read_def_cache != dir_last_read)
+ 		need_upgrade = 1;
+ 	    break;
+ 	}
+ 
+ 	if (need_upgrade) {
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "upgrade_last_read: %s -- last read %s need upgrade\n",
+ 			     stat_file,
+ 			     dir_last_read->cache_file_name));
+ 	}
+     }
+ 
+         
+     if (need_upgrade || !dir_last_read) {
+ 	
+ 	ret = give_last_read(sys_dir,last_read_loc,res_dir,
+ 			     dir_last_read ? last_read_def_create :
+ 			     last_read_def_existing
+ 			     );
+ 	
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "upgrade_last_read: %s ",
+ 			 stat_file));
+ 
+ 	if (ret) {
+ 	    DPRINT(Debug,13,(&Debug," last_read for %s changed or set",
+ 			     sys_dir));
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug," last_read for %s failed",
+ 			     sys_dir));
+ 	}
+ 	DPRINT(Debug,13,(&Debug,"\n"));
+ 	
+     } else {
+ 	if (FILE_CHANGES_magic != dir_last_read->cache_file.magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
+ 			  "Bad magic type (file_changes)",0);
+ 	
+ 	ret = dir_last_read;
+ 	inc_last_read_cache_refcount(ret);
+ 
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "upgrade_last_read: %s last_read %s not changed\n",
+ 			 stat_file,dir_last_read->cache_file_name));
+ 	
+     }
+ 
+     if (sys_dir) {
+ 	if (free_sys_dir)
+ 	    free(sys_dir);
+ 	sys_dir = NULL;
+     }
+ 
+     if (ret) {
+ 	if (LAST_READ_CACHE_magic != ret->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "upgrade_last_read=%p",ret));
+ 	if (ret->sys_dir) {
+ 	    DPRINT(Debug,13,(&Debug," sys_dir=%s",ret->sys_dir));
+ 	}
+ 	if (ret->cache_file_name) {
+ 	    DPRINT(Debug,13,(&Debug," cache_file_name=%s",ret->cache_file_name));
+ 	}	
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "upgrade_last_read=NULL"));
+     }
+     DPRINT(Debug,13,(&Debug,"; stat_file=%s\n",stat_file));
+     
+     return ret;
+ }
+ 
+ void inc_last_read_cache_refcount(cache)
+      struct last_read_cache * cache;
+ {
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"inc_last_read_cache_refcount",
+               "Bad magic type (last_read_cache)",0);
+ 
+     cache->refcount++;
+ }
+     
+ /* Decremetns refcount */
+ void free_last_read_cache(cache)
+      struct last_read_cache ** cache;
+ {
+ 
+     if (LAST_READ_CACHE_magic != (*cache)->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_cache",
+               "Bad magic type (last_read_cache)",0);
+ 
+     if ((*cache)->refcount < 1)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_cache",
+               "Bad refcount",0);
+ 
+     (*cache)->refcount--;
+ 
+     if ((*cache)->refcount > 0) {
+ 	(*cache) = NULL;
+ 
+ 	return;
+     }
+     
+ 
+     if ((*cache)->sys_dir) {
+ 	free((*cache)->sys_dir);
+ 	    
+ 	(*cache)->sys_dir = NULL;
+     }
+ 
+     if ((*cache)->cached_name)
+ 	free_string_sort(& ((*cache)->cached_name));
+     
+     if ((*cache)->cache_file_name) {
+ 	free((*cache)->cache_file_name);
+ 
+ 	(*cache)->cache_file_name = NULL;
+     }
+ 
+     
+     if ((*cache)->entries)
+ 	free_sort_list(& ((*cache)->entries));
+ 		       
+     (*cache)->magic = 0; /* Invalidate */
+     
+     free(*cache);
+     *cache = NULL;
+ }
+ 
+ 
+  /* NULL if / without absolute path */
+ static const char * pathname_to_entryname P_((struct last_read_cache * this_last_read,
+ 					      const char             * pathname,
+ 					      struct stat            * file_stat));
+ static const char * pathname_to_entryname(this_last_read,pathname,file_stat)
+      struct last_read_cache * this_last_read;
+      const char             * pathname;
+      struct stat            * file_stat;
+ {
+     const char             * name1 = pathname;
+ 
+     if (LAST_READ_CACHE_magic != this_last_read->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"pathname_to_entryname",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     if (this_last_read->sys_dir &&
+ 	in_directory(file_stat,pathname,this_last_read->sys_dir)) {
+ 
+ 	char * x = strrchr(pathname,'/');
+ 	
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "pathname_to_entryname: %s on directory %s",
+ 			 pathname,this_last_read->sys_dir));
+ 
+ 	if (x && x[1]) {
+ 	    name1 = x+1;
+ 
+ 	    DPRINT(Debug,13,(&Debug,", name => %s",
+ 			     name1));
+ 	}
+ 	DPRINT(Debug,13,(&Debug,"\n"));		
+     }
+ 
+     if (! name1[0]) {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "pathname_to_entryname: %s - empty name\n",
+ 			 pathname));
+ 	name1 = NULL;
+     } else if ('/' != name1[0] ) {
+ 
+ 	const char * x1;
+ 
+ 	for (x1 = name1; *x1; x1++) {
+ 	    if ('/' == *x1) {
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "pathname_to_entryname: %s - invalid name %s\n",
+ 				 pathname,name1));
+ 		name1 = NULL;
+ 		goto fail;
+ 	    }
+ 	}
+     }
+ 
+  fail:
+     return name1;
+ }
+ 
+ /* Cache assumed to point correct directory */
+ int have_last_read(this_last_read,pathname,file_stat,last_read_time)
+      struct last_read_cache * this_last_read;
+      const char             * pathname;
+      struct stat            * file_stat;
+      time_t                 * last_read_time;
+ {
+     /*  this_last_read is from upgrade_last_read() */
+ 
+     const char             * name1 = pathname;
+     int ret = 0;
+     
+     if (LAST_READ_CACHE_magic != this_last_read->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     name1 = pathname_to_entryname(this_last_read,pathname,file_stat);
+ 
+     if (!name1) {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "have_last_read: %s: Invalid name\n",
+ 			 pathname));
+ 	goto fail;
+     }
+     
+     if (this_last_read->entries) {
+ 	union sort_key            key;
+ 	union sort_item           res;
+ 	union sort_item_default   def;
+ 	size_t idx = 0;
+ 	
+ 	key.str             = name1;
+ 	def.last_read_entry = NULL;
+ 	res.dummy           = NULL;
+ 
+ 	if (search_sort_list_item(this_last_read->entries,
+ 				  sort_list_search_normal,
+ 				  key,def,&res,&idx,
+ 				  NULL)) {
+ 
+ 	    if (res.last_read_entry) {
+ 		struct last_read_entry * entry = res.last_read_entry;
+ 
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "have_last_read: %s: %s found from %s idx %zu\n",
+ 				 pathname,name1,
+ 				 this_last_read->cache_file_name ?
+ 				 this_last_read->cache_file_name : "(no name)",
+ 				 idx));
+ 		
+ 		if (LAST_READ_ENTRY_magic != entry->magic)
+ 		    panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
+ 			  "Bad magic type (last_read_entry)",0);
+ 
+ 		if (ison(entry->entry_flags,LAST_READ_valid)) {
+ 
+ 		    if (FILE_CHANGES_magic != this_last_read->cache_file.magic)
+ 			panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
+ 			      "Bad magic number (file_changes)",0);
+ 		    
+ 		    if (file_stat && this_last_read->cache_file.valid) {
+ 			
+ 			if (this_last_read->cache_file.dev != file_stat->st_dev) {
+ 	
+ 			    DPRINT(Debug,13,(&Debug,
+ 					     "have_last_read: %s:  directory %s st_dev %ld != stat dev %ld\n",
+ 					     pathname,
+ 					     this_last_read->sys_dir ?
+ 					     this_last_read->sys_dir :
+ 					     "(default)",
+ 					     (long) this_last_read->cache_file.dev,
+ 					     (long) file_stat->st_dev));
+ 
+ 			    if (ison(entry->entry_flags, LAST_READ_have_st_ino)) {
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "have_last_read: %s: idx %zu %s have st_ino -- no match\n",
+ 						 pathname,idx,
+ 						 entry->folder_sys));
+ 				goto fail_match;
+ 			    }
+ 			    
+ 			} else {		       
+ 			    if (isoff(entry->entry_flags, LAST_READ_have_st_ino)) {
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "have_last_read: %s: idx %zu %s have no st_ino -- no match\n",
+ 						 pathname,idx,
+ 						 entry->folder_sys));
+ 				goto fail_match;
+ 			    }
+ 
+ 			    if (entry->st_ino != file_stat->st_ino) {
+ 				DPRINT(Debug,13,(&Debug,
+ 						 "have_last_read: %s: idx %zu %s st_ino %lu != stat ino %lu -- no match\n",
+ 						 pathname,idx,
+ 						 (unsigned long) entry->st_ino,
+ 						 (unsigned long) file_stat->st_ino,
+ 						 entry->folder_sys));
+ 				
+ 				goto fail_match;
+ 			    }
+ 			}
+ 		    }
+ 
+ 		    if (entry->last_read > 0 &&
+ 			(time_t)-1 != entry->last_read) {
+ 			char *X = ctime(& (entry->last_read));
+ 
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "have_last_read: %s: entry %zu %s last_read %ld",
+ 					 pathname,idx,
+ 					 entry->folder_sys,
+ 					 (long)entry->last_read));
+ 
+ 			if (X) { /* ctime() includes newline */
+ 			    DPRINT(Debug,13,(&Debug," -- %s",X));
+ 			} else {
+ 			    DPRINT(Debug,13,(&Debug,"\n"));
+ 			}
+ 					 			
+ 			if (last_read_time)
+ 			    *last_read_time = entry->last_read;
+ 
+ 			ret = 1;
+ 		    }
+ 		    
+ 			
+ 		} else {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "have_last_read: %s: entry %zu %s not valid\n",
+ 				     pathname,idx,
+ 				     entry->folder_sys));
+ 		}
+ 
+ 	    fail_match:
+ 		    
+ 		/* Decrements refcount */
+ 		free_last_read_entry(& res.last_read_entry);
+ 		
+ 	    } else {
+ 		 DPRINT(Debug,13,(&Debug,
+ 				  "have_last_read: %s: %s found from %s idx %zu - search_sort_list_item did not set last_read_entry\n",
+ 				  pathname,name1,
+ 				  this_last_read->cache_file_name ?
+ 				  this_last_read->cache_file_name : "(no name)",
+ 				  idx));
+ 	    }
+ 
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "have_last_read: %s: %s not found from %s\n",
+ 			     pathname,name1,
+ 			     this_last_read->cache_file_name ?
+ 			     this_last_read->cache_file_name : "(no name)"));
+ 	}
+ 	    
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "have_last_read: %s no entries on %s\n",
+ 			 pathname,
+ 			 this_last_read->cache_file_name ?
+ 			 this_last_read->cache_file_name : "(no name)"));
+     }
+ 
+ 
+  fail:
+     DPRINT(Debug,13,(&Debug,
+ 		     "have_last_read=%d; pathname=%s",
+ 		     ret,pathname));
+ 
+     if (last_read_time && *last_read_time > 0 && (time_t)-1 != *last_read_time) {
+ 	char *X = ctime(last_read_time);
+ 	DPRINT(Debug,13,(&Debug,
+ 			 " *last_read_time=%ld",
+ 			 *last_read_time));
+ 	
+ 	if (X) { /* ctime() includes newline */
+ 	    DPRINT(Debug,13,(&Debug," -- %s",X));
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug,"\n"));
+ 	}	
+     }
+ 
+     DPRINT(Debug,13,(&Debug,"\n"));
+     
+     return ret;
+ }
+ 
+ /* Possible allocates new, decrement old refcount if name is changed */
+ int update_last_read(dir_last_read,sys_dir)
+      struct last_read_cache ** dir_last_read;
+      const char * sys_dir;
+ {
+     int cache_changed = 0;
+     int ret = 0;
+ 
+     const char * resolved_dir = NULL;
+     
+     enum last_read_location new_loc = last_read_dir_to_loc(sys_dir,
+ 							  &resolved_dir);
+     
+     if (*dir_last_read) {
+ 	if (LAST_READ_CACHE_magic != (*dir_last_read)->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "update_last_read: old cache %p",
+ 			 *dir_last_read));
+ 	
+ 	if ((*dir_last_read)->sys_dir) {
+ 	    DPRINT(Debug,13,(&Debug,"; sys_dir=%s",
+ 			     (*dir_last_read)->sys_dir));
+ 	}
+ 	if (last_read_def_cache == *dir_last_read) {
+ 	    DPRINT(Debug,13,(&Debug,"; default cache"));
+ 	}
+ 	if ((*dir_last_read)->cache_file_name) {
+ 	    DPRINT(Debug,13,(&Debug,"; cache_file_name=%s",
+ 			     (*dir_last_read)->cache_file_name));
+ 	}       
+ 	DPRINT(Debug,13,(&Debug,"\n"));
+ 	
+ 	switch (new_loc) {
+ 	case read_loc_none: cache_changed = 1; break;
+ 	case read_loc_dir:
+ 	    if (! (*dir_last_read)->sys_dir ||
+ 		! resolved_dir              ||
+ 		! same_dir_str((*dir_last_read)->sys_dir,
+ 			       resolved_dir))
+ 		cache_changed = 1;
+ 	    break;
+ 	case read_loc_def:
+ 	    if ((*dir_last_read)->sys_dir)
+ 		cache_changed = 1;
+ 	    
+ 	}
+ 
+ 	if (cache_changed)
+ 	    free_last_read_cache(dir_last_read);
+ 	
+     } else
+ 	cache_changed = 1;
+ 
+     if (cache_changed) {
+ 
+ 	if (*dir_last_read)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
+ 		  "Cache still set",0);
+ 	
+ 	if (read_loc_dir == new_loc) {
+ 	    enum syscall_status  r;
+ 	    	    
+ 	    r = access(sys_dir,WRITE_ACCESS|EXECUTE_ACCESS);
+ 	    
+ 	    switch (r) {
+ 		int err UNUSED_VAROK;
+ 	    case syscall_error /* -1 */: 
+ 		err = errno;
+ 		
+ 		DPRINT(Debug,10,(&Debug,
+ 				 "update_last_read: No write access (and search) for %s:  %s (errno=%d)\n",
+ 				 sys_dir,strerror(err), err));
+ 		
+ 		/* No last_read_cache, if directory
+ 		   is not writable and executable (searchable)
+ 		*/
+ 		ret = 0;
+ 		goto out;
+ 	    case syscall_success /* 0 */:
+ 		DPRINT(Debug,10,(&Debug,
+ 				 "update_last_read: %s is accessible\n",
+ 				 sys_dir));
+ 		break;
+ 	    }
+ 	}
+ 
+ 	/* locate from last_read_dir_cache */
+ 	/* or last_read_def_cache      */
+ 
+ 	(*dir_last_read) = give_last_read(sys_dir,
+ 					  new_loc,resolved_dir,
+ 					  last_read_def_existing);
+     }
+ 
+     if (*dir_last_read) {
+ 	if (LAST_READ_CACHE_magic != (*dir_last_read)->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
+ 		  "Bad magic type (last_read_cache)",0);
+ 
+ 	DPRINT(Debug,10,(&Debug,
+ 			 "update_last_read: %s: cache %p",
+ 			 sys_dir,*dir_last_read));
+ 	
+ 	if ((*dir_last_read)->sys_dir) {
+ 	    DPRINT(Debug,10,(&Debug,"; sys_dir=%s",
+ 			     (*dir_last_read)->sys_dir));
+ 	}
+ 	if (last_read_def_cache == *dir_last_read) {
+ 	    DPRINT(Debug,10,(&Debug,"; default cache"));
+ 	}
+ 	if ((*dir_last_read)->cache_file_name) {
+ 	    DPRINT(Debug,10,(&Debug,"; cache_file_name=%s",
+ 			     (*dir_last_read)->cache_file_name));
+ 	}       
+ 
+ 	ret = 1;
+     } else {
+ 	DPRINT(Debug,10,(&Debug,
+ 			 "update_last_read: %s: No cache",
+ 			 sys_dir));
+ 
+ 	ret = 0;
+     }
+ 
+     if (cache_changed) {
+ 	DPRINT(Debug,10,(&Debug,"; cache changed\n"));
+     }
+     DPRINT(Debug,10,(&Debug,"\n"));
+ 
+  out:
+     DPRINT(Debug,12,(&Debug,
+ 		     "update_last_read=%d%s\n",
+ 		     ret,
+ 		     ret ? " last_read active" : ""));
+ 
+     return ret;
+ }
+ 
+ 
+ /* Increments refcount */
+ 
+ 
+ struct last_read_cache * last_read_enabled(use_lastread,cur_folder_sys,
+ 					   oldstat,curstat)
+      enum use_lastread_v use_lastread;
+      char             * cur_folder_sys;
+      struct stat      * oldstat;
+      struct stat      * curstat;
+ {
+     struct last_read_cache *ret = NULL;
+ 
+     int          free_sys_dir = 0;
+     char       * sys_dir      =  stat_file_to_sys_dir(cur_folder_sys,
+ 						      &free_sys_dir);
+     enum last_read_location last_read_loc =  read_loc_none;
+     const char * res_dir = NULL;
+ 
+     enum last_read_default may_create = last_read_def_existing;
+     struct last_read_cache * last_read = NULL;
+     
+     DPRINT(Debug,13,(&Debug,
+ 		     "last_read_enabled: use_lastread=%d",
+ 		     use_lastread));
+ 
+     switch (use_lastread) {
+     case use_lastread_no:       DPRINT(Debug,13,(&Debug," use_lastread_no\n"));     goto fail;
+     case use_lastread_yes:      DPRINT(Debug,13,(&Debug," use_lastread_yes"));
+ 	may_create = last_read_def_create;
+ 	break;
+     case use_lastread_auto:     DPRINT(Debug,13,(&Debug," use_lastread_auto"));     break;
+     case use_lastread_existing: DPRINT(Debug,13,(&Debug," use_lastread_existing")); break;
+     case NUM_use_lastread:                                                          break;
+     }
+ 
+     DPRINT(Debug,13,(&Debug,", cur_folder_sys=%s", cur_folder_sys));
+ 
+     if (oldstat) {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 ", oldstat dev/ino=%lu/%lu atime=%ld",
+ 			 (unsigned long)(oldstat->st_dev),
+                          (unsigned long)(oldstat->st_ino),
+ 			 (long)oldstat->st_atime));
+     }
+     if (curstat) {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 ", curstat dev/ino=%lu/%lu atime=%ld",
+ 			 (unsigned long)(curstat->st_dev),
+                          (unsigned long)(curstat->st_ino),
+ 			 (long)curstat->st_atime));
+     }
+     
+     if (oldstat && curstat) {
+ 	if (oldstat->st_dev == curstat->st_dev &&
+ 	    oldstat->st_ino == curstat->st_ino) {
+ 	    if (oldstat->st_atime == curstat->st_atime){
+ 		DPRINT(Debug,13,(&Debug,", time stampt not updated"));
+ 		if (use_lastread_auto == use_lastread) {
+ 		    may_create = last_read_def_create;
+ 		    DPRINT(Debug,13,(&Debug,", use last read"));
+ 		}
+ 	    } else if (oldstat->st_atime < curstat->st_atime) {
+ 		DPRINT(Debug,13,(&Debug,", time stamp advanced"));
+ 	    }
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug,", file changed"));
+ 	}
+     }
+     
+     DPRINT(Debug,13,(&Debug,"; sys_dir=%s\n",sys_dir));
+ 
+     last_read_loc = last_read_dir_to_loc(sys_dir,&res_dir);
+ 
+     DPRINT(Debug,13,(&Debug,
+ 		     "last_read_enabled: sys_dir=%s => location %d",
+ 		     sys_dir,
+ 		     last_read_loc));
+ 
+     switch (last_read_loc) {
+     case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none\n"));   goto fail;
+     case read_loc_dir:  DPRINT(Debug,13,(&Debug," read_loc_dir"));      break;
+     case read_loc_def:  DPRINT(Debug,13,(&Debug," read_loc_def"));      break;
+     }
+ 
+     if (res_dir) {
+ 	DPRINT(Debug,13,(&Debug,", res_dir=%s",res_dir));
+     }
+     DPRINT(Debug,13,(&Debug,"\n"));
+ 
+     if (read_loc_dir == last_read_loc) {
+ 
+ 	enum syscall_status  r = access(sys_dir,WRITE_ACCESS|EXECUTE_ACCESS);
+ 
+ 	switch (r) {
+ 	    int err UNUSED_VAROK;
+ 	case syscall_error /* -1 */: 
+ 	    err = errno;
+ 	    
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "last_read_enabled: No write access (and search) for %s:  %s (errno=%d)\n",
+ 			     sys_dir,strerror(err), err));
+ 	    
+ 	    /* No last_read_cache, if directory
+ 	       is not writable and executable (searchable)
+ 	    */
+ 	    goto fail;
+ 	case syscall_success /* 0 */:
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "last_read_enabled: %s is accessible\n",
+ 			     sys_dir));
+ 	    break;
+ 	}
+     }
+ 
+     last_read =  give_last_read(sys_dir,last_read_loc,res_dir,
+ 				may_create);
+ 
+     if (last_read) {
+ 	if (LAST_READ_CACHE_magic != last_read->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"last_read_enabled",
+ 		   "Bad magic type (last_read_cache)",0);
+ 	
+ 	switch (may_create) {
+ 	case  last_read_def_existing:
+ 
+ 	    if (last_read->entries) {
+ 		const char             * name1 
+ 		    = pathname_to_entryname(last_read,
+ 					    cur_folder_sys,
+ 					    curstat);
+ 
+ 		if (name1) {  /* NULL if / without absolute path */
+ 
+ 		    union sort_key            key;
+ 		    union sort_item           res;
+ 		    union sort_item_default   def;
+ 		    size_t idx = 0;
+ 		    
+ 		    key.str             = name1;
+ 		    def.last_read_entry = NULL;
+ 		    res.dummy           = NULL;
+ 
+ 		    if (search_sort_list_item(last_read->entries,
+ 					      sort_list_search_normal,
+ 					      key,def,&res,&idx,
+ 					      NULL)) {
+ 
+ 			if (res.last_read_entry) {
+ 			    struct last_read_entry * entry = res.last_read_entry;
+ 			    DPRINT(Debug,13,(&Debug,
+ 					     "last_read_enabled: %s: %s found from %s idx %zu\n",
+ 					     cur_folder_sys,name1,
+ 					     last_read->cache_file_name ?
+ 					     last_read->cache_file_name : "(no name)",
+ 					     idx));
+ 
+ 			    if (LAST_READ_ENTRY_magic != entry->magic)
+ 				panic("MBX PANIC",__FILE__,__LINE__,"last_read_enabled",
+ 				      "Bad magic type (last_read_entry)",0);
+ 			    
+ 			    ret = last_read;
+ 			    last_read = NULL;
+ 
+ 			    /* Decrements refcount */
+ 			    free_last_read_entry(& res.last_read_entry);
+ 			    
+ 			} else {
+ 			    DPRINT(Debug,13,(&Debug,
+ 					     "last_read_enabled: %s: %s found from %s idx %zu - search_sort_list_item did not set last_read_entry\n",
+ 					     cur_folder_sys,name1,
+ 					     last_read->cache_file_name ?
+ 					     last_read->cache_file_name : "(no name)",
+ 					     idx));
+ 			}
+ 		    } else {
+ 			DPRINT(Debug,13,(&Debug,
+ 					 "last_read_enabled: %s: %s not found from %s\n",
+ 					 cur_folder_sys,name1,
+ 					 last_read->cache_file_name ?
+ 					 last_read->cache_file_name : "(no name)"));
+ 		    }
+ 		} else {
+ 		    DPRINT(Debug,13,(&Debug,
+ 				     "last_read_enabled: %s: not valid\n",
+ 				     cur_folder_sys));
+ 		}
+ 
+ 	    } else {
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "last_read_enabled: %s: no entries on %s\n",
+ 				 cur_folder_sys,
+ 				 last_read->cache_file_name ?
+ 				 last_read->cache_file_name : "(no name)"));
+ 				 
+ 	    }
+ 
+ 	    break;
+ 
+ 	case last_read_def_create:
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "last_read_enabled: using last read cache %s",
+ 			     last_read->cache_file_name ?
+ 			     last_read->cache_file_name : "(no name)"));
+ 	    if (last_read->sys_dir) {
+ 		DPRINT(Debug,13,(&Debug," for %s",
+ 				 last_read->sys_dir));
+ 	    }
+ 		       
+ 	    DPRINT(Debug,13,(&Debug,"\n"));
+ 	    ret = last_read;
+ 	    last_read = NULL;
+ 	    break;
+ 	}
+ 
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "last_read_enabled: last read cache not available, sys_dir=%s\n",
+ 			 sys_dir));
+     }
+     
+  fail:
+     if (last_read)
+ 	free_last_read_cache(& last_read);
+     
+     if (sys_dir) {
+ 	if (free_sys_dir)
+ 	    free(sys_dir);
+ 	sys_dir = NULL;
+     }
+ 
+ 
+      if (ret) {
+ 	 if (LAST_READ_CACHE_magic != ret->magic)
+ 	     panic("MBX PANIC",__FILE__,__LINE__,"last_read_enabled",
+ 		   "Bad magic type (last_read_cache)",0);
+ 	 
+ 	 DPRINT(Debug,13,(&Debug,
+ 			  "last_read_enabled=%p",ret));
+ 	 if (ret->sys_dir) {
+ 	     DPRINT(Debug,13,(&Debug," sys_dir=%s",ret->sys_dir));
+ 	 }
+ 	 if (ret->cache_file_name) {
+ 	     DPRINT(Debug,13,(&Debug," cache_file_name=%s",ret->cache_file_name));
+ 	 }	
+      } else {
+ 	 DPRINT(Debug,13,(&Debug,
+ 			  "last_read_enabled=NULL"));
+      }
+      DPRINT(Debug,13,(&Debug,"; cur_folder_sys=%s\n",cur_folder_sys));
+     
+     return ret;
+ }
+ 
+ /* Writes cache */
+ 
+ void mark_last_read(cache,
+ 		    cur_folder_sys,
+ 		    curstat)
+      struct last_read_cache * cache;
+      char                   * cur_folder_sys;
+      struct stat            * curstat;
+ {
+     struct dt_flags_info   * locking =   
+ 	cache_guess_locking(cache);
+     struct last_read_open  * H       = NULL; 
+     const char             * name1   = NULL;
+ 
+     enum last_read_mode      read_mode = last_read_read_update;
+      
+     if (LAST_READ_CACHE_magic != cache->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mark_last_read",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     if (cache->cache_file_name && ! cache->read) {
+ 	enum syscall_status  r_access =
+ 	    access(cache->cache_file_name, ACCESS_EXISTS);
+ 
+ 	switch ( r_access) {
+ 	    int err UNUSED_VAROK;
+ 	case syscall_success:
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "mark_last_read: %s: cache file %s exists\n",
+ 			     cur_folder_sys,cache->cache_file_name));
+ 	    break;
+ 	case syscall_error:
+ 	    err = errno;
+ 
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "mark_last_read: %s: cache file %s gives: %s\n",
+ 			     cur_folder_sys,cache->cache_file_name,
+ 			     strerror(err)));
+ 
+ 	    if (ENOENT == err) {
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "mark_last_read: Need create %s\n",
+ 				 cache->cache_file_name));
+ 		read_mode = last_read_create;
+ 	    }
+ 	}	
+     }
+     
+     reload_last_read_cache(cache,&H,NULL,locking,read_mode,
+ 			   NULL /* errno_res */);
+ 
+     name1 = pathname_to_entryname(cache,
+ 				  cur_folder_sys,
+ 				  curstat);
+     
+     if (name1) {
+ 	
+ 	 union sort_key            key;
+ 	 union sort_item           res;
+ 	 union sort_item_default   def;
+ 	 size_t idx = 0;
+ 
+ 	 static struct last_read_entry_def def1 = {
+ 	     LAST_READ_ENTRY_DEF_magic,
+ 	     0 /* entry_flags */
+ 	 };
+ 	 
+ 	 key.str             = name1;
+ 	 def.last_read_entry = &def1;
+ 	 res.dummy           = NULL;
+ 
+ 	 if (search_sort_list_item(cache->entries,
+ 				   sort_list_search_create,
+ 				   key,def,&res,&idx,
+ 				   NULL)) {
+ 
+ 	     if (res.last_read_entry) {
+ 		 struct last_read_entry * entry = res.last_read_entry;
+ 
+ 		 DPRINT(Debug,13,(&Debug,
+ 				  "mark_last_read: %s: %s found (or created) from %s idx %zu\n",
+ 				  cur_folder_sys,name1,
+ 				  cache->cache_file_name ?
+ 				  cache->cache_file_name : "(no name)",
+ 				  idx));
+ 		 
+ 		 if (LAST_READ_ENTRY_magic != entry->magic)
+ 		     panic("MBX PANIC",__FILE__,__LINE__,
+ 			   "mark_last_read",
+ 			   "Bad magic type (last_read_entry)",0);
+ 		 
+ 		 cache->modified    = 1;  /* mark need write */
+ 		 entry->entry_flags = LAST_READ_modified;
+ 		 
+ 		 entry->last_read   = 0;
+ 		 entry->st_ino      = 0;
+ 
+ 		 if (FILE_CHANGES_magic != cache->cache_file.magic)
+ 		     panic("MBX PANIC",__FILE__,__LINE__,
+ 			   "mark_last_read",
+ 			   "Bad magic type (file_changes)",0);
+ 
+ 		 if (curstat && cache->cache_file.valid &&
+ 		     cache->cache_file.dev == curstat->st_dev) {
+ 		     
+ 		     entry->st_ino = curstat->st_ino;
+ 		     setit(entry->entry_flags, LAST_READ_have_st_ino);
+ 		 }
+ 
+ 		 /* XXX  is this correct? */
+ 		 if ((time_t)-1 != time(& (entry->last_read))) {
+ 		     setit(entry->entry_flags, LAST_READ_valid);
+ 		 }
+ 		 
+ 		 /* Decrements refcount */
+ 		 free_last_read_entry(& res.last_read_entry);
+ 			    
+ 	     } else {
+ 		 DPRINT(Debug,13,(&Debug,
+ 				  "mark_last_read: %s: %s found (or created) from %s idx %zu - search_sort_list_item did not set last_read_entry\n",
+ 				  cur_folder_sys,name1,
+ 				  cache->cache_file_name ?
+ 				  cache->cache_file_name : "(no name)",
+ 				  idx));
+ 	     }
+ 		 
+ 	 } else { 	     
+ 	     DPRINT(Debug,13,(&Debug,
+ 			      "mark_last_read: %s: %s not found (or created) from %s\n",
+ 			      cur_folder_sys,name1,
+ 			      cache->cache_file_name ?
+ 			      cache->cache_file_name : "(no name)"));
+ 	 }
+ 	 
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "mark_last_read: %s: not valid\n",
+ 			 cur_folder_sys));
+     }
+         
+     if (H) {
+ 
+ 	if (LAST_READ_OPEN_magic != H->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "mark_last_read",
+ 		  "Bad magic number (last_read_open)",0);
+ 	
+ 	if (last_read_def_cache == cache) {
+ 	    last_read_def_rewrite =  ison(H->lread_open_flags,
+ 					 LREAD_OPEN_SUGGEST_REWRITE);
+ 	}
+ 		
+ 	if (cache->modified || ison(H->lread_open_flags,
+ 				    LREAD_OPEN_SUGGEST_REWRITE)) {
+ 
+ 	    if (write_last_read_cache(H,cache,locking,
+ 				      NULL /* errno_res */,
+ 
+ 				      /* commentfile,actor,version_buff */
+ 				      NULL,NULL,NULL
+ 				      )) {
+ 
+ 		DPRINT(Debug,13,(&Debug,
+ 				 "mark_last_read: %s: cache %s updated\n",
+ 				 cur_folder_sys,
+ 				 cache->cache_file_name ?
+ 				 cache->cache_file_name : "(no name)"));
+ 
+ 		if (last_read_def_cache == cache) {
+ 		    last_read_def_rewrite = 0;
+ 		}
+ 		
+ 	    }
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "mark_last_read: %s: cache %s not modified\n",
+ 			     cur_folder_sys,
+ 			     cache->cache_file_name ?
+ 			     cache->cache_file_name : "(no name)"));
+ 	}
+ 
+ 	free_last_read_open(&H);
+     } else {
+ 	DPRINT(Debug,13,(&Debug,
+ 			 "mark_last_read: %s: cache %s not open\n",
+ 			 cur_folder_sys,
+ 			 cache->cache_file_name ?
+ 			 cache->cache_file_name : "(no name)"));
+     }
+ }
+ 
+ 
+ static int flag_cache_entry P_((struct sortlist     * cache_entries,
+ 				const char          * sys_dir,
+ 				const char          * entryname,
+ 				const char          * cache_file_name
+ 				));
+ static int flag_cache_entry(cache_entries,sys_dir,entryname,cache_file_name)
+      struct sortlist     * cache_entries;
+      const char          * sys_dir;
+      const char          * entryname;
+      const char          * cache_file_name;
+ {
+     int ret = 0;
+     union sort_key            key;
+     union sort_item           res;
+     union sort_item_default   def;
+     size_t idx = 0;
+     
+     key.str             = entryname;
+     def.last_read_entry = NULL;
+     res.dummy           = NULL;
+ 
+     
+     if (search_sort_list_item(cache_entries,
+ 			      sort_list_search_normal,
+ 			      key,def,&res,&idx,
+ 			      NULL)) {
+ 
+ 	if (res.last_read_entry) {
+ 	    struct last_read_entry * entry = res.last_read_entry;
+ 	    
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "flag_cache_entry: %s: %s found from %s idx %zu\n",
+ 			     sys_dir,entryname,
+ 			     cache_file_name ?
+ 			     cache_file_name : "(no name)",
+ 			     idx));
+ 
+ 	    if (LAST_READ_ENTRY_magic != entry->magic)
+ 		panic("MBX PANIC",__FILE__,__LINE__,
+ 		      "flag_cache_entry",
+ 		      "Bad magic type (last_read_entry)",0);
+ 
+ 	    
+ 	    setit(entry->entry_flags,LAST_READ_flag);
+ 
+ 	    ret = 1;
+ 	    
+ 	    /* Decrements refcount */
+ 	    free_last_read_entry(& res.last_read_entry);
+ 		
+ 	} else {
+ 	    DPRINT(Debug,13,(&Debug,
+ 			     "flag_cache_entry: %s: %s found from %s idx %zu - search_sort_list_item did not set last_read_entry\n",
+ 			     sys_dir,entryname,
+ 			     cache_file_name ?
+ 			     cache_file_name : "(no name)",			     
+ 			     idx));
+ 	}
+ 
+     } else {
+ 	DPRINT(Debug,15,(&Debug,
+ 			 "flag_cache_entry: %s: %s not found from %s\n",
+ 			 sys_dir,entryname,
+ 			 cache_file_name ?
+ 			 cache_file_name : "(no name)"));
+     }
+ 
+     return ret;
+ }
+ 
+ /* Flag local entries  and matching with sys_dir prefix */
+ void flag_last_read(dir_last_read,sys_dir,entryname)
+      struct last_read_cache * dir_last_read;
+      const char * sys_dir;
+      const char * entryname;
+      
+ {    
+     if (LAST_READ_CACHE_magic != dir_last_read->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"flag_last_read",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     if (sys_dir && dir_last_read->sys_dir &&
+ 	! same_dir_str(sys_dir,dir_last_read->sys_dir)) {
+ 
+ 	DPRINT(Debug,15,(&Debug,
+ 			 "flag_last_read: dir_last_read=%p sys_dir=%s entryname=%s does dor match to cache dir %s\n",
+ 			 dir_last_read,sys_dir,entryname,dir_last_read->sys_dir));	
+     }
+ 
+     if (dir_last_read->entries) {
+ 
+ 	int r = 0;
+ 
+ 	r += flag_cache_entry(dir_last_read->entries,
+ 			      sys_dir,entryname,
+ 			      dir_last_read->cache_file_name);
+ 
+ 	if ('/' != entryname[0]) {
+ 	    char * str = cat_dir_entry(sys_dir,entryname);
+ 
+ 	    r += flag_cache_entry(dir_last_read->entries,
+ 				  sys_dir,str,
+ 				  dir_last_read->cache_file_name);
+ 
+ 	    free(str);
+ 	}
+ 
+ 	if (r) {
+ 	    DPRINT(Debug,15,(&Debug,
+ 			     "flag_last_read: dir_last_read=%p sys_dir=%s entryname=%s flagged\n",
+ 			     dir_last_read,sys_dir,entryname));
+ 	}
+     }
+ }
+ 
+ /* deletes not flagged local entries (and absolute path entries
+    matching with sys_dir prefix) 
+ */
+ void purge_last_read(dir_last_read,sys_dir)
+      struct last_read_cache * dir_last_read;
+      const char * sys_dir;
+ {
+     if (LAST_READ_CACHE_magic != dir_last_read->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"purge_last_read",
+ 	      "Bad magic type (last_read_cache)",0);
+ 
+     if (dir_last_read->entries) {
+ 	size_t  cache_len = sort_list_len(dir_last_read->entries);
+ 
+ 	DPRINT(Debug,15,(&Debug,
+ 			 "purge_last_read: dir_last_read=%p sys_dir=%s  %zu items\n",
+ 			 dir_last_read,sys_dir,cache_len));
+ 
+ 	if (cache_len > 0) {
+ 	    size_t i = cache_len -1;
+ 	    size_t deleted  = 0;
+ 	    size_t valid    = 0;
+ 	    size_t flagged    = 0;
+ 	    size_t bad_prefix = 0;
+ 	    size_t modified = 0;
+ 
+ 	    size_t sys_dir_len = strlen(sys_dir);
+ 
+ 	    if (sys_dir_len > 0 && '/' == sys_dir[sys_dir_len-1])
+ 		sys_dir_len--;
+ 	    		
+ 	    while (1) {
+ 		union sort_item res;
+ 
+ 		res.last_read_entry = NULL;
+ 		
+ 		/* Increments refcount */
+ 		get_sort_list_item(dir_last_read->entries,sort_list_get_normal,i,
+ 				   &res);
+ 
+ 		if (res.last_read_entry) {
+ 		    struct last_read_entry * entry;
+ 
+ 		    int need_delete = 0;
+ 		    
+ 		    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 			panic("MBX PANIC",__FILE__,__LINE__,
+ 			      "purge_last_read",
+ 			      "Bad magic type (last_read_entry)",0);
+ 		    
+ 		    entry = res.last_read_entry;
+ 		    
+ 		    if (ison(entry->entry_flags,LAST_READ_valid))
+ 			valid++;
+ 		    if (ison(entry->entry_flags,LAST_READ_modified))
+ 			modified++;
+ 
+ 		    if (ison(entry->entry_flags,LAST_READ_flag))
+ 			flagged++;
+ 		    else {
+ 
+ 			if ('/' != entry->folder_sys[0]) {
+ 			    need_delete = 1;
+ 			    
+ 			} else if (sys_dir_len > 0 &&
+ 				   0 == strncmp(entry->folder_sys,
+ 						sys_dir,sys_dir_len) &&
+ 				   '/' == entry->folder_sys[sys_dir_len]) {
+ 			    
+ 			    /* Matches prefix */
+ 
+ 			    need_delete = 1;
+ 
+ 			} else
+ 			    bad_prefix++;
+ 			    
+ 		    }
+ 
+ 		    if (isoff(entry->entry_flags,LAST_READ_valid) ||
+ 			(need_delete &&
+ 			 isoff(entry->entry_flags,LAST_READ_modified))) {
+ 
+ 			free_last_read_entry(& res.last_read_entry);
+ 
+ 			/* Increments refcount */
+ 			get_sort_list_item(dir_last_read->entries,sort_list_get_remove,i,
+ 					   &res);
+ 			
+ 			if (res.last_read_entry) {
+ 			    struct last_read_entry * entry;
+ 			    
+ 			    if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ 				panic("MBX PANIC",__FILE__,__LINE__,
+ 				      "purge_last_read",
+ 				      "Bad magic type (last_read_entry)",0);
+ 			    
+ 			    entry = res.last_read_entry;
+ 			    
+ 			    DPRINT(Debug,14,(&Debug,
+ 					     "purge_last_read: dir_last_read=%p #%zu folder_sys=%s - deleted\n",
+ 					     dir_last_read,i,entry->folder_sys));
+ 			    
+ 			    
+ 			    deleted++;
+ 			}
+ 		    } else
+ 			clearit(entry->entry_flags,LAST_READ_flag);
+ 		    
+ 		    if (res.last_read_entry) 
+ 			free_last_read_entry(& res.last_read_entry);
+ 		}	   
+ 
+ 		if (i > 0)
+ 		    i--;
+ 		else
+ 		    break;
+ 	    }
+ 	    
+ 	    DPRINT(Debug,14,(&Debug,
+ 			     "purge_last_read: dir_last_read=%p %zu valid, %zu flagged, %zu bad prefix, %zu modified - %zu deleted.\n",
+ 			     dir_last_read,valid,flagged,bad_prefix,modified,deleted));	    
+ 	}
+ 
+     }
+     
+ }
+ 
+ 
+ 
+ /*
+  * Local Variables:
+  *  mode:c
+  *  c-basic-offset:4
+  *  buffer-file-coding-system: iso-8859-1
+  * End:
+  */
Index: elmME+.2.5.alpha64-cvs/lib/mbox/localmbx.c
*** elmME+.2.5.alpha63/lib/mbox/localmbx.c	Sat Nov 25 10:59:28 2023
--- elmME+.2.5.alpha64-cvs/lib/mbox/localmbx.c	Thu Jun 13 20:36:55 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: localmbx.c,v 2.77 2022/12/16 17:55:15 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.77 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: localmbx.c,v 2.79 2024/06/13 17:36:55 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.79 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 249,254 ****
--- 249,257 ----
      DIR *   handle;
  
      int max_namelen;                     /* Max length of file name */
+ 
+     /* last read file for this directory */
+     struct last_read_cache * this_last_read;
  };
  
  
***************
*** 279,284 ****
--- 282,289 ----
      }
  
  
+     ret->this_last_read  = NULL;
+     
      return ret;
  }
  
***************
*** 295,300 ****
--- 300,313 ----
  	(*ptr)->handle = NULL;
      }
  
+ 
+     if ((*ptr)->this_last_read) {
+ 	flush_last_read((*ptr)->this_last_read);
+ 
+ 	/* Decrements refcount */
+ 	free_last_read_cache(& ((*ptr)->this_last_read));
+     }
+ 	
      (*ptr)->magic   = 0;        /* Invalidate */
  
      free(*ptr);
***************
*** 424,433 ****
--- 437,494 ----
  }
  
  
+ /* result is malloced */
+ char * cat_dir_entry(sys_dir,entryname)
+      const char *sys_dir;
+      const char *entryname;
+ {
+     size_t l1 = 0;
+     char * pathname = NULL;
+     
+     if (sys_dir) {
+ 	l1 = strlen(sys_dir);
+ 	pathname = safe_strdup(sys_dir);
+ 	if (l1 > 0 && '/' != sys_dir[l1-1])
+ 	    pathname = strmcat(pathname,"/");
+     }
+     
+     pathname = strmcat(pathname,entryname);
+ 
+     DPRINT(Debug,20,(&Debug,
+ 		     "cat_dir_entry=%s; sys_dir=%s (len %zu), entryname=%s\n",
+ 		     pathname,
+ 		     sys_dir ? sys_dir : "<NULL>",l1,entryname));
+ 
+     return pathname;
+ }
+ 
  /* Result is malloced */
  static char * give_sessionlock_fname P_((char *mbox,struct stat *mbox_stat));
  				 
  
+ struct last_read_cache *browser_local_last_read(dir)
+      struct folder_browser *dir;
+ {
+ 
+     if (FOLDER_BROWSER_magic != dir->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"browser_local_last_read",
+ 	      "Bad magic type (folder_browser)",0);
+ 
+     if (&local_browser == dir->type &&
+ 	dir->a.local_browser) {
+ 
+ 
+ 	if (LOCAL_BROWSER_magic != dir->a.local_browser->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,"browser_local_last_read",
+ 		  "Bad magic type",0);
+ 
+         return dir->a.local_browser->this_last_read;
+     }
+     
+     return NULL;
+ }
+ 
+ 
  static void browser_local_do_stat_2 P_((struct folder_browser *dir,
  					struct name_vector *entry,
  					int add_fbentry));
***************
*** 442,450 ****
  
      char * entryname;
      int flags;
-     int l1 = strlen(dir->sys_dir);
      int have_stat = 0;
! 
  #ifdef SYMLINK
      int       have_lbuf = 0;
      struct stat    lbuf;		/* lstat command  */
--- 503,511 ----
  
      char * entryname;
      int flags;
      int have_stat = 0;
!     enum syscall_status  r;
!     
  #ifdef SYMLINK
      int       have_lbuf = 0;
      struct stat    lbuf;		/* lstat command  */
***************
*** 454,473 ****
  
      entryname = entry->sys_name;
  
!     pathname = safe_strdup(dir->sys_dir);
!     if (l1 > 0 && '/' != dir->sys_dir[l1-1])
! 	pathname = strmcat(pathname,"/");
!     pathname = strmcat(pathname,entryname);
      
      DPRINT(Debug,20,(&Debug,
  		     "browser_local_do_stat_2: %s -> %s\n", 
  		     entryname,pathname));
  
  #ifdef SYMLINK
!     if (0 == lstat(pathname, &lbuf)) {
  	
  	have_lbuf = 1;
! 
  	if (
  #ifdef S_ISLNK
  	    S_ISLNK(lbuf.st_mode)
--- 515,538 ----
  
      entryname = entry->sys_name;
  
!     pathname =  cat_dir_entry(dir->sys_dir,entryname);
      
      DPRINT(Debug,20,(&Debug,
  		     "browser_local_do_stat_2: %s -> %s\n", 
  		     entryname,pathname));
  
+     if (LOCAL_BROWSER_magic != dir->a.local_browser->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"browser_local_do_stat_2",
+ 	      "Bad magic number (LOCAL_BROWSER)",0);
+   
  #ifdef SYMLINK
!     r = lstat(pathname, &lbuf);
! 
!     switch(r) {
!     case syscall_success /* 0 */: {
  	
  	have_lbuf = 1;
! 	
  	if (
  #ifdef S_ISLNK
  	    S_ISLNK(lbuf.st_mode)
***************
*** 475,485 ****
  	    (lbuf.st_mode & S_IFMT) == S_IFLNK
  #endif
  	    ) {
! 	    int maxlen = dir->a.local_browser->max_namelen;
! 
  	    char * buffer = safe_malloc(maxlen+4);
  	    int len;
! 
  	    DPRINT(Debug,13,(&Debug,
  			     "browser_local_do_stat_2: %s is symbolic link\n",pathname));
  
--- 540,549 ----
  	    (lbuf.st_mode & S_IFMT) == S_IFLNK
  #endif
  	    ) {
! 	    int    maxlen = dir->a.local_browser->max_namelen;
  	    char * buffer = safe_malloc(maxlen+4);
  	    int len;
! 	    
  	    DPRINT(Debug,13,(&Debug,
  			     "browser_local_do_stat_2: %s is symbolic link\n",pathname));
  
***************
*** 496,502 ****
  
  	    } else if (len == maxlen) {
  		DPRINT(Debug,13,(&Debug,
! 				 "browser_local_do_stat_2: Overflow? (maxlen=%d)\n",maxlen));
  
  		strcpy(buffer+maxlen,"...");
  	    } else if (len > 0) {
--- 560,567 ----
  
  	    } else if (len == maxlen) {
  		DPRINT(Debug,13,(&Debug,
! 				 "browser_local_do_stat_2: Overflow? (maxlen=%d)\n",
! 				 maxlen));
  
  		strcpy(buffer+maxlen,"...");
  	    } else if (len > 0) {
***************
*** 535,572 ****
  	    free(buffer); buffer = NULL;
  	}
  
!     } else {
! 	int err UNUSED_VAROK = errno;
  
  	DPRINT(Debug,13,(&Debug,
  			 "browser_local_do_stat_2: lstat %s: (errno=%d) %s\n",
  			 pathname,err,strerror(err)));
! 
! 
      }
  #endif
  
!     if (0 == stat(pathname,&buf))
  	have_stat = 1;
!     else {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,13,(&Debug,
  			 "browser_local_do_stat_2: stat %s: (errno=%d) %s\n",
  			 pathname,err,strerror(err)));
  	flags = BROWSER_NOFOLDER|BROWSER_NODIR;
! 
  #ifdef SYMLINK
  	if (have_lbuf) {
  	    buf = lbuf;
  	    have_stat = 1;
! 
  	    DPRINT(Debug,13,(&Debug,
  			     "browser_local_do_stat_2: Using lstat result instead\n"));
  	}
! #endif
! 
!     } 
! 
  
      if (have_stat) {
  	Xbuf = &buf;
--- 600,647 ----
  	    free(buffer); buffer = NULL;
  	}
  
!     }
! 	break;
  
+     case syscall_error /* -1 */: {
+ 	int err UNUSED_VAROK = errno;
+ 	
  	DPRINT(Debug,13,(&Debug,
  			 "browser_local_do_stat_2: lstat %s: (errno=%d) %s\n",
  			 pathname,err,strerror(err)));
! 	
! 	
!     }
! 	break;
      }
  #endif
  
!     r = stat(pathname,&buf);
! 
!     switch(r) {
!     case syscall_success /* 0 */:	
  	have_stat = 1;
! 	break;
! 
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,13,(&Debug,
  			 "browser_local_do_stat_2: stat %s: (errno=%d) %s\n",
  			 pathname,err,strerror(err)));
  	flags = BROWSER_NOFOLDER|BROWSER_NODIR;
! 	
  #ifdef SYMLINK
  	if (have_lbuf) {
  	    buf = lbuf;
  	    have_stat = 1;
! 	    
  	    DPRINT(Debug,13,(&Debug,
  			     "browser_local_do_stat_2: Using lstat result instead\n"));
  	}
! #endif	
!     }
! 	break;
!     }
  
      if (have_stat) {
  	Xbuf = &buf;
***************
*** 596,612 ****
  		DPRINT(Debug,12,(&Debug,"                           display_name =%S\n",
  				 fb->display_name));
  	    }
  	}
  
! 	
! 	flags = local_stat_flags(pathname,&buf);
  
  	if (entry->a.local_browser) {
  
  	    if (LOCAL_BR_entry_magic != entry->a.local_browser->magic)
  		panic("MBX PANIC",__FILE__,__LINE__,"browser_local_do_stat_2",
  		      "Bad magic number on local_browser",0);
  
  	    if (entry->a.local_browser->fbentry) {
  
  		struct fbentry *fb = entry->a.local_browser->fbentry;
--- 671,692 ----
  		DPRINT(Debug,12,(&Debug,"                           display_name =%S\n",
  				 fb->display_name));
  	    }
+ 
  	}
  
! 	flags = local_stat_flags(pathname,&buf,
! 				 /* Not correct if this is symlink entry */
! 				 dir->a.local_browser->this_last_read);
  
  	if (entry->a.local_browser) {
  
+ 
  	    if (LOCAL_BR_entry_magic != entry->a.local_browser->magic)
  		panic("MBX PANIC",__FILE__,__LINE__,"browser_local_do_stat_2",
  		      "Bad magic number on local_browser",0);
  
+ 
+ 	    
  	    if (entry->a.local_browser->fbentry) {
  
  		struct fbentry *fb = entry->a.local_browser->fbentry;
***************
*** 629,635 ****
  		DPRINT(Debug,13,(&Debug,"                           mtime        =%ld\n",
  				 (long) fb->mtime));
  	    }
! 	}
      }
  
  
--- 709,718 ----
  		DPRINT(Debug,13,(&Debug,"                           mtime        =%ld\n",
  				 (long) fb->mtime));
  	    }
! 	    
! 	} 
! 
! 	
      }
  
  
***************
*** 638,652 ****
  							"mailhome-dir",
  							NULL,NULL);
  	
! 	/* sessionlock filename  -- check that this is mailbox (not folder) */
  	is_mailbox = mailhome_val &&
  	    in_directory(Xbuf,pathname,mailhome_val);
      }
  
      if (! is_mailbox) {
! 	const char * default_val = give_dt_estr_as_str(&defaultfile_e,
! 						       "incoming-mailbox",
! 						       NULL, NULL); /* XXXX */
  	
  	if (default_val) {
  	    is_mailbox = 0 == strcmp(pathname, default_val);
--- 721,738 ----
  							"mailhome-dir",
  							NULL,NULL);
  	
! 	/* sessionlock filename  -- check that this is mailbox 
! 	   (not folder) 
! 	*/
  	is_mailbox = mailhome_val &&
  	    in_directory(Xbuf,pathname,mailhome_val);
      }
  
      if (! is_mailbox) {
! 	const char * default_val =
! 	    give_dt_estr_as_str(&defaultfile_e,
! 				"incoming-mailbox",
! 				NULL, NULL); /* XXXX */
  	
  	if (default_val) {
  	    is_mailbox = 0 == strcmp(pathname, default_val);
***************
*** 846,853 ****
--- 932,957 ----
  	}
      }
  #endif
+        
+     if (update_last_read(& (dir->a.local_browser->this_last_read),
+ 			 dir->sys_dir)) {
  
+ 	DPRINT(Debug,15,(&Debug,
+ 			 "browser_fill_local: dir=%p this_last_read=%p for %s\n",
+ 			 dir,
+ 			 dir->a.local_browser->this_last_read,
+ 			 dir->sys_dir));
+ 			 
+     } else {
+ 	DPRINT(Debug,15,(&Debug,
+ 			 "browser_fill_local: dir=%p No last read for %s\n",
+ 			 dir,
+ 			 dir->sys_dir));
+     }
+     
      rewinddir(dir->a.local_browser->handle);
+     
+     
     
      while (NULL != (Xptr = readdir(dir->a.local_browser->handle))) {
  	char * lock_basename = NULL;
***************
*** 865,871 ****
  	/* Returns static pointer */
  	lock_basename = is_lockname(entryname);
  	if (lock_basename) {
! 	    struct lockname_buffer * lbuffer = safe_zero_alloc(sizeof (struct lockname_buffer));
  
  	    lbuffer->next      = lockname_buffer;
  	    lbuffer->lockname  = entryname;    entryname = NULL;
--- 969,976 ----
  	/* Returns static pointer */
  	lock_basename = is_lockname(entryname);
  	if (lock_basename) {
! 	    struct lockname_buffer * lbuffer =
! 		safe_zero_alloc(sizeof (struct lockname_buffer));
  
  	    lbuffer->next      = lockname_buffer;
  	    lbuffer->lockname  = entryname;    entryname = NULL;
***************
*** 876,881 ****
--- 981,992 ----
  	} else 	if ('.' != Xptr->d_name[0] ||
  	    dir->a.local_browser->dotmode) {
  
+ 
+ 	    if (dir->a.local_browser->this_last_read)
+ 		flag_last_read(dir->a.local_browser->this_last_read,
+ 			       dir->sys_dir,
+ 			       entryname);
+ 	    
  	    /* WARNING: add_dir_vector does not allocate strings -- 
  	     *          it just assign pointers!	    
  	     */
***************
*** 918,923 ****
--- 1029,1039 ----
  	    if ('.' != X->lockname[0] ||
  		dir->a.local_browser->dotmode) {
  	    
+ 		if (dir->a.local_browser->this_last_read)
+ 		    flag_last_read(dir->a.local_browser->this_last_read,
+ 				   dir->sys_dir,
+ 				   X->lockname);
+ 
  		/* WARNING: add_dir_vector does not allocate strings -- 
  		 *          it just assign pointers!	    
  		 */
***************
*** 951,956 ****
--- 1067,1078 ----
      }
  
  
+     if (dir->a.local_browser->this_last_read) {
+ 	purge_last_read(dir->a.local_browser->this_last_read,
+ 			dir->sys_dir);
+ 	flush_last_read(dir->a.local_browser->this_last_read);
+     }
+ 
      DPRINT(Debug,13,(&Debug,
  		     "browser_fill_local: added=%d skipped=%d lockskipped=%d (marked=%d added=%d skipped=%d)\n",
  		     added,skipped,lockskipped,
***************
*** 1421,1429 ****
--- 1543,1555 ----
  
      DPRINT(Debug,11,(&Debug,"browser_change_local: dir=%p\n", dir));
  
+ 
+     
      if (dir->dirname)
  	old_dirname =  dup_string(dir->dirname);
  
+ 
+     
      relative = browser_descend_local(dir,rel_dirname);
  
      /* browser_select_generic uses 'rel_dirname' if
***************
*** 1436,1447 ****
      if (LOCAL_BROWSER_magic != dir->a.local_browser->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"browser_change_local",
  	      "Bad magic type",0);
!     
      if (0 != access(str,READ_ACCESS)) {
  	new_dir = NULL;
      } else
  	new_dir = opendir(str);
!     
      if (!new_dir) {
  	int err = errno;
  	lib_error(CATGETS(elm_msg_cat, MeSet, MeDirError,
--- 1562,1573 ----
      if (LOCAL_BROWSER_magic != dir->a.local_browser->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"browser_change_local",
  	      "Bad magic type",0);
! 
      if (0 != access(str,READ_ACCESS)) {
  	new_dir = NULL;
      } else
  	new_dir = opendir(str);
! 
      if (!new_dir) {
  	int err = errno;
  	lib_error(CATGETS(elm_msg_cat, MeSet, MeDirError,
***************
*** 1451,1460 ****
--- 1577,1594 ----
  	goto fail;
      }
  
+     
+     
      if (dir->a.local_browser->handle) 
  	closedir(dir->a.local_browser->handle);
      dir->a.local_browser->handle = new_dir;
  
+     if (dir->a.local_browser->this_last_read) {
+ 	flush_last_read(dir->a.local_browser->this_last_read);
+ 	
+ 	free_last_read_cache(& (dir->a.local_browser->this_last_read));
+     }
+ 	
      ret = 1;
  		
      if (dir->dirname)
***************
*** 1474,1480 ****
      DPRINT(Debug,12,(&Debug,
  		     "browser_change_local: Delaying reading of directory\n"));
      dir->vector_len = -1;
! 
   fail:
      if (!ret) {	
  	if (old_sys_dir && !dir->sys_dir)
--- 1608,1614 ----
      DPRINT(Debug,12,(&Debug,
  		     "browser_change_local: Delaying reading of directory\n"));
      dir->vector_len = -1;
!        
   fail:
      if (!ret) {	
  	if (old_sys_dir && !dir->sys_dir)
***************
*** 1564,1570 ****
  
      FAIL2:      
  	/* Handle changing to .. */
! 
  	if (0 == strcmp(X->sys_name,"..")) {    
  	    int slen = strlen(dir->sys_dir);
  	    int len = -1;
--- 1698,1704 ----
  
      FAIL2:      
  	/* Handle changing to .. */
! 	
  	if (0 == strcmp(X->sys_name,"..")) {    
  	    int slen = strlen(dir->sys_dir);
  	    int len = -1;
***************
*** 1658,1664 ****
  		      Lstr, strerror(err));
  	    goto fail;
  	}
! 	
  	ret = 1;
  	
  	
--- 1792,1803 ----
  		      Lstr, strerror(err));
  	    goto fail;
  	}
! 
! 	if (dir->a.local_browser->this_last_read) {
! 	    flush_last_read(dir->a.local_browser->this_last_read);
! 	    
! 	    free_last_read_cache(& (dir->a.local_browser->this_last_read));
! 	}
  	ret = 1;
  	
  	
***************
*** 1718,1723 ****
--- 1857,1868 ----
  	    goto fail_empty;
  	}
  
+ 	if (dir->a.local_browser->this_last_read) {
+ 	    flush_last_read(dir->a.local_browser->this_last_read);
+ 	    
+ 	    free_last_read_cache(& (dir->a.local_browser->this_last_read));
+ 	}
+ 	
  	ret = 1;
  	
  	dir->dirname = dup_string(X->disp_name);
***************
*** 1774,1779 ****
--- 1919,1930 ----
      }
  
  
+     if (dir->a.local_browser->this_last_read) {
+ 	flush_last_read(dir->a.local_browser->this_last_read);
+ 	
+ 	free_last_read_cache(& (dir->a.local_browser->this_last_read));
+     }
+     
      L1 =  browser_change_up_helper(dir->dirname,0x002F /* '/' */);
  
      if (L1 > 0) {
***************
*** 1866,1888 ****
       struct string **buffer;
  {
      int F = 0;
!     char * str = NULL;
! 
!     if (dir->sys_dir) {
! 	int l = strlen(dir->sys_dir);
! 	str = safe_strdup(dir->sys_dir);
! 
! 	if (l > 0 && '/' != str[l-1]) {
! 	    char buf[2];
!             buf[0] = '/';
!             buf[1] = '\0';
!             str = strmcat(str,buf);
! 	}
!     }
  
!     str = strmcat(str,entry->sys_name);
  
!     F = local_selection_stat(str);
  
      /* WARNING: set_dir_selection does not allocate strings -- 
       *          it just assign pointers!
--- 2017,2032 ----
       struct string **buffer;
  {
      int F = 0;
!     
!     char * str = cat_dir_entry(dir->sys_dir,entry->sys_name);
  
!     if (LOCAL_BROWSER_magic != dir->a.local_browser->magic)
! 	panic("MBX PANIC",__FILE__,__LINE__,"browser_select_idx_local",
! 	      "Bad magic number (LOCAL_BROWSER)",0);
  
!     
!     F = local_selection_stat(str,
! 			     dir->a.local_browser->this_last_read);
  
      /* WARNING: set_dir_selection does not allocate strings -- 
       *          it just assign pointers!
***************
*** 3023,3033 ****
  	
  	char *buffer = NULL;
  	int      len = 0;
! 
! 	if (0 == stat(str,&buf)) 
  	    have_stat = 1;
! 	else {
! 	    int err = errno;
  	    
  	    if (print_error) 
  		lib_error(CATGETS(elm_msg_cat, MeSet, MeSelectionNoAccess,
--- 3167,3182 ----
  	
  	char *buffer = NULL;
  	int      len = 0;
! 	enum syscall_status  r = stat(str,&buf);
! 	int err;
! 	
! 	switch (r) {
! 	case syscall_success /* 0 */:
  	    have_stat = 1;
! 	    break;
! 
! 	case syscall_error /* -1 */: {
! 	    err = errno;
  	    
  	    if (print_error) 
  		lib_error(CATGETS(elm_msg_cat, MeSet, MeSelectionNoAccess,
***************
*** 3041,3052 ****
  	    ret = 0;
  	    goto FAIL;       
  	}
  
  
  	F = fopen(str,"r");
  	
  	if (!F) {
! 	    int err = errno;
  	    
  	    if (print_error) 
  		lib_error(CATGETS(elm_msg_cat, MeSet, MeSelectionNoAccess,
--- 3190,3220 ----
  	    ret = 0;
  	    goto FAIL;       
  	}
+ 	    break;
+ 	}
+ 
+ 	err = can_open(str,"r");
+ 	if (err) {
+ 
+ 	    if (print_error) 
+ 		lib_error(CATGETS(elm_msg_cat, MeSet, MeSelectionNoAccess,
+ 				  "Selection \"%S\": %s"),
+ 			  Str,strerror(err));	
+ 	    
+ 	    
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "fbrowser_selection_is_mbox=0: can_open %s (%S) failed: %s (errno %d)\n",
+ 			     str,Str,strerror(err),err));
  
+ 	    ret = 0;
+ 	    goto FAIL;	    
+ 	}
  
+ 	
  	F = fopen(str,"r");
  	
  	if (!F) {
! 	    err = errno;
  	    
  	    if (print_error) 
  		lib_error(CATGETS(elm_msg_cat, MeSet, MeSelectionNoAccess,
***************
*** 3063,3069 ****
  
  	}
  	
- 
  	if (!mbx_read_line(F,&buffer,&len,1000)) {
  	    DPRINT(Debug,10,(&Debug,
  			     "fbrowser_selection_is_mbox=1: Empty file\n"));
--- 3231,3236 ----
***************
*** 3552,3558 ****
      char pid_buffer[STRING];
  
      struct stat    buf;		/* stat command  */
!     int stat_code = -1;
  
      int err       = 0;
      int temp_fd = -1;
--- 3719,3725 ----
      char pid_buffer[STRING];
  
      struct stat    buf;		/* stat command  */
!     enum syscall_status stat_code = -1;
  
      int err       = 0;
      int temp_fd = -1;
***************
*** 3611,3626 ****
  	int n;
  	struct stat oX;
  
! 	int ocode = fstat(temp_fd,&oX);
  
! 	if (ocode == 0) {
  
  	    DPRINT(Debug,5,(&Debug, 
  			    "mbx_dotlock_file: atime (before read) = %d \n",
  			    oX.st_atime)); 
! 
  	}
! 
  	n = read(temp_fd, pid_buffer, sizeof pid_buffer);
  	if (n < 0) {
  	    int err = errno;
--- 3778,3807 ----
  	int n;
  	struct stat oX;
  
! 	enum syscall_status   ocode = fstat(temp_fd,&oX);
  
! 	switch (ocode) {
! 	case syscall_success /* 0 */: {
  
  	    DPRINT(Debug,5,(&Debug, 
  			    "mbx_dotlock_file: atime (before read) = %d \n",
  			    oX.st_atime)); 
! 	    
  	}
! 	    break;
! 	case syscall_error /* -1 */: {
! 	    int err = errno;
! 	    
! 	    DPRINT(Debug,5,(&Debug, 
! 			    "mbx_dotlock_file: fstat %d failed: (errno=%d) %s\n",
! 			    temp_fd,err,strerror(err)));
! 	    
! 	    lib_error(FRM("%s: %s"), 
! 		      folder->p->a.spool.lockfile,strerror(err));	    	    
! 	}
! 	    break;
! 	}
! 	
  	n = read(temp_fd, pid_buffer, sizeof pid_buffer);
  	if (n < 0) {
  	    int err = errno;
***************
*** 3638,3648 ****
  	} else {
  
  	    struct stat X;
! 
  	    if (n > 0 && '\n' == pid_buffer[n-1])
  		n--;
  
! 	    if (fstat(temp_fd,&X) < 0) {
  		int err UNUSED_VAROK = errno;
  
  		DPRINT(Debug,5,(&Debug, 
--- 3819,3831 ----
  	} else {
  
  	    struct stat X;
! 	    enum syscall_status r = fstat(temp_fd,&X);
! 	    
  	    if (n > 0 && '\n' == pid_buffer[n-1])
  		n--;
  
! 	    switch (r) {
! 	    case syscall_error /* -1 */: {
  		int err UNUSED_VAROK = errno;
  
  		DPRINT(Debug,5,(&Debug, 
***************
*** 3650,3696 ****
  				folder->p->a.spool.lockfile,err));
  		
  		lib_error(FRM("%s: %s"), 
! 			  folder->p->a.spool.lockfile,strerror(errno));
! 
! 	    } else if (ocode == 0) {
! 		DPRINT(Debug,5,(&Debug, 
! 				"mbx_dotlock_file: atime (now) = %d \n",
! 				X.st_atime)); 
! 		DPRINT(Debug,5,(&Debug, 
! 				"                  mtime       = %d \n",
! 				X.st_mtime)); 
! 
! 		if (oX.st_atime == X.st_atime) {
! 		    time_t now = time(NULL);
  
  		    DPRINT(Debug,5,(&Debug, 
! 				    "mbx_dotlock_file: now         = %d \n",
! 				    now)); 
! 
! 
! 		    DPRINT(Debug,5,(&Debug, "File read does not change access time!\n"));
! 		    old_dotfile = X.st_mtime < now - 5 * 60;
! 
  		    DPRINT(Debug,5,(&Debug, 
! 				    "                  (modified %1.1f minutes ago)\n",
! 				    (double)(now - X.st_mtime) / 60.0));
! 
! 		    
! 		} else {
! 		    old_dotfile = X.st_mtime < X.st_atime - 5 * 60;
  		    
! 		    DPRINT(Debug,5,(&Debug, 
! 				    "                  (modified %1.1f minutes ago from read)\n",
! 				    (double)(X.st_atime - X.st_mtime) / 60.0));
  		    
  		}
! 
! 		DPRINT(Debug,1,(&Debug, 
! 				"mbx_dotlock_file: old_dotfile = %d\n",
! 				old_dotfile));
! 	    }	   
  	}
  
  	if (pidcheck_mode > pidcheck_no) {	    
  	    if (n > 0) {
  		int L;
--- 3833,3885 ----
  				folder->p->a.spool.lockfile,err));
  		
  		lib_error(FRM("%s: %s"), 
! 			  folder->p->a.spool.lockfile,strerror(err));
  
+ 	    }
+ 		break;
+ 	    case syscall_success /* 0 */:
+ 		if (ocode == syscall_success /* 0 */) {
  		    DPRINT(Debug,5,(&Debug, 
! 				    "mbx_dotlock_file: atime (now) = %d \n",
! 				    X.st_atime)); 
  		    DPRINT(Debug,5,(&Debug, 
! 				    "                  mtime       = %d \n",
! 				    X.st_mtime)); 
  		    
! 		    if (oX.st_atime == X.st_atime) {
! 			time_t now = time(NULL);
! 			
! 			DPRINT(Debug,5,(&Debug, 
! 					"mbx_dotlock_file: now         = %d \n",
! 					now)); 
! 			
! 			
! 			DPRINT(Debug,5,(&Debug, "File read does not change access time!\n"));
! 			old_dotfile = X.st_mtime < now - 5 * 60;
! 			
! 			DPRINT(Debug,5,(&Debug, 
! 					"                  (modified %1.1f minutes ago)\n",
! 					(double)(now - X.st_mtime) / 60.0));
! 			
! 			
! 		    } else {
! 			old_dotfile = X.st_mtime < X.st_atime - 5 * 60;
! 			
! 			DPRINT(Debug,5,(&Debug, 
! 					"                  (modified %1.1f minutes ago from read)\n",
! 					(double)(X.st_atime - X.st_mtime) / 60.0));
! 			
! 		    }
  		    
+ 		    DPRINT(Debug,1,(&Debug, 
+ 				    "mbx_dotlock_file: old_dotfile = %d\n",
+ 				    old_dotfile));
  		}
! 		break;
! 	    }
  	}
  
+ 	
  	if (pidcheck_mode > pidcheck_no) {	    
  	    if (n > 0) {
  		int L;
***************
*** 3746,3790 ****
  			      folder->cur_folder_disp, L);
  		} else if (pid_value == L) {
  
! 		    int kill_status = kill(pid_value, 0);
! 		    
! 		    if (kill_status != 0 && errno != EPERM) {
! 
! 			if (unlink(folder->p->a.spool.lockfile) != 0) {
! 			    int err = errno;
  
! 			    DPRINT(Debug,1,(&Debug, 
! 					    "Error %s\n\ttrying to unlink file %s (%s)\n", 
! 					    strerror(errno), 
! 					    folder->p->a.spool.lockfile, "lock"));
! 			    lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 					      ElmLeaveCouldntRemoveLock,
! 					      "Couldn't remove the current lock file %s: %s"), 
! 				      folder->p->a.spool.lockfile,
! 				      strerror(err));
! 
! 			    close(temp_fd);
! 			    status = 0;
! 			    goto clean;
  			} else {
! 			    DPRINT(Debug,9,(&Debug,
! 					    "mbx_dotlock_file: Folder %s: Removed stale lockfile %s: No process %d\n",
! 					    folder->cur_folder_sys,
! 					    folder->p->a.spool.lockfile,
! 					    pid_value));
! 			}
  
! 		    } else {
! 			lib_error(CATGETS(elm_msg_cat, ElmSet,
! 					  ElmMailboxLockedPid,
! 					  "Mailbox %S is locked by pid %ld"),
! 				  folder->cur_folder_disp,L);			
  		    }
  		}
- 	    }
  
  	no_pid_seen: ;
! 
  	}
  
  	close(temp_fd);
--- 3935,3996 ----
  			      folder->cur_folder_disp, L);
  		} else if (pid_value == L) {
  
! 		    enum syscall_status kill_status = kill(pid_value, 0);
  
! 		    switch (kill_status) {
! 			int err;
! 		    case syscall_error /* -1 */:
! 			err = errno;
! 			
! 			if (EPERM == err)  {
! 			case syscall_success /* 0 */:
! 			    lib_error(CATGETS(elm_msg_cat, ElmSet,
! 					      ElmMailboxLockedPid,
! 					      "Mailbox %S is locked by pid %ld"),
! 				      folder->cur_folder_disp,L);
! 			    break;
  			} else {
! 			    enum syscall_status unlink_status =
! 				unlink(folder->p->a.spool.lockfile);
  
! 			    switch (unlink_status) {
! 			    case syscall_error /* -1 */: {
! 				err = errno;
! 				
! 				DPRINT(Debug,1,(&Debug, 
! 						"Error %s\n\ttrying to unlink file %s (%s)\n", 
! 						strerror(errno), 
! 						folder->p->a.spool.lockfile, "lock"));
! 				lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 						  ElmLeaveCouldntRemoveLock,
! 						  "Couldn't remove the current lock file %s: %s"), 
! 					  folder->p->a.spool.lockfile,
! 					  strerror(err));
! 				
! 				close(temp_fd);
! 				status = 0;
! 				goto clean;
! 			    }
! 				break;
! 				
! 			    case syscall_success /* 0 */: {
! 				DPRINT(Debug,9,(&Debug,
! 						"mbx_dotlock_file: Folder %s: Removed stale lockfile %s: No process %d\n",
! 						folder->cur_folder_sys,
! 						folder->p->a.spool.lockfile,
! 						pid_value));
! 			    }
! 				break;
! 			    }
! 			}
! 			break;
  		    }
+ 		    
  		}
  
+ 	    }
  	no_pid_seen: ;
! 		
  	}
  
  	close(temp_fd);
***************
*** 3824,3878 ****
  
  	    stat_code = stat(folder->p->a.spool.lockfile,&buf);
  
! 	    if (0 == stat_code) {
  		DPRINT(Debug,9,(&Debug,
  				"stat %s succeed!\n",
  				folder->p->a.spool.lockfile));				
! 	    }
! 
  
  	    /* Creation of lock failed NOT because it already exists!!! */
  
! 	    if (err != EEXIST && stat_code < 0) {		    
! 
! 		const char * mailhome_val = 
! 		    give_dt_estr_as_str(&mailhome_dir_e,
! 					"mailhome-dir",
! 					NULL,NULL);
! 
! 
! 		DPRINT(Debug,1,(&Debug, 
! 				"Error encountered attempting to create lock %s\n", 
! 				folder->p->a.spool.lockfile));
! 		DPRINT(Debug,1,(&Debug, 
! 				"** %s **\n", strerror(err)));
! 
! 		/* If /var/mail nfs mounted on Solaris 2.3 at least you can */
! 		/* get EACCES.  Treat it like EEXIST.                       */
  		
! 		if (err != EACCES ||
! 		    ! mailhome_val ||
! 		    /* Stat buffer argument is NULL because stat failed */
! 		    ! in_directory(NULL,folder->p->a.spool.lockfile,
! 				   mailhome_val)) {
! 
! 		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 				      ElmLeaveErrorCreatingLock,
! 				      "\nError encountered while attempting to create lock file %s;\n"),
! 			      folder->p->a.spool.lockfile);
! 		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 				      ElmErrorAccess,
! 				      "%.45s: %.33s"),
! 			      folder->p->a.spool.lockfile,
! 			      strerror(err));
! 		} else {	
! 		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 				      ElmLeaveCantCreateLock,
! 				      "Can't create lock file! Need write permission in \"%s\".\n"),
! 			      mailhome_val);
  		}
! 		status = 0;
! 		goto clean;
  	    }
  	}
  	DPRINT(Debug,2,(&Debug, 
--- 4030,4088 ----
  
  	    stat_code = stat(folder->p->a.spool.lockfile,&buf);
  
! 	    switch (stat_code) {
! 	    case syscall_success /* 0 */:
  		DPRINT(Debug,9,(&Debug,
  				"stat %s succeed!\n",
  				folder->p->a.spool.lockfile));				
! 		break;
  
  	    /* Creation of lock failed NOT because it already exists!!! */
+ 		
+ 	    case syscall_error /* -1 */:
+ 		
+ 		if (err != EEXIST) {		    
  
! 		    const char * mailhome_val = 
! 			give_dt_estr_as_str(&mailhome_dir_e,
! 					    "mailhome-dir",
! 					    NULL,NULL);
! 		    
! 		    
! 		    DPRINT(Debug,1,(&Debug, 
! 				    "Error encountered attempting to create lock %s\n", 
! 				    folder->p->a.spool.lockfile));
! 		    DPRINT(Debug,1,(&Debug, 
! 				    "** %s **\n", strerror(err)));
! 		    
! 		    /* If /var/mail nfs mounted on Solaris 2.3 at least you can */
! 		    /* get EACCES.  Treat it like EEXIST.                       */
  		
! 		    if (err != EACCES ||
! 			! mailhome_val ||
! 			/* Stat buffer argument is NULL because stat failed */
! 			! in_directory(NULL,folder->p->a.spool.lockfile,
! 				       mailhome_val)) {
! 
! 			lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 					  ElmLeaveErrorCreatingLock,
! 					  "\nError encountered while attempting to create lock file %s;\n"),
! 				  folder->p->a.spool.lockfile);
! 			lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 					  ElmErrorAccess,
! 					  "%.45s: %.33s"),
! 				  folder->p->a.spool.lockfile,
! 				  strerror(err));
! 		    } else {	
! 			lib_error(CATGETS(elm_msg_cat, ElmSet, 
! 					  ElmLeaveCantCreateLock,
! 					  "Can't create lock file! Need write permission in \"%s\".\n"),
! 				  mailhome_val);
! 		    }
! 		    status = 0;
! 		    goto clean;
  		}
! 		break;
  	    }
  	}
  	DPRINT(Debug,2,(&Debug, 
***************
*** 3888,3904 ****
  	    sleep(5);
  
      } while (create_iteration++ < MAX_ATTEMPTS);
! 
      if(create_fd == -1) {	
  	struct stat    buf2;	/* stat command  */
! 	int stat2_code = stat(folder->cur_folder_sys,&buf2);
  	time_t now = time(NULL);
  	int can_remove = 0;
  
  	DPRINT(Debug,2,(&Debug, 
  			"mbx_dotlock_file: now       = %d \n",
! 			now)); 
! 	if (stat_code == 0) {
  	    DPRINT(Debug,1,(&Debug, 
  			    "mbx_dotlock_file: lock time = %d (%s)\n",
  			    buf.st_mtime,folder->p->a.spool.lockfile));
--- 4098,4116 ----
  	    sleep(5);
  
      } while (create_iteration++ < MAX_ATTEMPTS);
!     
      if(create_fd == -1) {	
  	struct stat    buf2;	/* stat command  */
! 	enum syscall_status  stat2_code = stat(folder->cur_folder_sys,&buf2);
  	time_t now = time(NULL);
  	int can_remove = 0;
  
  	DPRINT(Debug,2,(&Debug, 
  			"mbx_dotlock_file: now       = %d \n",
! 			now));
! 	
! 	switch (stat_code) {
! 	case syscall_success /* 0 */:
  	    DPRINT(Debug,1,(&Debug, 
  			    "mbx_dotlock_file: lock time = %d (%s)\n",
  			    buf.st_mtime,folder->p->a.spool.lockfile));
***************
*** 3906,3913 ****
  	    DPRINT(Debug,1,(&Debug, 
  			    "                  (modified %1.1f minutes ago)\n",
  			    (double)(now - buf.st_mtime) / 60.0));
  	}
! 	if (stat2_code == 0) {
  	    DPRINT(Debug,1,(&Debug, 
  			    "mbx_dotlock_file: read time = %d (%s)\n",
  			    buf2.st_atime,folder->cur_folder_sys));
--- 4118,4134 ----
  	    DPRINT(Debug,1,(&Debug, 
  			    "                  (modified %1.1f minutes ago)\n",
  			    (double)(now - buf.st_mtime) / 60.0));
+ 	    break;
+ 	case syscall_error /* -1 */:
+ 	     DPRINT(Debug,10,(&Debug, 
+ 			      "mbx_dotlock_file: %s: lock time not available\n",
+ 			      folder->p->a.spool.lockfile));
+ 	     break;
  	}
! 	
! 	switch (stat2_code) {
! 	case syscall_success /* 0 */:
! 	    
  	    DPRINT(Debug,1,(&Debug, 
  			    "mbx_dotlock_file: read time = %d (%s)\n",
  			    buf2.st_atime,folder->cur_folder_sys));
***************
*** 3916,3921 ****
--- 4137,4148 ----
  	    DPRINT(Debug,1,(&Debug, 
  			    "                  (read %1.1f minutes ago)\n",
  			    (double)(now - buf2.st_atime) / 60.0));
+ 	    break;
+ 	case syscall_error /* -1 */:
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "mbx_dotlock_file: %s: rwad time not available\n",
+ 			     folder->cur_folder_sys));
+ 	    break;	    
  	}
  	
  	DPRINT(Debug,2,(&Debug, 
***************
*** 3925,3930 ****
--- 4152,4158 ----
  	/* we weren't able to create the lock file */
  	
  	if (can_remove && old_dotfile) {
+ 	    enum syscall_status  r;
  
  	    /** time to waste the lock file!  Must be there in error! **/
  	    DPRINT(Debug,2,(&Debug, 
***************
*** 3937,3945 ****
  		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveThrowingAwayLock,
  				  "Throwing away the current lock file!"));
  
- 	    if (unlink(folder->p->a.spool.lockfile) != 0) {
- 		int err = errno;
  
  		DPRINT(Debug,1,(&Debug, 
  				"Error %s\n\ttrying to unlink file %s (%s)\n", 
  				strerror(errno), folder->p->a.spool.lockfile, "lock"));
--- 4165,4176 ----
  		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveThrowingAwayLock,
  				  "Throwing away the current lock file!"));
  
  
+ 	    r = unlink(folder->p->a.spool.lockfile);
+ 	    switch (r) {
+ 	    case syscall_error /* -1 */: {
+ 		int err = errno;
+ 		
  		DPRINT(Debug,1,(&Debug, 
  				"Error %s\n\ttrying to unlink file %s (%s)\n", 
  				strerror(errno), folder->p->a.spool.lockfile, "lock"));
***************
*** 3949,3959 ****
  				  "Couldn't remove the current lock file %s: %s"), 
  			  folder->p->a.spool.lockfile,
  			  strerror(err));
! 
  		status = 0;
  		goto clean;
  	    }
! 
  	    /* we've removed the bad lock, let's try to assert lock once more */
  	    if((create_fd=open(folder->p->a.spool.lockfile,
  			       O_WRONLY | O_CREAT | O_EXCL,0444)) == -1){
--- 4180,4197 ----
  				  "Couldn't remove the current lock file %s: %s"), 
  			  folder->p->a.spool.lockfile,
  			  strerror(err));
! 		
  		status = 0;
  		goto clean;
  	    }
! 		break;
! 	    case syscall_success /* 0 */:
! 		DPRINT(Debug,10,(&Debug, 
! 				 "mbx_dotlock_file: Removed %s\n",
! 				 folder->p->a.spool.lockfile));
! 		break;
! 	    }
! 	
  	    /* we've removed the bad lock, let's try to assert lock once more */
  	    if((create_fd=open(folder->p->a.spool.lockfile,
  			       O_WRONLY | O_CREAT | O_EXCL,0444)) == -1){
***************
*** 4490,4496 ****
      const char * mailhome_val = give_dt_estr_as_str(&mailhome_dir_e,
  						    "mailhome-dir",
  						    NULL,NULL);
! 
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_init_spool",
  	      "Bad magic number (folder_info)",0);
--- 4728,4735 ----
      const char * mailhome_val = give_dt_estr_as_str(&mailhome_dir_e,
  						    "mailhome-dir",
  						    NULL,NULL);
!     enum syscall_status  r;
!     
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_init_spool",
  	      "Bad magic number (folder_info)",0);
***************
*** 4505,4519 ****
  
      folder->p = malloc_mbx_private_data(NULL);
  
!     if (0 == stat(folder->cur_folder_sys,&buf)) {
  	Xbuf = &buf;
!     } else {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,11,(&Debug,
  			 "... stat %s: (errno=%d) %s\n",
  			 folder->cur_folder_sys,err,strerror(err)));
      }
! 
      if (mailhome_val &&
  	in_directory(Xbuf,folder->cur_folder_sys,mailhome_val)) {
  	DPRINT(Debug,11,(&Debug," .. in mailhome\n"));
--- 4744,4765 ----
  
      folder->p = malloc_mbx_private_data(NULL);
  
!     r = stat(folder->cur_folder_sys,&buf);
! 
!     switch(r) {
!     case syscall_success /* 0 */: {
  	Xbuf = &buf;
!     }
! 	break;
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,11,(&Debug,
  			 "... stat %s: (errno=%d) %s\n",
  			 folder->cur_folder_sys,err,strerror(err)));
      }
! 	break;
!     }
! 	
      if (mailhome_val &&
  	in_directory(Xbuf,folder->cur_folder_sys,mailhome_val)) {
  	DPRINT(Debug,11,(&Debug," .. in mailhome\n"));
***************
*** 4641,4657 ****
      **/
  
      struct stat    buf;		/* stat command  */
      char * result_name = NULL;
      int L;
  
!     if (stat(mbox,&buf) < 0) {
  	DPRINT(Debug,8,(&Debug, 
! 			"mk_temp_mail_fn: stat %s failed\n",
! 			mbox));
  
! 	result_name = give_sessionlock_fname(mbox,NULL);
!     } else 
! 	result_name = give_sessionlock_fname(mbox,&buf);
  
      if ((L = strlen(result_name)) > tempfn_size-2) {
  	DPRINT(Debug,1,(&Debug,
--- 4887,4915 ----
      **/
  
      struct stat    buf;		/* stat command  */
+     struct stat  * Xbuf = NULL;
      char * result_name = NULL;
      int L;
+     enum syscall_status  r;
+ 
+     r = stat(mbox,&buf);
  
!     switch(r) {
!     case syscall_error /* -1 */: {
! 	int err UNUSED_VAROK = errno;
! 	
  	DPRINT(Debug,8,(&Debug, 
! 			"mk_temp_mail_fn: stat %s failed:  (errno=%d) %s\n",
! 			mbox,err,strerror(err)));
! 	
!     }
! 	break;
!     case syscall_success /* 0 */:
! 	Xbuf = &buf;
! 	break;
!     }
  
!     result_name = give_sessionlock_fname(mbox,Xbuf);
  
      if ((L = strlen(result_name)) > tempfn_size-2) {
  	DPRINT(Debug,1,(&Debug,
***************
*** 4664,4672 ****
      strfcpy(tempfn,result_name,tempfn_size);
  
      free(result_name);
! 
      DPRINT(Debug,8,(&Debug, 
! 	      "mk_temp_mail_fn: tempfname=%s\n",tempfn));
  }
  
  S_(mbx_free_folder mbx_free_non_spool)
--- 4922,4930 ----
      strfcpy(tempfn,result_name,tempfn_size);
  
      free(result_name);
!     
      DPRINT(Debug,8,(&Debug, 
! 		    "mk_temp_mail_fn: tempfname=%s\n",tempfn));
  }
  
  S_(mbx_free_folder mbx_free_non_spool)
***************
*** 4730,4738 ****
      return ret;
  }
  
  static int mbx_sessionlock_filehandle P_((struct folder_info *folder,
  					  enum sessionlock_mode mode,
! 					  int *errcode /* errno */));
  
  static int mbx_sessionlock_filehandle(folder,mode,errcode)
       struct folder_info *folder;
--- 4988,5224 ----
      return ret;
  }
  
+ 
+ static int mbx_set_ostat P_((struct folder_info *folder,
+ 			     int *errcode /* errno */));
+ static int mbx_set_ostat(folder,errcode)
+      struct folder_info *folder;
+      int *errcode /* errno */;
+ {
+     int ret = 1;
+ 
+     enum use_lastread_v use_lastread =
+ 	give_dt_enumerate_as_int(&use_last_read_file);
+ 
+     enum syscall_status  ofolder_code;
+     
+     if (FOLDER_INFO_magic != folder->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_set_ostat",
+ 	      "Bad magic number (folder_info)",0);
+ 
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_set_ostat",
+ 	      "Bad magic number (private_data)",0);
+ 	      
+     if (!folder->p->fh_folder &&
+ 	use_lastread > use_lastread_no) {
+ 
+ 	clearit(folder->p->flags1,FLAG1_have_ostat);
+ 	
+ 	ofolder_code = stat(folder->cur_folder_sys,
+ 			    &(folder->p->ostat));
+ 	
+ 	switch (ofolder_code) {
+ 	case syscall_success /* 0 */: {
+ 	    char * X;
+ 	    
+ 	    setit(folder->p->flags1,FLAG1_have_ostat);
+ 
+ 	    DPRINT(Debug,11,(&Debug, 
+ 			     "mbx_set_ostat: folder=%p %s ostat dev/ino=%lu/%lu atime=%ld",
+ 			     folder,
+ 			     folder -> cur_folder_sys,
+ 			     (unsigned long)(folder->p->ostat.st_dev),
+ 			     (unsigned long)(folder->p->ostat.st_ino),
+ 			     (long)folder->p->ostat.st_atime));
+ 
+ 	    X = ctime(&(folder->p->ostat.st_atime));
+ 
+ 	    /* ctime() includes newline \n to result */
+ 	    if (X) {
+ 		DPRINT(Debug,14,(&Debug," %s",
+ 				 X));
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 	    }
+ 	    
+ 	}
+ 	    break;
+ 	case syscall_error /* -1 */: {
+ 	    int err = errno;
+ 
+ 	    DPRINT(Debug,11,(&Debug, 
+ 			     "mbx_set_ostat: folder=%p stat %s failed: %s\n",
+ 			     folder,
+ 			     folder -> cur_folder_sys,
+ 			     strerror(err)));
+ 	    
+ 	    if (err != ENOENT) {
+ 		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFolderRead,
+ 				  "Can't open folder '%S' for reading: %s"), 
+ 			  folder->cur_folder_disp,		  
+ 			  strerror(err));
+ 		
+ 		if (errcode)
+ 		    *errcode = err;
+ 		
+ 		ret = 0;
+ 	    }
+ 	}
+ 	    break;
+ 	}
+     } else if (folder->p->fh_folder) {
+ 	DPRINT(Debug,11,(&Debug, 
+ 			 "mbx_set_ostat: folder=%p %s already open",
+ 			 folder,
+ 			 folder -> cur_folder_sys));
+ 
+ 	if (ison(folder->p->flags1,FLAG1_have_ostat)) {
+ 	    char * X;
+ 	    DPRINT(Debug,13,(&Debug," ostat dev/ino=%lu/%lu atime=%ld",
+ 			     (unsigned long)(folder->p->ostat.st_dev),
+ 			     (unsigned long)(folder->p->ostat.st_ino),
+ 			     (long)folder->p->ostat.st_atime));
+ 	    X = ctime(&(folder->p->ostat.st_atime));
+ 	    
+ 	    /* ctime() includes newline \n to result */
+ 	    if (X) {
+ 		DPRINT(Debug,14,(&Debug," %s",
+ 				 X));
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 	    }
+ 	    
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug," no ostat\n"));
+ 	}	
+     }
+ 
+     DPRINT(Debug,11,(&Debug, 
+ 		     "mbx_set_ostat=%d folder=%s",
+ 		     ret,folder -> cur_folder_sys));
+     if (!ret && errcode && *errcode) {
+ 	DPRINT(Debug,11,(&Debug, " *errcode=%d %s",
+ 			 *errcode,strerror(*errcode)));
+     }
+     DPRINT(Debug,11,(&Debug, "\n"));
+     
+     return ret;
+ }
+ 
+ static int mbx_set_read P_((struct folder_info *folder));
+ static int mbx_set_read(folder)
+      struct folder_info *folder;
+ {
+     int ret = 1;
+ 
+     enum use_lastread_v use_lastread =
+ 	give_dt_enumerate_as_int(&use_last_read_file);
+     
+     if (FOLDER_INFO_magic != folder->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_set_read",
+ 	      "Bad magic number (folder_info)",0);
+     
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_set_read",
+ 	      "Bad magic number (private_data)",0);
+     
+     if (folder->p->fh_folder &&
+ 	use_lastread > use_lastread_no) {
+ 	struct stat          folder_stat;
+ 	enum syscall_status  folder_code;
+ 	enum FLAG1_bits x1;
+ 
+ 	DPRINT(Debug,13,(&Debug,"mbx_set_read: folder=%p %s",
+ 			 folder,
+ 			 folder->cur_folder_sys ?
+ 			 folder->cur_folder_sys : "(no name)"));
+ 
+ 	DPRINT(Debug,13,(&Debug," flags1=%d",
+ 			 folder->p->flags1));
+ 	for (x1 = 0; x1 < FLAG1_bit_count; x1++) {
+ 	    if (ison(folder->p->flags1,x1)) {
+ 		switch (x1) {
+ 		case FLAG1_bit_CHECKNEW:   DPRINT(Debug,13,(&Debug," FLAG1_CHECKNEW"));   break;
+ 		case FLAG1_bit_have_ostat: DPRINT(Debug,13,(&Debug," FLAG1_have_ostat")); break;
+ 		case FLAG1_bit_count:                                                     break;
+ 		}
+ 	    }
+ 	}
+ 	if (ison(folder->p->flags1,FLAG1_have_ostat)) {
+ 	    char * X;
+ 	    DPRINT(Debug,13,(&Debug," ostat dev/ino=%lu/%lu atime=%ld",
+ 			     (unsigned long)(folder->p->ostat.st_dev),
+ 			     (unsigned long)(folder->p->ostat.st_ino),
+ 			     (long)folder->p->ostat.st_atime));
+ 	    X = ctime(&(folder->p->ostat.st_atime));
+ 	    
+ 	    /* ctime() includes newline \n to result */
+ 	    if (X) {
+ 		DPRINT(Debug,14,(&Debug," %s",
+ 				 X));
+ 	    } else {
+ 		DPRINT(Debug,14,(&Debug,"\n"));
+ 	    }
+ 
+ 	} else {
+ 	    DPRINT(Debug,14,(&Debug," no ostat\n"));
+ 	}
+ 
+ 	
+ 	folder_code = fstat(fileno(folder -> p->fh_folder),
+ 			    &folder_stat);
+       	
+ 	switch (folder_code) {
+ 	case syscall_success /* 0 */: {
+ 	    struct last_read_cache * cache =
+ 		last_read_enabled(use_lastread,
+ 				  folder -> cur_folder_sys,
+ 				  ison(folder->p->flags1,FLAG1_have_ostat) ?
+ 				  &(folder->p->ostat) : NULL,
+ 				  &folder_stat);
+ 
+ 	    if (cache) {
+ 		mark_last_read(cache,folder -> cur_folder_sys,
+ 			       &folder_stat);
+ 	    
+ 		free_last_read_cache(& cache);
+ 	    }
+ 	}
+ 	    break;
+ 	case syscall_error /* -1 */: {
+ 	    int err = errno;
+ 	    
+ 	    DPRINT(Debug,11,(&Debug, 
+ 			     "mbx_set_read: fstat %d (%s) failed: %s\n",
+ 			     fileno(folder -> p->fh_folder),
+ 			     folder -> cur_folder_sys));
+ 	    
+ 	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFolderStatError,
+ 			      "Error encountered while attempting to stat folder %S: %s"), 
+ 		      folder->cur_folder_disp,
+ 		      strerror(err));
+ 	}
+ 	    ret = 0;
+ 	    goto clean;
+ 	}
+     }
+ 
+ 
+  clean:
+ 
+     DPRINT(Debug,11,(&Debug, 
+ 		     "mbx_set_read=%d folder=%s\n",
+ 		     ret,folder -> cur_folder_sys));
+ 
+     
+     return ret;
+ }
+ 
  static int mbx_sessionlock_filehandle P_((struct folder_info *folder,
  					  enum sessionlock_mode mode,
! 					  int *errcode /* errno */
! 					  ));
  
  static int mbx_sessionlock_filehandle(folder,mode,errcode)
       struct folder_info *folder;
***************
*** 4740,4749 ****
       int *errcode /* errno */;
  {
      int status = 0;
! 
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_filehandle",
  	      "Bad magic number (folder_info)",0);
      
      if (mode == SESSIONLOCK_CHECK) {
  	int code = 0;
--- 5226,5239 ----
       int *errcode /* errno */;
  {
      int status = 0;
!         
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_filehandle",
  	      "Bad magic number (folder_info)",0);
+ 
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_filehandle",
+ 	      "Bad magic number (private_data)",0);
      
      if (mode == SESSIONLOCK_CHECK) {
  	int code = 0;
***************
*** 4770,4779 ****
   			 code ? strerror(code) : ""));
      }
  
-     if (PRIVATE_DATA_magic != folder->p->magic) 
- 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_filehandle",
- 	      "Bad magic number (private_data)",0);
- 
      if (mode == SESSIONLOCK_REOPEN && folder->p->fh_folder) {
  	fclose(folder->p->fh_folder);
  	folder->p->fh_folder = NULL;
--- 5260,5265 ----
***************
*** 4802,4808 ****
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
! 
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_read_only",
  	      "Bad magic number (folder_info)",0);
--- 5288,5294 ----
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
! 	
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_read_only",
  	      "Bad magic number (folder_info)",0);
***************
*** 4817,4826 ****
      case SESSIONLOCK_CHECK:    DPRINT(Debug,11,(&Debug, " SESSIONLOCK_CHECK")); break;
      case SESSIONLOCK_NONE:     DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE")); break;
      case SESSIONLOCK_RECONNECT: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_RECONNECT")); break;
!     case SESSIONLOCK_NONE_CHECKNEW: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE_CHECKNEW")); break;
      }
      DPRINT(Debug,11,(&Debug, "\n"));
  
      if (mode == SESSIONLOCK_CHECK) {
  	if ((errno = can_open(folder->cur_folder_sys, 
  			      "r")) != 0) {
--- 5303,5323 ----
      case SESSIONLOCK_CHECK:    DPRINT(Debug,11,(&Debug, " SESSIONLOCK_CHECK")); break;
      case SESSIONLOCK_NONE:     DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE")); break;
      case SESSIONLOCK_RECONNECT: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_RECONNECT")); break;
!     case SESSIONLOCK_NONE_CHECKNEW: DPRINT(Debug,11,(&Debug,
! 						     " SESSIONLOCK_NONE_CHECKNEW")); break;
      }
      DPRINT(Debug,11,(&Debug, "\n"));
  
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_read_only",
+ 	      "Bad magic number (private_data)",0);
+ 
+     
+     if (! mbx_set_ostat(folder,errcode)) {
+ 	status = sessionlock_fail;
+ 	goto clean;
+     }
+         
      if (mode == SESSIONLOCK_CHECK) {
  	if ((errno = can_open(folder->cur_folder_sys, 
  			      "r")) != 0) {
***************
*** 4840,4848 ****
  	}
      }
  
-     if (PRIVATE_DATA_magic != folder->p->magic) 
- 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_read_only",
- 	      "Bad magic number (private_data)",0);
      
      if (mode == SESSIONLOCK_REOPEN && folder->p->fh_folder) {
  	fclose(folder->p->fh_folder);
--- 5337,5342 ----
***************
*** 4866,4872 ****
  		      folder->cur_folder_disp,
  		      strerror(err));
  	    DPRINT(Debug,1,(&Debug, 
! 			    "fail on open in mbx_sessionlock_non_spool, file %s!!\n",
  			    folder->cur_folder_sys));
  	    status = sessionlock_fail;
  	    if (errcode)
--- 5360,5366 ----
  		      folder->cur_folder_disp,
  		      strerror(err));
  	    DPRINT(Debug,1,(&Debug, 
! 			    "fail on open in mbx_sessionlock_read_only, file %s!!\n",
  			    folder->cur_folder_sys));
  	    status = sessionlock_fail;
  	    if (errcode)
***************
*** 4921,4926 ****
--- 5415,5421 ----
  	}
      }
  
+     
      status = sessionlock_open;
  
   clean:
***************
*** 4983,4993 ****
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
! 
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_non_spool",
  	      "Bad magic number (folder_info)",0);
!     
      DPRINT(Debug,11,(&Debug, 
  		     "mbx_sessionlock_non_spool: folder=%p (%s), mode=%d",
  		     folder,folder->cur_folder_sys,mode));
--- 5478,5488 ----
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
!         
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_non_spool",
  	      "Bad magic number (folder_info)",0);
! 	    
      DPRINT(Debug,11,(&Debug, 
  		     "mbx_sessionlock_non_spool: folder=%p (%s), mode=%d",
  		     folder,folder->cur_folder_sys,mode));
***************
*** 5001,5008 ****
      case SESSIONLOCK_NONE_CHECKNEW: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE_CHECKNEW")); break;
      }
      DPRINT(Debug,11,(&Debug, "\n"));
!     
!     
      if (!mbx_sessionlock_filehandle(folder,mode,errcode)) {
  	status =  sessionlock_fail;
  	goto clean;
--- 5496,5507 ----
      case SESSIONLOCK_NONE_CHECKNEW: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE_CHECKNEW")); break;
      }
      DPRINT(Debug,11,(&Debug, "\n"));
! 
!     if (! mbx_set_ostat(folder,errcode)) {
! 	status = sessionlock_fail;
! 	goto clean;
!     }
!       
      if (!mbx_sessionlock_filehandle(folder,mode,errcode)) {
  	status =  sessionlock_fail;
  	goto clean;
***************
*** 5085,5090 ****
--- 5584,5590 ----
  	}
      }
  
+    
      status = sessionlock_open;
  
   clean:
***************
*** 5108,5114 ****
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
! 
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_spool",
  	      "Bad magic number (folder_info)",0);
--- 5608,5614 ----
       RECONNECT_MODE * reconnect_ptr;
  {
      enum sessionlock_status status = sessionlock_fail;
!     
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_sessionlock_spool",
  	      "Bad magic number (folder_info)",0);
***************
*** 5126,5131 ****
--- 5626,5636 ----
      case SESSIONLOCK_NONE_CHECKNEW: DPRINT(Debug,11,(&Debug, " SESSIONLOCK_NONE_CHECKNEW")); break;
      }
      DPRINT(Debug,11,(&Debug, "\n"));
+ 
+     if (! mbx_set_ostat(folder,errcode)) {
+ 	status = sessionlock_fail;
+ 	goto clean;
+     }
      
      if (!mbx_sessionlock_filehandle(folder,mode,errcode)) {
  	status = sessionlock_fail;
***************
*** 5309,5314 ****
--- 5814,5821 ----
      default:
  	break;
      }
+ 
+     
      status = sessionlock_open;
  
   clean:
***************
*** 5365,5371 ****
  	
  	ret = 1;
  	
!     } else if (-1 == r) {
  	int err = errno;
  
  	DPRINT(Debug,12,(&Debug, 
--- 5872,5878 ----
  	
  	ret = 1;
  	
!     } else if (EOF == r) {
  	int err = errno;
  
  	DPRINT(Debug,12,(&Debug, 
***************
*** 5458,5464 ****
  
      if (0 == r) {
  	ret = 1;
!     } else if (-1 == r) {
  	int err = errno;
  
  	DPRINT(Debug,11,(&Debug, 
--- 5965,5971 ----
  
      if (0 == r) {
  	ret = 1;
!     } else if (EOF == r) {
  	int err = errno;
  
  	DPRINT(Debug,11,(&Debug, 
***************
*** 5658,5667 ****
  	      "Bad magic number (private_data)",0);
  
      if (add_new_only) {
! 	int r = fseek(folder->p->fh_folder, 
! 		      folder->mailfile_size, SEEK_SET);
! 	
! 	if (-1 == r) {
  	    int err = errno;
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekEndFolder,
  			      "Couldn't seek to %ld (end of folder) in %S: %s"),
--- 6165,6176 ----
  	      "Bad magic number (private_data)",0);
  
      if (add_new_only) {
! 	enum syscall_status r =
! 	    fseek(folder->p->fh_folder, 
! 		  folder->mailfile_size, SEEK_SET);
! 
! 	switch(r) {
! 	case syscall_error /* -1 */: {
  	    int err = errno;
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekEndFolder,
  			      "Couldn't seek to %ld (end of folder) in %S: %s"),
***************
*** 5675,5689 ****
  			      folder->mailfile_size,
  			      strerror(err),
  			      err));
! 	     status = 0;
! 	     goto clean;
! 	     
! 	} else if (0 == r) {
  	    DPRINT(Debug,12,(&Debug,
  			     "mbx_prepare_seek_folder: Seeked %s to end of file, offset %ld\n",
  			     folder -> cur_folder_sys,
  			     folder->mailfile_size));
  	}
  	
  	/* read_state_ptr->count  = message_count; */	  /* next available  */
  	read_state_ptr->fbytes = folder-> mailfile_size;  /* start correctly */
--- 6184,6200 ----
  			      folder->mailfile_size,
  			      strerror(err),
  			      err));
! 	}
! 	    status = 0;
! 	    goto clean;
! 	case syscall_success /* 0 */: {
  	    DPRINT(Debug,12,(&Debug,
  			     "mbx_prepare_seek_folder: Seeked %s to end of file, offset %ld\n",
  			     folder -> cur_folder_sys,
  			     folder->mailfile_size));
  	}
+ 	    break;
+ 	}
  	
  	/* read_state_ptr->count  = message_count; */	  /* next available  */
  	read_state_ptr->fbytes = folder-> mailfile_size;  /* start correctly */
***************
*** 5855,5864 ****
  			     "mbx_prepare_read_spool -- NO temp file %s\n",
  			     folder->cur_tempfolder));
  	} else {
! 	    int r = fseek(folder -> p->fh_temp, 
! 			  folder -> mailfile_size, SEEK_SET);
! 	    
! 	    if (-1 == r) {
  		int err = errno;
  		
  		unlock_folder(0,folder);	/* remove lock file! */
--- 6366,6377 ----
  			     "mbx_prepare_read_spool -- NO temp file %s\n",
  			     folder->cur_tempfolder));
  	} else {
! 	    enum syscall_status  r =
! 		fseek(folder -> p->fh_temp, 
! 		      folder -> mailfile_size, SEEK_SET);
! 
! 	    switch(r) {
! 	    case syscall_error /* -1 */: {
  		int err = errno;
  		
  		unlock_folder(0,folder);	/* remove lock file! */
***************
*** 5872,5886 ****
  				 folder->cur_tempfolder,
  				 folder -> mailfile_size,
  				 strerror(err),
! 				 err));		
  		status = prepare_fail;
! 		goto clean;	    
! 	    } else if (0 == r) {
  		DPRINT(Debug,11,(&Debug,
  				 "mbx_prepare_read_spool: Seeked temp %s to end of file, offset %ld\n",
  				 folder->cur_tempfolder,
  				 folder -> mailfile_size));
  	    }
  	}
      }
  
--- 6385,6402 ----
  				 folder->cur_tempfolder,
  				 folder -> mailfile_size,
  				 strerror(err),
! 				 err));
! 	    }
  		status = prepare_fail;
! 		goto clean;
! 	    case syscall_success /* 0 */:  {
  		DPRINT(Debug,11,(&Debug,
  				 "mbx_prepare_read_spool: Seeked temp %s to end of file, offset %ld\n",
  				 folder->cur_tempfolder,
  				 folder -> mailfile_size));
  	    }
+ 		break;
+ 	    }
  	}
      }
  
***************
*** 5932,5939 ****
  	      "Bad magic number (private_data)",0);
  
      rewind(folder->p->fh_folder);
-     status = 1;
  
      DPRINT(Debug,11,(&Debug, 
  		     "mbx_end_read_non_spool=%d\n",status));
      return status;
--- 6448,6456 ----
  	      "Bad magic number (private_data)",0);
  
      rewind(folder->p->fh_folder);
  
+     status = mbx_set_read(folder);
+     
      DPRINT(Debug,11,(&Debug, 
  		     "mbx_end_read_non_spool=%d\n",status));
      return status;
***************
*** 6012,6018 ****
      }
  	  
      rewind(folder->p->fh_temp);
!     status = 1;
      
   clean:
      DPRINT(Debug,11,(&Debug, 
--- 6529,6535 ----
      }
  	  
      rewind(folder->p->fh_temp);
!     status = mbx_set_read(folder);
      
   clean:
      DPRINT(Debug,11,(&Debug, 
***************
*** 6304,6310 ****
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_copy_envelope_non_spool",
  	      "Bad magic number (private_data)",0);
  
!     if ( 0 != (FLAG1_CHECKNEW & folder->p->flags1) ) {
  	/* Really treat as mailbox and not as folder ... */
  	entry->status  = VISIBLE | NEW | UNREAD; /* Default status of message    */
  
--- 6821,6827 ----
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_copy_envelope_non_spool",
  	      "Bad magic number (private_data)",0);
  
!     if (ison(folder->p->flags1,FLAG1_CHECKNEW)) {
  	/* Really treat as mailbox and not as folder ... */
  	entry->status  = VISIBLE | NEW | UNREAD; /* Default status of message    */
  
***************
*** 7269,7275 ****
       READ_STATE read_state_ptr;
  {
      int status = 0;
!     int r;
  
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_reset_folder",
--- 7786,7792 ----
       READ_STATE read_state_ptr;
  {
      int status = 0;
!     enum syscall_status  r;
  
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_reset_folder",
***************
*** 7282,7289 ****
  
      r = fseek(folder->p->fh_folder, read_state_ptr -> fbytes_body, 
  	      SEEK_SET);
!     
!     if (-1 == r) {
  	int err = errno;
  
  	lib_error(CATGETS(elm_msg_cat, ElmSet, 
--- 7799,7807 ----
  
      r = fseek(folder->p->fh_folder, read_state_ptr -> fbytes_body, 
  	      SEEK_SET);
! 
!     switch(r) {
!     case syscall_error /* -1 */: {
  	int err = errno;
  
  	lib_error(CATGETS(elm_msg_cat, ElmSet, 
***************
*** 7297,7311 ****
  			 folder->cur_folder_sys,
  			 read_state_ptr -> fbytes_body,
  			 strerror(err),err));
  	status = 0;
! 
  	goto clean;
!     } else if (0 == r) {
  	DPRINT(Debug,12,(&Debug,
  			 "mbx_reset_folder: Seeked %s to %ld: %s\n",
  			 folder->cur_folder_sys,
  			 read_state_ptr -> fbytes_body));
      }
      
      read_state_ptr -> fbytes = read_state_ptr -> fbytes_body;
      mbx_free_rs_fields_file(read_state_ptr);
--- 7815,7832 ----
  			 folder->cur_folder_sys,
  			 read_state_ptr -> fbytes_body,
  			 strerror(err),err));
+     }
  	status = 0;
! 	
  	goto clean;
!     case syscall_success /* 0 */: {
  	DPRINT(Debug,12,(&Debug,
  			 "mbx_reset_folder: Seeked %s to %ld: %s\n",
  			 folder->cur_folder_sys,
  			 read_state_ptr -> fbytes_body));
      }
+ 	break;
+     }
      
      read_state_ptr -> fbytes = read_state_ptr -> fbytes_body;
      mbx_free_rs_fields_file(read_state_ptr);
***************
*** 7380,7389 ****
  			 "mbx_copy_envelope_reset_body_spool -- NO temp file %s\n",
  			 folder->cur_tempfolder));
      } else {
! 	int r = fseek(folder->p->fh_temp, read_state_ptr -> fbytes_body , 
! 		       SEEK_SET);
! 	
! 	if (-1 == r) {
  	    int err = errno;
  	    
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
--- 7901,7912 ----
  			 "mbx_copy_envelope_reset_body_spool -- NO temp file %s\n",
  			 folder->cur_tempfolder));
      } else {
! 	enum syscall_status  r =
! 	    fseek(folder->p->fh_temp, read_state_ptr -> fbytes_body , 
! 		  SEEK_SET);
! 
! 	switch(r) {
! 	case syscall_error /* -1 */: {
  	    int err = errno;
  	    
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
***************
*** 7397,7412 ****
  			     folder->cur_tempfolder,
  			     read_state_ptr -> fbytes_body,
  			     strerror(err),
! 			     err));	    
  	    status = 0;
  
  	    goto clean;
! 	} else if (0 == r) {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_copy_envelope_reset_body_spool: Seeked %s to %ld\n",
  			     folder->cur_tempfolder,
  			     read_state_ptr -> fbytes_body));
  	}
      }
  
      status = mbx_reset_folder(folder,read_state_ptr);
--- 7920,7938 ----
  			     folder->cur_tempfolder,
  			     read_state_ptr -> fbytes_body,
  			     strerror(err),
! 			     err));
! 	}
  	    status = 0;
  
  	    goto clean;
! 	case syscall_success /* 0 */: {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_copy_envelope_reset_body_spool: Seeked %s to %ld\n",
  			     folder->cur_tempfolder,
  			     read_state_ptr -> fbytes_body));
  	}
+ 	    break;
+ 	}
      }
  
      status = mbx_reset_folder(folder,read_state_ptr);
***************
*** 7438,7448 ****
  	      "mbx_non_spool_to_fd",
  	      "Bad magic number (private_data)",0);
  
!     if (offset != -1L) { 
! 	int r = fseek(folder->p->fh_folder, offset , 
! 		      SEEK_SET);
! 	
! 	if (-1 == r) {
  	    int err = errno;
  	    
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
--- 7964,7976 ----
  	      "mbx_non_spool_to_fd",
  	      "Bad magic number (private_data)",0);
  
!     if (offset != -1L) {
! 	enum syscall_status  r =
! 	    fseek(folder->p->fh_folder, offset , 
! 		  SEEK_SET);
! 
! 	switch(r) {
! 	case syscall_error /* -1 */: {
  	    int err = errno;
  	    
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
***************
*** 7457,7471 ****
  			      offset,
  			      strerror(err),
  			      err));
! 	     
! 	     status = NULL;
! 	     goto clean;
! 	} else if (0 == r) {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_non_spool_to_fd: Seeked %s to %ld\n",
  			     folder -> cur_folder_sys,
  			     offset));
  	}
      }
  	
      status = folder->p->fh_folder;
--- 7985,8001 ----
  			      offset,
  			      strerror(err),
  			      err));
! 	}
! 	    status = NULL;
! 	    goto clean;
! 	case syscall_success /* 0 */: {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_non_spool_to_fd: Seeked %s to %ld\n",
  			     folder -> cur_folder_sys,
  			     offset));
  	}
+ 	    break;
+ 	}
      }
  	
      status = folder->p->fh_folder;
***************
*** 7500,7509 ****
  	      "Bad magic number (private_data)",0);
  
      if (offset != -1L) {
! 	int r = fseek(folder->p->fh_temp, offset , 
! 		      SEEK_SET);
  
! 	if (-1 == r) {
  	    int err = errno;
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
  			      ElmCouldntSeekBytesIntoFolder,
--- 8030,8041 ----
  	      "Bad magic number (private_data)",0);
  
      if (offset != -1L) {
! 	enum syscall_status  r = 
! 	    fseek(folder->p->fh_temp, offset , 
! 		  SEEK_SET);
  
! 	switch(r) {
! 	case syscall_error /* -1 */: {
  	    int err = errno;
  	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
  			      ElmCouldntSeekBytesIntoFolder,
***************
*** 7517,7530 ****
  			     offset,
  			     strerror(err),
  			     err));
  	    status = NULL;
  	    goto clean;
! 	} else if (0 == r) {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_spool_to_fd: Seeked %s to %ld\n",
  			     folder->cur_tempfolder,
  			     offset));
  	}
      }
  	
      status = folder->p->fh_temp;
--- 8049,8065 ----
  			     offset,
  			     strerror(err),
  			     err));
+ 	}
  	    status = NULL;
  	    goto clean;
! 	case syscall_success /* 0 */: {
  	    DPRINT(Debug,11,(&Debug,
  			     "mbx_spool_to_fd: Seeked %s to %ld\n",
  			     folder->cur_tempfolder,
  			     offset));
  	}
+ 	    break;
+ 	}
      }
  	
      status = folder->p->fh_temp;
***************
*** 7867,7873 ****
  
      struct stat    buf;		/* stat command  */
      int   have_stat = 0;
!     int r;
      
  #ifdef SYMLINK
      struct stat    lbuf;		/* lstat command  */
--- 8402,8408 ----
  
      struct stat    buf;		/* stat command  */
      int   have_stat = 0;
!     enum syscall_status  r;
      
  #ifdef SYMLINK
      struct stat    lbuf;		/* lstat command  */
***************
*** 7919,7925 ****
      /* Get original permissions and access time of the original
       * mail folder before we remove it.
       */
!     if(save_file_stats(folder->cur_folder_sys,&buf) != 0) {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,1,(&Debug,
  			"Error: errno %d (%s) attempting to stat file %s\n", 
--- 8454,8462 ----
      /* Get original permissions and access time of the original
       * mail folder before we remove it.
       */
!     r = save_file_stats(folder->cur_folder_sys,&buf);
!     switch (r) {
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,1,(&Debug,
  			"Error: errno %d (%s) attempting to stat file %s\n", 
***************
*** 7930,7943 ****
  			  "Problems saving permissions of folder %S!"), 
  		  folder->cur_folder_disp);
  	
!     } else
  	have_stat = 1;
! 
  #ifdef SYMLINK
      r = lstat(folder->cur_folder_sys, &lbuf);
!     if (0 == r) 
! 	have_lbuf = 1;	
!     else if (-1 == r) {
  	int err = errno;
  	DPRINT(Debug,1,(&Debug,
  			"Error: errno %d (%s) attempting to stat file %s\n", 
--- 8467,8487 ----
  			  "Problems saving permissions of folder %S!"), 
  		  folder->cur_folder_disp);
  	
!     }
! 	break;
!     case syscall_success /* 0 */:
  	have_stat = 1;
! 	break;
!     }
! 	
  #ifdef SYMLINK
      r = lstat(folder->cur_folder_sys, &lbuf);
! 
!     switch(r) {
!     case syscall_success /* 0 */:
! 	have_lbuf = 1;
! 	break;
!     case syscall_error /* -1 */: {
  	int err = errno;
  	DPRINT(Debug,1,(&Debug,
  			"Error: errno %d (%s) attempting to stat file %s\n", 
***************
*** 7948,7953 ****
--- 8492,8499 ----
  		  folder->cur_folder_disp,
  		  strerror(err));
      }
+ 	break;
+     }
  #endif
  
      if (!flush_folder(folder,NULL,NULL)) {
***************
*** 8010,8026 ****
  		     need_to_copy));
  
      if(!need_to_copy) {
! 	if (0 == unlink(folder->cur_folder_sys)) {
  	    DPRINT(Debug,10,(&Debug,
  			     "!! unlinked folder: %s\n",
  			     folder->cur_folder_sys));
! 	}
  
  	r = link(keep_state_ptr->a.file.temp_keep_file, 
  		 folder->cur_folder_sys);
! 	if (-1 == r) {
! 	    if(errno == EXDEV || errno == EEXIST) {
! 		int err UNUSED_VAROK = errno;
  		/* oops - can't link across file systems - 
  		   use copy instead */
  		
--- 8556,8587 ----
  		     need_to_copy));
  
      if(!need_to_copy) {
! 	r = unlink(folder->cur_folder_sys);
! 	switch (r) {
! 	case syscall_success /* 0 */:
  	    DPRINT(Debug,10,(&Debug,
  			     "!! unlinked folder: %s\n",
  			     folder->cur_folder_sys));
! 	    break;
! 	case syscall_error /* -1 */:  {
! 	    int err UNUSED_VAROK = errno;
  
+ 	    DPRINT(Debug,10,(&Debug,
+ 			     "mbx_move_temp_file: unlink %s: (errno=%d) %s\n",
+ 			     folder->cur_folder_sys, err,strerror(err)));
+ 	}
+ 	    break;
+ 	}
+ 	    	    
  	r = link(keep_state_ptr->a.file.temp_keep_file, 
  		 folder->cur_folder_sys);
! 	
! 	switch(r) {
! 	case syscall_error /* -1 */: {	    
! 	    int err = errno;
! 	    
! 	    if(err == EXDEV || err == EEXIST) {
! 
  		/* oops - can't link across file systems - 
  		   use copy instead */
  		
***************
*** 8031,8037 ****
  				 strerror(err),err));		
  		need_to_copy = TRUE;
  	    } else {
! 		int err = errno;
  		DPRINT(Debug,1,(&Debug,
  				"link(%s, %s) failed (leavembox)\n", 
  				keep_state_ptr->a.file.temp_keep_file, 
--- 8592,8598 ----
  				 strerror(err),err));		
  		need_to_copy = TRUE;
  	    } else {
! 
  		DPRINT(Debug,1,(&Debug,
  				"link(%s, %s) failed (leavembox)\n", 
  				keep_state_ptr->a.file.temp_keep_file, 
***************
*** 8044,8056 ****
  			  strerror(err));
  		need_to_copy = TRUE;
  	    }
! 	} else if (0 == r) {
  	    DPRINT(Debug,19,(&Debug,
  			     "!! linked %s to %s\n", 
  			     keep_state_ptr->a.file.temp_keep_file, 
  			     folder->cur_folder_sys));
  	    status = 1;
  	}
  
  	if (folder->p->fh_folder)
  	    fclose(folder->p->fh_folder);	
--- 8605,8621 ----
  			  strerror(err));
  		need_to_copy = TRUE;
  	    }
! 	}
! 	    break;
! 	case syscall_success /* 0 */: {
  	    DPRINT(Debug,19,(&Debug,
  			     "!! linked %s to %s\n", 
  			     keep_state_ptr->a.file.temp_keep_file, 
  			     folder->cur_folder_sys));
  	    status = 1;
  	}
+ 	    break;
+ 	}
  
  	if (folder->p->fh_folder)
  	    fclose(folder->p->fh_folder);	
***************
*** 8178,8184 ****
  		     status));
      return status;
  }
! 
  S_(mbx_end_keep_folder mbx_end_keep_read_only)
  static int mbx_end_keep_read_only P_((struct folder_info *folder,
  				    KEEP_STATE keep_state_ptr));
--- 8743,8749 ----
  		     status));
      return status;
  }
!     
  S_(mbx_end_keep_folder mbx_end_keep_read_only)
  static int mbx_end_keep_read_only P_((struct folder_info *folder,
  				    KEEP_STATE keep_state_ptr));
***************
*** 8261,8279 ****
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_end_keep_spool",
  	      "Bad magic number (folder_info)",0);
      
      if (have_saved_ids) {
! 	if (setgid(mailgroupid) < 0) {
!     	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      mailgroupid,strerror(err));
  	}
      }
  
-     DPRINT(Debug,11,(&Debug,
- 		     "mbx_end_keep_spool: folder=%p (%s)\n",
- 		     folder,folder->cur_folder_sys));
- 
  #ifdef SYSCALL_LOCKING
      DPRINT(Debug,10,(&Debug,
  		     "* SYSCALL_LOCKING (SPOOL)\n"));
--- 8826,8856 ----
      if (FOLDER_INFO_magic != folder->magic)
  	panic("MBX PANIC",__FILE__,__LINE__,"mbx_end_keep_spool",
  	      "Bad magic number (folder_info)",0);
+ 
+     DPRINT(Debug,11,(&Debug,
+ 		     "mbx_end_keep_spool: folder=%p (%s)\n",
+ 		     folder,folder->cur_folder_sys));
+ 
      
      if (have_saved_ids) {
! 	enum syscall_status  r = setgid(mailgroupid);
! 
! 	switch(r) {
! 	case syscall_success /* 0 */: {
! 	    DPRINT(Debug,11,(&Debug,
! 			     "mbx_end_keep_spool: setgid(%d) succeed\n",
! 			     mailgroupid));
! 	}
! 	    break;
! 	case syscall_error /* -1 */: {
! 	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      mailgroupid,strerror(err));
  	}
+ 	    break;
+ 	}
      }
  
  #ifdef SYSCALL_LOCKING
      DPRINT(Debug,10,(&Debug,
  		     "* SYSCALL_LOCKING (SPOOL)\n"));
***************
*** 8295,8305 ****
   clean:
  
      if (have_saved_ids) {
! 	if (setgid(oldgid) < 0) {
      	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      oldgid,strerror(err));
  	}
      }
  
      DPRINT(Debug,11,(&Debug,
--- 8872,8893 ----
   clean:
  
      if (have_saved_ids) {
! 	enum syscall_status  r = setgid(oldgid);
! 
! 	switch(r) {
! 	case syscall_success /* 0 */: {
! 	    DPRINT(Debug,11,(&Debug,
! 			     "mbx_end_keep_spool: setgid(%d) succeed\n",
! 			     oldgid));
! 	}
! 	    break;	    
! 	case syscall_error /* -1 */: {
      	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      oldgid,strerror(err));
  	}
+ 	    break;
+ 	}
      }
  
      DPRINT(Debug,11,(&Debug,
***************
*** 8751,8757 ****
      DPRINT(Debug,11,(&Debug,
  		     "mbx_end_edit_spool: folder=%p (%s)\n",
  		     folder,folder->cur_folder_sys));
! 
      switch (sessionlock_folder(folder,SESSIONLOCK_REOPEN,NULL,NULL)) {
      case sessionlock_fail:
  	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntOpenFolder,
--- 9339,9345 ----
      DPRINT(Debug,11,(&Debug,
  		     "mbx_end_edit_spool: folder=%p (%s)\n",
  		     folder,folder->cur_folder_sys));
!     
      switch (sessionlock_folder(folder,SESSIONLOCK_REOPEN,NULL,NULL)) {
      case sessionlock_fail:
  	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntOpenFolder,
***************
*** 8787,8793 ****
  	if ( size !=  folder->mailfile_size) {
  	    char buffer[1000];
  	    int len;
! 	
  	    /* SIGH.  We've received mail since we invoked the editor
  	       on the folder.  We'll have to do some strange stuff to
  	       remedy the problem... */
--- 9375,9382 ----
  	if ( size !=  folder->mailfile_size) {
  	    char buffer[1000];
  	    int len;
! 	    enum syscall_status  r;
! 	    
  	    /* SIGH.  We've received mail since we invoked the editor
  	       on the folder.  We'll have to do some strange stuff to
  	       remedy the problem... */
***************
*** 8795,8811 ****
  	    lib_transient(CATGETS(elm_msg_cat, ElmSet, 
  				  ElmWarnNewMailRecv,
  				  "Warning: new mail received..."));
  	    
! 	    if (0 != fseek(folder->p->fh_temp,0,SEEK_END)) {
  		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekTemp,
  				  "Couldn't seek to end of temp file. Edit LOST!"));
  		status = end_edit_none;
  		unlock_folder(0,folder);
  		goto clean;
  	    }
! 	    
! 	    if (fseek(folder->p->fh_folder, 
! 		      folder->mailfile_size, 0) == -1) {
  		DPRINT(Debug,1,(&Debug,
  				"Couldn't seek to end of cur_folder (offset %ld) (%s)\n",
  				folder->mailfile_size, "mbx_end_edit_non_spool"));
--- 9384,9416 ----
  	    lib_transient(CATGETS(elm_msg_cat, ElmSet, 
  				  ElmWarnNewMailRecv,
  				  "Warning: new mail received..."));
+ 
  	    
! 	    r = fseek(folder->p->fh_temp,0,SEEK_END);
! 	    switch(r) {
! 	    case syscall_success /* 0 */: 
! 		DPRINT(Debug,11,(&Debug,
! 				 "mbx_end_edit_spool: Seek end of temp file\n"));
! 		break;		    	    
! 	    case syscall_error /* -1 */: {
  		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekTemp,
  				  "Couldn't seek to end of temp file. Edit LOST!"));
  		status = end_edit_none;
  		unlock_folder(0,folder);
  		goto clean;
  	    }
! 		break;
! 	    }
! 		
! 	    r = fseek(folder->p->fh_folder, 
! 		      folder->mailfile_size, 0);
! 	    switch(r) {
! 	    case syscall_success /* 0 */: 
! 		DPRINT(Debug,11,(&Debug,
! 				 "mbx_end_edit_spool: Seek end of cur_folder (offset %ld)\n",
! 				 folder->mailfile_size));
! 		break;
! 	    case syscall_error /* -1 */: {
  		DPRINT(Debug,1,(&Debug,
  				"Couldn't seek to end of cur_folder (offset %ld) (%s)\n",
  				folder->mailfile_size, "mbx_end_edit_non_spool"));
***************
*** 8816,8821 ****
--- 9421,9428 ----
  		status = end_edit_none;
  		goto clean;
  	    }
+ 		break;
+ 	    }
  	    
  	    /** Now we can finally stream the new mail into the tempfile **/
  	    
***************
*** 8847,8860 ****
  	} else 
  	    lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmResyncingNewVersion,
  				  "Resynchronizing with new version of folder..."));
! 	
! 	
  	if (have_saved_ids) {
! 	    if (setgid(mailgroupid) < 0) {
  		int err = errno;
  		lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  			  mailgroupid,strerror(err));
  	    }
  	}
  
  	/* remove real mail_file and then
--- 9454,9476 ----
  	} else 
  	    lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmResyncingNewVersion,
  				  "Resynchronizing with new version of folder..."));
! 		
  	if (have_saved_ids) {
! 	    enum syscall_status  r = setgid(mailgroupid);
! 	    switch(r) {
! 	    case syscall_success /* 0 */: {
! 		DPRINT(Debug,11,(&Debug,
! 				 "mbx_end_edit_spool: setgid(%d) succeed\n",
! 				 mailgroupid));
! 	    }
! 		break;	    
! 	    case syscall_error /* -1 */: {
  		int err = errno;
  		lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  			  mailgroupid,strerror(err));
  	    }
+ 		break;
+ 	    }
  	}
  
  	/* remove real mail_file and then
***************
*** 8882,8892 ****
   clean:
      
      if (have_saved_ids) {
! 	if (setgid(oldgid) < 0) {
  	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      oldgid,strerror(err));
  	}
      }
  
      DPRINT(Debug,11,(&Debug,
--- 9498,9519 ----
   clean:
      
      if (have_saved_ids) {
! 	enum syscall_status  r = setgid(oldgid);
! 
! 	switch(r) {
! 	case syscall_success /* 0 */: {
! 	    DPRINT(Debug,11,(&Debug,
! 			     "mbx_end_edit_spool: setgid(%d) succeed\n",
! 			     oldgid));
! 	}
! 	    break;	    
! 	case syscall_error /* -1 */: {
  	    int err = errno;
  	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
  		      oldgid,strerror(err));
  	}
+ 	    break;
+ 	}
      }
  
      DPRINT(Debug,11,(&Debug,
***************
*** 9068,9074 ****
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default
  
  };
  
--- 9695,9702 ----
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default,
! 				 mbx_give_message_count_default
  
  };
  
***************
*** 9109,9115 ****
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default
  
  };
  
--- 9737,9744 ----
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default,
! 				 mbx_give_message_count_default
  
  };
  
***************
*** 9150,9156 ****
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default
  };
  
  void mailbox_2_status(status,entry)
--- 9779,9786 ----
  				 mbx_update_prev_hdr_default,
  				 mbx_have_default_quota,
  				 mbx_give_default_quotar_list,
! 				 mbx_give_message_msize_default,
! 				 mbx_give_message_count_default
  };
  
  void mailbox_2_status(status,entry)
Index: elmME+.2.5.alpha64-cvs/lib/mbox/mbox.c
*** elmME+.2.5.alpha63/lib/mbox/mbox.c	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/mbox.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: mbox.c,v 2.35 2021/08/20 18:11:57 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.35 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: mbox.c,v 2.38 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.38 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 727,733 ****
  					mbx_update_prev_hdr_default,
  					mbx_have_default_quota,
  					mbx_give_default_quotar_list,
! 					mbx_give_message_msize_default
  };
  
  const folder_type_p NO_NAME   = &no_name;
--- 727,734 ----
  					mbx_update_prev_hdr_default,
  					mbx_have_default_quota,
  					mbx_give_default_quotar_list,
! 					mbx_give_message_msize_default,
! 					mbx_give_message_count_default
  };
  
  const folder_type_p NO_NAME   = &no_name;
***************
*** 758,764 ****
      const char *mbx_dir = NULL;
      const char ** inf = NULL;
      const char * mailhome_val = NULL;
! 
      if (in_mail)
  	*in_mail = in_none;
  
--- 759,766 ----
      const char *mbx_dir = NULL;
      const char ** inf = NULL;
      const char * mailhome_val = NULL;
!     enum syscall_status  r1;
!     
      if (in_mail)
  	*in_mail = in_none;
  
***************
*** 771,786 ****
      
      DPRINT(Debug,8,(&Debug,
  		    "get_folder_type: filename=%s\n",filename));
!     
!     if (stat(filename, &bufX) != 0) {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug,
  			"get_folder_type: errno %d (%s) attempting to stat file %s\n", 
  			err, strerror(err), filename));
!     } else 
  	buf = &bufX;
  
! 
      mailhome_val = give_dt_estr_as_str(&mailhome_dir_e,
  				       "mailhome-dir",
  				       NULL,NULL);    
--- 773,794 ----
      
      DPRINT(Debug,8,(&Debug,
  		    "get_folder_type: filename=%s\n",filename));
! 
!     r1 = stat(filename, &bufX);
!     switch (r1) {
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug,
  			"get_folder_type: errno %d (%s) attempting to stat file %s\n", 
  			err, strerror(err), filename));
!     }
! 	break;
!     case syscall_success /* 0 */:
  	buf = &bufX;
+ 	break;
+     }
  
!     /* give_dt_estr_as_str adds / to end */
      mailhome_val = give_dt_estr_as_str(&mailhome_dir_e,
  				       "mailhome-dir",
  				       NULL,NULL);    
***************
*** 947,971 ****
  	char * cmp = elm_message(FRM("%.*s/%s"),l1,dir,X);
  	struct stat buf2;
  
! 	int r = stat(cmp, &buf2);
! 	
! 	if (-1 == r) {
  	    int err UNUSED_VAROK = errno;
  	    DPRINT(Debug,8,(&Debug,
  			    "in_directory=0: %s (errno=%d) attempting to stat file %s\n", 
  			    strerror(err), err, cmp));
  	    free(cmp);
  	    return 0;
! 	    
! 	} else if (0 == r) {
  	    if (buf1->st_ino == buf2.st_ino && buf1->st_dev == buf2.st_dev) {
  		DPRINT(Debug,8,(&Debug,
! 				"in_directory=1  (same dev=%ld and ino=%ld as %s)\n",
! 				(long)buf1->st_dev,(long)buf1->st_ino,cmp)); 
  		free(cmp);
  		return 1;
! 	    
  	    }
  	}
  	free(cmp);
      }
--- 955,983 ----
  	char * cmp = elm_message(FRM("%.*s/%s"),l1,dir,X);
  	struct stat buf2;
  
! 	enum syscall_status  r = stat(cmp, &buf2);
! 
! 	switch (r) {
! 	case syscall_error /* -1 */: {
  	    int err UNUSED_VAROK = errno;
  	    DPRINT(Debug,8,(&Debug,
  			    "in_directory=0: %s (errno=%d) attempting to stat file %s\n", 
  			    strerror(err), err, cmp));
  	    free(cmp);
  	    return 0;
! 	}
! 	case syscall_success /* 0 */:
  	    if (buf1->st_ino == buf2.st_ino && buf1->st_dev == buf2.st_dev) {
  		DPRINT(Debug,8,(&Debug,
! 				"in_directory=1  (same dev=%lu and ino=%lu as %s)\n",
! 				(unsigned long)buf1->st_dev,
! 				(unsigned long)buf1->st_ino,
! 				cmp)); 
  		free(cmp);
  		return 1;
! 		
  	    }
+ 	    break;
  	}
  	free(cmp);
      }
***************
*** 979,1014 ****
       const char *name1, *name2;
  {
      struct stat buf1, buf2;
!     int r;
      
      if (0 == strcmp(name1,name2)) {
  	DPRINT(Debug,8,(&Debug,
  			"same_file(%s,%s)=TRUE\n",name1,name2)); 
  	return TRUE;
      }
!     
!     if (stat(name1, &buf1) != 0) {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug, 
  			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
  			name1,name2,strerror(err), err, name1));
  	return FALSE;
      }
  
!     r = stat(name2, &buf2);
!     if (-1 == r) {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug,
  			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
  			name1,name2,strerror(err), err, name2));
  	return FALSE;
!     }  else if (0 == r) {
  	if (buf1.st_ino == buf2.st_ino && buf1.st_dev == buf2.st_dev) {
  	    DPRINT(Debug,8,(&Debug,
  			    "same_file(%s,%s)=TRUE\n",name1,name2)); 
  	    return TRUE;
  	}
      }
      DPRINT(Debug,8,(&Debug, 
  		    "same_file(%s,%s)=FALSE\n",name1,name2)); 
      return FALSE;
--- 991,1045 ----
       const char *name1, *name2;
  {
      struct stat buf1, buf2;
!     enum syscall_status  r1,r2;
      
      if (0 == strcmp(name1,name2)) {
  	DPRINT(Debug,8,(&Debug,
  			"same_file(%s,%s)=TRUE\n",name1,name2)); 
  	return TRUE;
      }
! 
!     r1 = stat(name1, &buf1);
!     switch (r1) {
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug, 
  			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
  			name1,name2,strerror(err), err, name1));
  	return FALSE;
      }
+ 	break;
+     case syscall_success /* 0 */:
+ 	DPRINT(Debug,10,(&Debug, 
+ 			 "same_file(%s,%s): stat %s succeed\n",
+ 			 name1,name2,name1));
+ 	break;
+     }
  
!     r2 = stat(name2, &buf2);
!     switch (r2) {
!     case syscall_error /* -1 */: {
  	int err UNUSED_VAROK = errno;
  	DPRINT(Debug,8,(&Debug,
  			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
  			name1,name2,strerror(err), err, name2));
  	return FALSE;
!     }
!     case syscall_success /* 0 */:
! 	DPRINT(Debug,10,(&Debug, 
! 			 "same_file(%s,%s): stat %s succeed\n",
! 			 name1,name2,name2));
! 	break;
!     }
!     
!     if (syscall_success == r1 && syscall_success == r2) {
  	if (buf1.st_ino == buf2.st_ino && buf1.st_dev == buf2.st_dev) {
  	    DPRINT(Debug,8,(&Debug,
  			    "same_file(%s,%s)=TRUE\n",name1,name2)); 
  	    return TRUE;
  	}
      }
+     
      DPRINT(Debug,8,(&Debug, 
  		    "same_file(%s,%s)=FALSE\n",name1,name2)); 
      return FALSE;
***************
*** 1326,1339 ****
  	    panic("MBX PANIC",__FILE__,__LINE__,"sessionlock_folder",
  		  "Bad magic number (private_data)",0);
  
! 	folder->p->flags1 = 0;    
      }
  
      switch (mode) {
      case SESSIONLOCK_NONE_CHECKNEW:
      
  	if (folder->p)	
! 	    folder->p->flags1   |=  FLAG1_CHECKNEW;
  	else {
  	    DPRINT(Debug,10,(&Debug,
  			     "sessionlock_folder: SESSIONLOCK_NONE_CHECKNEW unsupported\n"));
--- 1357,1370 ----
  	    panic("MBX PANIC",__FILE__,__LINE__,"sessionlock_folder",
  		  "Bad magic number (private_data)",0);
  
! 	clearit(folder->p->flags1,FLAG1_CHECKNEW);
      }
  
      switch (mode) {
      case SESSIONLOCK_NONE_CHECKNEW:
      
  	if (folder->p)	
! 	    setit (folder->p->flags1,FLAG1_CHECKNEW);
  	else {
  	    DPRINT(Debug,10,(&Debug,
  			     "sessionlock_folder: SESSIONLOCK_NONE_CHECKNEW unsupported\n"));
***************
*** 3348,3353 ****
--- 3379,3386 ----
      return read_state_ptr->fbytes;
  }
  
+ 
+ 
  int copy_lines_folder(folder,read_state_ptr)
       struct folder_info *folder;
       READ_STATE read_state_ptr;
***************
*** 4203,4208 ****
--- 4236,4268 ----
      return ret;
  }
  
+ /* -1 if not available (local mail) */
+ int copy_num_messages_folder(folder) 
+     struct folder_info *folder;
+ {
+     int ret = -1;
+ 
+     if (FOLDER_INFO_magic != folder->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"copy_num_messages_folder",
+ 	      "Bad magic number (folder_info)",0);
+ 
+     if (FOLDER_TYPE_magic != folder->folder_type->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"copy_num_messages_folder",
+ 	      "Bad magic number (folder_type)",0);
+ 
+     DPRINT(Debug,10,(&Debug,
+ 		     "copy_num_messages_folder: folder=%p (%s), type=%p (%s)\n",
+ 		     folder,folder->cur_folder_sys,folder -> folder_type,
+ 		     folder->folder_type->type_name));
+ 
+     ret = folder->folder_type->mbx_give_message_count_it(folder);
+ 
+     DPRINT(Debug,10,(&Debug,
+ 		     "copy_num_messages_folder=%d\n",ret));
+     
+     return ret;
+ }
+ 
  int get_folder_mode(folder) 
       struct folder_info *folder;
  {
***************
*** 4315,4323 ****
  }
  
  /* Increments refcount */
! struct mail_quotaroot_list * give_folder_quotaroot_l(folder,cd)
       struct folder_info * folder;     
       struct cancel_data * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
  {
      struct mail_quotaroot_list * ret = NULL;
  
--- 4375,4384 ----
  }
  
  /* Increments refcount */
! struct mail_quotaroot_list * give_folder_quotaroot_l(folder,cd,refresh)
       struct folder_info * folder;     
       struct cancel_data * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
+      enum quota_mode      refresh;
  {
      struct mail_quotaroot_list * ret = NULL;
  
***************
*** 4330,4374 ****
  	      "Bad magic number (folder_type)",0);
  
      DPRINT(Debug,10,(&Debug,
! 		     "give_folder_quotaroot_l: folder=%p (%s), type=%p (%s)\n",
  		     folder,folder->cur_folder_sys,folder -> folder_type,
  		     folder->folder_type->type_name));
  
      if (folder->p) {	
      	if (PRIVATE_DATA_magic != folder->p->magic) 
  	    panic("MBX PANIC",__FILE__,__LINE__,"give_folder_quotaroot_l",
  		  "Bad magic number (private_data)",0);
! 	
  	if (folder->p->quota) {
  	    DPRINT(Debug,11,(&Debug,
  			     "give_folder_quotaroot_l: have folder quota\n"));
  	    
! 	    ret = folder->folder_type->mbx_give_it_quotar_list(folder,folder->p->quota,cd);
  	    
  	} else {
! 
  	    struct mail_quota *quota_temp = NULL;
  
! 	     DPRINT(Debug,11,(&Debug,
! 			      "give_folder_quotaroot_l: Need folder quota, calling  ...->have_it_quota()\n"));
! 
! 	     quota_temp = folder->folder_type->have_it_quota(folder);
! 	     if (quota_temp) {
! 		 ret = folder->folder_type->mbx_give_it_quotar_list(folder,quota_temp,cd);
! 
! 		 free_mail_quota(&quota_temp);
! 	     } else {
! 		  DPRINT(Debug,11,(&Debug,
! 				   "give_folder_quotaroot_l: Folder quota not available\n"));
! 	     }
  	}
  
      } else {
  	DPRINT(Debug,11,(&Debug,
  			 "give_folder_quotaroot_l: No private data\n"));
      }
  
!     DPRINT(Debug,10,(&Debug,"give_folder_quotaroot_="));
      if (ret) {
  	DPRINT(Debug,10,(&Debug,"%p",ret));
      } else {
--- 4391,4452 ----
  	      "Bad magic number (folder_type)",0);
  
      DPRINT(Debug,10,(&Debug,
! 		     "give_folder_quotaroot_l: folder=%p (%s), type=%p (%s)",
  		     folder,folder->cur_folder_sys,folder -> folder_type,
  		     folder->folder_type->type_name));
  
+     DPRINT(Debug,10,(&Debug,
+ 		     "; refresh=%d",refresh));
+     switch (refresh) {
+     case quotam_normal:     DPRINT(Debug,10,(&Debug," quotam_normal"));  break;
+     case quotam_refresh:    DPRINT(Debug,10,(&Debug," quotam_refresh")); break;
+     }
+     DPRINT(Debug,10,(&Debug,"\n"));
+ 
      if (folder->p) {	
      	if (PRIVATE_DATA_magic != folder->p->magic) 
  	    panic("MBX PANIC",__FILE__,__LINE__,"give_folder_quotaroot_l",
  		  "Bad magic number (private_data)",0);
! 		
  	if (folder->p->quota) {
  	    DPRINT(Debug,11,(&Debug,
  			     "give_folder_quotaroot_l: have folder quota\n"));
  	    
! 	    ret = folder->folder_type->mbx_give_it_quotar_list(folder,folder->p->quota,cd,
! 							       refresh);
  	    
  	} else {
! 	    
  	    struct mail_quota *quota_temp = NULL;
+ 	    
+ 	    DPRINT(Debug,11,(&Debug,
+ 			     "give_folder_quotaroot_l: Need folder quota, calling  ...->have_it_quota()\n"));
+ 	    
+ 	    quota_temp = folder->folder_type->have_it_quota(folder);
+ 	    if (quota_temp) {
+ 		ret = folder->folder_type->mbx_give_it_quotar_list(folder,quota_temp,cd,
+ 								   refresh);
+ 		
+ 		free_mail_quota(&quota_temp);
+ 	    } else {
+ 		DPRINT(Debug,11,(&Debug,
+ 				 "give_folder_quotaroot_l: Folder quota not available\n"));
+ 	    }
+ 	}
  
! 	if (ret) {
! 	    quotaroot_list_set_refresh(ret,refresh);
  	}
  
+ 	
      } else {
  	DPRINT(Debug,11,(&Debug,
  			 "give_folder_quotaroot_l: No private data\n"));
      }
  
! 	
! 	
!     DPRINT(Debug,10,(&Debug,"give_folder_quotaroot_l="));
      if (ret) {
  	DPRINT(Debug,10,(&Debug,"%p",ret));
      } else {
***************
*** 4690,4695 ****
--- 4768,4776 ----
      p->fh_temp     = NULL;
      p->fh_folder   = NULL;
      p->flags1      = 0;
+ 
+     /* p->ostat */
+     
      p->lock_info   = lock_info;
      p->magic       = PRIVATE_DATA_magic;
      p->a.dummy     = 0;
Index: elmME+.2.5.alpha64-cvs/lib/mbox/mbox_generic.c
*** elmME+.2.5.alpha63/lib/mbox/mbox_generic.c	Tue Apr 20 20:32:06 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/mbox_generic.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: mbox_generic.c,v 2.9 2021/01/10 15:47:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.9 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: mbox_generic.c,v 2.11 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.11 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 151,160 ****
  }
  
  E_(mbx_give_folder_quotar_list mbx_give_default_quotar_list)
! struct mail_quotaroot_list * mbx_give_default_quotar_list(folder,mq,cd)
       struct folder_info * folder;
       struct mail_quota   * mq; 
       struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
  {
      DPRINT(Debug,12,(&Debug,"mbx_give_default_quotar_list=NULL\n"));
  
--- 151,161 ----
  }
  
  E_(mbx_give_folder_quotar_list mbx_give_default_quotar_list)
! struct mail_quotaroot_list * mbx_give_default_quotar_list(folder,mq,cd,refresh)
       struct folder_info * folder;
       struct mail_quota   * mq; 
       struct cancel_data  * cd /* Allow cancelation (Ctrl-C) on remote mailbox */;
+      enum quota_mode      refresh;
  {
      DPRINT(Debug,12,(&Debug,"mbx_give_default_quotar_list=NULL\n"));
  
***************
*** 167,179 ****
       struct header_rec  * entry;
       unsigned long      * ret_size;
  {
- 
      DPRINT(Debug,12,(&Debug,
  		     "mbx_give_message_msize_default=0 (dummy): folder=%p (%s)\n",
  		     folder,folder->cur_folder_sys));
  
      return 0;
  
  }
  
  int sessionlock_create_tempfolder(folder,errcode)
--- 168,190 ----
       struct header_rec  * entry;
       unsigned long      * ret_size;
  {
      DPRINT(Debug,12,(&Debug,
  		     "mbx_give_message_msize_default=0 (dummy): folder=%p (%s)\n",
  		     folder,folder->cur_folder_sys));
  
      return 0;
+ }
+ 
+ E_(mbx_give_message_count_folder mbx_give_message_count_default)
+ /* Return -1 if not available (local mail) */
+ int mbx_give_message_count_default(folder)
+      struct folder_info * folder;
+ {
+     DPRINT(Debug,12,(&Debug,
+ 		     "mbx_give_message_count_default=-1 (dummy): folder=%p (%s)\n",
+ 		     folder,folder->cur_folder_sys));
  
+     return -1;
  }
  
  int sessionlock_create_tempfolder(folder,errcode)
Index: elmME+.2.5.alpha64-cvs/lib/mbox/pop.c
*** elmME+.2.5.alpha63/lib/mbox/pop.c	Thu May 26 11:16:29 2022
--- elmME+.2.5.alpha64-cvs/lib/mbox/pop.c	Thu Jun 13 20:36:55 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: pop.c,v 2.46 2022/02/20 13:46:55 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.46 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: pop.c,v 2.48 2024/06/13 17:36:55 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.48 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 485,491 ****
      
      return 1;
  }
! 			     
  static int read_uidls P_((const char            * name,
  			  FILE                  * F,
  			  struct sortlist      ** uidl_list,
--- 485,494 ----
      
      return 1;
  }
! 
! static const char UIDLS_HEADER[] = "ELMME+ UIDL\n";
! static const int  UIDLS_HEADER_len = (sizeof UIDLS_HEADER) -1;
! 
  static int read_uidls P_((const char            * name,
  			  FILE                  * F,
  			  struct sortlist      ** uidl_list,
***************
*** 503,509 ****
      size_t idx = 0;   /* For append mode hint */
  
      if ((ret = mail_gets(buffer, sizeof buffer,F)) > 0) {
! 	if (ret != 12 || 0 != memcmp(buffer,"ELMME+ UIDL\n",12)) {
  	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
  			      "File %s is corrupted."),
  		      name);
--- 506,513 ----
      size_t idx = 0;   /* For append mode hint */
  
      if ((ret = mail_gets(buffer, sizeof buffer,F)) > 0) {
! 	if (ret != UIDLS_HEADER_len || 0 != memcmp(buffer,UIDLS_HEADER,
! 						   UIDLS_HEADER_len)) {
  	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
  			      "File %s is corrupted."),
  		      name);
***************
*** 545,560 ****
  
  	r = fseek(F,pos,SEEK_SET);
  	switch (r) {
! 
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
  			     "read_uidls: Reading again from offset %ld at %s\n",
  			     pos,name));
  	    break;
  	case syscall_error:
  	    DPRINT(Debug,14,(&Debug,
! 			     "read_uidls: Failed to seek to offset %ld at %s\n",
! 			     pos,name));
  
  	    return 0;
  	}
--- 549,566 ----
  
  	r = fseek(F,pos,SEEK_SET);
  	switch (r) {
! 	    int err UNUSED_VAROK;
  	case syscall_success:
  	    DPRINT(Debug,14,(&Debug,
  			     "read_uidls: Reading again from offset %ld at %s\n",
  			     pos,name));
  	    break;
  	case syscall_error:
+ 	    err = errno;
+ 	    
  	    DPRINT(Debug,14,(&Debug,
! 			     "read_uidls: Failed to seek to offset %ld at %s: %s\n",
! 			     pos,name,strerror(err)));
  
  	    return 0;
  	}
***************
*** 812,818 ****
  	DPRINT(Debug,14,(&Debug,"update_uidls: ftruncate of %s failed\n",name));
      }
  #endif
!     fprintf(F,"ELMME+ UIDL\n");
      print_uidls(F,*uidl_list);
      fprintf(F,"--END\n");   /* So that truncate of file is not necessary */
      fflush(F);
--- 818,824 ----
  	DPRINT(Debug,14,(&Debug,"update_uidls: ftruncate of %s failed\n",name));
      }
  #endif
!     fprintf(F,UIDLS_HEADER);
      print_uidls(F,*uidl_list);
      fprintf(F,"--END\n");   /* So that truncate of file is not necessary */
      fflush(F);
***************
*** 4684,4689 ****
--- 4690,4718 ----
  
  }
  
+ /* Return -1 if not available (local mail) */
+ S_(mbx_give_message_count_folder mbx_give_message_count_pop)
+ static int mbx_give_message_count_pop P_((struct folder_info * folder));
+ static int mbx_give_message_count_pop(folder)
+      struct folder_info * folder;
+ {
+     int ret;
+     
+     DPRINT(Debug,11,(&Debug,
+ 		     "mbx_give_message_count_pop: folder=%p (%s)\n",
+ 		     folder,folder->cur_folder_sys));
+         
+     if (PRIVATE_DATA_magic != folder->p->magic) 
+ 	panic("MBX PANIC",__FILE__,__LINE__,"mbx_give_message_count_pop",
+ 	      "Bad magic number (private_data)",0);
+ 
+     ret = folder -> p->a.pop_mbx.stat_count;
+ 
+     DPRINT(Debug,11,(&Debug,
+ 		     "mbx_give_message_count_pop=%d\n",ret));
+ 
+     return ret;
+ }
  
  struct folder_type pop_mbx = { FOLDER_TYPE_magic, 
  			       "POP",
***************
*** 4722,4728 ****
  			       mbx_update_prev_hdr_pop,
  			       mbx_have_default_quota,
  			       mbx_give_default_quotar_list,
! 			       mbx_give_message_msize_pop
  };
  
  struct remote_account * set_pop_connection(fh,X,passhm)
--- 4751,4758 ----
  			       mbx_update_prev_hdr_pop,
  			       mbx_have_default_quota,
  			       mbx_give_default_quotar_list,
! 			       mbx_give_message_msize_pop,
! 			       mbx_give_message_count_pop
  };
  
  struct remote_account * set_pop_connection(fh,X,passhm)
Index: elmME+.2.5.alpha64-cvs/lib/mbox/quota.c
*** elmME+.2.5.alpha63/lib/mbox/quota.c	Wed Jun 16 20:17:54 2021
--- elmME+.2.5.alpha64-cvs/lib/mbox/quota.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: quota.c,v 2.2 2021/06/13 16:13:58 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.2 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: quota.c,v 2.3 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.3 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *       or Kari Hurtta <elm@elmme-mailer.org>
***************
*** 207,213 ****
  			  1 for mail_quota->quotarootl_list[] pointer
  		       */
      ret->mail_quota = mail_quota;
! 
      if (MAIL_QUOTA_TYPE_magic != mail_quota->quota_type->magic)
  	  panic("MBX PANIC",__FILE__,__LINE__,
                "malloc_mail_quotaroot_list",
--- 207,213 ----
  			  1 for mail_quota->quotarootl_list[] pointer
  		       */
      ret->mail_quota = mail_quota;
!     
      if (MAIL_QUOTA_TYPE_magic != mail_quota->quota_type->magic)
  	  panic("MBX PANIC",__FILE__,__LINE__,
                "malloc_mail_quotaroot_list",
***************
*** 454,459 ****
--- 454,485 ----
      return NULL;
  }
  
+ void quotaroot_list_set_refresh(quota_list,refresh)
+      struct mail_quotaroot_list *quota_list;
+      enum quota_mode refresh;
+ {
+     if (MAIL_QUOTAROOT_LIST_magic != quota_list->magic)
+ 	panic("MBX PANIC",__FILE__,__LINE__,
+ 	      "quotaroot_list_set_refresh",
+ 	      "Bad magic number (mail_quotaroot_list)",0);
+ 
+     if (quota_list->mail_quota) {
+ 	
+ 	if (MAIL_QUOTA_magic != quota_list->mail_quota->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "quotaroot_list_set_refresh",
+ 		  "Bad magic number (mail_quota)",0);
+ 	
+ 	if (MAIL_QUOTA_TYPE_magic != quota_list->quota_type->magic)
+ 	    panic("MBX PANIC",__FILE__,__LINE__,
+ 		  "quotaroot_list_set_refresh",
+ 		  "Bad magic number (mail_quota_type)",0);
+ 
+ 	quota_list->quota_type->mq_refresh_mqrl_it(quota_list->mail_quota,
+ 						   quota_list,refresh);
+     }    
+ }
+ 
  /* Previous quotaroot with same is removed from list */
  
  struct mail_quotaroot * malloc_mail_quotaroot(mail_quota,name,name_token)
***************
*** 926,932 ****
  	      "free_mail_quota_item_internal",
  	      "Bad magic number (mail_quota_type)",0);
  
-     
      if ((*quota_item)->mail_quota) {
  	size_t i;
  
--- 952,957 ----
Index: elmME+.2.5.alpha64-cvs/lib/mbox/remote_server.c
*** elmME+.2.5.alpha63/lib/mbox/remote_server.c	Thu Jul 28 18:49:52 2022
--- elmME+.2.5.alpha64-cvs/lib/mbox/remote_server.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: remote_server.c,v 2.25 2022/06/26 16:55:20 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.25 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                  (was hurtta+elm@posti.FMI.FI)  
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: remote_server.c,v 2.26 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.26 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                  (was hurtta+elm@posti.FMI.FI)  
***************
*** 873,879 ****
  		DPRINT(Debug,16,(&Debug,
  				 "rs_select_local: FOLDER_is_local_file is set for value\n"));
  
! 		F = local_selection_stat(default_val);
  	    
  		/* WARNING: set_dir_selection does not allocate strings -- 
  		 *          it just assign pointers!
--- 873,881 ----
  		DPRINT(Debug,16,(&Debug,
  				 "rs_select_local: FOLDER_is_local_file is set for value\n"));
  
! 		F = local_selection_stat(default_val,
! 					 /* struct last_read_cache * */
! 					 NULL);
  	    
  		/* WARNING: set_dir_selection does not allocate strings -- 
  		 *          it just assign pointers!
***************
*** 889,895 ****
  		DPRINT(Debug,16,(&Debug,
  				 "rs_select_local: Using local incoming mailbox\n"));
  		
! 		F = local_selection_stat(default_val);
  		
  		/* WARNING: set_dir_selection does not allocate strings -- 
  		 *          it just assign pointers!
--- 891,899 ----
  		DPRINT(Debug,16,(&Debug,
  				 "rs_select_local: Using local incoming mailbox\n"));
  		
! 		F = local_selection_stat(default_val,
! 					 /* struct last_read_cache * */
! 					 NULL);
  		
  		/* WARNING: set_dir_selection does not allocate strings -- 
  		 *          it just assign pointers!
Index: elmME+.2.5.alpha64-cvs/lib/misc/commentfile.c
*** elmME+.2.5.alpha63/lib/misc/commentfile.c	Wed May  3 22:34:22 2017
--- elmME+.2.5.alpha64-cvs/lib/misc/commentfile.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: commentfile.c,v 2.2 2017/05/03 19:34:22 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.2 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: commentfile.c,v 2.3 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.3 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 37,48 ****
  	} else 
  	    close_comment_file++;
      }
-     
-     elm_fprintf(f, 
- 		CATGETS(elm_msg_cat, MeSet, MeSavedAutoWrite1,
- 			"# Saved automatically by %s %s\n#\n\n"), 
- 		actor,version_buff);
  
      if (commentfile) {
  	char line_buffer[SLEN];
  	int len;
--- 37,55 ----
  	} else 
  	    close_comment_file++;
      }
  
+     if (actor && version_buff) {
+ 	elm_fprintf(f, 
+ 		    CATGETS(elm_msg_cat, MeSet, MeSavedAutoWrite1,
+ 			    "# Saved automatically by %s %s\n#\n\n"), 
+ 		    actor,version_buff);
+     } else {
+ 	elm_fprintf(f, 
+ 		    CATGETS(elm_msg_cat, MeSet, MeSavedAutoWrite2,
+ 			    "# Saved automatically\n#\n\n"));
+ 
+     }
+ 	
      if (commentfile) {
  	char line_buffer[SLEN];
  	int len;
Index: elmME+.2.5.alpha64-cvs/lib/misc/conf_writer.c
*** elmME+.2.5.alpha63/lib/misc/conf_writer.c	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/lib/misc/conf_writer.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: conf_writer.c,v 2.11 2021/08/20 18:11:57 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.11 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: conf_writer.c,v 2.12 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.12 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 386,397 ****
  		    case syscall_success:
  			
  			DPRINT(Debug,14, (&Debug,
! 					  "write_conf: %s - fstat %d: %s succeed: dev %ld ino %ld size %ld modified %ld",
  					  cfiles[i].shortname,
  					  config_handles[i].old_fd,
  					  cfiles[i].fname,
! 					  (long)config_handles[i].old_fd_stat.st_dev,
! 					  (long)config_handles[i].old_fd_stat.st_ino,
  					  (long)(config_handles[i].old_fd_stat.st_size),
  					  (long)(config_handles[i].old_fd_stat.st_mtime)));
  			
--- 386,397 ----
  		    case syscall_success:
  			
  			DPRINT(Debug,14, (&Debug,
! 					  "write_conf: %s - fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
  					  cfiles[i].shortname,
  					  config_handles[i].old_fd,
  					  cfiles[i].fname,
! 					  (unsigned long)config_handles[i].old_fd_stat.st_dev,
! 					  (unsigned long)config_handles[i].old_fd_stat.st_ino,
  					  (long)(config_handles[i].old_fd_stat.st_size),
  					  (long)(config_handles[i].old_fd_stat.st_mtime)));
  			
***************
*** 479,486 ****
  			if ( config_handles[i].old_fd_have_stat && ! config_handles[i].bck)
  			    config_handles[i].bck = elm_message(FRM("%s.%lx_%lx.old"),
  								cfiles[i].fname,
! 								(long)config_handles[i].old_fd_stat.st_dev,
! 								(long)config_handles[i].old_fd_stat.st_ino);
  			
  			if (config_handles[i].bck) {
  			    config_handles[i].require_bck = 1;
--- 479,486 ----
  			if ( config_handles[i].old_fd_have_stat && ! config_handles[i].bck)
  			    config_handles[i].bck = elm_message(FRM("%s.%lx_%lx.old"),
  								cfiles[i].fname,
! 								(unsigned long)config_handles[i].old_fd_stat.st_dev,
! 								(unsigned long)config_handles[i].old_fd_stat.st_ino);
  			
  			if (config_handles[i].bck) {
  			    config_handles[i].require_bck = 1;
***************
*** 564,573 ****
  		    case syscall_success:
  			
  			DPRINT(Debug,14, (&Debug,
! 					  "write_conf: %s - stat %s succeed: dev %d ino %d size %ld modified %ld",
  					  cfiles[i].shortname,
  					  cfiles[i].fname,
! 					  filename_stat.st_dev,filename_stat.st_ino,
  					  (long)filename_stat.st_size,
  					  (long)filename_stat.st_mtime));
  			X = ctime(& (filename_stat.st_mtime));
--- 564,574 ----
  		    case syscall_success:
  			
  			DPRINT(Debug,14, (&Debug,
! 					  "write_conf: %s - stat %s succeed: dev %lu ino %lu size %ld modified %ld",
  					  cfiles[i].shortname,
  					  cfiles[i].fname,
! 					  (unsigned long)filename_stat.st_dev,
! 					  (unsigned long)filename_stat.st_ino,
  					  (long)filename_stat.st_size,
  					  (long)filename_stat.st_mtime));
  			X = ctime(& (filename_stat.st_mtime));
***************
*** 795,800 ****
--- 796,802 ----
  			lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
  					  "File %.50s is not writeable: %s"),
  				  config_handles[i].tmp, strerror(err));
+ 
  			break;
  		    }		    
  		}
***************
*** 817,828 ****
  
  			
  			if (config_handles[i].tmp) {
! 			    
! 			    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
! 					      "File %.50s is not writeable: %s"),
! 				      config_handles[i].tmp, strerror(err));
  			    
  			    unlink(config_handles[i].tmp);   /* Ignore error */
  			}
  
  			fclose(config_handles[i].tmp_f);  /* ignore error */
--- 819,836 ----
  
  			
  			if (config_handles[i].tmp) {
! 
! 			    if (err)
! 				lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
! 						  "File %.50s is not writeable: %s"),
! 					  config_handles[i].tmp, strerror(err));
! 
! 			    /* No error message if error code is not given */
  			    
  			    unlink(config_handles[i].tmp);   /* Ignore error */
+ 			    
+ 			    free(config_handles[i].tmp);
+ 			    config_handles[i].tmp = NULL;
  			}
  
  			fclose(config_handles[i].tmp_f);  /* ignore error */
Index: elmME+.2.5.alpha64-cvs/lib/read_rc.c
*** elmME+.2.5.alpha63/lib/read_rc.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/lib/read_rc.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: read_rc.c,v 2.148 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.148 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: read_rc.c,v 2.149 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.149 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 693,698 ****
--- 693,700 ----
  
  char user_hash_marks[SLEN] =   USER_HASHMARK_FILE;  /* user_init fixes */
  char user_tagfilter_entfile[SLEN] =  USER_TAGFILTER_ENTFILE; /* user_init fixes */
+ char user_last_read_def[SLEN]  =  USER_LAST_READ;  /* user_init fixes */
+ char user_last_read_dot[SLEN]  = ".elm-last-read"; /* user_init fixes */
  
  #if ANSI_C
  #define S_(x) static x;
***************
*** 700,709 ****
  #define S_(x)
  #endif
  
! 
! 
! static char * MAILBOX_LOCKING[NUM_mailbox_locking_v+1] = {
!     "lockfile", "flock", "fcntl", NULL
  }; 
  
  
--- 702,712 ----
  #define S_(x)
  #endif
  
! /* exported for lib/mbox/init.c */
! char * MAILBOX_LOCKING[NUM_mailbox_locking_v+1] = {
!     "lockfile", "flock", "fcntl",
!     "prefer",
!     NULL
  }; 
  
  
***************
*** 2692,2698 ****
  
      if (pass->pw_dir)
  	strfcpy(home, pass->pw_dir, sizeof home);
!     else if (NULL != (cp = getenv("HOME")))
  	strfcpy(home,cp,sizeof home);
      else
  	strfcpy(home,"/",sizeof home);
--- 2695,2702 ----
  
      if (pass->pw_dir)
  	strfcpy(home, pass->pw_dir, sizeof home);
!     else if (NULL != (cp = getenv("HOME")) &&
! 	     '/' == cp[0])
  	strfcpy(home,cp,sizeof home);
      else
  	strfcpy(home,"/",sizeof home);
***************
*** 2745,2750 ****
--- 2749,2759 ----
      elm_sfprintf(user_tagfilter_entfile, sizeof user_tagfilter_entfile,
  		 FRM("%s/%s"), home, USER_TAGFILTER_ENTFILE);
      
+     elm_sfprintf(user_last_read_def,sizeof user_last_read_def,
+ 		 FRM("%s/%s"), home, USER_LAST_READ);
+     elm_sfprintf(user_last_read_dot,sizeof user_last_read_dot,
+ 		 FRM(".elm-last-read-%d"),userid);
+     
  #if DEBUG    
      /* Open debug files and print spooled debug output */
      debug_user_init();
Index: elmME+.2.5.alpha64-cvs/lib/static-hosts.c
*** elmME+.2.5.alpha63/lib/static-hosts.c	Thu May 28 08:02:12 2020
--- elmME+.2.5.alpha64-cvs/lib/static-hosts.c	Wed Jun 26 19:54:27 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: static-hosts.c,v 2.3 2020/05/28 05:02:12 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.3 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: static-hosts.c,v 2.4 2024/06/26 16:54:27 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.4 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 1590,1596 ****
  	schedule_valid_until_ok(&etc_hosts_valid_until,
  				now)) {
      
! 	struct file_hostentry * fhe = NULL;
  	char * etc_valid_until_t;
  	char * now_t;
  
--- 1590,1596 ----
  	schedule_valid_until_ok(&etc_hosts_valid_until,
  				now)) {
      
! 	struct file_hostentry * fhe;
  	char * etc_valid_until_t;
  	char * now_t;
  
***************
*** 1598,1603 ****
--- 1598,1604 ----
  	    *static_status_p = etc_hosts_maybe;   /* Not queried */
  	
      retry_cache:
+ 	fhe = NULL;
  	etc_valid_until_t = schedule_timeout_string(&etc_hosts_valid_until);
  	now_t             = schedule_timeout_string(now);
  	
Index: elmME+.2.5.alpha64-cvs/nls/C/C/C/s_me.m
*** elmME+.2.5.alpha63/nls/C/C/C/s_me.m	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/nls/C/C/C/s_me.m	Mon Jun 10 21:05:34 2024
***************
*** 2116,2121 ****
  1120	|[ Tags filtered from %s/%s format: %S ]\n|
  $ #UnknownTerminalAttribute
  1121	|Unknown terminal attribute %s (file %s)|
! 
! 
  							  
--- 2116,2141 ----
  1120	|[ Tags filtered from %s/%s format: %S ]\n|
  $ #UnknownTerminalAttribute
  1121	|Unknown terminal attribute %s (file %s)|
! $ #FolderStatError
! 1122	|Error encountered while attempting to stat folder %S: %s|
! $ #LastReadWaitingFail
! 1123	|Waiting last-read file %s to be updated... Fail: %s|
! $ #LastReadWaitingOK
! 1124	|Waiting last-read file %s to be updated... OK|
! $ #LastReadWaiting
! 1125	|Waiting last-read file %s to be updated...|
! $ #LastReadWaitingError
! 1126	|Waiting last-read file %s to be updated... Error|
! $ #LastReadWriteTempFail
! 1127	|Write failed for last-read temp file %s: %s|
! $ #LastReadCreatTempFail
! 1128	|Failed to create last-read temp file %s: %s|
! $ #LastReadCheckTempFail
! 1129	|Failed to check last-read temp file %s: %s|
! $ #LastReadRenameFail
! 1130	|Failed to rename last-read file to %s: %s|
! $ #DefaultLastReadW
! 1140	|Default last read file %s written.|
! $ #SavedAutoWrite2
! 1141	|# Saved automatically\n#\n\n|
  							  
Index: elmME+.2.5.alpha64-cvs/shared_libs/tls/tls.c
*** elmME+.2.5.alpha63/shared_libs/tls/tls.c	Thu Jul 28 18:49:52 2022
--- elmME+.2.5.alpha64-cvs/shared_libs/tls/tls.c	Wed Jun 26 19:54:27 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: tls.c,v 2.33 2022/06/26 16:55:20 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.33 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: tls.c,v 2.34 2024/06/26 16:54:27 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.34 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 20,26 ****
  
  #ifdef REMOTE_MBX
  
! static unsigned char *s2us P_((char *str));
  static unsigned char *s2us(str)
       char *str;
  {
--- 20,26 ----
  
  #ifdef REMOTE_MBX
  
! static unsigned char *s2us P_((char *str)) UNUSED_FUNCOK;
  static unsigned char *s2us(str)
       char *str;
  {
Index: elmME+.2.5.alpha64-cvs/src/args.c
*** elmME+.2.5.alpha63/src/args.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/src/args.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: args.c,v 2.60 2024/01/01 17:00:40 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.60 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: args.c,v 2.61 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.61 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
***************
*** 18,24 ****
   *  Incorparated Elm 2.5 code from src/args.c. 
   *  That code was following copyright:
   *
!  *  The Elm Mail System  -  $Revision: 2.60 $   $State: Exp $
   *
   *                      Copyright (c) 1988-1995 USENET Community Trust
   * 			Copyright (c) 1986,1987 Dave Taylor
--- 18,24 ----
   *  Incorparated Elm 2.5 code from src/args.c. 
   *  That code was following copyright:
   *
!  *  The Elm Mail System  -  $Revision: 2.61 $   $State: Exp $
   *
   *                      Copyright (c) 1988-1995 USENET Community Trust
   * 			Copyright (c) 1986,1987 Dave Taylor
***************
*** 1760,1773 ****
  		) {
  		
  		struct stat buf, *Xbuf = NULL;
! 		
! 		if (0 == stat(default_val,&buf)) {
  		    Xbuf = &buf;
! 		} else {
  		    int err = errno;
! 
  		    printf("\t(error: %s)",strerror(err));
  		}
  		putchar('\n');
  
  		if (mailhome_val &&
--- 1760,1779 ----
  		) {
  		
  		struct stat buf, *Xbuf = NULL;
! 		enum syscall_status  r = stat(default_val,&buf);
! 
! 		switch (r) {
! 		case syscall_success /* 0 */: {
  		    Xbuf = &buf;
! 		}
! 		    break;
! 		case syscall_error /* -1 */: {
  		    int err = errno;
! 		    
  		    printf("\t(error: %s)",strerror(err));
  		}
+ 		    break;
+ 		}
  		putchar('\n');
  
  		if (mailhome_val &&
Index: elmME+.2.5.alpha64-cvs/src/browser.c
*** elmME+.2.5.alpha63/src/browser.c	Thu Jul 28 18:49:52 2022
--- elmME+.2.5.alpha64-cvs/src/browser.c	Mon Jun 10 21:05:34 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: browser.c,v 2.49 2022/07/14 14:16:01 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.49 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: browser.c,v 2.50 2024/06/10 18:05:34 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.50 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 528,544 ****
      case BROWSER_NOFOLDER: c = 'D'; break;
      }
  		
!     if (flags & BROWSER_HAVELOCKFILE)
  	n = 'L';
!     else if (flags & BROWSER_SESSIONLOCK)
  	n = 'S';
!     else if (flags & BROWSER_MARKED)
  	n = 'N';
  
      if (current && !arrow_cursor)
  	menu_StartXX(I->current_page,pg_STANDOUT);
  
- 
   restart:
      if (I->browser->comment_col < COLUMNS && comment1) {
  	size = I->browser->comment_col-5;
--- 528,543 ----
      case BROWSER_NOFOLDER: c = 'D'; break;
      }
  		
!     if (ison(flags,BROWSER_HAVELOCKFILE))
  	n = 'L';
!     else if (ison(flags,BROWSER_SESSIONLOCK))
  	n = 'S';
!     else if (ison(flags,BROWSER_MARKED))
  	n = 'N';
  
      if (current && !arrow_cursor)
  	menu_StartXX(I->current_page,pg_STANDOUT);
  
   restart:
      if (I->browser->comment_col < COLUMNS && comment1) {
  	size = I->browser->comment_col-5;
Index: elmME+.2.5.alpha64-cvs/src/extended.c
*** elmME+.2.5.alpha63/src/extended.c	Wed Jan 29 18:20:24 2020
--- elmME+.2.5.alpha64-cvs/src/extended.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: extended.c,v 2.18 2020/01/29 16:20:24 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.18 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: extended.c,v 2.20 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.20 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 136,142 ****
  	    !storage->current_folder)
  	    continue;
  
- 
  	mquota = have_folder_quota(storage->current_folder);
  	if (mquota) {
  
--- 136,141 ----
***************
*** 156,162 ****
  
  	if (quotad) {
  	    struct mail_quotaroot_list * quota_list =
! 		give_folder_quotaroot_l(storage->current_folder,cd);
  	    
  	    if (quota_list) {
  		quota_display_add_qlist(quotad,quota_list,
--- 155,162 ----
  
  	if (quotad) {
  	    struct mail_quotaroot_list * quota_list =
! 		give_folder_quotaroot_l(storage->current_folder,cd,
! 					quotam_refresh);
  	    
  	    if (quota_list) {
  		quota_display_add_qlist(quotad,quota_list,
***************
*** 377,383 ****
      if (is_current) {
  
  	if (has_highlighting && ! arrow_cursor) {
! 
  	    menu_StartXX(ptr,pg_STANDOUT);
  
  	    menu_PutLine0(ptr,line_number,0,"   ");
--- 377,383 ----
      if (is_current) {
  
  	if (has_highlighting && ! arrow_cursor) {
! 	    
  	    menu_StartXX(ptr,pg_STANDOUT);
  
  	    menu_PutLine0(ptr,line_number,0,"   ");
Index: elmME+.2.5.alpha64-cvs/src/newmbox.c
*** elmME+.2.5.alpha63/src/newmbox.c	Sat Feb  8 09:08:06 2020
--- elmME+.2.5.alpha64-cvs/src/newmbox.c	Sun Jun 23 10:38:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: newmbox.c,v 2.19 2020/02/08 07:08:06 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.19 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: newmbox.c,v 2.22 2024/06/23 07:38:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.22 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 27,32 ****
--- 27,36 ----
  extern int errno;
  #endif       
  
+ /* For INT_MAX */
+ #include <limits.h>
+ 
+ 
  #if  !defined(ANSI_C) && !defined(atol) /* avoid problems with systems that declare atol as a macro */
  extern void rewind();
  extern long atol();
***************
*** 257,263 ****
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(new_folder,cd);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
--- 261,267 ----
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(new_folder,cd,quotam_normal);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
***************
*** 453,459 ****
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(*new_folder,cd);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
--- 457,463 ----
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(*new_folder,cd,quotam_normal);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
***************
*** 649,655 ****
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(new_folder,cd);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
--- 653,659 ----
  
  	setup_mbx_cancel_message(&cd,mbx_checking_mailbox);
  
! 	quota_list = give_folder_quotaroot_l(new_folder,cd,quotam_normal);
  
  	if (quota_list) {
  	    quota_display_add_qlist(quotad,quota_list,
***************
*** 895,902 ****
      
      int count_x, count_y, lastpercent;
      struct string * truncated_name;
!     long previous_bytes;
  
      int tail_x, tail_y;
      time_t   tail_time;
  };
--- 899,912 ----
      
      int count_x, count_y, lastpercent;
      struct string * truncated_name;
!     
!     long   previous_bytes;
!     int    previous_messages;
! 
!     int prompt_factor;
!     int skipped_factor;
  
+     
      int tail_x, tail_y;
      time_t   tail_time;
  };
***************
*** 908,925 ****
  		    COUNT_fail_cleanup
  };
  
! const int counter_tail_showtime = 5;   /* Show tail (new mails arrcied) message 5 seconds */
  
  static void reading_updater P_((enum counter_mode mode,
  				struct string *name,
  				struct counter_data *counter,
  				int count, int percent,
  				int skipcount, int percent2,
! 				struct menu_context    * page  /* May be NULL */
  				));
  static void reading_updater(mode,
  			    name, counter,count,percent,skipcount,
! 			    percent2,page)
       enum counter_mode mode;
       struct string *name;
       struct counter_data *counter;
--- 918,952 ----
  		    COUNT_fail_cleanup
  };
  
! const int counter_tail_showtime = 5;   /* Show tail (new mails arrived) message 5 seconds */
! 
! static int digits P_((int val));
! static int digits(val)
!      int val;
! {
!     int ret = 1;
! 
!     while (val >= 10 && ret < 9) {
! 
! 	val /= 10;
! 	ret++;
! 	
!     }
!     
!     return ret;
! }
  
  static void reading_updater P_((enum counter_mode mode,
  				struct string *name,
  				struct counter_data *counter,
  				int count, int percent,
  				int skipcount, int percent2,
! 				struct menu_context    * page  /* May be NULL */,
! 				int num_messages /* maybe -1 */
  				));
  static void reading_updater(mode,
  			    name, counter,count,percent,skipcount,
! 			    percent2,page,num_messages)
       enum counter_mode mode;
       struct string *name;
       struct counter_data *counter;
***************
*** 928,947 ****
--- 955,989 ----
       int skipcount; 
       int percent2;
       struct menu_context    * page; /* May be NULL *, if mode != COUNT_initialize */
+      int num_messages /* maybe -1 */;   
  {
      int initialize = mode == COUNT_initialize;
  
      int width;
      int LINES, COLUMNS;
+     int have_skipped = 0;
  
+     int d1, d2, d3 = 0, d4 = 0,d5 = 0;
+     int w;
+     
+     int text_x, text_y;
+     int total = 0;
  
+     int len;
+ 
+     int recalculate = 0;
+     
      if (initialize) {
  	/* bzero is defined hdrs/elm_defs.h */
  	bzero((void *)counter,sizeof (*counter));
  	
  	counter->truncated_name = NULL;
  	counter->previous_bytes = 0;
+ 	counter->previous_messages = 0;
  	counter->page           = page;
+ 
+ 	counter->prompt_factor  = 32;
+ 	counter->skipped_factor = 19;
  	
      } else if (page) {
  	if (counter->page != page) {
***************
*** 956,1037 ****
      width = COLUMNS - 53
  	        - ((skipcount >= 10000) ? 1 : 0)
  	        - ((count >= 10000) ? 1 : 0);
-     
  
-     if (width <= 6) {
- 	DPRINT(Debug,10,(&Debug, "reading_updater: width=%d\n",
- 			 width));
  
! 	if (initialize)
! 	    return;
! 
! 	menu_MoveCursor(page,counter->count_x,0);
! 	menu_CleartoEOLN(page);
! 			
! 	goto out;
!     }
  
!     if (COUNT_fail_cleanup == mode) {
! 	menu_MoveCursor(page,counter->count_x,0);
! 	menu_CleartoEOLN(page);
! 	goto out;
      }
      
!     if (string_len( counter->truncated_name ? 
! 		    counter->truncated_name : name ) 
! 	> width) {
! 	int A = width/2 -2;
! 	int B = string_len(name);
! 	int C = B-A;
! 	struct string *D = clip_from_string(name,&C,A);
  
! 	if (counter->truncated_name)
! 	    free_string(&(counter->truncated_name));
  
! 	counter->truncated_name = 
! 	    format_string(FRM("%.*S...%S"),
! 			  A,name,D);
  		
! 	free_string(&D);
! 	initialize++;
!     }
  
!     if (need_refresh_low_line() || 
! 	mode == COUNT_refresh)
! 	initialize++;
  
!     if (initialize) {
  	menu_PutLineX(page,
! 		      LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
! 					  ElmReadingInMessage,
! 					  "Reading in %S, message: ."),
! 		      counter->truncated_name ? counter->truncated_name : name);
  	
- 	menu_GetXYLocation(page,
- 			   &(counter->count_x),&(counter->count_y)); 
- 	counter->count_y--;
- 	counter->lastpercent = -1;
- 	menu_CleartoEOLN(page);
      }
  
!     menu_PutLineX(page,
! 		  counter->count_x, counter->count_y, 
! 		  FRM("%d (%02d%%) "), count,percent);
! 
!     if (skipcount > 0 || percent2 >= 0) {
! 	int add = 12 	- ((skipcount >= 100)  ? 1 : 0)
! 	                - ((skipcount >= 1000) ? 1 : 0)
!                         + ((count >= 10000) ? 1 : 0);
! 
  
  	menu_PutLineX(page,
! 		      counter->count_x, counter->count_y+add,
  		      CATGETS(elm_msg_cat, ElmSet,
  			      ElmSkippingInMessage,
  			      " %d (%02d%%) skipped "),
  		      skipcount,percent2);
  
! 	
      }
  
      if (initialize) {
--- 998,1218 ----
      width = COLUMNS - 53
  	        - ((skipcount >= 10000) ? 1 : 0)
  	        - ((count >= 10000) ? 1 : 0);
  
  
!     
  
!     if (count > 0)
! 	total += count;
!     if (counter->previous_messages > 0) {
! 	total += counter->previous_messages;
! 	d4 = digits(counter->previous_messages) +1;
      }
+ 	
+     /* Another way */
      
!     d1 = digits(count);
!     d2 = digits(skipcount);
!     d5 = digits(total);
  
!     have_skipped = (skipcount > 0 || percent2 >= 0);
  
!     do {
! 	if (recalculate) {
! 	    DPRINT(Debug,10,(&Debug, "reading_updater: recalculate loop #%d\n",
! 			     recalculate));   
! 	}
!     
! 	if (num_messages > 0) {
! 	    d3 = digits(num_messages);
! 
! 	    /* num_messages do not truncate filename,
! 	       but it is printed if there is enough
! 	       space
! 	    */
! 	    
! 	    w = COLUMNS - counter->prompt_factor - 2 * d3 - d4;
! 	    
! 	    
! 	} else 
! 	    w = COLUMNS - counter->prompt_factor - d1 - d2;
! 	
! 	if (have_skipped) {
! 	    
! 	    if (w > counter->skipped_factor + d2)
! 		w -= counter->skipped_factor - d2;
! 	    else  {
! 		DPRINT(Debug,10,(&Debug, "reading_updater: skipped text disabled, width=%d d1=%d d2=%d d3=%d d4=%d d5=%d skipped_factor=%d\n",
! 				 width,d1,d2,d3,d4,d5,counter->skipped_factor));
  		
! 		have_skipped = 0;
! 	    }
! 	}
!         
! 	if (w < width) {
! 	    DPRINT(Debug,15,(&Debug, "reading_updater: name width=%d => %d\n",
! 			     width,w));
! 	    width = w;
! 	}
! 	
! 	if (width <= 6) {
! 	    DPRINT(Debug,10,(&Debug, "reading_updater: width=%d d1=%d d2=%d d3=%d d4=%d d5=%d prompt_factor=%d\n",
! 			     width,d1,d2,d3,d4,d5,counter->prompt_factor));
! 	    
! 	    if (initialize && !recalculate)
! 		return;
! 	    
! 	    menu_MoveCursor(page,counter->count_x,0);
! 	    menu_CleartoEOLN(page);
! 	    
! 	    goto out;
! 	}
! 	
! 	if (COUNT_fail_cleanup == mode) {
! 	    menu_MoveCursor(page,counter->count_x,0);
! 	    menu_CleartoEOLN(page);
! 	    goto out;
! 	}
! 	
! 	if ((len = string_len( counter->truncated_name ? 
! 			       counter->truncated_name : name ))
! 	    > width) {
! 	    int A = width/2 -2;
! 	    int B = string_len(name);
! 	    int C = B-A;
! 	    struct string *D = clip_from_string(name,&C,A);
! 	    
! 	    DPRINT(Debug,10,(&Debug,
! 			     "reading_updater: truncating name width=%d => %d name=%S",
! 			     len,width,
! 			     counter->truncated_name ? 
! 			     counter->truncated_name : name));
! 	    
! 	    if (counter->truncated_name)
! 		free_string(&(counter->truncated_name));
! 	    
! 	    counter->truncated_name = 
! 		format_string(FRM("%.*S...%S"),
! 			      A,name,D);
! 	    
! 	    DPRINT(Debug,10,(&Debug," => %S\n",
! 			     counter->truncated_name));
! 	    
! 	    free_string(&D);
! 	    initialize++;	    
  
! 	}
! 	    
! 	if (need_refresh_low_line() || 
! 	    mode == COUNT_refresh)
! 	    initialize++;
! 	
! 	if (initialize) {
! 	    int A;
! 	    
! 	    menu_PutLineX(page,
! 			  LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
! 					      ElmReadingInMessage,
! 					      "Reading in %S, message: ."),
! 			  counter->truncated_name ? counter->truncated_name : name);
! 	    
! 	    menu_GetXYLocation(page,
! 			       &(counter->count_x),&(counter->count_y)); 
! 	    counter->count_y--;
! 	    counter->lastpercent = -1;
! 	    menu_CleartoEOLN(page);
! 	    
! 	    A = counter->count_y -
! 		string_len(counter->truncated_name ? counter->truncated_name : name)
! 		-9;
! 	    
! 	    if (A > counter->prompt_factor) {
! 		
! 		DPRINT(Debug,10,(&Debug,
! 				 "reading_updater: prompt_factor=%d => %d\n",
! 				 counter->prompt_factor,A));
! 		
! 		counter->prompt_factor = A;
! 		recalculate++;
! 		
! 	    } else
! 		recalculate = 0;
! 	    
! 	} else
! 	    recalculate = 0;
! 		    
!     } while (recalculate && recalculate < 5);
! 	    
!     if (num_messages > 0 &&
!        	COLUMNS >
! 	counter->count_y +
! 	d5 + d3 + d4 + 22 + (have_skipped ? d3 : 0 )
! 	&&
! 	count     <= total &&
! 	skipcount <= num_messages) {
! 
! 	if (counter->previous_messages > 0) {
! 	    menu_PutLineX(page,
! 			  counter->count_x, counter->count_y, 
! 			  FRM("%*d/%d+%d (%02d%%)%s "),
! 			  d5,count,
! 			  num_messages,counter->previous_messages,
! 			  percent,
! 			  have_skipped ? "," : ""
! 			  );
! 	} else {	
! 	    menu_PutLineX(page,
! 			  counter->count_x, counter->count_y, 
! 			  FRM("%*d/%d (%02d%%)%s "),
! 			  d3,count,num_messages,percent,
! 			  have_skipped ? "," : ""
! 			  );
! 	}
  
!     } else {
  	menu_PutLineX(page,
! 		      counter->count_x, counter->count_y, 
! 		      FRM("%d (%02d%%)%s "), count,percent,
! 		      have_skipped ? "," : ""
! 		      );
  	
      }
  
!     menu_GetXYLocation(page,
! 		       &text_x,&text_y); 
  
+     if (counter->count_x == text_x &&
+ 	num_messages > 0 &&
+ 	(count     > total ||
+ 	 skipcount > num_messages)) {
+ 	menu_CleartoEOLN(page);
+     }
+     
+     if (have_skipped && counter->count_x == text_x) {
+ 	int test_x,test_y;
+ 	
  	menu_PutLineX(page,
! 		      text_x, text_y -1,
  		      CATGETS(elm_msg_cat, ElmSet,
  			      ElmSkippingInMessage,
  			      " %d (%02d%%) skipped "),
  		      skipcount,percent2);
  
! 	menu_GetXYLocation(page,
! 			   &test_x,&test_y); 
! 
! 	if (text_x == test_x && test_y >  text_y) {
! 	    
! 	    int A =  test_y - text_y - d2;
! 
! 	    if (A > counter->skipped_factor) {
! 		DPRINT(Debug,10,(&Debug,
! 				 "reading_updater: skipped_factor=%d => %d\n",
! 				 counter->skipped_factor,A));
! 		
! 		counter->skipped_factor = A;
! 	    }
! 	}
      }
  
      if (initialize) {
***************
*** 1264,1270 ****
      enum copy_env_end_status endstat = copy_env_end_failure;
      long newbytes = 0;
      int newmails  = 0;
!     
      if (content_length_found)
  	content_remaining = current_header->content_length;
      else
--- 1445,1452 ----
      enum copy_env_end_status endstat = copy_env_end_failure;
      long newbytes = 0;
      int newmails  = 0;
!     int num_messages = -1;   /* -1 if not available (local mail) */
! 
      if (content_length_found)
  	content_remaining = current_header->content_length;
      else
***************
*** 1272,1277 ****
--- 1454,1462 ----
      content_start     = copy_fbytes_folder(current_folder,
  					   read_state_ptr);
  
+     /* If IMAP/POP mailbox */   
+     num_messages = copy_num_messages_folder(current_folder);
+     
      DPRINT(Debug,10,(&Debug,
  		     "parse_body_routine: reading body"));
      if (content_remaining >= 0L) {
***************
*** 1322,1334 ****
  		reading_updater(COUNT_update,
  				current_folder->cur_folder_disp,counter,
  				current_header->index_number_X,
! 				percent,skipcount,percent2,NULL);
  		
  	    } else
  		reading_updater(COUNT_update,
  				current_folder->cur_folder_disp,counter,
  				current_header->index_number_X,
! 				percent,-1,-1,NULL);
  	    
  	    counter->lastpercent = percent;
  	    
--- 1507,1521 ----
  		reading_updater(COUNT_update,
  				current_folder->cur_folder_disp,counter,
  				current_header->index_number_X,
! 				percent,skipcount,percent2,NULL,
! 				num_messages);
  		
  	    } else
  		reading_updater(COUNT_update,
  				current_folder->cur_folder_disp,counter,
  				current_header->index_number_X,
! 				percent,-1,-1,NULL,
! 				num_messages);
  	    
  	    counter->lastpercent = percent;
  	    
***************
*** 1632,1637 ****
--- 1819,1827 ----
  	current_folder->mailfile_size +
  	counter->previous_bytes;
  
+     /* -1 if not available (local mail) */
+     int num_messages =  copy_num_messages_folder(current_folder);
+        
      copy_skipcount_folder(current_folder,read_state_ptr,&skipcount,&skipbytes);
  		    
      f += skipbytes;
***************
*** 1652,1664 ****
  	reading_updater(refresh ? COUNT_refresh : COUNT_update,
  			current_folder->cur_folder_disp,
  			counter,
! 			count,percent,skipcount,percent2,NULL);
  			
      } else
  	reading_updater(refresh ? COUNT_refresh : COUNT_update,
  			current_folder->cur_folder_disp,
  			counter,
! 			count,percent,-1,-1,NULL);
  		    
      counter->lastpercent = percent;
  }
--- 1842,1856 ----
  	reading_updater(refresh ? COUNT_refresh : COUNT_update,
  			current_folder->cur_folder_disp,
  			counter,
! 			count,percent,skipcount,percent2,NULL,
! 			num_messages);
  			
      } else
  	reading_updater(refresh ? COUNT_refresh : COUNT_update,
  			current_folder->cur_folder_disp,
  			counter,
! 			count,percent,-1,-1,NULL,
! 			num_messages);
  		    
      counter->lastpercent = percent;
  }
***************
*** 1695,1700 ****
--- 1887,1896 ----
      size_t                 previous_count = 0;
      long                   previous_bytes = 0;
  
+     int                    previous_messages = 0;
+     
+     int num_messages = -1;
+     
      menu_get_sizes(page,&LINES, &COLUMNS);
  
      DPRINT(Debug,10,(&Debug,
***************
*** 1749,1755 ****
  
  		if (storage->headers[i]) {
  
! 		    if (0 != (storage->headers[i]->status1 & S1_NODATA)) {
  
  			header_free(& (storage->headers[i]));
  		    } else {		   		    
--- 1945,1951 ----
  
  		if (storage->headers[i]) {
  
! 		    if (ison(storage->headers[i]->status1,S1_NODATA)) {
  
  			header_free(& (storage->headers[i]));
  		    } else {		   		    
***************
*** 1766,1778 ****
  			previous_headers[previous_count].rec = storage->headers[i];
  			storage->headers[i] = NULL;
  			previous_count++;
  		    }
  		}
  	    }
  
  	    DPRINT(Debug,10,(&Debug,
! 			     "read_headers: previous_count=%lu previous_bytes=%ld\n",
! 			     (unsigned long)previous_count,previous_bytes));
  	    
  	}
  	
--- 1962,1984 ----
  			previous_headers[previous_count].rec = storage->headers[i];
  			storage->headers[i] = NULL;
  			previous_count++;
+ 
+ 			
  		    }
  		}
  	    }
  
  	    DPRINT(Debug,10,(&Debug,
! 			     "read_headers: previous_count=%zu previous_bytes=%ld\n",
! 			     previous_count,previous_bytes));	    
! 
! 	    if (previous_count < (size_t)INT_MAX)
! 		previous_messages = previous_count;
! 	    else {
! 		DPRINT(Debug,10,(&Debug,
! 				 "read_headers: Message count overflow\n"));
! 		previous_messages = INT_MAX;
! 	    }
  	    
  	}
  	
***************
*** 1799,1808 ****
      ClearLine(LINES-2);
      ClearLine(LINES-1);
  
      /* Initialize */
      reading_updater(COUNT_initialize,
  		    storage->current_folder->cur_folder_disp,&COUNTER,
! 		    count,0,-1,-1,page);
  
      
      
--- 2005,2017 ----
      ClearLine(LINES-2);
      ClearLine(LINES-1);
  
+     /* If IMAP/POP mailbox */   
+     num_messages = copy_num_messages_folder(storage->current_folder);
+     
      /* Initialize */
      reading_updater(COUNT_initialize,
  		    storage->current_folder->cur_folder_disp,&COUNTER,
! 		    count,0,-1,-1,page,num_messages);
  
      
      
***************
*** 1889,1895 ****
  				    
  				    if (previous_header->rec->content_length > 0) 
  					previous_bytes -= previous_header->rec->content_length;
! 				    
  				    if (COUNTER.previous_bytes != previous_bytes) {
  					DPRINT(Debug,10,(&Debug,"read_headers:  previous_bytes=%ld",
  							 previous_bytes));
--- 2098,2106 ----
  				    
  				    if (previous_header->rec->content_length > 0) 
  					previous_bytes -= previous_header->rec->content_length;
! 
! 				    previous_messages--;
! 				    				    
  				    if (COUNTER.previous_bytes != previous_bytes) {
  					DPRINT(Debug,10,(&Debug,"read_headers:  previous_bytes=%ld",
  							 previous_bytes));
***************
*** 1900,1905 ****
--- 2111,2125 ----
  					}
  					DPRINT(Debug,10,(&Debug,"\n"));
  				    }
+ 
+ 				    DPRINT(Debug,10,(&Debug,"read_headers: previous_messages=%d",
+ 						     previous_messages));
+ 
+ 				    if (previous_messages < 0) {
+ 					DPRINT(Debug,10,(&Debug," UNDERFLOW"));
+ 					previous_messages = 0;
+ 				    }
+ 				    DPRINT(Debug,10,(&Debug,"\n"));
  				}
  
  				if (previous_header->rec->status_chgd) {
***************
*** 1937,1943 ****
  			}
  		    }
  		    
! 		    COUNTER.previous_bytes = previous_bytes;
  		}
  		
  		if (count % readmsginc == 0 || refresh) {
--- 2157,2164 ----
  			}
  		    }
  		    
! 		    COUNTER.previous_bytes     = previous_bytes;
! 		    COUNTER.previous_messages  = previous_messages;
  		}
  		
  		if (count % readmsginc == 0 || refresh) {
***************
*** 2012,2018 ****
  	int read_folder = 1;
  	int y = 0;  /* for counter refresh */
  	struct header_rec * work = NULL;
! 	
  	DPRINT(Debug,10,(&Debug,
  			 "read_headers: Have %d previous headers, starting count %d\n",
  			 previous_count,count));
--- 2233,2241 ----
  	int read_folder = 1;
  	int y = 0;  /* for counter refresh */
  	struct header_rec * work = NULL;
! 
! 	num_messages =  copy_num_messages_folder(storage->current_folder);	
! 		
  	DPRINT(Debug,10,(&Debug,
  			 "read_headers: Have %d previous headers, starting count %d\n",
  			 previous_count,count));
***************
*** 2202,2207 ****
--- 2425,2431 ----
  	}       
      }	
  
+     
      {
  	/* Final counter */
  	int skipcount;
***************
*** 2210,2216 ****
  	
  	long f = copy_fbytes_folder(storage->current_folder,
  				    read_state_ptr);
! 
  	long total_size =
  	    storage->current_folder->mailfile_size +
  	    COUNTER.previous_bytes;
--- 2434,2440 ----
  	
  	long f = copy_fbytes_folder(storage->current_folder,
  				    read_state_ptr);
! 	
  	long total_size =
  	    storage->current_folder->mailfile_size +
  	    COUNTER.previous_bytes;
***************
*** 2237,2248 ****
  	    
  	    reading_updater(COUNT_finalize,
  			    storage->current_folder->cur_folder_disp,&COUNTER,
! 			    count,percent,skipcount,percent2,page);
  
  	} else
  	    reading_updater(COUNT_finalize,
  			    storage->current_folder->cur_folder_disp,&COUNTER,
! 			    count,percent,-1,-1,page);
  	
  	COUNTER.lastpercent = percent;
      }
--- 2461,2476 ----
  	    
  	    reading_updater(COUNT_finalize,
  			    storage->current_folder->cur_folder_disp,&COUNTER,
! 			    count,percent,skipcount,percent2,page,
! 			    num_messages
! 			    );
  
  	} else
  	    reading_updater(COUNT_finalize,
  			    storage->current_folder->cur_folder_disp,&COUNTER,
! 			    count,percent,-1,-1,page,
! 			    num_messages
! 			    );
  	
  	COUNTER.lastpercent = percent;
      }
***************
*** 2272,2278 ****
  
      reading_updater(COUNT_fail_cleanup,
  		    storage->current_folder->cur_folder_disp,&COUNTER,
! 		    count,COUNTER.lastpercent,-1,-1,page);
      show_last_error();
             
      DPRINT(Debug,7,(&Debug, 
--- 2500,2506 ----
  
      reading_updater(COUNT_fail_cleanup,
  		    storage->current_folder->cur_folder_disp,&COUNTER,
! 		    count,COUNTER.lastpercent,-1,-1,page,num_messages);
      show_last_error();
             
      DPRINT(Debug,7,(&Debug, 
Index: elmME+.2.5.alpha64-cvs/src/quotadisp.c
*** elmME+.2.5.alpha63/src/quotadisp.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/src/quotadisp.c	Wed Jun 26 19:54:27 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: quotadisp.c,v 2.4 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.4 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: quotadisp.c,v 2.6 2024/06/26 16:54:27 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.6 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *      or  Kari Hurtta <elm@elmme-mailer.org
***************
*** 1521,1527 ****
      { "k",     1000,    10000 },
      { "M",  1000000, 10000000 }
  };
!       
  static void qd_draw_resource_values(print_area,qr_item,current_line_p,current_col_p,
  				  redrawing_p,resize,list,mayclear_p,start_of_line_p)
       struct menu_context    * print_area;
--- 1521,1537 ----
      { "k",     1000,    10000 },
      { "M",  1000000, 10000000 }
  };
! 
! static void qd_draw_resource_values P_((struct menu_context    * print_area,
! 					struct mail_quota_item * qr_item,
! 					int                    * current_line_p,
! 					int                    * current_col_p,
! 					int                    * redrawing_p,
! 					struct resize_columns  * resize,
! 					struct menu_param      * list,
! 					int                   * mayclear_p,
! 					int                   * start_of_line_p));
! 					       
  static void qd_draw_resource_values(print_area,qr_item,current_line_p,current_col_p,
  				  redrawing_p,resize,list,mayclear_p,start_of_line_p)
       struct menu_context    * print_area;
***************
*** 1768,1775 ****
  			   & (qd-> mail_quota_list[mq_ptr].virtual_mq_start_line),
  			   &exceed)) {
       
- 
- 
  	 DPRINT(Debug,12,(&Debug,
  			  "qd_draw_mail_quota: L_current_line = %d top_line=%d mail_quota_list[%zu].virtual_mq_start_line=%d top_offset=%d L_add=%d\n",
  			  L_current_line,qd->top_line,
--- 1778,1783 ----
***************
*** 2151,2157 ****
  			 struct mail_quotaroot * qr =
  			     quotaroot_list_item(ql,k,cd);
  			 
- 
  			 if (qr) {
  			     enum quota_reserved_quotaroot qr_name_token = qr_root_none;
  			     struct string * qr_name /* May be NULL */ =
--- 2159,2164 ----
***************
*** 2606,2612 ****
  		    
  		    if (new_top_qrl > qd->top_quotarootl) {
  			DPRINT(Debug,10,(&Debug,
! 					 "qd_chnage_page: top_mail_quota=%zu,  top_quotarootl=%zu",
  					 qd->top_mail_quota,qd->top_quotarootl));
  			qd->top_quotarootl = new_top_qrl;
  			DPRINT(Debug,10,(&Debug," => %zu\n",qd->top_quotarootl));			
--- 2613,2619 ----
  		    
  		    if (new_top_qrl > qd->top_quotarootl) {
  			DPRINT(Debug,10,(&Debug,
! 					 "qd_chnage_page: top_mail_quota=%zu, top_quotarootl=%zu",
  					 qd->top_mail_quota,qd->top_quotarootl));
  			qd->top_quotarootl = new_top_qrl;
  			DPRINT(Debug,10,(&Debug," => %zu\n",qd->top_quotarootl));			
***************
*** 2614,2620 ****
  		}
  	    } else if (qd->top_quotarootl > 0) {
  		DPRINT(Debug,10,(&Debug,
! 				 "qd_change_page: top_mail_quota=%zu,  top_quotarootl=%zu",
  				 qd->top_mail_quota,qd->top_quotarootl));
  		qd->top_quotarootl = 0;
  		DPRINT(Debug,10,(&Debug," => %zu\n",qd->top_quotarootl));
--- 2621,2627 ----
  		}
  	    } else if (qd->top_quotarootl > 0) {
  		DPRINT(Debug,10,(&Debug,
! 				 "qd_change_page: top_mail_quota=%zu, top_quotarootl=%zu",
  				 qd->top_mail_quota,qd->top_quotarootl));
  		qd->top_quotarootl = 0;
  		DPRINT(Debug,10,(&Debug," => %zu\n",qd->top_quotarootl));
***************
*** 3735,3743 ****
  		break;
  		
  	    }
- 	    
- 
- 
  	}
      }
  }
--- 3742,3747 ----
***************
*** 3985,3990 ****
--- 3989,4001 ----
  
      /* Increments refcount! */
      mquota = quotaroot_list_mquota(qlist);
+ 
+     if (!mquota) {
+ 	DPRINT(Debug,12,(&Debug,
+ 			 "quota_display_add_qlist: No mail quota on quota_list\n"));
+ 
+ 	return;
+     }
      
      /* Should always succeed */
      if (quota_display_quota_index(quotad,mquota,&mquota_idx,qd_create)) {
***************
*** 4083,4089 ****
  		do_redraw = 1;
  	    }
  	    
- 
  	resize_mark:
  	    if (menu_resized(quotad->current_page)) {
  		DPRINT(Debug,12,(&Debug,"quota_display_show: resized\n"));
--- 4094,4099 ----
***************
*** 4244,4250 ****
  		case '\n':
  		case '\r':
  		    if (quotad->is_end) {
! 			DPRINT(Debug,12,(&Debug,"quota_display_show: End of quota listing reached.\n"));
  			goto out;
  		    }
  		    /* FALLTHRU */
--- 4254,4260 ----
  		case '\n':
  		case '\r':
  		    if (quotad->is_end) {
! 			DPRINT(Debug,10,(&Debug,"quota_display_show: End of quota listing reached.\n"));
  			goto out;
  		    }
  		    /* FALLTHRU */
Index: elmME+.2.5.alpha64-cvs/src/screen/curses.c
*** elmME+.2.5.alpha63/src/screen/curses.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/src/screen/curses.c	Sun Jun 16 13:40:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: curses.c,v 2.23 2023/12/13 16:55:32 hurtta Exp $";
  
  /************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.23 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: curses.c,v 2.24 2024/06/16 10:40:36 hurtta Exp $";
  
  /************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.24 $   $State: Exp $
   *
   *  Modified by: Kari Hurtta <hurtta+elm@siilo.FMI.FI>
   *                       (was hurtta+elm@posti.FMI.FI, 
***************
*** 770,777 ****
  	) {
  
  	DPRINT(Debug,9, (&Debug, 
! 			 "cur_changemode: nothing to do: for %x set and %x reset: mode = %x\n",
! 			 set,reset,*mode));
  
  	return;
      }
--- 770,778 ----
  	) {
  
  	DPRINT(Debug,9, (&Debug, 
! 			 "cur_changemode: nothing to do: for %x set and %x reset: mode = %x %s\n",
! 			 set,reset,*mode,
! 			 give_pg_flags(*mode)));
  
  	return;
      }
***************
*** 796,802 ****
  			     f,d, give_pg_flags(d)));
  
  	    setit(reset,d);
- 
  	}
      }
  
--- 797,802 ----
***************
*** 808,813 ****
--- 808,819 ----
      */
  
      
+     if (reset) {
+ 	DPRINT(Debug,7, (&Debug, 
+ 			 "cur_changemode: need reset %x %s\n",
+ 			 reset, give_pg_flags(reset)));	       
+     }
+ 	    
      if (ison(reset,ansi_attr_pg_flags)) {
  
  	short ANSI_sgr_settings [ NUM_pg_attr_bits ];
***************
*** 837,848 ****
  		    clearit(*mode,ansi_attr[j]->pg_flag);
  		    setit(found,ansi_attr[j]->pg_flag);
  
! 		     DPRINT(Debug,7, (&Debug, 
! 				      "cur_changemode: %s %x reset %x => mode = %x (%s)\n",
! 				      ansi_attr[j]->name ?
! 				      ansi_attr[j]->name : "",
! 				      ansi_attr[j]->pg_flag,
! 				      reset, *mode,
  				      give_pg_flags(*mode)));
  		}		
  	    }
--- 843,859 ----
  		    clearit(*mode,ansi_attr[j]->pg_flag);
  		    setit(found,ansi_attr[j]->pg_flag);
  
! 		    DPRINT(Debug,7, (&Debug, 
! 				     "cur_changemode: %s %x %s reset %x ",
! 				     ansi_attr[j]->name ?
! 				     ansi_attr[j]->name : "",
! 				     ansi_attr[j]->pg_flag,
! 				     give_pg_flags(ansi_attr[j]->pg_flag),
! 				     reset));
! 
! 		    DPRINT(Debug,7, (&Debug, 
! 				      "=> mode = %x (%s)\n",
! 				      *mode,
  				      give_pg_flags(*mode)));
  		}		
  	    }
***************
*** 860,870 ****
  	    setit(found,set_modes[i].mode);
  
  	    DPRINT(Debug,7, (&Debug, 
! 			     "cur_changemode: %s %x reset %x => mode = %x (%s)\n",
  			     set_modes[i].set_off ?
  			     set_modes[i].set_off : "",
  			     set_modes[i].mode,
! 			     reset, *mode,
  			     give_pg_flags(*mode)));
  	   
  	}
--- 871,885 ----
  	    setit(found,set_modes[i].mode);
  
  	    DPRINT(Debug,7, (&Debug, 
! 			     "cur_changemode: %s %x %s reset %x ",
  			     set_modes[i].set_off ?
  			     set_modes[i].set_off : "",
  			     set_modes[i].mode,
! 			     give_pg_flags(set_modes[i].mode),
! 			     reset));
! 
! 	    DPRINT(Debug,7, (&Debug, "=> mode = %x (%s)\n",
! 			     *mode,
  			     give_pg_flags(*mode)));
  	   
  	}
***************
*** 885,890 ****
--- 900,910 ----
  	setit(set,needmode);
      }
  
+     if (set) {
+ 	DPRINT(Debug,7, (&Debug, 
+ 			 "cur_changemode: need set %x %s\n",
+ 			 set, give_pg_flags(set)));	       
+     }
  
      for (i =0 ; i < (sizeof set_modes) / sizeof (set_modes[0]); i++) {
  
***************
*** 894,904 ****
  	    setit(*mode,set_modes[i].mode);
  
  	    DPRINT(Debug,7, (&Debug, 
! 			     "cur_changemode: %s %x set %x => mode = %x (%s)\n",
  			     set_modes[i].set_on ?
  			     set_modes[i].set_on : "",
  			     set_modes[i].mode,
! 			     set, *mode,
  			     give_pg_flags(*mode)));
  
  	}
--- 914,929 ----
  	    setit(*mode,set_modes[i].mode);
  
  	    DPRINT(Debug,7, (&Debug, 
! 			     "cur_changemode: %s %x %s set %x ",
  			     set_modes[i].set_on ?
  			     set_modes[i].set_on : "",
  			     set_modes[i].mode,
! 			     give_pg_flags(set_modes[i].mode),
! 			     set));
! 
! 	    DPRINT(Debug,7, (&Debug, 
! 			     "=> mode = %x (%s)\n",
! 			     *mode,
  			     give_pg_flags(*mode)));
  
  	}
***************
*** 933,943 ****
  		    setit(*mode,ansi_attr[j]->pg_flag);
  
  		    DPRINT(Debug,7, (&Debug, 
! 				     "cur_changemode: %s %x set %x => mode = %x (%s)\n",
  				     ansi_attr[j]->name ?
  				     ansi_attr[j]->name : "",
  				     ansi_attr[j]->pg_flag,
! 				     set, *mode,
  				     give_pg_flags(*mode)));
  
  		}
--- 958,973 ----
  		    setit(*mode,ansi_attr[j]->pg_flag);
  
  		    DPRINT(Debug,7, (&Debug, 
! 				     "cur_changemode: %s %x %s set %x ",
  				     ansi_attr[j]->name ?
  				     ansi_attr[j]->name : "",
  				     ansi_attr[j]->pg_flag,
! 				     give_pg_flags(ansi_attr[j]->pg_flag),
! 				     set));
! 
! 		    DPRINT(Debug,7, (&Debug, 
! 				     "=> mode = %x (%s)\n",
! 				     *mode,
  				     give_pg_flags(*mode)));
  
  		}
Index: elmME+.2.5.alpha64-cvs/src/screen/screen.c
*** elmME+.2.5.alpha63/src/screen/screen.c	Mon Jan  1 21:18:53 2024
--- elmME+.2.5.alpha64-cvs/src/screen/screen.c	Sun Jun 16 13:40:36 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: screen.c,v 2.12 2023/12/13 16:55:32 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.12 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: screen.c,v 2.13 2024/06/16 10:40:36 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.13 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> 
   *                  (was hurtta+elm@posti.FMI.FI, hurtta+elm@ozone.FMI.FI)
***************
*** 1011,1016 ****
--- 1011,1027 ----
  
      enter_terminal_hook();
  
+     DPRINT(Debug,7, (&Debug,"menu_StartXX(ctx=%p,f=%x %s)",
+ 		     ctx,f,give_pg_flags(f)));
+ 
+     if (disable) {
+ 	DPRINT(Debug,7, (&Debug," - disable=%x %s",
+ 			 disable,give_pg_flags(disable)));
+     }
+     DPRINT(Debug,7, (&Debug,"\n"));
+ 
+ 	   
+ 		     
      SYNC(ctx);
      ctx->routine->wra_changemode(ctx, f, disable);
  }
***************
*** 1029,1034 ****
--- 1040,1048 ----
  
      enter_terminal_hook();
  
+     DPRINT(Debug,7, (&Debug,"menu_EndXX(ctx=%p,f=%x %s)\n",
+ 		     ctx,f,give_pg_flags(f)));
+     
      SYNC(ctx);
      ctx->routine->wra_changemode(ctx, 0, f);
  }
Index: elmME+.2.5.alpha64-cvs/src/thread.c
*** elmME+.2.5.alpha63/src/thread.c	Sat Aug 28 14:11:45 2021
--- elmME+.2.5.alpha64-cvs/src/thread.c	Wed Jun 26 19:54:27 2024
***************
*** 1,7 ****
! static char rcsid[] = "@(#)$Id: thread.c,v 2.18 2021/07/15 17:30:00 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.18 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
--- 1,7 ----
! static char rcsid[] = "@(#)$Id: thread.c,v 2.19 2024/06/26 16:54:27 hurtta Exp $";
  
  /******************************************************************************
!  *  The Elm (ME+) Mail System  -  $Revision: 2.19 $   $State: Exp $
   *
   *  Author: Kari Hurtta <hurtta+elm@siilo.FMI.FI> (was hurtta+elm@posti.FMI.FI)
   *      or  Kari Hurtta <elm@elmme-mailer.org>
***************
*** 116,122 ****
       const struct thread_info *X1;
       const struct thread_info *X2;
  {
!     long diff;
      
      if (unstable_reverse_thread) {
  	/* Move thread new location when new mail arrives,
--- 116,122 ----
       const struct thread_info *X1;
       const struct thread_info *X2;
  {
!     long diff = 0;
      
      if (unstable_reverse_thread) {
  	/* Move thread new location when new mail arrives,
