static char rcsid[] = "@(#)$Id: savecopy.c,v 1.53 2006/06/11 17:21:53 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.53 $ $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
*****************************************************************************/
/** Save a copy of the specified message in a folder.
**/
#include "def_elm.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"mbox");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
void zero_copy_file(cf)
struct copy_file *cf;
{
cf->copy_file = NULL;
cf->dir = NULL;
}
void clear_copy_file(cf)
struct copy_file *cf;
{
if (cf->copy_file)
free_string(&(cf->copy_file));
if (cf->dir)
free_dir(&(cf->dir));
}
/*
* save_copy() - Append a copy of the message contained in "filename" to
* the file specified by "copy_file". This routine simply gets all of
* the filenames right, and then invokes "append_copy_to_file()" to do
* the dirty work.
*/
int save_copy(headers, cf, form, mime_info, conv_file,
page)
struct mailing_headers * headers;
struct copy_file *cf;
int form;
mime_send_t *mime_info;
FILE * conv_file;
struct menu_context *page;
{
int
is_ordinary_file;
int flags = 0;
int is_sent_mail = 0;
int is_current_folder = 0;
WRITE_STATE write_ptr = NULL;
int ra, rb;
int reopen_current = 0;
struct current_storage *storage = NULL;
struct MailboxView *m;
int idx;
if (!cf->copy_file)
return 0; /* Selected NONE */
if (cf->dir)
flags = give_dir_flags(cf->dir);
else
cf->dir = new_browser(selection_folder);
if (!flags) {
int s_len=string_len(cf->copy_file);
if (s_len < 1)
return 0; /* Selected NONE */
switch (give_unicode_from_string(cf->copy_file,0)) {
case 0x003D: /* '=' Handle save copy prompt! */
if (1 == s_len /* "=" Unconditionally save by name */
||
/* Conditionally save by name name */
(2 == s_len &&
give_unicode_from_string(cf->copy_file,1)
== 0x003F /* '?' */)) {
if (headers->to.addrs_len > 0) {
char buffer[LONG_STRING];
struct string *S1 = NULL;
int r;
/* determine 'to' login */
get_return_name(headers->to.addrs[0].addr,
buffer, TRUE, sizeof buffer);
if (!buffer[0])
goto use_sent_mail;
S1 = format_string(FRM("=%s"),buffer);
r = select_dir_item(cf->dir,&S1);
free_string(&S1);
if (!r)
goto use_sent_mail; /* Selection failed! */
flags = give_dir_flags(cf->dir);
if (2 == s_len &&
give_unicode_from_string(cf->copy_file,1)
== 0x003F /* '?' */ &&
0 == (BROWSER_EXIST & flags)) {
DPRINT(Debug,5,(&Debug,
"Conditional save by name: file doesn't exist - using \"<\".\n"));
goto use_sent_mail2;
}
} else {
char * sent_val;
use_sent_mail:
sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotDetermineToName,
"Cannot determine `to' name to save by! Saving to \"sent\" folder %s instead."),
sent_val );
is_sent_mail++;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotDetermineToName1,
"Cannot determine `to' name to save by!"));
return 0;
}
}
}
}
}
if (is_sent_mail) {
int r;
use_sent_mail2:
/* If we come here via goto label, increment is_sent_mail */
if (!is_sent_mail)
is_sent_mail++;
if (cf->copy_file)
free_string(&(cf->copy_file));
cf->copy_file = new_string(system_charset);
add_ascii_to_string(cf->copy_file,s2us("<"));
r = select_dir_item(cf->dir,&(cf->copy_file));
if (!r) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo,
"Cannot save to %s!"),
sent_val);
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo2,
"sent -folder is not available."));
sleep_message();
return 0;
}
}
flags = give_dir_flags(cf->dir);
if (!flags) { /* No selection so try it */
if (!select_dir_item(cf->dir,&(cf->copy_file))) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveToSavingInstead,
"Cannot save to %S! Saving to \"sent\" folder %s instead."),
cf->copy_file,
sent_val);
sleep_message();
if (is_sent_mail)
panic("FILE PANIC",__FILE__,__LINE__,"save copy",
"sent mail panic",0);
goto use_sent_mail2;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveTo1,
"Cannot save to %S!"),
cf->copy_file);
sleep_message();
return 0;
}
}
flags = give_dir_flags(cf->dir);
}
if (cf->copy_file)
DPRINT(Debug,8,(&Debug,
"*** %S have flags:%s%s%s%s%s%s%s%s\n",
cf->copy_file,
flags & BROWSER_NODIR ? " NODIR": "",
flags & BROWSER_NOFOLDER ? " NOFOLDER": "",
flags & BROWSER_MARKED ? " MARKED": "",
flags & BROWSER_MAILFILE ? " MAILFILE": "",
flags & BROWSER_SELECTED ? " SELECTED": "",
flags & BROWSER_EXIST ? " EXIST" : "",
flags & BROWSER_DIRPREFIX ? " DIRPREFIX" : "",
!flags ? " none" : ""));
/*
* Allow options
* confirm_files, confirm_folders,
* confirm_append and confirm_create
* to control where the actual copy
* should be saved.
*/
is_ordinary_file = 0 == (flags & BROWSER_MAILFILE);
/* Replace editing buffer with expanded version ... */
if (cf->copy_file)
free_string(&(cf->copy_file));
cf->copy_file = selection_name_dir(cf->dir);
idx = 0;
while (NULL != (m = give_next_open_mailbox(&idx,0))) {
int mbc,i;
mbc = get_storage_count(m);
is_current_folder = 0;
for (i = 0; i < mbc; i++) {
storage = get_storage(m,i);
if (storage &&
storage->current_folder)
is_current_folder = selection_is_folder(cf->dir,
storage->current_folder);
if (is_current_folder)
break; /* FOUND */
}
if (is_current_folder)
break; /* FOUND */
}
if (is_sent_mail) {
if ((flags & BROWSER_EXIST) == 0) {
/* Create it now ... */
if (!create_selection_dir(cf->dir))
return 0;
}
} else if ((flags & BROWSER_EXIST) != 0) { /* already there!! */
if (confirm_append || (confirm_files && is_ordinary_file)) {
/*
* OK in batch mode it may be impossible
* to ask the user to confirm. So we have
* to use sent_mail anyway.
*/
if (batch_only)
goto use_sent_mail2;
else {
char * msg_buffer = NULL;
char answer;
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
if (is_ordinary_file)
msg_buffer = elm_message(CATGETS(elm_msg_cat, ElmSet,
ElmConfirmFilesAppend,
"Append to an existing file `%S'? (%c/%c) "),
cf->copy_file,
*def_ans_yes, *def_ans_no);
else
msg_buffer = elm_message(CATGETS(elm_msg_cat, ElmSet,
ElmConfirmFolderAppend,
"Append to mail folder `%S'? (%c/%c) "),
cf->copy_file,
*def_ans_yes, *def_ans_no);
answer = want_to(msg_buffer, *def_ans_no, LINES-3, 1, page);
free(msg_buffer);
if (answer != *def_ans_yes) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val) {
PutLineX (LINES-1-2, 0,
CATGETS(elm_msg_cat,
ElmSet,
ElmSavingToInstead,
"Alright - saving to `%s' instead"),
sent_val);
sleep_message();
ClearLine (LINES-1-2);
goto use_sent_mail2;
} else {
PutLineX (LINES-1-2, 0,
CATGETS(elm_msg_cat,
ElmSet,
ElmSaving1,
"Alright"));
sleep_message();
return 0;
}
}
}
}
}
else {
if (confirm_create || (confirm_folders && !is_ordinary_file)) {
/*
* OK in batch mode it may be impossible
* to ask the user to confirm. So we have
* to use sent_mail anyway.
*/
if (batch_only)
goto use_sent_mail2;
else {
char * msg_buffer = NULL;
char answer;
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
if (is_ordinary_file)
msg_buffer = elm_message(CATGETS(elm_msg_cat, ElmSet,
ElmConfirmFilesCreate,
"Create a new file `%S'? (%c/%c) "),
cf->copy_file,
*def_ans_yes, *def_ans_no);
else
msg_buffer = elm_message(CATGETS(elm_msg_cat, ElmSet,
ElmConfirmFolderCreate,
"Create a new mail folder `%S'? (%c/%c) "),
cf->copy_file,
*def_ans_yes, *def_ans_no);
answer = want_to(msg_buffer, *def_ans_no, LINES-3, 1,
page);
free(msg_buffer);
if (answer != *def_ans_yes) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val) {
PutLineX (LINES-1-2, 0,
CATGETS(elm_msg_cat,
ElmSet,
ElmSavingToInstead,
"Alright - saving to `%s' instead"),
sent_val);
sleep_message();
ClearLine (LINES-1-2);
goto use_sent_mail2;
} else {
PutLineX (LINES-1-2, 0,
CATGETS(elm_msg_cat,
ElmSet,
ElmSaving1,
"Alright"));
sleep_message();
return 0;
}
}
}
}
/* Create it now ... */
if (!create_selection_dir(cf->dir)) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (sent_val) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveToSavingInstead,
"Cannot save to %S! Saving to \"sent\" folder %s instead."),
cf->copy_file,
sent_val);
sleep_message();
goto use_sent_mail2;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveTo1,
"Cannot save to %S!"),
cf->copy_file);
sleep_message();
return 0;
}
}
}
if (is_current_folder) {
int M = get_folder_mode(storage->current_folder);
DPRINT(Debug,1,(&Debug, "*** Current folder is save copy folder!\n"));
if (0 != (M & FOLDER_FILE)) {
DPRINT(Debug,3,(&Debug, "--> Need close current folder...\n"));
/* current_folder is same than save copy folder,
we need close current_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!
*/
close_folder(storage->current_folder,CLOSE_NORMAL);
reopen_current = 1;
}
}
if (!prepare_write_folder(cf->dir,&write_ptr)) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (!is_sent_mail) {
if (sent_val) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveToSavingInstead,
"Cannot save to %S! Saving to \"sent\" folder %s instead."),
cf->copy_file,
sent_val);
sleep_message();
goto use_sent_mail2;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveTo1,
"Cannot save to %S!"),
cf->copy_file);
sleep_message();
return 0;
}
}
if (sent_val)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo,
"Cannot save to %s!"),
sent_val);
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo2,
"sent -folder is not available."));
sleep_message();
return 0;
}
ra = append_copy_to_file(headers, cf->dir, form,
mime_info,conv_file,write_ptr);
rb = end_write_folder(cf->dir,&write_ptr);
if (reopen_current) {
DPRINT(Debug,3,(&Debug, "--> Reopeing current folder...\n"));
if (!sessionlock_folder(storage->current_folder,SESSIONLOCK_NORMAL)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmFailedReopenFolder,
"Failed to reopen %S folder"),
storage->current_folder->cur_folder_disp);
}
}
if (!rb || ra < 0) {
char * sent_val = give_dt_estr_as_str(&sent_mail_e,"sentmail");
if (!is_sent_mail) {
if (sent_val) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveToSavingInstead,
"Cannot save to %S! Saving to \"sent\" folder %s instead."),
cf->copy_file,
sent_val);
sleep_message();
goto use_sent_mail2;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCannotSaveTo1,
"Cannot save to %S!"),
cf->copy_file);
sleep_message();
return 0;
}
}
if (sent_val)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo,
"Cannot save to %s!"),
sent_val);
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotSaveTo2,
"sent -folder is not available."));
return 0;
}
return 1;
}
void name_copy_file(cf,aview, page)
struct copy_file *cf;
struct AliasView *aview;
struct menu_context *page;
{
/** Prompt user for name of file for saving copy of outbound msg to.
Called menu_trigger_redraw(page) if we need redraw **/
if (!cf->dir)
cf->dir = new_browser(selection_folder);
gen_browser(page,
cf->dir, &(cf->copy_file),
word_save_copy,NULL,
aview,
CATGETS(elm_msg_cat, ElmSet, ElmSaveCopyInPrompt,
"Save copy in (use '?' for help): "));
}
int append_copy_to_file(headers, dir, form, mime_info, conv_file,dest)
struct mailing_headers * headers;
struct folder_browser *dir;
int form;
mime_send_t *mime_info;
FILE * conv_file;
WRITE_STATE dest;
{
int err = 0;
struct header_rec X;
FILE *F = NULL;
out_state_t fp_copy; /* We need another out_state_t because
dest is not seekable !!!
*/
int env_flag;
char * tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
char * fname_copy = elm_message(FRM("%selmcopy-%d"),
tmp ? tmp : "/tmp/",
getpid ());
out_state_t buffer;
charset_t charset_vector[2];
/* Needed by STATE_out_dir */
charset_vector[0] = RAW_BUFFER;
charset_vector[1] = NULL;
header_zero(&X);
strfcpy(X.env_from,username,sizeof X.env_from);
if (headers->env_from) {
int x;
CONST char *t = mailer_env_from_value(headers->env_from,&x);
if (t)
strfcpy(X.env_from,t,sizeof X.env_from);
}
/* We have perfect out_state_t (dest), but it is not seekable
so we need build another one ....
TODO: Rethink this...
*/
out_state_clear(&fp_copy,STATE_out_file);
F = safeopen_rdwr(fname_copy);
if (!F) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: safeopen_rdwr failed!\n"));
free (fname_copy);
out_state_destroy(&fp_copy);
header_clear(&X);
return -1;
}
set_out_state_file(F,&fp_copy);
unlink (fname_copy);
write_header_info(&fp_copy, headers, (form == YES), TRUE, mime_info);
X.mime_rec.offset = out_state_ftell(&fp_copy);
rewind(conv_file);
/* dump the contents of the message to the end of the copy file */
if (!copy_message_across(mime_info,&fp_copy, TRUE, conv_file)) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: copy_message_across failed!\n"));
out_state_destroy(&fp_copy);
fclose(F);
free (fname_copy);
header_clear(&X);
return -1;
}
X.content_length = out_state_ftell(&fp_copy) - X.mime_rec.offset;
out_state_destroy(&fp_copy);
rewind(F);
out_state_clear(&buffer,STATE_out_dir);
buffer.display_charset = charset_vector;
set_out_state_dir(dir,dest,&buffer);
if (!write_envelope_start(dir,dest,1,&X,&env_flag)) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: write_envelope_start failed!\n"));
err = -1;
goto fail;
}
if (!copy_message_2(F,&X, "",&buffer,0,env_flag)) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: copy_message_2 failed!\n"));
err = -1;
}
if (!write_envelope_end(dir,dest,1,&X)) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: write_envelope_end failed!\n"));
err = -1;
}
fail:
free (fname_copy);
header_clear(&X);
out_state_destroy(&buffer);
if (EOF == fclose(F)) {
DPRINT(Debug,5,(&Debug,
"append_copy_to_file: fclose failed!\n"));
err = -1;
}
return err;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1