Patch: Elm ME+ 2.5 PLalpha63 -> Elm ME+ 2.5 PLalpha64 [2/4] (3/5)
From
Kari Hurtta@21:1/5 to
All on Tue Jul 2 20:52:17 2024
[continued from previous message]
+ "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) {
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)