home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume22
/
elm2.3
/
part17
< prev
next >
Wrap
Text File
|
1990-06-07
|
50KB
|
1,616 lines
Subject: v22i076: ELM mail syste, release 2.3, Part17/26
Newsgroups: comp.sources.unix
Approved: rsalz@uunet.UU.NET
X-Checksum-Snefru: be6ab14a 542cdba5 7368fbd2 f3129d3b
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
Posting-number: Volume 22, Issue 76
Archive-name: elm2.3/part17
---- Cut Here and unpack ----
#!/bin/sh
# this is part 17 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/leavembox.c continued
#
CurArch=17
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file src/leavembox.c"
sed 's/^X//' << 'SHAR_EOF' >> src/leavembox.c
X */
X
X for (num_chgd_status = 0, i = 0; i < message_count; i++)
X if(headers[i]->status_chgd == TRUE)
X num_chgd_status++;
X
X if(!to_delete && !to_store && !num_chgd_status && !resyncing) {
X dprint(3, (debugfile, "Folder keep as is!\n"));
X error("Folder unchanged.");
X return(0);
X }
X
X /** we have to check to see what the sorting order was...so that
X the order in which we write messages is the same as the order
X of the messages originally.
X We only need to do this if there are any messages to be
X written out (either to keep or to store). **/
X
X if ((to_keep || to_store ) && sortby != MAILBOX_ORDER) {
X last_sortby = sortby;
X sortby = MAILBOX_ORDER;
X sort_mailbox(message_count, FALSE);
X sortby = last_sortby;
X }
X
X /* Formulate message as to number of keeps, stores, and deletes.
X * This is only complex so that the message is good English.
X */
X if (to_keep > 0) {
X if (to_store > 0) {
X if (to_delete > 0)
X sprintf(buffer,
X "[Keeping %d message%s, storing %d, and deleting %d.]",
X to_keep, plural(to_keep), to_store, to_delete);
X else
X sprintf(buffer, "[Keeping %d message%s and storing %d.]",
X to_keep, plural(to_keep), to_store);
X } else {
X if (to_delete > 0)
X sprintf(buffer, "[Keeping %d message%s and deleting %d.]",
X to_keep, plural(to_keep), to_delete);
X else
X sprintf(buffer, "[Keeping %s.]",
X to_keep > 1 ? "all messages" : "message");
X }
X } else if (to_store > 0) {
X if (to_delete > 0)
X sprintf(buffer, "[Storing %d message%s and deleting %d.]",
X to_store, plural(to_store), to_delete);
X else
X sprintf(buffer, "[Storing %s.]",
X to_store > 1? "all messages" : "message");
X
X } else {
X if (to_delete > 0)
X sprintf(buffer, "[Deleting all messages.]");
X else
X buffer[0] = '\0';
X }
X /* NOTE: don't use variable "buffer" till message is output later */
X
X /** next, let's lock the file up and make one last size check **/
X
X if (folder_type == SPOOL)
X lock(OUTGOING);
X
X if (mailfile_size != bytes(cur_folder)) {
X unlock();
X error("New mail has just arrived. Resynchronizing...");
X return(-1);
X }
X
X /* Everything's GO - so ouput that user message and go to it. */
X
X dprint(2, (debugfile, "Action: %s\n", buffer));
X error(buffer);
X
X /* Store messages slated for storage in received mail folder */
X if (to_store > 0) {
X if ((errno = can_open(recvd_mail, "a"))) {
X error1(
X "Permission to append to %s denied! Leaving folder intact.\n",
X recvd_mail);
X dprint(1, (debugfile,
X "Error: Permission to append to folder %s denied!! (%s)\n",
X recvd_mail, "leavembox"));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X unlock();
X return(0);
X }
X if ((temp = fopen(recvd_mail,"a")) == NULL) {
X unlock();
X dprint(1, (debugfile, "Error: could not append to file %s\n",
X recvd_mail));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X sprintf(buffer, "Could not append to folder %s!", recvd_mail);
X Centerline(LINES-1, buffer);
X emergency_exit();
X }
X dprint(2, (debugfile, "Storing message%s ", plural(to_store)));
X for (i = 0; i < message_count; i++) {
X if(headers[i]->exit_disposition == STORE) {
X current = i+1;
X dprint(2, (debugfile, "#%d, ", current));
X copy_message("", temp, FALSE, FALSE, TRUE, FALSE);
X }
X }
X fclose(temp);
X dprint(2, (debugfile, "\n\n"));
X chown(recvd_mail, userid, groupid);
X }
X
X /* If there are any messages to keep, first copy them to a
X * temp file, then remove original and copy whole temp file over.
X */
X if (to_keep > 0) {
X sprintf(temp_keep_file, "%s%s%d", temp_dir, temp_file, getpid());
X if ((errno = can_open(temp_keep_file, "w"))) {
X error1(
X"Permission to create temp file %s for writing denied! Leaving folder intact.",
X temp_keep_file);
X dprint(1, (debugfile,
X "Error: Permission to create temp file %s denied!! (%s)\n",
X temp_keep_file, "leavembox"));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X unlock();
X return(0);
X }
X if ((temp = fopen(temp_keep_file,"w")) == NULL) {
X unlock();
X dprint(1, (debugfile, "Error: could not create file %s\n",
X temp_keep_file));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X sprintf(buffer, "Could not create temp file %s!", temp_keep_file);
X Centerline(LINES-1, buffer);
X emergency_exit();
X }
X dprint(2, (debugfile, "Copying to temp file message%s to be kept ",
X plural(to_keep)));
X for (i = 0; i < message_count; i++) {
X if(headers[i]->exit_disposition == KEEP) {
X current = i+1;
X dprint(2, (debugfile, "#%d, ", current));
X copy_message("", temp, FALSE, FALSE, TRUE, FALSE);
X }
X }
X if ( fclose(temp) == EOF ) {
X Write_to_screen("\n\rClose failed on temp keep file in leavembox\n\r", 0);
X perror(temp_keep_file);
X dprint(2, (debugfile, "\n\rfclose err on temp_keep_file - leavembox\n\r"));
X rm_temps_exit();
X }
X dprint(2, (debugfile, "\n\n"));
X
X } else if (folder_type == NON_SPOOL && !keep_empty_files) {
X
X /* i.e. if no messages were to be kept and this is not a spool
X * folder and we aren't keeping empty non-spool folders,
X * simply remove the old original folder and that's it!
X */
X (void)unlink(cur_folder);
X return(1);
X }
X
X /* Otherwise we have some work left to do! */
X
X /* Get original permissions and access time of the original
X * mail folder before we remove it.
X */
X if(save_file_stats(cur_folder) != 0) {
X error1("Problems saving permissions of folder %s!", cur_folder);
X sleep(2);
X }
X
X if (stat(cur_folder, &buf) != 0) {
X dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n",
X error_name(errno), cur_folder));
X error3("Error %s (%s) on stat(%s).", error_name(errno),
X error_description(errno), cur_folder);
X }
X
X /* Close and remove the original folder.
X * However, if we are going to copy a temp file of kept messages
X * to it, and this is a locked (spool) mailbox, we need to keep
X * it locked during this process. Unfortunately,
X * if we did our LOCK_BY_FLOCK, unlinking the original will kill the
X * lock, so we have to resort to copying the temp file to the original
X * file while keeping the original open.
X * Also, if the file has a link count > 1, then it has links, so to
X * prevent destroying the links, we do a copy back, even though its
X * slower.
X */
X
X fclose(mailfile);
X
X if(to_keep) {
X#ifdef LOCK_BY_FLOCK
X need_to_copy = (folder_type == SPOOL ? TRUE : FALSE);
X#else
X need_to_copy = FALSE;
X#endif
X if (buf.st_nlink > 1)
X need_to_copy = TRUE;
X
X if(!need_to_copy) {
X unlink(cur_folder);
X if (link(temp_keep_file, cur_folder) != 0) {
X if(errno == EXDEV || errno == EEXIST) {
X /* oops - can't link across file systems - use copy instead */
X need_to_copy = TRUE;
X } else {
X dprint(1, (debugfile, "link(%s, %s) failed (leavembox)\n",
X temp_keep_file, cur_folder));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X error2("Link failed! %s - %s.", error_name(errno),
X error_description(errno));
X unlock();
X emergency_exit();
X }
X }
X }
X
X if(need_to_copy) {
X
X if (copy(temp_keep_file, cur_folder) != 0) {
X
X /* copy to cur_folder failed - try to copy to special file */
X dprint(1, (debugfile, "leavembox: copy(%s, %s) failed;",
X temp_keep_file, cur_folder));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X error("Couldn't modify folder!");
X sleep(1);
X sprintf(cur_folder,"%s/%s", home, unedited_mail);
X if (copy(temp_keep_file, cur_folder) != 0) {
X
X /* couldn't copy to special file either */
X dprint(1, (debugfile,
X "leavembox: couldn't copy to %s either!! Help;",
X cur_folder));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X error("Can't copy mailbox, system trouble!!!");
X unlock();
X emergency_exit();
X } else {
X dprint(1, (debugfile,
X "\nWoah! Confused - Saved mail in %s (leavembox)\n",
X cur_folder));
X error1("Saved mail in %s.", cur_folder);
X sleep(1);
X }
X }
X }
X
X /* link or copy complete - remove temp keep file */
X unlink(temp_keep_file);
X
X } else if(folder_type == SPOOL || keep_empty_files) {
X
X /* if this is an empty spool file, or if this is an empty non spool
X * file and we keep empty non spool files (we always keep empty
X * spool files), create an empty file */
X
X if(folder_type == NON_SPOOL)
X error1("Keeping empty folder '%s'.", cur_folder);
X temp = fopen(cur_folder, "w");
X fclose(temp);
X }
X
X /* restore permissions and access times of folder */
X
X if(restore_file_stats(cur_folder) != 1) {
X error1("Problems restoring permissions of folder %s!", cur_folder);
X sleep(2);
X }
X
X#ifdef BSD
X utime_buffer[0] = buf.st_atime;
X utime_buffer[1] = buf.st_mtime;
X#else
X utime_buffer.actime = buf.st_atime;
X utime_buffer.modtime= buf.st_mtime;
X#endif
X
X#ifdef BSD
X if (utime(cur_folder, utime_buffer) != 0) {
X#else
X if (utime(cur_folder, &utime_buffer) != 0) {
X#endif
X dprint(1, (debugfile,
X "Error: encountered error doing utime (leavmbox)\n"));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X error2("Error %s trying to change file %s access time.",
X error_name(errno), cur_folder);
X }
X
X
X mailfile_size = bytes(cur_folder);
X unlock(); /* remove the lock on the file ASAP! */
X
X return(1);
X}
X
Xstatic int lock_state = OFF;
X
Xstatic char lock_name[SLEN];
X
Xchar *
Xmk_lockname(file_to_lock)
Xchar *file_to_lock;
X{
X /** Create the proper name of the lock file for file_to_lock,
X which is presumed to be a spool file full path (see
X get_folder_type()), and put it in the static area lock_name.
X Return lock_name for informational purposes.
X **/
X
X#ifdef XENIX
X /* lock is /tmp/[basename of file_to_lock].mlk */
X sprintf(lock_name, "/tmp/%.10s.mlk", rindex(file_to_lock, '/')+1);
X#else
X /* lock is [file_to_lock].lock */
X sprintf(lock_name, "%s.lock", file_to_lock);
X#endif
X return(lock_name);
X}
X
X
Xstatic int flock_fd, /* file descriptor for flocking mailbox itself */
X create_fd; /* file descriptor for creating lock file */
X
Xlock(direction)
Xint direction;
X{
X /** Create lock file to ensure that we don't get any mail
X while altering the folder contents!
X If it already exists sit and spin until
X either the lock file is removed...indicating new mail
X or
X we have iterated MAX_ATTEMPTS times, in which case we
X either fail or remove it and make our own (determined
X by if REMOVE_AT_LAST is defined in header file
X
X If direction == INCOMING then DON'T remove the lock file
X on the way out! (It'd mess up whatever created it!).
X
X But if that succeeds and if we are also locking by flock(),
X follow a similar algorithm. Now if we can't lock by flock(),
X we DO need to remove the lock file, since if we got this far,
X we DID create it, not another process.
X **/
X
X register int create_iteration = 0,
X flock_iteration = 0;
X char pid_buffer[SHORT];
X
X#ifndef LOCK_FLOCK_ONLY /* { LOCK_FLOCK_ONLY */
X /* formulate lock file name */
X mk_lockname(cur_folder);
X
X#ifdef PIDCHECK
X /** first, try to read the lock file, and if possible, check the pid.
X If we can validate that the pid is no longer active, then remove
X the lock file.
X **/
X if((create_fd=open(lock_name,O_RDONLY)) != -1) {
X if (read(create_fd, pid_buffer, SHORT) > 0) {
X create_iteration = atoi(pid_buffer);
X if (create_iteration) {
X if (kill(create_iteration, 0)) {
X close(create_fd);
X if (unlink(lock_name) != 0) {
X dprint(1, (debugfile,
X "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
X error_name(errno), error_description(errno), lock_name, "lock"));
X PutLine1(LINES, 0,
X "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
X PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
X error_description(errno));
X if (direction == INCOMING)
X leave();
X else
X emergency_exit();
X }
X }
X }
X }
X create_iteration = 0;
X }
X#endif
X
X /* try to assert create lock file MAX_ATTEMPTS times */
X do {
X
X errno = 0;
X if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0444)) != -1)
X break;
X else {
X if(errno != EEXIST) {
X /* Creation of lock failed NOT because it already exists!!! */
X
X if (direction == OUTGOING) {
X dprint(1, (debugfile,
X "Error encountered attempting to create lock %s\n", lock_name));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X MoveCursor(LINES, 0);
X printf(
X "\n\rError encountered while attempting to create lock file %s;\n\r",
X lock_name);
X printf("** %s - %s.**\n\r\n\r",
X error_name(errno), error_description(errno));
X } else { /* incoming - permission denied in the middle? Odd. */
X dprint(1, (debugfile,
X "Can't create lock file: creat(%s) raises error %s (lock)\n",
X lock_name, error_name(errno)));
X error1(
X "Can't create lock file! Need write permission in \"%s\".\n\r",
X mailhome);
X }
X leave();
X }
X }
X dprint(2, (debugfile,"File '%s' already exists! Waiting...(lock)\n",
X lock_name));
X error1(
X "Waiting to read mailbox while mail is being received: attempt #%d",
X create_iteration);
X sleep(5);
X } while (create_iteration++ < MAX_ATTEMPTS);
X clear_error();
X
X if(errno != 0) {
X
X /* we weren't able to create the lock file */
X
X#ifdef REMOVE_AT_LAST
X
X /** time to waste the lock file! Must be there in error! **/
X dprint(2, (debugfile,
X "Warning: I'm giving up waiting - removing lock file(lock)\n"));
X if (direction == INCOMING)
X PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
X else
X error("Throwing away the current lock file!");
X
X if (unlink(lock_name) != 0) {
X dprint(1, (debugfile,
X "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
X error_name(errno), error_description(errno), lock_name, "lock"));
X PutLine1(LINES, 0,
X "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
X PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
X error_description(errno));
X if (direction == INCOMING)
X leave();
X else
X emergency_exit();
X }
X
X /* we've removed the bad lock, let's try to assert lock once more */
X if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0444)) == -1){
X
X /* still can't lock it - just give up */
X dprint(1, (debugfile,
X "Error encountered attempting to create lock %s\n", lock_name));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X MoveCursor(LINES, 0);
X printf(
X "\n\rError encountered while attempting to create lock file %s;\n\r",
X lock_name);
X printf("** %s - %s.**\n\r\n\r", error_name(errno),
X error_description(errno));
X leave();
X }
X#else
X /* Okay...we die and leave, not updating the mailfile mbox or
X any of those! */
X
X if (direction == INCOMING) {
X PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r",
X create_iteration);
X PutLine0(LINES, 0,
X "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
X dprint(1, (debugfile,
X "Warning: bailing out after %d iterations...(lock)\n",
X create_iteration));
X leave_locked(0);
X } else {
X dprint(1, (debugfile,
X "Warning: after %d iterations, timed out! (lock)\n",
X create_iteration));
X leave(error("Timed out on locking mailbox. Leaving program."));
X }
X#endif
X }
X
X /* If we're here we successfully created the lock file */
X dprint(5,
X (debugfile, "Lock %s %s for file %s on.\n", lock_name,
X (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
X
X /* Place the pid of Elm into the lock file for SVR3.2 and its ilk */
X sprintf(pid_buffer, "%d", getpid());
X write(create_fd, pid_buffer, strlen(pid_buffer));
X
X (void)close(create_fd);
X#endif /* } LOCK_FLOCK_ONLY */
X
X#ifdef LOCK_BY_FLOCK
X /* Now we also need to lock the file with flock(2) */
X
X /* Open mail file separately for locking */
X if((flock_fd = open(cur_folder, O_RDONLY)) < 0) {
X dprint(1, (debugfile,
X "Error encountered attempting to reopen %s for lock\n", cur_folder));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X MoveCursor(LINES, 0);
X printf(
X "\n\rError encountered while attempting to reopen mailbox %s for lock;\n\r",
X cur_folder);
X printf("** %s - %s.**\n\r\n\r", error_name(errno),
X error_description(errno));
X (void)unlink(lock_name);
X leave();
X }
X
X /* try to assert lock MAX_ATTEMPTS times */
X do {
X
X errno = 0;
X if(flock(flock_fd, LOCK_NB | LOCK_EX) != -1)
X break;
X else {
X if(errno != EWOULDBLOCK && errno != EAGAIN) {
X
X /* Creation of lock failed NOT because it already exists!!! */
X
X dprint(1, (debugfile,
X "Error encountered attempting to flock %s\n", cur_folder));
X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X error_description(errno)));
X MoveCursor(LINES, 0);
X printf(
X "\n\rError encountered while attempting to flock mailbox %s;\n\r",
X cur_folder);
X printf("** %s - %s.**\n\r\n\r", error_name(errno),
X error_description(errno));
X (void)unlink(lock_name);
X leave();
X }
X }
X dprint(2, (debugfile,
X "Mailbox '%s' already locked! Waiting...(lock)\n", cur_folder));
X error1(
X "Waiting to read mailbox while mail is being received: attempt #%d",
X flock_iteration);
X sleep(5);
X } while (flock_iteration++ < MAX_ATTEMPTS);
X clear_error();
X
X if(errno != 0) {
X
X /* We couldn't lock the file. We die and leave not updating
X * the mailfile mbox or any of those! */
X
X if (direction == INCOMING) {
X PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r",
X flock_iteration);
X PutLine0(LINES, 0,
X "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
X dprint(1, (debugfile,
X "Warning: bailing out after %d iterations...(lock)\n",
X flock_iteration));
X } else {
X dprint(1, (debugfile,
X "Warning: after %d iterations, timed out! (lock)\n",
X flock_iteration));
X }
X#ifndef LOCK_FLOCK_ONLY
X (void)unlink(lock_name);
X#endif
X leave(error("Timed out on locking mailbox. Leaving program."));
X }
X
X /* We locked the file */
X dprint(5,
X (debugfile, "Lock %s on file %s on.\n",
X (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
X#endif
X
X dprint(5,
X (debugfile, "Lock %s for file %s on successfully.\n",
X (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
X lock_state = ON;
X return(0);
X}
X
Xint
Xunlock()
X{
X /** Remove the lock file! This must be part of the interrupt
X processing routine to ensure that the lock file is NEVER
X left sitting in the mailhome directory!
X
X If also using flock(), remove the file lock as well.
X **/
X
X int retcode = 0;
X
X dprint(5,
X (debugfile, "Lock %s for file %s %s off.\n",
X (*lock_name ? lock_name : "none"), cur_folder,
X (lock_state == ON ? "going" : "already")));
X
X if(lock_state == ON) {
X
X#ifdef LOCK_BY_FLOCK
X if((retcode = flock(flock_fd, LOCK_UN)) == -1) {
X dprint(1, (debugfile,
X "Error %s (%s)\n\ttrying to unlock file %s (%s)\n",
X error_name(errno), error_description(errno), cur_folder, "unlock"));
X
X /* try to force unlock by closing file */
X if(close(flock_fd) == -1) {
X dprint(1, (debugfile,
X "Error %s (%s)\n\ttrying to force unlock file %s via close() (%s)\n",
X error_name(errno), error_description(errno), cur_folder, "unlock"));
X error1("Couldn't unlock my own mailbox %s!", cur_folder);
X return(retcode);
X }
X }
X (void)close(flock_fd);
X#endif
X#ifdef LOCK_FLOCK_ONLY /* { LOCK_FLOCK_ONLY */
X *lock_name = '\0'; /* null lock file name */
X lock_state = OFF; /* indicate we don't have a lock on */
X#else
X if((retcode = unlink(lock_name)) == 0) { /* remove lock file */
X *lock_name = '\0'; /* null lock file name */
X lock_state = OFF; /* indicate we don't have a lock on */
X } else {
X dprint(1, (debugfile,
X "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
X error_name(errno), error_description(errno), lock_name,"unlock"));
X error1("Couldn't remove my own lock file %s!", lock_name);
X }
X#endif /* } LOCK_FLOCK_ONLY */
X }
X return(retcode);
X}
SHAR_EOF
echo "File src/leavembox.c is complete"
chmod 0444 src/leavembox.c || echo "restore of src/leavembox.c fails"
echo "x - extracting src/limit.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/limit.c &&
X
Xstatic char rcsid[] = "@(#)$Id: limit.c,v 4.1 90/04/28 22:43:21 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: limit.c,v $
X * Revision 4.1 90/04/28 22:43:21 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** This stuff is inspired by MH and dmail and is used to 'select'
X a subset of the existing mail in the folder based on one of a
X number of criteria. The basic tricks are pretty easy - we have
X as status of VISIBLE associated with each header stored in the
X (er) mind of the computer (!) and simply modify the commands to
X check that flag...the global variable `selected' is set to the
X number of messages currently selected, or ZERO if no select.
X**/
X
X#include "headers.h"
X
X#define TO 1
X#define FROM 2
X
Xchar *shift_lower();
X
Xint
Xlimit()
X{
X /** returns non-zero if we changed selection criteria = need redraw **/
X
X char criteria[STRING], first[STRING], rest[STRING], msg[STRING];
X static char prompt[] = "Enter criteria or '?' for help: ";
X int last_selected, all;
X
X last_selected = selected;
X all = 0;
X
X if (selected) {
X PutLine1(LINES-2, 0,
X "Already have selection criteria - add more? (y/n) n%c",
X BACKSPACE);
X criteria[0] = ReadCh();
X if (tolower(criteria[0]) == 'y') {
X Write_to_screen("Yes.", 0);
X PutLine0(LINES-3, COLUMNS-30, "Adding criteria...");
X } else {
X Write_to_screen("No.", 0);
X selected = 0;
X PutLine0(LINES-3, COLUMNS-30, "Change criteria...");
X }
X }
X
X while(1) {
X PutLine1(LINES-2, 0, prompt);
X CleartoEOLN();
X
X criteria[0] = '\0';
X optionally_enter(criteria, LINES-2, strlen(prompt), FALSE, FALSE);
X error("");
X
X if (strlen(criteria) == 0) {
X /* no change */
X selected = last_selected;
X return(FALSE);
X }
X
X split_word(criteria, first, rest);
X
X if (equal(first, "?")) {
X if(last_selected)
X error(
X "Enter: {\"subject\",\"to\",\"from\"} [pattern] OR \"all\"");
X else
X error("Enter: {\"subject\",\"to\",\"from\"} [pattern]");
X continue;
X } else if (equal(first, "all")) {
X all++;
X selected = 0;
X }
X else if (equal(first, "subj") || equal(first, "subject"))
X selected = limit_selection(SUBJECT, rest, selected);
X else if (equal(first, "to"))
X selected = limit_selection(TO, rest, selected);
X else if (equal(first, "from"))
X selected = limit_selection(FROM, rest, selected);
X else {
X error1("\"%s\" not a valid criterion.", first);
X continue;
X }
X break;
X }
X
X if(all && last_selected)
X strcpy(msg, "Returned to unlimited display.");
X else if(selected)
X sprintf(msg, "%d message%s selected.", selected, plural(selected));
X else
X strcpy(msg, "No messages selected.");
X set_error(msg);
X
X /* we need a redraw if there had been a selection or there is now. */
X if(last_selected || selected) {
X /* if current message won't be on new display, go to first message */
X if(selected && !(headers[current-1]->status & VISIBLE))
X current = visible_to_index(1)+1;
X return(TRUE);
X } else {
X return(FALSE);
X }
X}
X
Xint
Xlimit_selection(based_on, pattern, additional_criteria)
Xint based_on, additional_criteria;
Xchar *pattern;
X{
X /** Given the type of criteria, and the pattern, mark all
X non-matching headers as ! VISIBLE. If additional_criteria,
X don't mark as visible something that isn't currently!
X **/
X
X register int iindex, count = 0;
X
X dprint(2, (debugfile, "\n\n\n**limit on %d - '%s' - (%s) **\n\n",
X based_on, pattern, additional_criteria?"add'tl":"base"));
X
X if (based_on == SUBJECT) {
X for (iindex = 0; iindex < message_count; iindex++)
X if (! in_string(shift_lower(headers[iindex]->subject), pattern))
X headers[iindex]->status &= ~VISIBLE;
X else if (additional_criteria &&
X !(headers[iindex]->status & VISIBLE))
X headers[iindex]->status &= ~VISIBLE; /* shut down! */
X else { /* mark it as readable */
X headers[iindex]->status |= VISIBLE;
X count++;
X dprint(5, (debugfile,
X " Message %d (%s from %s) marked as visible\n",
X iindex, headers[iindex]->subject,
X headers[iindex]->from));
X }
X }
X else if (based_on == FROM) {
X for (iindex = 0; iindex < message_count; iindex++)
X if (! in_string(shift_lower(headers[iindex]->from), pattern))
X headers[iindex]->status &= ~VISIBLE;
X else if (additional_criteria &&
X !(headers[iindex]->status & VISIBLE))
X headers[iindex]->status &= ~VISIBLE; /* shut down! */
X else { /* mark it as readable */
X headers[iindex]->status |= VISIBLE;
X count++;
X dprint(5, (debugfile,
X " Message %d (%s from %s) marked as visible\n",
X iindex, headers[iindex]->subject,
X headers[iindex]->from));
X }
X }
X else if (based_on == TO) {
X for (iindex = 0; iindex < message_count; iindex++)
X if (! in_string(shift_lower(headers[iindex]->to), pattern))
X headers[iindex]->status &= ~VISIBLE;
X else if (additional_criteria &&
X !(headers[iindex]->status & VISIBLE))
X headers[iindex]->status &= ~VISIBLE; /* shut down! */
X else { /* mark it as readable */
X headers[iindex]->status |= VISIBLE;
X count++;
X dprint(5, (debugfile,
X " Message %d (%s from %s) marked as visible\n",
X iindex, headers[iindex]->subject,
X headers[iindex]->from));
X }
X }
X
X dprint(4, (debugfile, "\n** returning %d selected **\n\n\n", count));
X
X return(count);
X}
X
Xint
Xnext_message(iindex, skipdel)
Xregister int iindex, skipdel;
X{
X /** Given 'iindex', this routine will return the actual iindex into the
X array of the NEXT message, or '-1' iindex is the last.
X If skipdel, return the iindex for the NEXT undeleted message.
X If selected, return the iindex for the NEXT message marked VISIBLE.
X **/
X
X register int remember_for_debug;
X
X if(iindex < 0) return(-1); /* invalid argument value! */
X
X remember_for_debug = iindex;
X
X for(iindex++;iindex < message_count; iindex++)
X if (((headers[iindex]->status & VISIBLE) || (!selected))
X && (!(headers[iindex]->status & DELETED) || (!skipdel))) {
X dprint(9, (debugfile, "[Next%s%s: given %d returning %d]\n",
X (skipdel ? " undeleted" : ""),
X (selected ? " visible" : ""),
X remember_for_debug+1, iindex+1));
X return(iindex);
X }
X return(-1);
X}
X
Xint
Xprev_message(iindex, skipdel)
Xregister int iindex, skipdel;
X{
X /** Like next_message, but the PREVIOUS message. **/
X
X register int remember_for_debug;
X
X if(iindex >= message_count) return(-1); /* invalid argument value! */
X
X remember_for_debug = iindex;
X for(iindex--; iindex >= 0; iindex--)
X if (((headers[iindex]->status & VISIBLE) || (!selected))
X && (!(headers[iindex]->status & DELETED) || (!skipdel))) {
X dprint(9, (debugfile, "[Previous%s%s: given %d returning %d]\n",
X (skipdel ? " undeleted" : ""),
X (selected ? " visible" : ""),
X remember_for_debug+1, iindex+1));
X return(iindex);
X }
X return(-1);
X}
X
X
Xint
Xcompute_visible(message)
Xint message;
X{
X /** return the 'virtual' iindex of the specified message in the
X set of messages - that is, if we have the 25th message as
X the current one, but it's #2 based on our limit criteria,
X this routine, given 25, will return 2.
X **/
X
X register int iindex, count = 0;
X
X if (! selected) return(message);
X
X if (message < 1) message = 1; /* normalize */
X
X for (iindex = 0; iindex < message; iindex++)
X if (headers[iindex]->status & VISIBLE)
X count++;
X
X dprint(4, (debugfile,
X "[compute-visible: displayed message %d is actually %d]\n",
X count, message));
X
X return(count);
X}
X
Xint
Xvisible_to_index(message)
Xint message;
X{
X /** Given a 'virtual' iindex, return a real one. This is the
X flip-side of the routine above, and returns (message_count+1)
X if it cannot map the virtual iindex requested (too big)
X **/
X
X register int iindex = 0, count = 0;
X
X for (iindex = 0; iindex < message_count; iindex++) {
X if (headers[iindex]->status & VISIBLE)
X count++;
X if (count == message) {
X dprint(4, (debugfile,
X "visible-to-index: (up) index %d is displayed as %d\n",
X message, iindex));
X return(iindex);
X }
X }
X
X dprint(4, (debugfile, "index %d is NOT displayed!\n", message));
X
X return(message_count+1);
X}
SHAR_EOF
chmod 0444 src/limit.c || echo "restore of src/limit.c fails"
echo "x - extracting src/mailmsg1.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mailmsg1.c &&
X
Xstatic char rcsid[] = "@(#)$Id: mailmsg1.c,v 4.1 90/04/28 22:43:26 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: mailmsg1.c,v $
X * Revision 4.1 90/04/28 22:43:26 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** Interface to allow mail to be sent to users. Part of ELM **/
X
X
X#include "headers.h"
X
X/** strings defined for the hdrconfg routines **/
X
Xchar subject[SLEN], in_reply_to[SLEN], expires[SLEN],
X action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING],
X cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING],
X expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
X bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
X
Xchar *format_long(), *strip_commas(), *tail_of_string(), *strcpy();
Xunsigned long sleep();
X
Xint
Xsendmsg(given_to, given_cc, given_subject, edit_message, form_letter, replying)
Xchar *given_to, *given_cc, *given_subject;
Xint edit_message, form_letter, replying;
X{
X /** Prompt for fields and then call mail() to send the specified
X message. If 'edit_message' is true then don't allow the
X message to be edited. 'form_letter' can be "YES" "NO" or "MAYBE".
X if YES, then add the header. If MAYBE, then add the M)ake form
X option to the last question (see mailsg2.c) etc. etc.
X if (replying) then add an In-Reply-To: header...
X Return TRUE if the main part of the screen has been changed
X (useful for knowing whether a redraw is needed.
X **/
X
X int copy_msg = FALSE, is_a_response = FALSE;
X
X /* First: zero all current global message strings */
X
X cc[0] = bcc[0] = reply_to[0] = expires[0] = '\0';
X action[0] = priority[0] = user_defined_header[0] = in_reply_to[0] ='\0';
X expanded_to[0] = expanded_cc[0] = expanded_bcc[0] = '\0';
X
X strcpy(subject, given_subject); /* copy given subject */
X strcpy(to, given_to); /* copy given to: */
X strcpy(cc, given_cc); /* and so on.. */
X
X /******* And now the real stuff! *******/
X
X copy_msg=copy_the_msg(&is_a_response); /* copy msg into edit buffer? */
X
X if (get_to(to, expanded_to) == 0) /* get the To: address and expand */
X return(0);
X
X /** if we're batchmailing, let's send it and GET OUTTA HERE! **/
X
X if (batch_only) {
X return(mail(FALSE, FALSE, form_letter));
X }
X
X display_to(expanded_to); /* display the To: field on screen... */
X
X dprint(3, (debugfile, "\nMailing to \"%s\"\n", expanded_to));
X
X if (get_subject(subject) == 0) /* get the Subject: field */
X return(0);
X
X dprint(4, (debugfile, "Subject is %s\n", subject));
X
X if (prompt_for_cc) {
X if (get_copies(cc, expanded_to, expanded_cc, copy_msg) == 0)
X return(0);
X
X if (strlen(cc) > 0)
X dprint(4, (debugfile, "Copies to %s\n", expanded_cc));
X }
X
X MoveCursor(LINES,0); /* so you know you've hit <return> ! */
X
X /** generate the In-Reply-To: header... **/
X
X if (is_a_response && replying)
X generate_reply_to(current-1);
X
X /* and mail that puppy outta here! */
X
X return(mail(copy_msg, edit_message, form_letter));
X}
X
Xget_to(to_field, address)
Xchar *to_field, *address;
X{
X /** prompt for the "To:" field, expanding into address if possible.
X This routine returns ZERO if errored, or non-zero if okay **/
X
X if (strlen(to_field) == 0) {
X if (user_level < 2) {
X PutLine0(LINES-2, 0, "Send the message to: ");
X (void) optionally_enter(to_field, LINES-2, 21, FALSE, FALSE);
X }
X else {
X PutLine0(LINES-2, 0, "To: ");
X (void) optionally_enter(to_field, LINES-2, 4, FALSE, FALSE);
X }
X if (strlen(to_field) == 0) {
X ClearLine(LINES-2);
X return(0);
X }
X (void) build_address(strip_commas(to_field), address);
X }
X else if (mail_only)
X (void) build_address(strip_commas(to_field), address);
X else
X strcpy(address, to_field);
X
X if (strlen(address) == 0) { /* bad address! Removed!! */
X ClearLine(LINES-2);
X return(0);
X }
X
X return(1); /* everything is okay... */
X}
X
Xget_subject(subject_field)
Xchar *subject_field;
X{
X char ch;
X
X /** get the subject and return non-zero if all okay... **/
X int len = 9, prompt_line;
X
X prompt_line = mail_only ? 4 : LINES-2;
X
X if (user_level == 0) {
X PutLine0(prompt_line,0,"Subject of message: ");
X len = 20;
X }
X else
X PutLine0(prompt_line,0,"Subject: ");
X
X CleartoEOLN();
X
X if(optionally_enter(subject_field, prompt_line, len, TRUE, FALSE)==-1){
X /** User hit the BREAK key! **/
X MoveCursor(prompt_line,0);
X CleartoEOLN();
X error("Mail not sent.");
X return(0);
X }
X
X if (strlen(subject_field) == 0) { /* zero length subject?? */
X PutLine1(prompt_line,0,
X "No subject - Continue with message? (y/n) n%c", BACKSPACE);
X
X ch = ReadCh();
X if (tolower(ch) != 'y') { /* user says no! */
X Write_to_screen("No.", 0);
X ClearLine(prompt_line);
X error("Mail not sent.");
X return(0);
X }
X else {
X Write_to_screen("Yes.", 0);
X PutLine0(prompt_line,0,"Subject: <none>");
X CleartoEOLN();
X }
X }
X
X return(1); /** everything is cruising along okay **/
X}
X
Xget_copies(cc_field, address, addressII, copy_message)
Xchar *cc_field, *address, *addressII;
Xint copy_message;
X{
X /** Get the list of people that should be cc'd, returning ZERO if
X any problems arise. Address and AddressII are for expanding
X the aliases out after entry!
X If 'bounceback' is nonzero, add a cc to ourselves via the remote
X site, but only if hops to machine are > bounceback threshold.
X If copy-message, that means that we're going to have to invoke
X a screen editor, so we'll need to delay after displaying the
X possibly rewritten Cc: line...
X **/
X int prompt_line;
X
X prompt_line = mail_only ? 5 : LINES - 1;
X PutLine0(prompt_line,0,"Copies to: ");
X
X fflush(stdout);
X
X if (optionally_enter(cc_field, prompt_line, 11, FALSE, FALSE) == -1) {
X ClearLine(prompt_line-1);
X ClearLine(prompt_line);
X
X error("Mail not sent.");
X return(0);
X }
X
X /** The following test is that if the build_address routine had
X reason to rewrite the entry given, then, if we're mailing only
X print the new Cc line below the old one. If we're not, then
X assume we're in screen mode and replace the incorrect entry on
X the line above where we are (e.g. where we originally prompted
X for the Cc: field).
X **/
X
X if (build_address(strip_commas(cc_field), addressII)) {
X PutLine1(prompt_line, 11, "%s", addressII);
X if ((strcmp(editor, "builtin") != 0 && strcmp(editor, "none") != 0)
X || copy_message)
X sleep(2);
X }
X
X if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
X dprint(2, (debugfile,
X "String length of \"To:\" + \"Cc\" too long! (get_copies)\n"));
X error("Too many people. Copies ignored.");
X sleep(2);
X cc_field[0] = '\0';
X }
X
X return(1); /* everything looks okay! */
X}
X
Xint
Xcopy_the_msg(is_a_response)
Xint *is_a_response;
X{
X /** Returns True iff the user wants to copy the message being
X replied to into the edit buffer before invoking the editor!
X Sets "is_a_response" to true if message is a response...
X **/
X
X int answer = FALSE;
X
X if (forwarding)
X answer = TRUE;
X else if (strlen(to) > 0 && !mail_only) { /* predefined 'to' line! */
X if (auto_copy)
X answer = TRUE;
X else
X answer = (want_to("Copy message? (y/n) ", 'n') == 'y');
X *is_a_response = TRUE;
X }
X
X return(answer);
X}
X
Xstatic int to_line, to_col;
X
Xdisplay_to(address)
Xchar *address;
X{
X /** Simple routine to display the "To:" line according to the
X current configuration (etc)
X **/
X register int open_paren;
X
X to_line = mail_only ? 3 : LINES - 3;
X to_col = mail_only ? 0 : COLUMNS - 50;
X if (names_only)
X if ((open_paren = chloc(address, '(')) > 0) {
X if (open_paren < chloc(address, ')')) {
X output_abbreviated_to(address);
X return;
X }
X }
X if(mail_only)
X if(strlen(address) > 80)
X PutLine1(to_line, to_col, "To: (%s)",
X tail_of_string(address, 75));
X else
X PutLine1(to_line, to_col, "To: %s", address);
X else if (strlen(address) > 45)
X PutLine1(to_line, to_col, "To: (%s)",
X tail_of_string(address, 40));
X else {
X if (strlen(address) > 30)
X PutLine1(to_line, to_col, "To: %s", address);
X else
X PutLine1(to_line, to_col, " To: %s", address);
X CleartoEOLN();
X }
X}
X
Xoutput_abbreviated_to(address)
Xchar *address;
X{
X /** Output just the fields in parens, separated by commas if need
X be, and up to COLUMNS-50 characters...This is only used if the
X user is at level BEGINNER.
X **/
X
X char newaddress[LONG_STRING];
X register int iindex, newindex = 0, in_paren = 0, add_len;
X
X iindex = 0;
X
X add_len = strlen(address);
X while (newindex < 55 && iindex < add_len) {
X if (address[iindex] == '(') in_paren++;
X else if (address[iindex] == ')') {
X in_paren--;
X if (iindex < add_len-4) {
X newaddress[newindex++] = ',';
X newaddress[newindex++] = ' ';
X }
X }
X
X /* copy if in_paren but not at the opening outer parens */
X if (in_paren && !(address[iindex] == '(' && in_paren == 1))
X newaddress[newindex++] = address[iindex];
X
X iindex++;
X }
X
X newaddress[newindex] = '\0';
X
X if (mail_only)
X if (strlen(newaddress) > 80)
X PutLine1(to_line, to_col, "To: (%s)",
X tail_of_string(newaddress, 60));
X else
X PutLine1(to_line, to_col, "To: %s", newaddress);
X else if (strlen(newaddress) > 50)
X PutLine1(to_line, to_col, "To: (%s)",
X tail_of_string(newaddress, 40));
X else {
X if (strlen(newaddress) > 30)
X PutLine1(to_line, to_col, "To: %s", newaddress);
X else
X PutLine1(to_line, to_col, " To: %s", newaddress);
X CleartoEOLN();
X }
X
X return;
X}
SHAR_EOF
chmod 0444 src/mailmsg1.c || echo "restore of src/mailmsg1.c fails"
echo "x - extracting src/mailmsg2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mailmsg2.c &&
X
Xstatic char rcsid[] = "@(#)$Id: mailmsg2.c,v 4.1 90/04/28 22:43:28 syd Exp $";
X
X/*******************************************************************************
X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
X *
X * Copyright (c) 1986, 1987 Dave Taylor
X * Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X * Syd Weinstein, Elm Coordinator
X * elm@DSI.COM dsinc!elm
X *
X *******************************************************************************
X * $Log: mailmsg2.c,v $
X * Revision 4.1 90/04/28 22:43:28 syd
X * checkin of Elm 2.3 as of Release PL0
X *
X *
X ******************************************************************************/
X
X/** Interface to allow mail to be sent to users. Part of ELM **/
X
X#include "headers.h"
X#include <errno.h>
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#undef toupper
X#endif
X
Xextern int errno;
Xextern char version_buff[];
X
Xchar *error_name(), *error_description(), *strip_parens();
Xchar *strcat(), *strcpy(), *index();
Xchar *format_long(), *strip_commas(), *tail_of_string();
X
Xunsigned long sleep();
X
X#ifdef SITE_HIDING
X char *get_ctime_date();
X#endif
XFILE *write_header_info();
X
X/* these are all defined in the mailmsg1.c file! */
X
Xextern char subject[SLEN], in_reply_to[SLEN], expires[SLEN],
X action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING],
X cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING],
X expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
X bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
X
X
Xint gotten_key;
Xchar *bounce_off_remote();
X
Xmail(copy_msg, edit_message, form)
Xint copy_msg, edit_message, form;
X{
X /** Given the addresses and various other miscellany (specifically,
X 'copy-msg' indicates whether a copy of the current message should
X be included, 'edit_message' indicates whether the message should
X be edited) this routine will invoke an editor for the user and
X then actually mail off the message. 'form' can be YES, NO, or
X MAYBE. YES=add "Content-Type: mailform" header, MAYBE=add the
X M)ake form option to last question, and NO=don't worry about it!
X Also, if 'copy_msg' = FORM, then grab the form temp file and use
X that...
X Return TRUE if the main part of the screen has been changed
X (useful for knowing whether a redraw is needed.
X **/
X
X FILE *reply, *real_reply; /* second is post-input buffer */
X char *whole_msg_file, *tempnam();
X char filename[SLEN], fname[SLEN], copy_file[SLEN],
X very_long_buffer[VERY_LONG_STRING], mailerflags[NLEN];
X int ch, sys_status;
X register int retransmit = FALSE;
X int already_has_text = FALSE; /* we need an ADDRESS */
X int signature_done = FALSE;
X int need_redraw = 0;
X
X static int cancelled_msg = 0;
X
X dprint(4, (debugfile, "\nMailing to \"%s\" (with%s editing)\n",
X expanded_to, edit_message? "" : "out"));
X
X gotten_key = 0; /* ignore previously gotten encryption key */
X
X /** first generate the temporary filename **/
X
X sprintf(filename,"%s%s%d", temp_dir, temp_file, getpid());
X
X /** if possible, let's try to recall the last message? **/
X
X if (! batch_only && copy_msg != FORM && user_level != 0)
X retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg,
X &already_has_text);
X
X /** if we're not retransmitting, create the file.. **/
X
X if (! retransmit)
X if ((reply = fopen(filename,"w")) == NULL) {
X dprint(1, (debugfile,
X "Attempt to write to temp file %s failed with error %s (mail)\n",
X filename, error_name(errno)));
X if(batch_only)
X printf("Could not create file %s (%s).\n",filename,
X error_name(errno));
X else
X error2("Could not create file %s (%s).",filename,
X error_name(errno));
X return(need_redraw);
X }
X
X chown (filename, userid, groupid);
X
X /* copy the message from standard input */
X if (batch_only) {
X while (fgets(very_long_buffer, VERY_LONG_STRING, stdin) != NULL)
X fprintf(reply, "%s", very_long_buffer);
X }
X
X if (copy_msg == FORM) {
X sprintf(fname, "%s%s%d", temp_dir, temp_form_file, getpid());
X fclose(reply); /* we can't retransmit a form! */
X if (access(fname,ACCESS_EXISTS) != 0) {
X if(batch_only)
X printf("Couldn't find forms file!\n");
X else
X error("Couldn't find forms file!");
X return(need_redraw);
X }
X dprint(4, (debugfile, "-- renaming existing file %s to file %s --\n",
X fname, filename));
X rename(fname, filename);
X }
X else if (copy_msg && ! retransmit) { /* if retransmit we have it! */
X if (attribution[0]) {
X fprintf(reply, attribution, headers[current-1]->from);
X fputc('\n', reply);
X }
X else if (forwarding) {
X fputs("Forwarded message:\n", reply);
X }
X if (edit_message) {
X copy_message(prefixchars, reply, noheader, FALSE, FALSE, TRUE);
X already_has_text = TRUE; /* we just added it, right? */
X }
X else
X copy_message("", reply, noheader, FALSE, FALSE, TRUE);
X }
X
X /* append signature now if we are going to use an external editor */
X /* Don't worry about the remote/local determination too much */
X
X if (already_has_text ||
X (strcmp(editor,"builtin") != 0 && strcmp(editor,"none") != 0)) {
X signature_done = TRUE;
X if (!retransmit && copy_msg != FORM)
X already_has_text |= append_sig(reply);
X }
X
X if (! retransmit && copy_msg != FORM)
X if (reply != NULL)
X (void) fclose(reply); /* on replies, it won't be open! */
X
X /** Edit the message **/
X
X if (edit_message)
X create_readmsg_file(); /* for "readmsg" routine */
X
X ch = edit_message? 'e' : ' '; /* drop through if needed... */
X
X /* calculate default save_file name */
X if(auto_cc) {
X if(save_by_name) {
X if(force_name) {
X strcpy(copy_file, "="); /* signals save by 'to' logname */
X } else {
X strcpy(copy_file, "=?"); /* conditional save by 'to' logname */
X }
X } else {
X strcpy(copy_file, "<"); /* signals save to sentmail */
X }
X } else *copy_file = '\0'; /* signals to not save a copy */
X
X
X if (! batch_only) {
X do {
X switch (ch) {
X case 'e': need_redraw = 1;
X if (edit_the_message(filename, already_has_text)) {
X cancelled_msg = TRUE;
X return(need_redraw);
X }
X break;
X
X case 'c': if (name_copy_file(copy_file))
X need_redraw = 1;
X break;
X
X case 'h': edit_headers();
X need_redraw = 1;
X break;
X
X#ifdef ALLOW_SUBSHELL
X case '!': if (subshell()) {
X ClearScreen();
X need_redraw = 1;
X }
X break;
X#endif
X
X default : /* do nothing */ ;
X }
X
X /** ask that silly question again... **/
X
X if ((ch = verify_transmission(filename, &form)) == 'f') {
X cancelled_msg = TRUE;
X return(need_redraw);
X }
X
X } while (ch != 's');
X
X if (form == YES)
X if (format_form(filename) < 1) {
X cancelled_msg = TRUE;
X return(need_redraw);
X }
X
X if ((reply = fopen(filename,"r")) == NULL) {
X dprint(1, (debugfile,
X "Attempt to open file %s for reading failed with error %s (mail)\n",
X filename, error_name(errno)));
X error1("Could not open reply file (%s).", error_name(errno));
X return(need_redraw);
X }
X }
X else if ((reply = fopen(filename,"r")) == NULL) {
X dprint(1, (debugfile,
X "Attempt to open file %s for reading failed with error %s (mail)\n",
X filename, error_name(errno)));
X printf("Could not open reply file (%s).\n", error_name(errno));
X return(need_redraw);
X }
X
X cancelled_msg = FALSE; /* it ain't cancelled, is it? */
X
X /** ask about bounceback if the user wants us to.... **/
X
X if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM)
SHAR_EOF
echo "End of part 17"
echo "File src/mailmsg2.c is continued in part 18"
echo "18" > s2_seq_.tmp
exit 0