static char rcsid[] = "@(#)$Id: leavembox.c,v 1.61.2.3 2007/08/25 06:13:03 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.61.2.3 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
******************************************************************************
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*****************************************************************************/
/** leave current folder, updating etc. as needed...
**/
#include "def_elm.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"mbox");
#ifdef USE_FLOCK_LOCKING
#define SYSCALL_LOCKING
#endif
#ifdef USE_FCNTL_LOCKING
#define SYSCALL_LOCKING
#endif
#ifdef SYSCALL_LOCKING
# if (defined(BSD_TYPE) || !defined(apollo))
# include <sys/file.h>
# endif
#endif
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static void block_signals P_((void));
static void unblock_signals P_((void));
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
static void action_message P_((int to_keep,int to_store, int to_delete));
static void action_message(to_keep,to_store,to_delete)
int to_keep;
int to_store;
int to_delete;
{
/* Formulate message as to number of keeps, stores, and deletes.
* This is only complex so that the message is good English.
*/
if (to_keep > 0) {
if (to_store > 0) {
if (to_delete > 0) {
if (to_keep == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepStoreDelete,
"[Keeping 1 message, storing %d, and deleting %d.]"),
to_store, to_delete);
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepStoreDeletePlural,
"[Keeping %d messages, storing %d, and deleting %d.]"),
to_keep, to_store, to_delete);
} else {
if (to_keep == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveKeepStore,
"[Keeping 1 message and storing %d.]"),
to_store);
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepStorePlural,
"[Keeping %d messages and storing %d.]"),
to_keep, to_store);
}
} else {
if (to_delete > 0) {
if (to_keep == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveKeepDelete,
"[Keeping 1 message and deleting %d.]"),
to_delete);
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepDeletePlural,
"[Keeping %d messages and deleting %d.]"),
to_keep, to_delete);
} else {
if (to_keep == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveKeep,
"[Keeping message.]"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepPlural,
"[Keeping all messages.]"));
}
}
} else if (to_store > 0) {
if (to_delete > 0) {
if (to_store == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveStoreDelete,
"[Storing 1 message and deleting %d.]"),
to_delete);
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLeaveStoreDeletePlural,
"[Storing %d messages and deleting %d.]"),
to_store, to_delete);
} else {
if (to_store == 1)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveStore,
"[Storing message.]"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveStorePlural,
"[Storing all messages.]"));
}
} else {
if (to_delete > 0)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveDelete,
"[Deleting all messages.]"));
}
}
static int real_save P_((struct current_storage *storage,
struct folder_browser * recv_browser,
WRITE_STATE recv_writeptr,
int to_store,
int to_keep,
int resyncing,
int to_delete,
int to_hide));
static int real_save(storage, recv_browser, recv_writeptr,
to_store, to_keep, resyncing, to_delete,
to_hide)
struct current_storage *storage;
struct folder_browser * recv_browser;
WRITE_STATE recv_writeptr;
int to_store;
int to_keep;
int resyncing;
int to_delete;
int to_hide;
{
int new_bytes;
int i;
struct keep_folder_state * keep_state_ptr = NULL;
/** next, let's lock the file up and make one last size check **/
DPRINT(Debug,2,(&Debug,
"-- Handling folder %S (%s)\n",
storage->current_folder->cur_folder_disp,
storage->current_folder->cur_folder_sys));
if(!open_folder_lock(OUTGOING,storage->current_folder)) {
DPRINT(Debug,2,(&Debug,
" Failed to lock %S (%s)\n",
storage->current_folder->cur_folder_disp,
storage->current_folder->cur_folder_sys));
return -2; /* failure */
}
/*
* lock routine will call clear_error so we print our action
* message after it.
*/
action_message(to_keep,to_store, to_delete);
flush_folder(storage->current_folder);
if (new_mail_on_folder(storage->current_folder,&new_bytes)) {
unlock(0,storage->current_folder);
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveNewMailArrived,
"New mail has just arrived. Resynchronizing..."));
return -1;
}
block_signals();
DPRINT(Debug,2,(&Debug, "Action...\n"));
/* Store messages slated for storage in received mail folder */
if (to_store > 0) {
/* Permissons check for and opening of =received done earlier */
DPRINT(Debug,10,(&Debug,
"!! Copying from %s to received folder\n",
storage->current_folder->cur_folder_sys));
DPRINT(Debug,2,(&Debug, "Storing message%s ", plural(to_store)));
for (i = 0; i < storage->message_count; i++) {
if(storage->headers[i] &&
storage->headers[i]->exit_disposition == STORE) {
DPRINT(Debug,2,(&Debug, "#%d, ", i+1));
if (!copy_message_d(storage->current_folder,
storage->headers[i],
"",recv_browser,recv_writeptr
, CM_UPDATE_STATUS,NULL)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCopyMessageFailed,
"OOPS! Storing of mail failed!"));
unlock(0,storage->current_folder);
unblock_signals();
return -2;
}
}
}
/* Be sure that writing to =received succeed before we
rewrite folder
*/
if (!sync_write_folder(recv_browser,recv_writeptr)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCopyMessageFailed,
"OOPS! Storing of mail failed!"));
unlock(0,storage->current_folder);
unblock_signals();
return -2;
}
DPRINT(Debug,2,(&Debug, "\n\n"));
if (ferror_folder(storage->current_folder,TRUE)) {
unlock(0,storage->current_folder);
DPRINT(Debug,1,(&Debug, "error when reading mailfile\n"));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadMailfile,
"Error when reading mailfile %S"),
storage->current_folder->cur_folder_disp);
sleep_message();
unblock_signals();
return -2;
}
}
if (!prepare_keep_folder(storage->current_folder,
&keep_state_ptr)) {
unlock(0,storage->current_folder);
unblock_signals();
return -2;
}
for (i = 0; i < storage->message_count; i++) {
if (storage->headers[i])
mark_keep_folder(storage->current_folder,keep_state_ptr,
storage->headers[i],
storage->headers[i]->exit_disposition
== KEEP ||
storage->headers[i]->exit_disposition
== HIDE);
}
if (!end_keep_folder(storage->current_folder,&keep_state_ptr)) {
#if POLL_METHOD
wait_for_timeout(5);
#else
sleep(5);
#endif
close_folder(storage->current_folder,CLOSE_NORMAL);
emergency_exit(0);
}
/* Just unlock ... folder closing is not needed on here ... */
unlock(0,storage->current_folder);
unblock_signals();
return 1;
}
void close_cleanup_mbox(mailbox)
struct MailboxView *mailbox;
{
int i, sc;
int to_delete = 0, to_store = 0, to_keep = 0, to_unset = 0,
to_hide = 0, to_bad = 0;;
DPRINT(Debug,1,
(&Debug, "\n\n-- closing folder --\n\n"));
/* Examine dispositions done by sync_mailbox() */
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for(j = 0; j < storage->message_count; j++)
if (storage->headers[j]) {
if (HIDE == storage->headers[j]->exit_disposition)
to_hide++;
else if (KEEP == storage->headers[j]->exit_disposition)
to_keep++;
else if (DELETE == storage->headers[j]->exit_disposition)
to_delete++;
else if (STORE == storage->headers[j]->exit_disposition)
to_store++;
else if (UNSET == storage->headers[j]->exit_disposition)
to_unset++;
else {
DPRINT(Debug,1,(&Debug,
"--- Bad message disposition %d, storage=%d, index=%d\n",
storage->headers[j]->exit_disposition,i,j));
to_bad++;
}
}
}
DPRINT(Debug,3,(&Debug, "On close_cleanup_mbox: \n"));
DPRINT(Debug,3,(&Debug, "Messages to keep: %d\n",to_keep));
DPRINT(Debug,3,(&Debug, "Messages to hide: %d (keep)\n", to_hide));
DPRINT(Debug,3,(&Debug, "Messages to delete: %d\n", to_delete));
DPRINT(Debug,3,(&Debug, "Messages to store: %d\n", to_store));
DPRINT(Debug,1,(&Debug, "Messages unset: %d\n",to_unset));
DPRINT(Debug,1,(&Debug, "Messages bad: %d\n",to_bad));
if (to_unset > 0 || to_bad > 0)
panic("MBOX PANIC",__FILE__,__LINE__,"close_cleanup_mbox",
"Something wrong in message dispositions!",0);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (!storage->current_folder)
continue;
if (to_keep == 0 &&
to_hide == 0) {
/* consider_remove_folder closes folder if removed */
if (consider_remove_folder(storage->current_folder)) {
/* i.e. if no messages were to be kept and this is not a spool
* folder and we aren't keeping empty non-spool folders,
* simply remove the old original folder and that's it!
*/
DPRINT(Debug,3,(&Debug, "Removing folder!\n"));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderSRemoved,
"Folder %S removed."),
storage->current_folder->cur_folder_disp
);
#if POLL_METHOD
wait_for_timeout(5);
#else
sleep(5);
#endif
continue;
}
}
close_folder(storage->current_folder,CLOSE_NORMAL);
}
}
/* Both resyncing, quitting are set if leaving visited mailbox */
int sync_mbox(resyncing, quitting, prompt, new_folder, mailbox,
page)
int resyncing, quitting, prompt;
struct folder_info **new_folder;
struct MailboxView *mailbox;
struct menu_context *page;
{
/** Close folder, deleting some messages, storing others in mbox,
and keeping others, as directed by user input and elmrc options.
Return 1 Folder altered
0 Folder not altered
-1 New mail arrived during the process and
syncing was aborted.
-2 Leaving of folder failed
If "resyncing" we are just writing out folder to reopen it. We
therefore only consider deletes and keeps, not stores to mbox.
Also we don't remove NEW status so that it can be preserved
across the resync.
If "quitting" and "prompt" is false, then no prompting is done.
Otherwise prompting is dependent upon the variable
question_me, as set by an elmrc option. This behavior makes
the 'q' command prompt just like 'c' and '$', while
retaining the 'Q' command for a quick exit that never
prompts.
**/
int to_delete = 0, to_store = 0, to_keep = 0, to_ignore = 0,
to_hide = 0;
int marked_deleted=0;
int i,
last_sortby, ask_questions, asked_storage_q,
num_chgd_status = 0;
int return_value = -1;
struct folder_browser * recv_browser = new_browser(selection_folder);
struct string * recv_name = new_string(system_charset);
int recv_flags = 0;
WRITE_STATE recv_writeptr = NULL;
int can_store = 0;
int current_is_received = 0;
int new_is_received = 0;
int sc, need_handle;
int LINES, COLUMNS;
int delay_redraw = 0;
int received_is_disabled = dt_estr_is_disabled(&recvd_mail_e);
menu_get_sizes(page,&LINES, &COLUMNS);
if (resyncing) {
DPRINT(Debug,1,
(&Debug, "\n\n-- syncing folder --\n\n"));
} else {
DPRINT(Debug,1,
(&Debug, "\n\n-- leaving folder --\n\n"));
}
add_ascii_to_string(recv_name,s2us(">")); /* Received folder */
can_store = select_dir_item(recv_browser,&recv_name);
if (can_store) {
int sc = get_storage_count(mailbox);
int i;
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
if (storage &&
selection_is_folder(recv_browser,storage->current_folder))
current_is_received++;
}
if (new_folder && *new_folder)
new_is_received = selection_is_folder(recv_browser,*new_folder);
recv_flags = give_dir_flags(recv_browser);
/* Create it if not exists yet ... */
if (0 == (recv_flags & BROWSER_EXIST)) {
if (!create_selection_dir(recv_browser))
can_store = 0;
else {
DPRINT(Debug,1,(&Debug,
"*** Creating received folder!\n"));
}
}
}
if (current_is_received) {
DPRINT(Debug,4,(&Debug, "*** Current folder is received folder!\n"));
}
if (new_is_received) {
DPRINT(Debug,4,(&Debug, "*** New folder is received folder!\n"));
}
if (!can_store) {
DPRINT(Debug,4,(&Debug, "*** Received folder is not available!\n"));
}
if (received_is_disabled) {
DPRINT(Debug,4,(&Debug, "*** Received folder is disabled!\n"));
}
/* Be sure that current number of messages match to that what
is on storages .... */
if (update_view(mailbox)) {
return_value = -2; /* failure */
goto cleanup;
}
/* ================================================================== */
/* Check if ALL folders are read_only */
need_handle = 0;
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
/* Clear the exit dispositions of all messages, just in case
* they were left set by a previous call to this function
* that was interrupted by the receipt of new mail.
*/
if (storage->headers)
for(j = 0; j < storage->message_count; j++)
if (storage->headers[j]) {
if (HIDE == storage->headers[j]->exit_disposition)
to_hide++;
else
storage->headers[j]->exit_disposition = UNSET;
}
if (! storage->current_folder) {
if (storage->headers) {
for (j = 0; j < storage->message_count; j++) {
if (storage->headers[j]) {
storage->headers[j]->exit_disposition = KEEP;
to_ignore ++;
}
}
}
continue;
}
if (0 != (get_folder_mode(storage->current_folder) &
FOLDER_RDONLY)) {
if (storage->headers) {
for (j = 0; j < storage->message_count; j++) {
if (storage->headers[j]) {
storage->headers[j]->exit_disposition = KEEP;
to_keep ++;
}
}
}
continue;
}
need_handle++;
}
DPRINT(Debug,3,(&Debug, "Messages to ignore: %d (no folder)\n",
to_ignore));
DPRINT(Debug,3,(&Debug, "Messages to keep: %d (readonly)\n",
to_keep));
DPRINT(Debug,3,(&Debug, "Messages to hide: %d (keep)\n",
to_hide));
if (0 == need_handle) {
DPRINT(Debug,4,(&Debug, "*** ALL folders are read only!\n"));
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
if (!storage ||
! storage->current_folder)
continue;
if (0 != (get_folder_mode(storage->current_folder) &
FOLDER_RDONLY)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmFolderSReadOnlyUnchanged,
"Folder %S is read-only and unchanged."),
storage->current_folder->cur_folder_disp
);
}
}
return_value = 0; /* nothing changed */
goto cleanup;
}
/* ================================================================== */
/* Check if all folders are empty */
need_handle = 0;
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
if (!storage ||
storage->message_count == 0)
continue;
need_handle++;
}
if (0 == need_handle) {
DPRINT(Debug,4,(&Debug, "*** ALL folders are empty!\n"));
return_value = 0; /* nothing changed */
goto cleanup;
}
/* =================================================================== */
ask_questions = ((quitting && !prompt) ? FALSE : question_me);
/* YES or NO on softkeys */
/*
if (hp_softkeys && ask_questions) {
define_softkeys(YESNO);
softkeys_on();
}
*/
/* Determine if deleted messages are really to be deleted */
/* we need to know if there are none, or one, or more to delete */
need_handle = 0;
marked_deleted = 0;
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (j=0;
j<storage->message_count && marked_deleted<2; j++) {
if (! storage->headers[j])
continue;
/* If message is already marked to keep, we do not
have intrested ....
*/
if (storage->headers[j]->exit_disposition != UNSET)
continue;
if (ison(storage->headers[j]->status, DELETED))
marked_deleted++;
}
}
/* ============================================================== */
if(marked_deleted) {
int answer = (always_del ?
*def_ans_yes : *def_ans_no); /* default answer */
if(ask_questions) {
int def = answer;
againD:
menu_get_sizes(page, &LINES, &COLUMNS);
/* FIXME -- add prompt_area instead of LINES-4 */
/* NOTICE: prompt_letter may return EOF */
if (marked_deleted == 1)
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmLeaveDeleteMessage,
"Delete message? (%c/%c) "),
*def_ans_yes, *def_ans_no);
else
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmLeaveDeleteMessages,
"Delete messages? (%c/%c) "),
*def_ans_yes, *def_ans_no);
if (TERMCH_interrupt_char == answer) {
return_value = -1; /* failure */
goto cleanup;
}
if (answer == ('L'&31) || answer == REDRAW_MARK) {
menu_ClearScreen(page); /* Reset possible redraw flag */
/* Call refresh routines of children */
menu_redraw_children(page);
delay_redraw++; /* Can't trigger redraw yet... */
goto againD;
}
if (answer == EOF)
emergency_exit(0);
}
if (answer == *def_ans_yes) {
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (j = 0; j < storage->message_count; j++) {
if (! storage->headers[j])
continue;
/* If message is already marked to keep, we do not
have intrested ....
*/
if (storage->headers[j]->exit_disposition != UNSET)
continue;
if (ison(storage->headers[j]->status, DELETED)) {
storage->headers[j]->exit_disposition = DELETE;
to_delete++;
}
}
}
}
}
DPRINT(Debug,3,(&Debug, "Messages to delete: %d\n", to_delete));
/* ================================================================== */
/* If this is a non spool file( or if received folder is treated
* as mailbox because of protection mask of folder) , or if we are
* merely resyncing, all messages with an unset disposition (i.e.
* not slated for deletion) are to be kept.
* Otherwise, we need to determine if read and unread messages
* are to be stored or kept.
*/
need_handle = 0;
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
if (!storage ||
! storage->current_folder || !storage->headers)
continue;
if(0 == (get_folder_mode(storage->current_folder) & FOLDER_MBOX) ||
current_is_received || resyncing) {
int j;
for (j = 0; j < storage->message_count; j++) {
if(storage->headers[j] &&
storage->headers[j]->exit_disposition == UNSET) {
storage->headers[j]->exit_disposition = KEEP;
to_keep++;
}
}
continue;
}
need_handle++;
}
DPRINT(Debug,3,(&Debug,
"Messages to keep: %d (not mbox or syncing) -- %d mboxes need handling\n",
to_keep,need_handle));
if (need_handle) {
if (received_is_disabled) {
DPRINT(Debug,3,(&Debug,"Disabling receiving processing...\n"));
goto disabled_1;
}
if (!can_store) {
int answer = '\0';
again1:
menu_get_sizes(page, &LINES, &COLUMNS);
/* FIXME -- add prompt_area instead of LINES-4 */
/* NOTICE: prompt_letter may return EOF */
answer = prompt_letter(LINES-4,"P",*def_ans_yes,
PROMPT_center|PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmNoReceived,
"\"received\" folder not available, continue leaving folder? ([P]anic/%c/%c) "),
*def_ans_yes, *def_ans_no);
if (answer == ('L'&31) || answer == REDRAW_MARK) {
menu_ClearScreen(page); /* Reset possible redraw flag */
/* Call refresh routines of children */
menu_redraw_children(page);
delay_redraw++; /* Can't trigger redraw yet... */
goto again1;
}
if (answer == 'P' || answer == EOF)
emergency_exit(0);
if (TERMCH_interrupt_char == answer) {
return_value = -1; /* failure */
goto cleanup;
}
if (answer != *def_ans_yes) {
return_value = -2; /* failure */
goto cleanup;
}
disabled_1:
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (j = 0; j < storage->message_count; j++) {
if(storage->headers[j] &&
storage->headers[j]->exit_disposition == UNSET) {
storage->headers[j]->exit_disposition = KEEP;
to_keep++;
}
}
}
DPRINT(Debug,3,(&Debug,
"Messages to keep: %d (no received folder)\n",
to_keep));
} else {
int answer = '\0';
int marked_read=0;
/* Let's first see if user wants to store read messages
* that aren't slated for deletion */
asked_storage_q = FALSE;
/* we need to know if there are none, or one, or more marked read
*/
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (j=0;
j < storage->message_count && marked_read < 2; j++) {
if((storage->headers[j] &&
isoff(storage->headers[j]->status, UNREAD))
&& (storage->headers[j]->exit_disposition == UNSET))
marked_read++;
}
}
if (marked_read) {
answer = (always_store ?
*def_ans_yes : *def_ans_no); /* default answer */
if(ask_questions) {
int def = answer;
againR:
menu_get_sizes(page, &LINES, &COLUMNS);
/* NOTICE: prompt_letter may return EOF */
/* FIXME -- add prompt_area instead of LINES-4 */
if (marked_read == 1)
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmLeaveMoveMessage,
"Move read message to \"received\" folder? (%c/%c) "),
*def_ans_yes, *def_ans_no);
else
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmLeaveMoveMessages,
"Move read messages to \"received\" folder? (%c/%c) "),
*def_ans_yes, *def_ans_no);
if (TERMCH_interrupt_char == answer) {
return_value = -1; /* failure */
goto cleanup;
}
if (answer == ('L'&31) || answer == REDRAW_MARK) {
menu_ClearScreen(page); /* Reset possible redraw flag */
/* Call refresh routines of children */
menu_redraw_children(page);
delay_redraw++; /* Can't trigger redraw yet... */
goto againR;
}
if (answer == EOF)
emergency_exit(0);
asked_storage_q = TRUE;
}
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
int c = 0;
if (!storage)
continue;
if (storage->headers)
for (j = 0; j < storage->message_count; j++) {
if((storage->headers[j] &&
isoff(storage->headers[j]->status, UNREAD))
&& (storage->headers[j]->
exit_disposition == UNSET)) {
if(answer == *def_ans_yes) {
storage->headers[j]->
exit_disposition = STORE;
to_store++;
c++;
} else {
storage->headers[j]->
exit_disposition = KEEP;
to_keep++;
c++;
}
}
}
DPRINT(Debug,3,(&Debug,
" mailbox #%d: %d messages marked to keep or storen\n",
i,c));
}
} else {
DPRINT(Debug,3,(&Debug,
"No messages marked to read (or disposition is set)\n"));
}
/* If we asked the user if read messages should be stored,
* and if the user wanted them kept instead, then certainly the
* user would want the unread messages kept as well.
*/
if(asked_storage_q && answer == *def_ans_no) {
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
int c = 0;
if (!storage)
continue;
if (storage->headers)
for (j = 0; j < storage->message_count; j++) {
if((storage->headers[j] &&
ison(storage->headers[j]->status, UNREAD))
&& (storage->headers[j]->
exit_disposition == UNSET)) {
storage->headers[j]->exit_disposition = KEEP;
to_keep++;
c++;
}
}
DPRINT(Debug,3,(&Debug,
" mailbox #%d: %d messages marked to keep\n",
i,c));
}
} else {
int marked_unread = 0;
/* Determine if unread messages are to be kept */
/* we need to know if there are none, or one, or more unread */
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (j=0;
j<storage->message_count && marked_unread<2; j++)
if((storage->headers[j] &&
ison(storage->headers[j]->status, UNREAD))
&& (storage->headers[j]->
exit_disposition == UNSET))
marked_unread++;
}
if(marked_unread) {
answer = (always_keep ?
*def_ans_yes : *def_ans_no); /* default answer */
if(ask_questions) {
int def = answer;
againK:
menu_get_sizes(page, &LINES, &COLUMNS);
/* NOTICE: prompt_letter may return EOF */
/* FIXME -- add prompt_area instead of LINES-4 */
if (marked_unread == 1)
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet,
ElmLeaveKeepMessage,
"Keep unread message in incoming mailbox? (%c/%c) "),
*def_ans_yes, *def_ans_no);
else
answer = prompt_letter(LINES-4,"",def,
PROMPT_yesno|PROMPT_cancel|
PROMPT_redraw_mark|PROMPT_ctrlL,
page,
CATGETS(elm_msg_cat, ElmSet, ElmLeaveKeepMessages,
"Keep unread messages in incoming mailbox? (%c/%c) "),
*def_ans_yes, *def_ans_no);
if (TERMCH_interrupt_char == answer) {
return_value = -1; /* failure */
goto cleanup;
}
if (answer == ('L'&31) || answer == REDRAW_MARK) {
menu_ClearScreen(page); /* Reset possible redraw flag */
/* Call refresh routines of children */
menu_redraw_children(page);
delay_redraw++; /* Can't trigger redraw yet... */
goto againK;
}
if (answer == EOF)
emergency_exit(0);
}
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage =
get_storage(mailbox,i);
int j;
int c = 0;
if (!storage)
continue;
if (storage->headers)
for (j = 0; j < storage->message_count; j++) {
if((storage->headers[j] &&
ison(storage->headers[j]->status, UNREAD))
&& (storage->headers[j]->
exit_disposition == UNSET)) {
if(answer == *def_ans_no) {
storage->headers[j]->
exit_disposition = STORE;
to_store++;
c++;
} else {
storage->headers[j]->
exit_disposition = KEEP;
to_keep++;c++;
}
}
}
DPRINT(Debug,3,(&Debug,
" mailbox #%d: %d messages marked to keep or storen\n",
i,c));
}
} else {
DPRINT(Debug,3,(&Debug,
"No messages marked to unread (or disposition is set)\n"));
}
}
}
}
DPRINT(Debug,3,(&Debug, "Messages to store: %d\n", to_store));
DPRINT(Debug,3,(&Debug, "Messages to keep: %d (+ %d hide)\n",
to_keep, to_hide));
/* ================================================================ */
/* get_message_count do not calclulate hidden (to_hide) messages !! */
if(to_delete + to_store + to_keep + to_ignore !=
get_message_count(mailbox)) {
MoveCursor(LINES-1, 0);
Raw(OFF);
DPRINT(Debug,1,(&Debug,
"Error: %d to delete + %d to store + %d to keep + %d to ignore != %d message cnt\n",
to_delete, to_store, to_keep, to_ignore,
get_message_count(mailbox)));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSomethingWrongInCounts,
"Something wrong in message counts! Folder unchanged.\n"));
panic("MBOX PANIC",__FILE__,__LINE__,"sync_mbox",
"Something wrong in message counts!",0);
}
/* If we are not resyncing, we are leaving the mailfile and
* the new messages are new no longer. Note that this changes
* their status.
*/
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if(!resyncing && storage && storage->headers) {
for (j = 0; j < storage->message_count; j++) {
if (storage->headers[j] &&
ison(storage->headers[j]->status, NEW)) {
clearit(storage->headers[j]->status, NEW);
storage->headers[j]->status_chgd = TRUE;
}
}
}
}
/* If all messages are to be kept and none have changed status
* we don't need to do anything because the current folder won't
* be changed by our writing it out - unless we are resyncing, in
* which case we force the writing out of the mailfile.
*/
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int j;
if (!storage)
continue;
if (storage->headers)
for (num_chgd_status = 0, j = 0; j < storage->message_count; j++)
if(storage->headers[j] &&
storage->headers[j]->status_chgd == TRUE)
num_chgd_status++;
}
if(!to_delete && !to_store && !num_chgd_status && !resyncing) {
DPRINT(Debug,3,(&Debug, "Folder keep as is!\n"));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderUnchanged,
"Folder unchanged."));
return_value = 0;
goto cleanup;
}
if (to_store > 0) {
if (new_is_received) {
int M = get_folder_mode(*new_folder);
if (0 != (M & FOLDER_FILE)) {
DPRINT(Debug,3,(&Debug, "--> Need close new folder...\n"));
/* new_folder is same than =received,
we need close new_folder so that locking does not
cause problems
Two problems:
- Possible locking on prepare_write_folder()
may fail on some situations
- Unlocking on end_write_folder() may cause
that lock of new_folder is lost!
leave_old_folder frees data.
*/
leave_old_folder(new_folder,CLOSE_NORMAL);
/* change_file() on quit.c will reopen
new_folder when needed
*/
}
}
/* Permissons check for =received, and open of it ... */
if (!prepare_write_folder(recv_browser,&recv_writeptr)) {
#if POLL_METHOD
wait_for_timeout(5);
#else
sleep(5);
#endif
return_value = 0;
goto cleanup;
}
}
/* Formulate message as to number of keeps, stores, and deletes.
* This is only complex so that the message is good English.
*/
action_message(to_keep,to_store, to_delete);
need_handle = 0;
sc = get_storage_count(mailbox);
for (i = 0; i < sc; i++) {
struct current_storage *storage = get_storage(mailbox,i);
int r;
DPRINT(Debug,11,(&Debug,
"-- storage #%d/%d\n",i,sc));
if (! storage ||
! storage->current_folder ||
! storage->headers) {
DPRINT(Debug,11,(&Debug,
"storage #%d -- empty or no folder\n",
i));
continue; /* IGNORE */
}
r = real_save(storage,recv_browser,recv_writeptr,
to_store, to_keep, resyncing, to_delete,
to_hide);
DPRINT(Debug,11,(&Debug,
"-- real_save returned %d for %S (%s)\n",
r,
storage->current_folder->cur_folder_disp,
storage->current_folder->cur_folder_sys));
if (r == -1 && !need_handle) {
/* New mail is arrived */
return_value = -1; /* failure */
goto cleanup;
}
if (r < 0)
need_handle++;
}
if (to_store > 0) {
if (!end_write_folder(recv_browser,&recv_writeptr)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCopyMessageFailed,
"OOPS! Storing of mail failed!"));
return_value = -2; /* failure */
goto cleanup;
}
}
if (need_handle) {
return_value = -2; /* failure */
goto cleanup;
}
return_value = 1;
/* Clear action message */
lib_error(FRM(""));
cleanup:
if (recv_writeptr) /* If not done ealrier ... */
end_write_folder(recv_browser,&recv_writeptr);
if (recv_browser)
free_dir(&recv_browser);
if (recv_name)
free_string(&recv_name);
if (delay_redraw)
menu_trigger_redraw(page);
DPRINT(Debug,11,(&Debug, "sync_mbox=%d\n",return_value));
return return_value;
}
#ifdef HASSIGPROCMASK
sigset_t toblock, oldset;
#else /* HASSIGPROCMASK */
# ifdef HASSIGBLOCK
int toblock, oldset;
# else /* HASSIGBLOCK */
# ifdef HASSIGHOLD
/* Nothing required */
# else /* HASSIGHOLD */
SIGHAND_TYPE (*oldhup)();
SIGHAND_TYPE (*oldint)();
SIGHAND_TYPE (*oldquit)();
SIGHAND_TYPE (*oldstop)();
# endif /* HASSIGHOLD */
# endif /* HASSIGBLOCK */
#endif /* HASSIGPROCMASK */
/*
* Block all keyboard generated signals. Need to do this while
* rewriting mailboxes to avoid inadvertant corruption. In
* particular, a SIGHUP (from logging out under /bin/sh), can
* corrupt a spool mailbox during an elm autosync.
*/
static void block_signals()
{
DPRINT(Debug,1, (&Debug, "block_signals\n"));
#ifdef HASSIGPROCMASK
sigemptyset(&oldset);
sigemptyset(&toblock);
sigaddset(&toblock, SIGHUP);
sigaddset(&toblock, SIGINT);
sigaddset(&toblock, SIGQUIT);
#ifdef SIGTSTP
sigaddset(&toblock, SIGTSTP);
#endif /* SIGTSTP */
sigprocmask(SIG_BLOCK, &toblock, &oldset);
#else /* HASSIGPROCMASK */
# ifdef HASSIGBLOCK
toblock = sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT);
#ifdef SIGTSTP
toblock |= sigmask(SIGTSTP);
#endif /* SIGTSTP */
oldset = sigblock(toblock);
# else /* HASSIGBLOCK */
# ifdef HASSIGHOLD
sighold(SIGHUP);
sighold(SIGINT);
sighold(SIGQUIT);
#ifdef SIGTSTP
sighold(SIGTSTP);
#endif /* SIGTSTP */
# else /* HASSIGHOLD */
oldhup = signal(SIGHUP, SIG_IGN);
oldint = signal(SIGINT, SIG_IGN);
oldquit = signal(SIGQUIT, SIG_IGN);
#ifdef SIGTSTP
oldstop = signal(SIGTSTP, SIG_IGN);
#endif /* SIGTSTP */
# endif /* HASSIGHOLD */
# endif /* HASSIGBLOCK */
#endif /* HASSIGPROCMASK */
}
/*
* Inverse of the previous function. Restore keyboard generated
* signals.
*/
static void unblock_signals()
{
DPRINT(Debug,1, (&Debug, "unblock_signals\n"));
#ifdef HASSIGPROCMASK
sigprocmask(SIG_SETMASK, &oldset, (sigset_t *)0);
#else /* HASSIGPROCMASK */
# ifdef HASSIGBLOCK
sigsetmask(oldset);
# else /* HASSIGBLOCK */
# ifdef HASSIGHOLD
sigrelse(SIGHUP);
sigrelse(SIGINT);
sigrelse(SIGQUIT);
#ifdef SIGTSTP
sigrelse(SIGTSTP);
#endif /* SIGTSTP */
# else /* HASSIGHOLD */
signal(SIGHUP, oldhup);
signal(SIGINT, oldint);
signal(SIGQUIT, oldquit);
#ifdef SIGTSTP
signal(SIGTSTP, oldstop);
#endif /* SIGTSTP */
# endif /* HASSIGHOLD */
# endif /* HASSIGBLOCK */
#endif /* HASSIGPROCMASK */
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1