• 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)