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 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 ! */ 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: "); 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 X#include 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