rsalz@uunet.uu.net (Rich Salz) (04/13/89)
Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein) Posting-number: Volume 18, Issue 93 Archive-name: elm2.2/part14 #!/bin/sh # this is part 14 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/elm.c continued # CurArch=14 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/elm.c" sed 's/^X//' << 'SHAR_EOF' >> src/elm.c X current); X X Write_to_screen("Lines : %-5d\t\t\tStatus: A C D E F N O P T U V\n\r", 1, X current_header->lines); X Write_to_screen(" \t\t\t c o e x o e l r a r i\n\r", 0); X Write_to_screen(" \t\t\t t n l p r w d i g g s\n\r", 0); X Write_to_screen(" \t\t\t n f d d m v d n i\n\r", 0); X X sprintf(buffer, X "\n\rOffset: %ld\t\t\t %d %d %d %d %d", X current_header->offset, X (current_header->status & ACTION) != 0, X (current_header->status & CONFIDENTIAL) != 0, X (current_header->status & DELETED) != 0, X (current_header->status & EXPIRED) != 0, X (current_header->status & FORM_LETTER) != 0); X sprintf(buffer + strlen(buffer), X " %d %d %d %d %d %d\n", X (current_header->status & NEW) != 0, X (current_header->status & UNREAD) != 0, X (current_header->status & PRIVATE) != 0, X (current_header->status & TAGGED) != 0, X (current_header->status & URGENT) != 0, X (current_header->status & VISIBLE) != 0); X X Write_to_screen(buffer, 0); X X sprintf(buffer, "\n\rReceived on: %d/%d/%d at %d:%02d\n\r", X current_header->received.month+1, X current_header->received.day, X current_header->received.year, X current_header->received.hour, X current_header->received.minute); X Write_to_screen(buffer, 0); X X sprintf(buffer, "Message sent on: %s, %s %s, %s at %s\n\r", X current_header->dayname, X current_header->month, X current_header->day, X current_header->year, X current_header->time); X Write_to_screen(buffer, 0); X X Write_to_screen("From: %s\n\rSubject: %s", 2, X current_header->from, X current_header->subject); X X Write_to_screen("\n\rPrimary Recipient: %s\nInternal Index Reference Number = %d\n\r", 2, X current_header->to, X current_header->index_number); X X Write_to_screen("Message-ID: %s\n\r", 1, X strlen(current_header->messageid) > 0 ? X current_header->messageid : "<none>"); X X Write_to_screen("Status: %s\n\r", 1, current_header->mailx_status); X X Raw(ON); X X PutLine0(LINES,0,"Please Press any key to return."); X (void) ReadCh(); X} SHAR_EOF echo "File src/elm.c is complete" chmod 0444 src/elm.c || echo "restore of src/elm.c fails" echo "x - extracting src/encode.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/encode.c && X Xstatic char rcsid[] = "@(#)$Id: encode.c,v 2.9 89/03/25 21:46:13 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.9 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: encode.c,v $ X * Revision 2.9 89/03/25 21:46:13 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This is a heavily mangled version of the 'cypher' program written by X person or persons unknown. X X**/ X X#include "headers.h" X X#define RS 94 X#define RN 4 X#define RMASK 0x7fff /* use only 15 bits */ X Xstatic char r[RS][RN]; /* rotors */ Xstatic char ir[RS][RN]; /* inverse rotors */ Xstatic char h[RS]; /* half rotor */ Xstatic char s[RS]; /* shuffle vector */ Xstatic int p[RN]; /* rotor indices */ X Xstatic char the_key[SLEN]; /* unencrypted key */ Xstatic char *encrypted_key; /* encrypted key */ X Xchar *strncpy(), *strcpy(); Xunsigned long sleep(); X X#define DECRYPT_PROMPT "Enter decryption key: " X#define FIRST_ENC_PROMPT "Enter encryption key: " X#define SECOND_ENC_PROMPT "Please enter it again: " X#define PROMPT_LINE LINES-1 X Xgetkey(send) Xint send; X{ X /** this routine prompts for and returns an encode/decode X key for use in the rest of the program. **/ X X char buffer[2][NLEN]; X X while (1) { X PutLine0(PROMPT_LINE, 0, (send ? FIRST_ENC_PROMPT : DECRYPT_PROMPT)); X CleartoEOLN(); X optionally_enter(buffer[0], PROMPT_LINE, X strlen(send ? FIRST_ENC_PROMPT : DECRYPT_PROMPT), FALSE, TRUE); X if (send) { X PutLine0(PROMPT_LINE, 0, SECOND_ENC_PROMPT); X CleartoEOLN(); X optionally_enter(buffer[1], PROMPT_LINE, strlen(SECOND_ENC_PROMPT), X FALSE, TRUE); X if(strcmp(buffer[0], buffer[1]) != 0) { X error("Your keys were not the same!"); X sleep(1); X clear_error(); X continue; X } X } X break; X } X strcpy(the_key, buffer[0]); /* save unencrypted key */ X makekey(buffer[0]); X X setup(); /** initialize the rotors etc. **/ X X ClearLine(PROMPT_LINE); X clear_error(); X} X Xget_key_no_prompt() X{ X /** This performs the same action as get_key, but assumes that X the current value of 'the_key' is acceptable. This is used X when a message is encrypted twice... **/ X X char buffer[SLEN]; X X strcpy(buffer, the_key); X X makekey( buffer ); X X setup(); X} X Xencode(line) Xchar *line; X{ X /** encrypt or decrypt the specified line. Uses the previously X entered key... **/ X X register int i, iindex, j, ph = 0; X X for (iindex=0; iindex < strlen(line); iindex++) { X i = (int) line[iindex]; X X if ( (i >= ' ') && (i < '~') ) { X i -= ' '; X X for ( j = 0; j < RN; j++ ) /* rotor forwards */ X i = r[(i+p[j])%RS][j]; X X i = ((h[(i+ph)%RS])-ph+RS)%RS; /* half rotor */ X X for ( j-- ; j >= 0; j-- ) /* rotor backwards */ X i = (ir[i][j]+RS-p[j])%RS; X X j = 0; /* rotate rotors */ X p[0]++; X while ( p[j] == RS ) { X p[j] = 0; X j++; X if ( j == RN ) break; X p[j]++; X } X X if ( ++ph == RS ) X ph = 0; X X i += ' '; X } X X line[iindex] = (char) i; /* replace with altered one */ X } X} X X Xmakekey( rkey) Xchar *rkey; X{ X /** encrypt the key using the system routine 'crypt' **/ X X char key[9], salt[2], *crypt(); X X strncpy( key, rkey, 8); X key[8] = '\0'; X salt[0] = key[0]; X salt[1] = key[1]; X#ifdef CRYPT X encrypted_key = crypt( key, salt); X#else X encrypted_key = key; X#endif X} X X/* X * shuffle rotors. X * shuffle each of the rotors indiscriminately. shuffle the half-rotor X * using a special obvious and not very tricky algorithm which is not as X * sophisticated as the one in crypt(1) and Oh God, I'm so depressed. X * After all this is done build the inverses of the rotors. X */ X Xsetup() X{ X register long i, j, k, temp; X long seed; X X for ( j = 0; j < RN; j++ ) { X p[j] = 0; X for ( i = 0; i < RS; i++ ) X r[i][j] = i; X } X X seed = 123; X for ( i = 0; i < 13; i++) /* now personalize the seed */ X seed = (seed*encrypted_key[i] + i) & RMASK; X X for ( i = 0; i < RS; i++ ) /* initialize shuffle vector */ X h[i] = s[i] = i; X X for ( i = 0; i < RS; i++) { /* shuffle the vector */ X seed = (5 * seed + encrypted_key[i%13]) & RMASK;; X k = ((seed % 65521) & RMASK) % RS; X temp = s[k]; X s[k] = s[i]; X s[i] = temp; X } X X for ( i = 0; i < RS; i += 2 ) { /* scramble the half-rotor */ X temp = h[s[i]]; /* swap rotor elements ONCE */ X h[s[i]] = h[s[i+1]]; X h[s[i+1]] = temp; X } X X for ( j = 0; j < RN; j++) { /* select a rotor */ X X for ( i = 0; i < RS; i++) { /* shuffle the vector */ X seed = (5 * seed + encrypted_key[i%13]) & RMASK;; X k = ((seed % 65521) & RMASK) % RS; X temp = r[i][j]; X r[i][j] = r[k][j]; X r[k][j] = temp; X } X X for ( i = 0; i < RS; i++) /* create inverse rotors */ X ir[r[i][j]][j] = i; X } X} SHAR_EOF chmod 0444 src/encode.c || echo "restore of src/encode.c fails" echo "x - extracting src/errno.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/errno.c && X Xstatic char rcsid[] = "@(#)$Id: errno.c,v 2.3 89/03/25 21:46:14 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.3 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: errno.c,v $ X * Revision 2.3 89/03/25 21:46:14 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This routine maps error numbers to error names and error messages. X These are all directly ripped out of the include file errno.h, and X are HOPEFULLY standardized across the different breeds of Unix!! X X If (alas) yours are different, you should be able to use awk to X mangle your errno.h file quite simply... X X**/ X X#include "headers.h" X Xchar *err_name[] = { X/* 0 */ "NOERROR", "No error status currently", X/* 1 */ "EPERM", "Not super-user", X/* 2 */ "ENOENT", "No such file or directory", X/* 3 */ "ESRCH", "No such process", X/* 4 */ "EINTR", "Interrupted system call", X/* 5 */ "EIO", "I/O error", X/* 6 */ "ENXIO", "No such device or address", X/* 7 */ "E2BIG", "Arg list too long", X/* 8 */ "ENOEXEC", "Exec format error", X/* 9 */ "EBADF", "Bad file number", X/* 10 */ "ECHILD", "No children", X/* 11 */ "EAGAIN", "No more processes", X/* 12 */ "ENOMEM", "Not enough core", X/* 13 */ "EACCES", "Permission denied", X/* 14 */ "EFAULT", "Bad address", X/* 15 */ "ENOTBLK", "Block device required", X/* 16 */ "EBUSY", "Mount device busy", X/* 17 */ "EEXIST", "File exists", X/* 18 */ "EXDEV", "Cross-device link", X/* 19 */ "ENODEV", "No such device", X/* 20 */ "ENOTDIR", "Not a directory", X/* 21 */ "EISDIR", "Is a directory", X/* 22 */ "EINVAL", "Invalid argument", X/* 23 */ "ENFILE", "File table overflow", X/* 24 */ "EMFILE", "Too many open files", X/* 25 */ "ENOTTY", "Not a typewriter", X/* 26 */ "ETXTBSY", "Text file busy", X/* 27 */ "EFBIG", "File too large", X/* 28 */ "ENOSPC", "No space left on device", X/* 29 */ "ESPIPE", "Illegal seek", X/* 30 */ "EROFS", "Read only file system", X/* 31 */ "EMLINK", "Too many links", X/* 32 */ "EPIPE", "Broken pipe", X/* 33 */ "EDOM", "Math arg out of domain of func", X/* 34 */ "ERANGE", "Math result not representable", X/* 35 */ "ENOMSG", "No message of desired type", X/* 36 */ "EIDRM", "Identifier removed" X }; X Xchar *strcpy(); X Xchar *error_name(errnumber) Xint errnumber; X{ X static char buffer[50]; X X if (errnumber < 0 || errnumber > 36) X sprintf(buffer,"ERR-UNKNOWN (%d)", errnumber); X else X strcpy(buffer, err_name[2*errnumber]); X X return( (char *) buffer); X} X Xchar *error_description(errnumber) Xint errnumber; X{ X static char buffer[50]; X X if (errnumber < 0 || errnumber > 36) X sprintf(buffer,"Unknown error - %d - No description", errnumber); X else X strcpy(buffer, err_name[2*errnumber + 1]); X X return ( (char *) buffer); X} SHAR_EOF chmod 0444 src/errno.c || echo "restore of src/errno.c fails" echo "x - extracting src/expires.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/expires.c && X Xstatic char rcsid[] = "@(#)$Id: expires.c,v 2.5 89/03/25 21:46:16 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.5 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: expires.c,v $ X * Revision 2.5 89/03/25 21:46:16 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This routine is written to deal with the Expires: header on the X individual mail coming in. What it does is to look at the date, X compare it to todays date, then set the EXPIRED flag on the X current message if it is true... X**/ X X#include "headers.h" X X#ifdef BSD X# ifdef TMINSYS X# include <sys/time.h> X# else X# include <time.h> X# include <sys/types.h> X# include <sys/timeb.h> X# endif X#else X# include <time.h> X#endif X X#include <ctype.h> X X#ifdef BSD X#undef toupper X#undef tolower X#endif X Xprocess_expiration_date(date, message_status) Xchar *date; Xint *message_status; X{ X struct tm *timestruct, *localtime(); X long thetime, time(); X char word1[WLEN], word2[WLEN], word3[WLEN], word4[WLEN], word5[WLEN]; X int month = 0, day = 0, year = 0, hour = 0, minute = 0; X X /** first step is to break down the date given into MM DD YY HH MM X format: The possible formats for this field are, by example: X X (1) Mon, Jun 11, 87 X (2) Mon, 11 Jun 87 X (3) Jun 11, 87 X (4) 11 Jun 87 X (5) 11/06/87 <- ambiguous - will be ignored!! X (6) 8711061248GMT X (7) Mon, Jun 11, 87 12:48:35 GMT X X The reason #5 is considered ambiguous will be made clear X if we consider a message to be expired on Jan 4, 88: X 01/04/88 in the United States X 04/01/88 in Europe X so is the first field the month or the day? Standard prob. X **/ X X sscanf(date, "%s %s %s %s %s", X word1, word2, word3, word4, word5); X X if (strlen(word5) != 0) { /* we have form #7 */ X day = atoi(word1); X month = month_number(word2); X year = atoi(word3); X sscanf(word4, "%02d%*c%02d", X &hour, &minute); X } X else if (strlen(word2) == 0) { /* we have form #6 or form #5 */ X if (isdigit(word1[1]) && isdigit(word1[2])) /* form #6 */ X sscanf(word1, "%02d%02d%02d%02d%02d%*c", X &year, &month, &day, &hour, &minute); X } X else if (strlen(word4) != 0) { /* form #1 or form #2 */ X if(isdigit(word2[0])) { /* form #2 */ X month = month_number(word3); X day = atoi(word2); X year = atoi(word4); X } else { /* form #1 */ X month = month_number(word2); X day = atoi(word3); X year = atoi(word4); X } X } X else if (! isdigit(word1[0])) { /* form #3 */ X month = month_number(word1); X day = atoi(word2); X year = atoi(word3); X } X else { /* form #4 */ X day = atoi(word1); X month = month_number(word2); X year = atoi(word3); X } X X if (day == 0 || year == 0) X return; /* we didn't get a valid date */ X X /** next let's get the current time and date, please **/ X X thetime = time((long *) 0); X X timestruct = localtime(&thetime); X X /** and compare 'em **/ X X if (year > timestruct->tm_year) X return; X else if (year < timestruct->tm_year) X goto expire_message; X X if (month > timestruct->tm_mon) X return; X else if (month < timestruct->tm_mon) X goto expire_message; X X if (day > timestruct->tm_mday) X return; X else if (day < timestruct->tm_mday) X goto expire_message; X X if (hour > timestruct->tm_hour) X return; X else if (hour < timestruct->tm_hour) X goto expire_message; X X if (minute > timestruct->tm_min) X return; X Xexpire_message: X X /** it's EXPIRED! Yow!! **/ X X (*message_status) |= EXPIRED; X} SHAR_EOF chmod 0444 src/expires.c || echo "restore of src/expires.c fails" echo "x - extracting src/file.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/file.c && X Xstatic char rcsid[] = "@(#)$Id: file.c,v 2.19 89/03/25 21:46:17 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.19 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: file.c,v $ X * Revision 2.19 89/03/25 21:46:17 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** File I/O routines, mostly the save to file command... X X**/ X X#include "headers.h" X#include <ctype.h> X#include <errno.h> X X#ifdef BSD X#undef tolower X#endif X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(), *getenv(), *nameof(); Xunsigned long sleep(); X Xint Xsave(redraw, silently, delete) Xint *redraw, silently, delete; X{ X /** Save all tagged messages + current in a folder. If no messages X are tagged, save the current message instead! This routine X will return ZERO if the operation failed. X 'redraw' is set to TRUE iff we use the '?' and mess up X the screen. Pretty reasonable, eh? If "silently" is set, X then don't output the "D" character upon marking for X deletion... X If delete is set, then delete the saved messages, else X we are just copying the messages without deletion. X **/ X X register int tagged = 0, i, oldstat, appending = 0; X int mesgnum; /* message whose address is used for save-by-name fn */ X char filename[SLEN], address[SLEN], buffer[SLEN]; X static char helpmsg[LONG_STRING]; X FILE *save_file; X X oldstat = headers[current-1]->status; /* remember */ X *redraw = FALSE; X X for (i=0; i < message_count; i++) { X if (ison(headers[i]->status, TAGGED)) { X if(!tagged) X mesgnum = i; /* first tagged msg - use this one for X * save-by-name folder name */ X tagged++; X } X } X X if (tagged == 0) { X mesgnum = current-1; /* use this one for save-by-name folder name */ X tagged = 1; X setit(headers[current-1]->status, TAGGED); X } X X dprint(4, (debugfile, "%d message%s tagged for saving (save)\n", tagged, X plural(tagged))); X X while (1) { X X PutLine2(LINES-2, 0, "%s message%s to: ", X (delete ? "Save" : "Copy"), plural(tagged)); X X if (save_by_name) { X /** build default filename to save to **/ X get_return(address, mesgnum); X get_return_name(address, buffer, TRUE); X if(strcmp(buffer, username) == 0) { X get_existing_address(address, mesgnum); X get_return_name(address, buffer, TRUE); X } X sprintf(filename, "=%s", buffer); X } X else X filename[0] = '\0'; X X if (tagged > 1) X optionally_enter(filename, LINES-2, 19, FALSE, FALSE); X else X optionally_enter(filename, LINES-2, 18, FALSE, FALSE); X X X if (strlen(filename) == 0) { /** <return> means 'cancel', right? **/ X headers[current-1]->status = oldstat; /* BACK! */ X return(0); X } X X if (strcmp(filename,"?") == 0) { /* user asked for listing */ X *redraw = TRUE; /* set the flag so we know what to do later */ X if(!*helpmsg) { /* format helpmsg if not yet done */ X X strcpy(helpmsg, "\n\r\n\rEnter: <nothing> to not "); X strcat(helpmsg, (delete ? "save" : "copy")); X strcat(helpmsg, " your message"); X strcat(helpmsg, (plural(tagged) ? "s" : "")); X strcat(helpmsg, "\n\r '>' to "); X strcat(helpmsg, (delete ? "save" : "copy")); X strcat(helpmsg, " your message"); X strcat(helpmsg, (plural(tagged) ? "s" : "")); X strcat(helpmsg, " to your \"received\" folder ("); X strcat(helpmsg, nameof(recvd_mail)); X strcat(helpmsg, ")\n\r '<' to "); X strcat(helpmsg, (delete ? "save" : "copy")); X strcat(helpmsg, " your message"); X strcat(helpmsg, (plural(tagged) ? "s" : "")); X strcat(helpmsg, " to your \"sent\" folder ("); X strcat(helpmsg, nameof(sent_mail)); X strcat(helpmsg, ") \n\r a filename"); X strcat(helpmsg, " (leading '=' denotes your folder directory "); X strcat(helpmsg, folders); X strcat(helpmsg, ").\n\r"); X } X X list_folders(4, helpmsg); X continue; X } X X /* else - got a folder name - check it out */ X if (! expand_filename(filename, TRUE)) { X dprint(2, (debugfile, X "Error: Failed on expansion of filename %s (save)\n", X filename)); X continue; X } X if ((errno = can_open(filename, "a"))) { X error2("Cannot %s message to folder %s!", X delete ? "save":"copy", filename); X continue; X } X break; /* got a valid filename */ X } X X save_file_stats(filename); X X if (access(filename,ACCESS_EXISTS)== 0) /* already there!! */ X appending = 1; X X dprint(4,(debugfile, "Saving mail to folder '%s'...\n", filename)); X X if ((save_file = fopen(filename,"a")) == NULL) { X dprint(2, (debugfile, X "Error: couldn't append to specified folder %s (save)\n", X filename)); X error1("Couldn't append to folder %s!", filename); X headers[current-1]->status = oldstat; /* BACK! */ X return(0); X } X X /* if we need a redraw that means index screen no longer present X * so whatever silently was, now it's true - we can't show those X * delete markings. X */ X if(*redraw) silently = TRUE; X X for (i=0; i < message_count; i++) /* save each tagged msg */ X if (headers[i]->status & TAGGED) X save_message(i, filename, save_file, (tagged > 1), appending++, X silently, delete); X X fclose(save_file); X X restore_file_stats(filename); X X if (tagged > 1) X error2("Message%s %s.", plural(tagged), delete ? "saved": "copied"); X return(1); X} X Xint Xsave_message(number, filename, fd, pause, appending, silently, delete) Xint number, pause, appending, silently, delete; Xchar *filename; XFILE *fd; X{ X /** Save an actual message to a folder. This is called by X "save()" only! The parameters are the message number, X and the name and file descriptor of the folder to save to. X If 'pause' is true, a sleep(2) will be done after the X saved message appears on the screen... X 'appending' is only true if the folder already exists X If 'delete' is true, mark the message for deletion. X **/ X X register int save_current, is_new; X X dprint(4, (debugfile, "\tSaving message %d to folder...\n", number)); X X save_current = current; X current = number+1; X X /* change status from NEW before copy and reset to what it was X * so that copy doesn't look new, but we can preserve new status X * of message in this mailfile. This is important because if X * user does a resync, we don't want NEW status to be lost. X * I.e. NEW becomes UNREAD when we "really" leave a mailfile. X */ X if(is_new = ison(headers[number]->status, NEW)) X clearit(headers[number]->status, NEW); X copy_message("", fd, FALSE, FALSE, TRUE); X if(is_new) X setit(headers[number]->status, NEW); X current = save_current; X X if (delete) X setit(headers[number]->status, DELETED); /* deleted, but ... */ X clearit(headers[number]->status, TAGGED); /* not tagged anymore */ X X if (appending) X error2("Message %d appended to folder %s.", number+1, filename); X else X error3("Message %d %s to folder %s.", number+1, X delete ? "saved" : "copied", filename); X X if (! silently) X show_new_status(number); /* update screen, if needed */ X X if (pause && ! silently) sleep(2); X} X Xint Xexpand_filename(filename, use_cursor_control) Xchar *filename; Xint use_cursor_control; X{ X /** Expands ~ to the user's home directory X =,+,% to the user's folder's directory X ! to the user's incoming mailbox X > to the user's received folder X < to the user's sent folder X shell variables (begun with $) X X Returns 1 upon proper expansions X 0 upon failed expansions X **/ X X char temp_filename[SLEN], varname[SLEN], env_value[SLEN], *ptr; X register int i = 1, iindex = 0; X char *getenv(); X X ptr = filename; X while (*ptr == ' ') ptr++; /* leading spaces GONE! */ X strcpy(temp_filename, ptr); X X /** New stuff - make sure no illegal char as last **/ X if (lastch(temp_filename) == '\n' || lastch(temp_filename) == '\r') X lastch(temp_filename) = '\0'; X X if (temp_filename[0] == '~') { X sprintf(filename, "%s%s%s", home, X (temp_filename[1] != '/' && lastch(folders) != '/')? "/" : "", X &temp_filename[1]); X } X else if (temp_filename[0] == '=' || temp_filename[0] == '+' || X temp_filename[0] == '%') { X sprintf(filename, "%s%s%s", folders, X (temp_filename[1] != '/' && lastch(folders) != '/')? "/" : "", X &temp_filename[1]); X } X else if (temp_filename[0] == '$') { /* env variable! */ X while (isalnum(temp_filename[i])) X varname[iindex++] = temp_filename[i++]; X varname[iindex] = '\0'; X X env_value[0] = '\0'; /* null string for strlen! */ X if (getenv(varname) != NULL) X strcpy(env_value, getenv(varname)); X X if (strlen(env_value) == 0) { X dprint(3,(debugfile, X "Error: Can't expand environment variable $%s (%s)\n", X varname, "expand_filename")); X if(use_cursor_control) X error1("Don't know what the value of $%s is!", varname); X else X printf("\n\rDon't know what the value of $%s is!\n\r", varname); X return(0); X } X X sprintf(filename, "%s%s%s", env_value, X (temp_filename[i] != '/' && lastch(env_value) != '/')? "/" : "", X &temp_filename[1]); X X } else if (strcmp(temp_filename, "!") == 0) { X strcpy(filename, defaultfile); X } else if (strcmp(temp_filename, ">") == 0) { X strcpy(filename, recvd_mail); X } else if (strcmp(temp_filename, "<") == 0) { X strcpy(filename, sent_mail); X } else X strcpy(filename, temp_filename); X X return(1); X} SHAR_EOF chmod 0444 src/file.c || echo "restore of src/file.c fails" echo "x - extracting src/file_util.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/file_util.c && X Xstatic char rcsid[] = "@(#)$Id: file_util.c,v 2.8 89/03/25 21:46:19 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.8 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: file_util.c,v $ X * Revision 2.8 89/03/25 21:46:19 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** File oriented utility routines for ELM X X**/ X X#include "headers.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <ctype.h> X#include <errno.h> X X#ifdef BSD X# undef tolower X#endif X X#include <signal.h> X#include <errno.h> X X#ifdef BSD X# include <sys/wait.h> X#endif X Xextern int errno; /* system error number */ X Xchar *error_name(), *error_description(), *strcpy(), *getlogin(); Xlong fsize(); X Xlong Xbytes(name) Xchar *name; X{ X /** return the number of bytes in the specified file. This X is to check to see if new mail has arrived.... (also X see "fsize()" to see how we can get the same information X on an opened file descriptor slightly more quickly) X **/ X X int ok = 1; X extern int errno; /* system error number! */ X struct stat buffer; X X if (stat(name, &buffer) != 0) X if (errno != 2) { X dprint(1,(debugfile, X "Error: errno %s on fstat of file %s (bytes)\n", X error_name(errno), name)); X Write_to_screen("\n\rError attempting fstat on file %s!\n\r", X 1, name); X Write_to_screen("** %s - %s. **\n\r", 2, error_name(errno), X error_description(errno)); X emergency_exit(); X } X else X ok = 0; X X return(ok ? (long) buffer.st_size : 0L); X} X Xint Xcan_access(file, mode) Xchar *file; Xint mode; X{ X /** returns ZERO iff user can access file or "errno" otherwise **/ X X int the_stat = 0, pid, w; X void _exit(), exit(); X#ifdef BSD X union wait status; X#else X int status; X#endif X#ifdef VOIDSIG X register void (*istat)(), (*qstat)(); X#else X register int (*istat)(), (*qstat)(); X#endif X X if ((pid = vfork()) == 0) { X setgid(groupid); X setuid(userid); /** back to normal userid **/ X X errno = 0; X X if (access(file, mode) == 0) X _exit(0); X else X _exit(errno != 0? errno : 1); /* never return zero! */ X _exit(127); X } X X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X X while ((w = wait(&status)) != pid && w != -1) X ; X X#ifdef BSD X the_stat = status.w_retcode; X#else X the_stat = status >> 8; X#endif X X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X X return(the_stat); X} X Xint Xcan_open(file, mode) Xchar *file, *mode; X{ X /** Returns 0 iff user can open the file. This is not X the same as can_access - it's used for when the file might X not exist... **/ X X FILE *fd; X int the_stat = 0, pid, w, preexisted = 0; X void _exit(), exit(); X#ifdef BSD X union wait status; X#else X int status; X#endif X#ifdef VOIDSIG X register void (*istat)(), (*qstat)(); X#else X register int (*istat)(), (*qstat)(); X#endif X X if ((pid = vfork()) == 0) { X setgid(groupid); X setuid(userid); /** back to normal userid **/ X errno = 0; X if (access(file, ACCESS_EXISTS) == 0) X preexisted = 1; X if ((fd = fopen(file, mode)) == NULL) X _exit(errno); X else { X fclose(fd); /* don't just leave it open! */ X if(!preexisted) /* don't leave it if this test created it! */ X unlink(file); X _exit(0); X } X _exit(127); X } X X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X X while ((w = wait(&status)) != pid && w != -1) X ; X X#ifdef BSD X the_stat = status.w_retcode; X#else X the_stat = status >> 8; X#endif X X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X X return(the_stat); X} X Xint Xcopy(from, to) Xchar *from, *to; X{ X /** this routine copies a specified file to the destination X specified. Non-zero return code indicates that something X dreadful happened! **/ X X FILE *from_file, *to_file; X char buffer[VERY_LONG_STRING]; X X if ((from_file = fopen(from, "r")) == NULL) { X dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n", X from)); X error1("Could not open file %s.", from); X return(1); X } X X if ((to_file = fopen(to, "w")) == NULL) { X dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n", X to)); X error1("Could not open file %s.", to); X return(1); X } X X while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL) X fputs(buffer, to_file); X X fclose(from_file); X fclose(to_file); X chown( to, userid, groupid); X X return(0); X} X Xmove(from, to) Xchar *from, *to; X{ X /** This routine moves a specified file to the destination X specified. It starts by trying to it all by link'ing. X **/ X X FILE *from_file, *to_file; X char buffer[VERY_LONG_STRING]; X X if (access(from, ACCESS_EXISTS) == -1) /* doesn't exist? */ X return; X X /** does the dest file exist?? **/ X X if (access(to, ACCESS_EXISTS) != -1) { /* dest DOES exist! */ X printf("File %s already exists! Overwriting...\n", to); X (void) unlink(to); X } X X /** first off, let's try to link() it **/ X X if (link(from, to) != -1) { /* yeah! */ X return; X } X X /** nope. Let's open 'em both up and move the data... **/ X X if ((from_file = fopen(from, "r")) == NULL) { X dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n", X from)); X printf("Could not open file %s for reading\n", from); X return; X } X X if ((to_file = fopen(to, "w")) == NULL) { X dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n", X to)); X printf("Could not open file %s for writing\n", to); X return; X } X X while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL) X fputs(buffer, to_file); X X fclose(from_file); X fclose(to_file); X chown( to, userid, groupid); X X return; X} X X Xint Xappend(fd, filename) XFILE *fd; Xchar *filename; X{ X /** This routine appends the specified file to the already X open file descriptor.. Returns non-zero if fails. **/ X X FILE *my_fd; X char buffer[VERY_LONG_STRING]; X X if ((my_fd = fopen(filename, "r")) == NULL) { X dprint(1, (debugfile, X "Error: could not open %s for reading (append)\n", filename)); X return(1); X } X X while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL) X fputs(buffer, fd); X X fclose(my_fd); X X return(0); X} X X#define FORWARDSIGN "Forward to " Xint Xcheck_mailfile_size(mfile) Xchar *mfile; X{ X /** Check to ensure we have mail. Only used with the '-z' X starting option. So we output a diagnostic if there is X no mail to read (including forwarding). X Return 0 if there is mail, X <0 if no permission to check, X 1 if no mail, X 2 if no mail because mail is being forwarded. X **/ X X char firstline[SLEN]; X int retcode; X struct stat statbuf; X FILE *fp; X X /* see if file exists first */ X if (access(mfile, ACCESS_EXISTS) != 0) X retcode = 1; /* no file */ X X /* exists - now see if user has read access */ X else if (can_access(mfile, READ_ACCESS) != 0) X retcode = -1; /* no perm */ X X /* read access - now see if file has a reasonable size */ X else if ((fp = fopen(mfile, "r")) == NULL) X retcode = -1; /* no perm? should have detected this above! */ X else if (fstat(fileno(fp), &statbuf) == -1) X retcode = -1; /* arg error! */ X else if (statbuf.st_size < 2) X retcode = 1; /* empty or virtually empty, e.g. just a newline */ X X /* file has reasonable size - see if forwarding */ X else if (fgets (firstline, SLEN, fp) == NULL) X retcode = 1; /* empty? should have detected this above! */ X else if (first_word(firstline, FORWARDSIGN)) X retcode = 2; /* forwarding */ X X /* not forwarding - so file must have some mail in it */ X else X retcode = 0; X X /* now display the appropriate message if there isn't mail in it */ X switch(retcode) { X X case -1: printf("You have no permission to read %s!\n\r", mfile); X break; X case 1: printf("You have no mail.\n\r"); X break; X case 2: no_ret(firstline) /* remove newline before using */ X printf("Your mail is being forwarded to %s.\n\r", X firstline + strlen(FORWARDSIGN)); X break; X } X return(retcode); X} X Xcreate_readmsg_file() X{ X /** Creates the file ".current" in the users home directory X for use with the "readmsg" program. X **/ X X FILE *fd; X char buffer[SLEN]; X X sprintf(buffer,"%s/%s", home, readmsg_file); X X if ((fd = fopen (buffer, "w")) == NULL) { X dprint(1, (debugfile, X "Error: couldn't create file %s - error %s (%s)\n", X buffer, error_name(errno), "create_readmsg_file")); X return; /* no error to user */ X } X X if (current) X fprintf(fd, "%d\n", headers[current-1]->index_number); X else X fprintf(fd, "\n"); X X fclose(fd); X chown( buffer, userid, groupid); X} X Xlong fsize(fd) XFILE *fd; X{ X /** return the size of the current file pointed to by the given X file descriptor - see "bytes()" for the same function with X filenames instead of open files... X **/ X X struct stat buffer; X X (void) fstat(fd, &buffer); X X return( (long) buffer.st_size ); X} SHAR_EOF chmod 0444 src/file_util.c || echo "restore of src/file_util.c fails" echo "x - extracting src/fileio.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/fileio.c && X Xstatic char rcsid[] = "@(#)$Id: fileio.c,v 2.16 89/03/25 21:46:21 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.16 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: fileio.c,v $ X * Revision 2.16 89/03/25 21:46:21 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** File I/O routines, including deletion from the folder! X X**/ X X#include "headers.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <ctype.h> X#include <errno.h> X X#ifdef BSD X#undef tolower X#endif X Xextern int errno; X Xchar *error_name(); X Xcopy_message(prefix, dest_file, remove_header, remote, update_status) Xchar *prefix; XFILE *dest_file; Xint remove_header, remote, update_status; X{ X /** Copy current message to destination file, with optional 'prefix' X as the prefix for each line. If remove_header is true, it will X skip lines in the message until it finds the end of header line... X then it will start copying into the file... If remote is true X then it will append "remote from <hostname>" at the end of the X very first line of the file (for remailing) X X If "forwarding" is true then it'll do some nice things to X ensure that the forwarded message looks pleasant (e.g. remove X stuff like ">From " lines and "Received:" lines, and prefix X the entire message with "Forwarded message:\n" etc etc) X X If "update_status" is true then it will write a new Status: X line at the end of the headers and not copy any existing one. X **/ X X char buffer[SLEN]; X register struct header_rec *current_header = headers[current-1]; X register int lines, front_line, next_front, X in_header = 1, first_line = TRUE, ignoring = FALSE; X int end_header = 0; X X /** get to the first line of the message desired **/ X X if (fseek(mailfile, current_header->offset, 0) == -1) { X dprint(1, (debugfile, X "ERROR: Attempt to seek %d bytes into file failed (%s)", X current_header->offset, "copy_message")); X error1("ELM [seek] failed trying to read %d bytes into file.", X current_header->offset); X return; X } X X /* how many lines in message? */ X X lines = current_header->lines; X X /* set up for forwarding just in case... */ X X if (forwarding) X remove_header = FALSE; X X /* now while not EOF & still in message... copy it! */ X X next_front = TRUE; X X while (lines) { X if (fgets(buffer, SLEN, mailfile) == NULL) X break; X X front_line = next_front; X X if(buffer[strlen(buffer)-1] == '\n') { X lines--; /* got a full line */ X next_front = TRUE; X } X else X next_front = FALSE; X X if (front_line && ignoring) X ignoring = whitespace(buffer[0]); X X if (ignoring) X continue; X X if (first_line && forwarding) { X first_line = FALSE; X fprintf(dest_file, "Forwarded message:\n\n"); X } X X /* are we still in the header? */ X X if (in_header && front_line) { X if (strlen(buffer) < 2) { X in_header = 0; X end_header = -1; X } else if ((!isspace(*buffer)) && strchr(buffer, ':') == NULL) { X in_header = 0; X end_header = 1; X } X if (end_header) { X if (update_status) { X if (isoff(current_header->status, NEW)) { X if (ison(current_header->status, UNREAD)) X fprintf(dest_file, "%sStatus: O\n", prefix); X else /* read */ X#ifdef BSD X fprintf(dest_file, "%sStatus: OR\n", prefix); X#else X fprintf(dest_file, "%sStatus: RO\n", prefix); X#endif X update_status = FALSE; /* do it only once */ X } /* else if NEW - indicate NEW with no Status: line. This is X * important if we resync a mailfile - we don't want X * NEW status lost when we copy each message out. X * It is the responsibility of the function that calls X * this function to unset NEW as appropriate to its X * reason for using this function to copy a message X */ X X if (end_header > 0) X fprintf(dest_file, "\n"); /* add the missing newline for RFC 822 */ X } X } X } X X if (in_header) { X /* Process checks while in header area */ X X if (remove_header) { X ignoring = TRUE; X continue; X } X X /* add remote on to front? */ X if (first_line && remote) { X no_ret(buffer); X fprintf(dest_file, "%s%s remote from %s\n", X prefix, buffer, hostname); X first_line = FALSE; X continue; X } X X if (!forwarding) { X if(! first_word(buffer, "Status:")) { X fprintf(dest_file, "%s%s", prefix, buffer); X continue; X } X else if (update_status) { X ignoring = TRUE; X continue; /* we will output a new Status: line later. */ X } else { X fprintf(dest_file, "%sStatus: %s\n", prefix, buffer); X continue; X } X } X else { /* forwarding */ X X if (first_word(buffer, "Received:" ) || X first_word(buffer, ">From" ) || X first_word(buffer, "Status:" ) || X first_word(buffer, "Return-Path:")) X ignoring = TRUE; X else X fprintf(dest_file, "%s%s", prefix, buffer); X } X } X else { /* not in header */ X /* Process checks that occur after the header area */ X X if(first_word(buffer, "From ") && (real_from(buffer, NULL))) { X dprint(1, (debugfile, X "\n*** Internal Problem...Tried to add the following;\n")); X dprint(1, (debugfile, X " '%s'\nto output file (copy_message) ***\n", buffer)); X break; /* STOP NOW! */ X } X X fprintf(dest_file, "%s%s", prefix, buffer); X } X } X if (strlen(buffer) + strlen(prefix) > 1) X fprintf(dest_file, "\n"); /* blank line to keep mailx happy *sigh* */ X} X X Xstatic struct stat saved_buf; Xstatic char saved_fname[SLEN]; X Xint Xsave_file_stats(fname) Xchar *fname; X{ X /* if fname exists, save the owner, group, mode and filename. X * otherwise flag nothing saved. Return 0 if saved, else -1. X */ X X if(stat(fname, &saved_buf) != -1) { X (void)strcpy(saved_fname, fname); X dprint(2, (debugfile, X "** saved stats for file owner = %d group = %d mode = %o %s **\n", X saved_buf.st_uid, saved_buf.st_gid, saved_buf.st_mode, fname)); X return(0); X } X dprint(2, (debugfile, X "** couldn't save stats for file %s [errno=%d] **\n", X fname, errno)); X return(-1); X X} X Xrestore_file_stats(fname) Xchar *fname; X{ X /* if fname matches the saved file name, set the owner and group X * of fname to the saved owner, group and mode, X * else to the userid and groupid of the user and to 700. X * Return -1 if the either mode or owner/group not set X * 0 if the default values were used X * 1 if the saved values were used X */ X X int old_umask, i, new_mode, new_owner, new_group, ret_code; X X X new_mode = 0600; X new_owner = userid; X new_group = groupid; X ret_code = 0; X X if(strcmp(fname, saved_fname) == 0) { X new_mode = saved_buf.st_mode; X new_owner = saved_buf.st_uid; X new_group = saved_buf.st_gid; X ret_code = 1; X } X dprint(2, (debugfile, "** %s file stats for %s **\n", X (ret_code ? "restoring" : "setting"), fname)); X X old_umask = umask(0); X if((i = chmod(fname, new_mode & 0777)) == -1) X ret_code = -1; X X dprint(2, (debugfile, "** chmod(%s, %.3o) returns %d [errno=%d] **\n", X fname, new_mode & 0777, i, errno)); X X (void) umask(old_umask); X X#ifdef BSD X /* X * Chown is restricted to root on BSD unix X */ X (void) chown(fname, new_owner, new_group); X#else X if((i = chown(fname, new_owner, new_group)) == -1) X ret_code = -1; X X dprint(2, (debugfile, "** chown(%s, %d, %d) returns %d [errno=%d] **\n", X fname, new_owner, new_group, i, errno)); X#endif X X return(ret_code); X X} X X/** and finally, here's something for that evil trick: site hiding **/ X X#ifdef SITE_HIDING X Xint Xis_a_hidden_user(specific_username) Xchar *specific_username; X{ X /** Returns true iff the username is present in the list of X 'hidden users' on the system. X **/ X X FILE *hidden_users; X char buffer[SLEN]; X X /* X this line is deliberately inserted to ensure that you THINK X about what you're doing, and perhaps even contact the author X of Elm before you USE this option... X */ X X if ((hidden_users = fopen (HIDDEN_SITE_USERS,"r")) == NULL) { X dprint(1, (debugfile, X "Couldn't open hidden site file %s [%s]\n", X HIDDEN_SITE_USERS, error_name(errno))); X return(FALSE); X } X X while (fscanf(hidden_users, "%s", buffer) != EOF) X if (strcmp(buffer, specific_username) == 0) { X dprint(3, (debugfile, "** Found user '%s' in hidden site file!\n", X specific_username)); X fclose(hidden_users); X return(TRUE); X } X X fclose(hidden_users); X dprint(3, (debugfile, X "** Couldn't find user '%s' in hidden site file!\n", X specific_username)); X X return(FALSE); X} X X#endif SHAR_EOF chmod 0444 src/fileio.c || echo "restore of src/fileio.c fails" echo "x - extracting src/forms.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/forms.c && X Xstatic char rcsid[] = "@(#)$Id: forms.c,v 2.7 89/03/25 21:46:23 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.7 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: forms.c,v $ X * Revision 2.7 89/03/25 21:46:23 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This set of files supports the 'forms' options (AT&T Mail Forms) to X the mail system. The specs are drawn from a document from AT&T entitled X "Standard for Exchanging Forms on AT&T Mail", version 1.9. X X**/ X X/** Some notes on the format of a FORM; X X First off, in AT&T Mail parlance, this program only supports SIMPLE X forms, currently. This means that while each form must have three X sections; X X [options-section] X *** X [form-image] X *** X [rules-section] X X this program will ignore the first and third sections completely. The X program will assume that the user merely enteres the form-image section, X and will append and prepend the triple asterisk sequences that *MUST* X be part of the message. The messages are also expected to have a X specific header - "Content-Type: mailform" - which will be added on all X outbound mail and checked on inbound... X**/ X X#include "headers.h" X#include <errno.h> X Xextern int errno; X Xchar *error_name(), *strcat(), *strcpy(); X Xcheck_form_file(filename) Xchar *filename; X{ X /** This routine returns the number of fields in the specified file, X or -1 if an error is encountered. **/ X X FILE *form; X char buffer[SLEN]; X register int field_count = 0; X X if ((form = fopen(filename, "r")) == NULL) { X error2("Error %s trying to open %s to check fields!", X error_name(errno), filename); X return(-1); X } X X while (fgets(buffer, SLEN, form) != NULL) { X field_count += occurances_of(COLON, buffer); X } X X fclose(form); X X return(field_count); X} X Xformat_form(filename) Xchar *filename; X{ X /** This routine accepts a validated file that is the middle X section of a form message and prepends and appends the appropriate X instructions. It's pretty simple. X This returns the number of forms in the file, or -1 on errors X **/ X X FILE *form, *newform; X char newfname[SLEN], buffer[SLEN]; X register form_count = 0; X X dprint(4, (debugfile, "Formatting form file '%s'\n", filename)); X X /** first off, let's open the files... **/ X X if ((form = fopen(filename, "r")) == NULL) { X error("Can't read the message to validate the form!"); X dprint(1, (debugfile, X "** Error encountered opening file \"%s\" - %s (check_form) **\n", X filename, error_name(errno))); X return(-1); X } X X sprintf(newfname, "%s%d", temp_form_file, getpid()); X X if ((newform = fopen(newfname, "w")) == NULL) { X error("Couldn't open newform file for form output!"); X dprint(1, (debugfile, X "** Error encountered opening file \"%s\" - %s (check_form) **\n", X newfname, error_name(errno))); X return(-1); X } X X /** the required header... **/ X X /* these are actually the defaults, but let's be sure, okay? */ X X fprintf(newform, "WIDTH=78\nTYPE=SIMPLE\nOUTPUT=TEXT\n***\n"); X X /** and let's have some fun transfering the stuff across... **/ X X while (fgets(buffer, SLEN, form) != NULL) { X fputs(buffer, newform); X form_count += occurances_of(COLON, buffer); X } X X fprintf(newform, "***\n"); /* that closing bit! */ X X fclose(form); X fclose(newform); X X if (form_count > 0) { X if (unlink(filename) != 0) { X error2("Error %s unlinking file %s.", error_name(errno), filename); X return(-1); X } X if (link(newfname, filename)) { X error3("Error %s linking %s to %s.", error_name(errno), X newfname, filename); X return(-1); X } X } X X if (unlink(newfname)) { X error2("Error %s unlinking file %s.", error_name(errno), newfname); X return(-1); X } X X return(form_count); SHAR_EOF echo "End of part 14" echo "File src/forms.c is continued in part 15" echo "15" > s2_seq_.tmp exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.