Subject: v22i081: ELM mail syste, release 2.3, Part22/26 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 0e2b97fa ddaa5585 f39798e4 27be6325 Submitted-by: Syd Weinstein Posting-number: Volume 22, Issue 81 Archive-name: elm2.3/part22 ---- Cut Here and unpack ---- #!/bin/sh # this is part 22 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/showmsg.c continued # CurArch=22 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/showmsg.c" sed 's/^X//' << 'SHAR_EOF' >> src/showmsg.c X sleep(2); X break; X } X if ((buf_len=strlen(buffer)) > 0) { X if(buffer[buf_len - 1] == '\n') { X lines--; X lines_displayed++; X } X no_ret(buffer); X } X X if (strlen(buffer) == 0) { X weed_header = 0; /* past header! */ X weeding_out = 0; X } X X if (form_letter && weed_header) X /* skip it. NEVER display random headers in forms! */; X else if (weed_header && matches_weedlist(buffer)) X weeding_out = 1; /* aha! We don't want to see this! */ X else if (buffer[0] == '[') { X if (strcmp(buffer, START_ENCODE)==0) X crypted = ON; X else if (strcmp(buffer, END_ENCODE)==0) X crypted = OFF; X else if (crypted) { X encode(buffer); X val = show_line(buffer, builtin); X } X else X val = show_line(buffer, builtin); X } X else if (crypted) { X encode(buffer); X val = show_line(buffer, builtin); X } X else if (weeding_out) { X weeding_out = (whitespace(buffer[0])); /* 'n' line weed */ X if (! weeding_out) /* just turned on! */ X val = show_line(buffer, builtin); X } X else if (form_letter && first_word(buffer,"***") && filter) { X strcpy(buffer, X"\n------------------------------------------------------------------------------\n"); X val = show_line(buffer, builtin); /* hide '***' */ X form_letter_section++; X } X else if (form_letter_section == 1 || form_letter_section == 3) X /** skip this stuff - we can't deal with it... **/; X else X val = show_line(buffer, builtin); X X if (val != 0) /* discontinue the display */ X break; X } X X if (cursor_control) transmit_functions(ON); X X if (!builtin) { X fclose(pipe_wr_fp); X while ((wait_ret = wait(&wait_stat)) != fork_ret X && wait_ret!= -1) X ; X /* turn raw on **after** child terminates in case child X * doesn't put us back to cooked mode after we return ourselves X * to raw. X */ X Raw(ON); X } X X /* If we are to prompt for a user input command and we don't X * already have one */ X if ((prompt_after_pager || builtin) && val == 0) { X MoveCursor(LINES,0); X StartBold(); X Write_to_screen(" Command ('i' to return to index): ", 0); X EndBold(); X fflush(stdout); X val = ReadCh(); X } X X if (memory_lock) EndMemlock(); /* turn it off!! */ X X /* 'q' means quit current operation and pop back up to previous level - X * in this case it therefore means return to index screen. X */ X return(val == 'i' || val == 'q' ? 0 : val); X} X Xint Xshow_line(buffer, builtin) Xchar *buffer; Xint builtin; X{ X /** Hands the given line to the output pipe. 'builtin' is true if X we're using the builtin pager. X Return the character entered by the user to indicate X a command other than continuing with the display (only possible X with the builtin pager), otherwise 0. **/ X X#ifdef MMDF X if (strcmp(buffer, MSG_SEPERATOR) == 0) X strcpy(buffer," "); X#endif /* MMDF */ X if (builtin) { X strcat(buffer, "\n"); X return(display_line(buffer)); X } X errno = 0; X fprintf(pipe_wr_fp, "%s\n", buffer); X if (errno != 0) X dprint(1, (debugfile, "\terror %s hit!\n", error_name(errno))); X return(0); X} SHAR_EOF echo "File src/showmsg.c is complete" chmod 0444 src/showmsg.c || echo "restore of src/showmsg.c fails" echo "x - extracting src/showmsg_c.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/showmsg_c.c && X Xstatic char rcsid[] = "@(#)$Id: showmsg_c.c,v 4.1 90/04/28 22:44:08 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: showmsg_c.c,v $ X * Revision 4.1 90/04/28 22:44:08 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This is an interface for the showmsg command line. The possible X functions that could be invoked from the showmsg command line are X almost as numerous as those from the main command line and include X the following; X X | = pipe this message to command... X ! = call Unix command X < = scan message for calendar info X b = bounce (remail) message X d = mark message for deletion X f = forward message X g = group reply X h = redisplay this message from line #1, showing headers X = redisplay this message from line #1, weeding out headers X i,q = move back to the index page (simply returns from function) X J = move to body of next message X j,n = move to body of next undeleted message X K = move to body of previous message X k = move to body of previous undeleted message X m = mail a message out to someone X p = print this (all tagged) message X r = reply to this message X s = save this message to a maibox/folder X t = tag this message X u = undelete message X x = Exit Elm NOW X X all commands not explicitly listed here are beeped at. Use i)ndex X to get back to the main index page, please. X X This function returns when it is ready to go back to the index X page. X**/ X X#include "headers.h" X Xint screen_mangled = 0; Xchar msg_line[SLEN]; X#define store_msg(a) (void)strcpy(msg_line,a) X#define put_prompt() PutLine0(LINES-3, 0, "Command:") X#define put_help() PutLine0(LINES-3, 45, "(Use 'i' to return to index.)") X#define POST_PROMPT_COL strlen("Command: ") X X Xint Xprocess_showmsg_cmd(command) Xint command; X{ X int i, intbuf; /* for dummy parameters...etc */ X int ch; /* for arrow keys */ X int key_offset; /* for arrow keys */ X int istagged; /* for tagging and subsequent msg */ X X Raw(ON); X X while (TRUE) { X clear_error(); X switch (command) { X case '?' : if (help(TRUE)) { X ClearScreen(); X build_bottom(); X } else screen_mangled = TRUE; X break; X X case '|' : put_cmd_name("Pipe", TRUE); X (void) do_pipe(); /* do pipe - ignore return val */ X ClearScreen(); X build_bottom(); X break; X X#ifdef ALLOW_SUBSHELL X case '!' : put_cmd_name("System call", TRUE); X (void) subshell(); X ClearScreen(); X build_bottom(); X break; X#endif X X case '<' : X#ifdef ENABLE_CALENDAR X put_cmd_name("Scan messages for calendar entries", TRUE); X scan_calendar(); X#else X store_msg("Can't scan for calendar entries!"); X#endif X break; X X case '%' : put_cmd_name("Display return address", TRUE); X get_return(msg_line, current-1); X break; X X case 'b' : put_cmd_name("Bounce message", TRUE); X remail(); X break; X X case 'd' : delete_msg(TRUE, FALSE); /* really delete it, silent */ X if (! resolve_mode) X store_msg("Message marked for deletion."); X else X goto next_undel_msg; X break; X X case 'f' : put_cmd_name("Forward message", TRUE); X if(forward()) put_border(); X break; X X case 'g' : put_cmd_name("Group reply", TRUE); X (void) reply_to_everyone(); X break; X X case 'h' : screen_mangled = 0; X if (filter) { X filter = 0; X intbuf = show_msg(current); X filter = 1; X return(intbuf); X } else X return(show_msg(current)); X X case 'q' : X case 'i' : (void) get_page(current); X clear_error(); /* zero out pending msg */ X if (cursor_control) X transmit_functions(ON); X screen_mangled = 0; X return(0); /* avoid looping */ X Xnext_undel_msg : /* a target for resolve mode actions */ X X case ' ' : X case 'j' : X case 'n' : screen_mangled = 0; X if((i=next_message(current-1, TRUE)) != -1) X return(show_msg(current = i+1)); X else return(0); X Xnext_msg: X case 'J' : screen_mangled = 0; X if((i=next_message(current-1, FALSE)) != -1) X return(show_msg(current = i+1)); X else return(0); X Xprev_undel_msg: X case 'k' : screen_mangled = 0; X if((i=prev_message(current-1, TRUE)) != -1) X return(show_msg(current = i+1)); X else return(0); X X case 'K' : screen_mangled = 0; X if((i=prev_message(current-1, FALSE)) != -1) X return(show_msg(current = i+1)); X else return(0); X X case 'm' : put_cmd_name("Mail message", TRUE); X if(sendmsg("","","", TRUE, allow_forms, FALSE)) X put_border(); X break; X X case 'p' : put_cmd_name("Print message", FALSE); X print_msg(); X store_msg("Queued for printing."); X break; X X case 'r' : put_cmd_name("Reply to message", TRUE); X if(reply()) put_border(); X break; X X case '>' : X case 'C' : X case 's' : put_cmd_name((command != 'C' ? "Save" : "Copy"), TRUE); X (void) save(&intbuf, TRUE, (command != 'C')); X if (resolve_mode && command != 'C') X goto next_undel_msg; X break; X X case 't' : istagged=tag_message(FALSE); X if(istagged) X store_msg("Message tagged."); X else X store_msg("Message untagged."); X break; X X case 'u' : undelete_msg(FALSE); /* undelete it, silently */ X if (! resolve_mode) X store_msg("Message undeleted."); X else { X/****************************************************************************** X ** We're special casing the U)ndelete command here *not* to move to the next X ** undeleted message ; instead it'll blindly move to the next message in the X ** list. See 'elm.c' and the command by "case 'u'" for further information. X ** The old code was: X goto next_undel_msg; X*******************************************************************************/ X goto next_msg; X } X break; X X case 'x' : put_cmd_name("Exit", TRUE); X exit_prog(); X break; X X case ctrl('J'): X case ctrl('M'): screen_mangled = 0; X return(show_msg(current)); X X X case ESCAPE : if (cursor_control) { X X key_offset = 1; X X ch = ReadCh(); X X if (ch == ESCAPE) X ch = ReadCh(); X X if ( ch == '[' || ch == 'O') X { X ch = ReadCh(); X key_offset++; X } X X if (ch == up[key_offset]) X goto prev_undel_msg; X else if (ch == down[key_offset]) X goto next_undel_msg; X else { X screen_mangled = 0; X return(0); X } X } X else /* Eat 2 chars for escape codes */ X { X ch = ReadCh(); X ch = ReadCh(); X putchar((char) 007); X fflush(stdout); X screen_mangled = 0; X return(0); X } X X default : putchar((char) 007); /* BEEP! */ X } X X /* display prompt */ X if (screen_mangled) { X /* clear what was left over from previous command X * and display last generated message. X */ X put_prompt(); X CleartoEOS(); X put_help(); X Centerline(LINES, msg_line); X MoveCursor(LINES-3, POST_PROMPT_COL); X } else { X /* display bottom line prompt with last generated message */ X MoveCursor(LINES, 0); X CleartoEOS(); X StartBold(); X Write_to_screen("%s Command ('i' to return to index): ", X 1, msg_line); X EndBold(); X } X *msg_line = '\0'; /* null last generated message */ X X command = ReadCh(); /* get next command from user */ X } X} X Xput_cmd_name(command, will_mangle) Xchar *command; Xint will_mangle; X{ X X /* If screen is or will be mangled display the command name X * and erase the bottom of the screen. X * But first if the border line hasn't yet been drawn, draw it. X */ X if(will_mangle && !screen_mangled) { X build_bottom(); X screen_mangled = TRUE; X } X if(screen_mangled) { X PutLine0(LINES-3, POST_PROMPT_COL, command); X CleartoEOS(); X } X} X Xput_border() X{ X PutLine0(LINES-4, 0, X"--------------------------------------------------------------------------\n"); X} X Xbuild_bottom() X{ X MoveCursor(LINES-4, 0); X CleartoEOS(); X put_border(); X put_prompt(); X put_help(); X} SHAR_EOF chmod 0444 src/showmsg_c.c || echo "restore of src/showmsg_c.c fails" echo "x - extracting src/signals.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/signals.c && X Xstatic char rcsid[] = "@(#)$Id: signals.c,v 4.1 90/04/28 22:44:10 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: signals.c,v $ X * Revision 4.1 90/04/28 22:44:10 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This set of routines traps various signals and informs the X user of the error, leaving the program in a nice, graceful X manner. X X**/ X X#include "headers.h" X#include X X#ifdef VOIDSIG Xtypedef void sighan_type; X#else Xtypedef int sighan_type; X#endif X Xextern int pipe_abort; /* set to TRUE if receive SIGPIPE */ X Xsighan_type Xquit_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGQUIT **\n\n\n\n")); X leave(); X} X Xsighan_type Xhup_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n")); X leave(); X} X Xsighan_type Xterm_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n")); X leave(); X} X Xsighan_type Xill_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGILL **\n\n\n\n")); X PutLine0(LINES, 0, "\n\nIllegal Instruction signal!\n\n"); X emergency_exit(); X} X Xsighan_type Xfpe_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGFPE **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nFloating Point Exception signal!\n\n"); X emergency_exit(); X} X Xsighan_type Xbus_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGBUS **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nBus Error signal!\n\n"); X emergency_exit(); X} X Xsighan_type Xsegv_signal() X{ X dprint(1, (debugfile,"\n\n** Received SIGSEGV **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nSegment Violation signal!\n\n"); X emergency_exit(); X} X Xsighan_type Xalarm_signal() X{ X /** silently process alarm signal for timeouts... **/ X#ifdef BSD X if (InGetPrompt) X longjmp(GetPromptBuf, 1); X#else X signal(SIGALRM, alarm_signal); X#endif X} X Xsighan_type Xpipe_signal() X{ X /** silently process pipe signal... **/ X dprint(2, (debugfile, "*** received SIGPIPE ***\n\n")); X X pipe_abort = TRUE; /* internal signal ... wheeee! */ X X signal(SIGPIPE, pipe_signal); X} X X#ifdef SIGTSTP Xint was_in_raw_state; X Xsighan_type Xsig_user_stop() X{ X /* This is called when the user presses a ^Z to stop the X process within BSD X */ X if (signal(SIGTSTP, SIG_DFL) != SIG_DFL) X signal(SIGTSTP, SIG_DFL); X X was_in_raw_state = RawState(); X Raw(OFF); /* turn it off regardless */ X X printf("\n\nStopped. Use \"fg\" to return to ELM\n\n"); X X kill(0, SIGSTOP); X} X Xsighan_type Xsig_return_from_user_stop() X{ X /** this is called when returning from a ^Z stop **/ X X if (signal(SIGTSTP, sig_user_stop) == SIG_DFL) X signal(SIGTSTP, sig_user_stop); X X printf( X "\nBack in ELM. (You might need to explicitly request a redraw.)\n\n"); X X if (was_in_raw_state) X Raw(ON); X X#ifdef BSD X if (InGetPrompt) X longjmp(GetPromptBuf, 1); X#endif X} X#endif SHAR_EOF chmod 0444 src/signals.c || echo "restore of src/signals.c fails" echo "x - extracting src/softkeys.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/softkeys.c && X Xstatic char rcsid[] = "@(#)$Id: softkeys.c,v 4.1 90/04/28 22:44:11 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: softkeys.c,v $ X * Revision 4.1 90/04/28 22:44:11 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************* X */ X X#include "headers.h" X Xdefine_softkeys(level) Xint level; X{ X if (! hp_softkeys) return; X X if (level == MAIN) { X X define_key(f1, " Display Msg", "\r"); X define_key(f2, " Mail Msg", "m"); X define_key(f3, " Reply to Msg", "r"); X X if (user_level == 0) { X define_key(f4, " Save Msg", "s"); X define_key(f5, " Delete Msg", "d"); X define_key(f6, "Undelete Msg", "u"); X } X else { X define_key(f4, " Change Folder", "c"); X define_key(f5, " Save Msg", "s"); X define_key(f6, " Delete/Undelete", "^"); X } X X define_key(f7, " Print Msg", "p"); X define_key(f8, " Quit ELM", "q"); X } X else if (level == ALIAS) { X define_key(f1, " Alias Current", "a"); X define_key(f2, " Check Person", "p"); X define_key(f3, " Check System", "s"); X define_key(f4, " Make Alias", "m"); X clear_key(f5); X clear_key(f6); X clear_key(f7); X define_key(f8, " Return to ELM", "r"); X } X else if (level == YESNO) { X define_key(f1, " Yes", "y"); X clear_key(f2); X clear_key(f3); X clear_key(f4); X clear_key(f5); X clear_key(f6); X clear_key(f7); X define_key(f8, " No", "n"); X } X else if (level == READ) { X define_key(f1, " Next Page ", " "); X clear_key(f2); X define_key(f3, " Next Msg ", "j"); X define_key(f4, " Prev Msg ", "k"); X define_key(f5, " Reply to Msg ", "r"); X define_key(f6, " Delete Msg ", "d"); X define_key(f7, " Send Msg ", "m"); X define_key(f8, " Return to ELM ", "q"); X } X else if (level == CHANGE) { X define_key(f1, " Mail Directry", "=/"); X define_key(f2, " Home Directry", "~/"); X clear_key(f3); X define_key(f4, "Incoming Mailbox", "!\n"); X define_key(f5, "\"Received\" Folder", ">\n"); X define_key(f6, "\"Sent\" Folder ", "<\n"); X clear_key(f7); X define_key(f8, " Cancel", "\n"); X } X X softkeys_on(); X} X Xdefine_key(key, display, send) Xint key; Xchar *display, *send; X{ X X char buffer[30]; X X sprintf(buffer,"%s%s", display, send); X X fprintf(stderr, "%c&f%dk%dd%dL%s", ESCAPE, key, X strlen(display), strlen(send), buffer); X fflush(stdout); X} X Xsoftkeys_on() X{ X /* enable (esc&s1A) turn on softkeys (esc&jB) and turn on MENU X and USER/SYSTEM options. */ X X if (hp_softkeys) { X fprintf(stderr, "%c&s1A%c&jB%c&jR", ESCAPE, ESCAPE, ESCAPE); X fflush(stdout); X } X X} X Xsoftkeys_off() X{ X /* turn off softkeys (esc&j@) */ X X if (hp_softkeys) { X fprintf(stderr, "%c&s0A%c&j@", ESCAPE, ESCAPE); X fflush(stdout); X } X} X Xclear_key(key) X{ X /** set a key to nothing... **/ X X if (hp_softkeys) X define_key(key, " ", ""); X} SHAR_EOF chmod 0444 src/softkeys.c || echo "restore of src/softkeys.c fails" echo "x - extracting src/sort.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/sort.c && X Xstatic char rcsid[] = "@(#)$Id: sort.c,v 4.1 90/04/28 22:44:12 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: sort.c,v $ X * Revision 4.1 90/04/28 22:44:12 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Sort folder header table by the field specified in the global X variable "sortby"...if we're sorting by something other than X the default SENT_DATE, also put some sort of indicator on the X screen. X X**/ X X#include "headers.h" X Xchar *sort_name(), *skip_re(); Xvoid qsort(); X Xsort_mailbox(entries, visible) Xint entries, visible; X{ X /** Sort the header_table definitions... If 'visible', then X put the status lines etc **/ X X int last_index = -1; X int compare_headers(); /* for sorting */ X X dprint(2, (debugfile, "\n** sorting folder by %s **\n\n", X sort_name(FULL))); X X /* Don't get last_index if no entries or no current. */ X /* There would be no current if we are sorting a new mail file. */ X if (entries > 0 && current > 0) X last_index = headers[current-1]->index_number; X X if (entries > 30 && visible) X error1("Sorting messages by %s...", sort_name(FULL)); X X if (entries > 1) X qsort(headers, (unsigned) entries, sizeof (struct header_rec *), X compare_headers); X X if (last_index > -1) X find_old_current(last_index); X X clear_error(); X} X Xint Xcompare_headers(p1, p2) Xstruct header_rec **p1, **p2; X{ X /** compare two headers according to the sortby value. X X Sent Date uses a routine to compare two dates, X Received date is keyed on the file offsets (think about it) X Sender uses the truncated from line, same as "build headers", X and size and subject are trivially obvious!! X (actually, subject has been modified to ignore any leading X patterns [rR][eE]*:[ \t] so that replies to messages are X sorted with the message (though a reply will always sort to X be 'greater' than the basenote) X **/ X X char from1[SLEN], from2[SLEN]; /* sorting buffers... */ X struct header_rec *first, *second; X int ret; X long diff; X X first = *p1; X second = *p2; X X switch (abs(sortby)) { X case SENT_DATE: X diff = first->time_sent - second->time_sent; X if ( diff < 0 ) ret = -1; X else if ( diff > 0 ) ret = 1; X else ret = 0; X break; X X case RECEIVED_DATE: X ret = compare_parsed_dates(first->received, second->received); X break; X X case SENDER: X tail_of(first->from, from1, first->to); X tail_of(second->from, from2, second->to); X ret = strcmp(from1, from2); X break; X X case SIZE: X ret = (first->lines - second->lines); X break; X X case MAILBOX_ORDER: X ret = (first->index_number - second->index_number); X break; X X case SUBJECT: X /* need some extra work 'cause of STATIC buffers */ X strcpy(from1, skip_re(shift_lower(first->subject))); X ret = strcmp(from1, skip_re(shift_lower(second->subject))); X break; X X case STATUS: X ret = (first->status - second->status); X break; X X default: X /* never get this! */ X ret = 0; X break; X } X X if (sortby < 0) X ret = -ret; X X return ret; X} X Xchar *sort_name(type) Xint type; X{ X /** return the name of the current sort option... X type can be "FULL", "SHORT" or "PAD" X **/ X int pad, abr; X X pad = (type == PAD); X abr = (type == SHORT); X X if (sortby < 0) { X switch (- sortby) { X case SENT_DATE : return( X pad? "Reverse Date Mail Sent " : X abr? "Reverse-Sent" : X "Reverse Date Mail Sent"); X case RECEIVED_DATE: return( X abr? "Reverse-Received": X "Reverse Date Mail Rec'vd" ); X X case MAILBOX_ORDER: return( X pad? "Reverse Mailbox Order " : X abr? "Reverse-Mailbox": X "Reverse Mailbox Order"); X X case SENDER : return( X pad? "Reverse Message Sender " : X abr? "Reverse-From": X "Reverse Message Sender"); X case SIZE : return( X abr? "Reverse-Lines" : X "Reverse Lines in Message"); X case SUBJECT : return( X pad? "Reverse Message Subject " : X abr? "Reverse-Subject" : X "Reverse Message Subject"); X case STATUS : return( X pad? "Reverse Message Status " : X abr? "Reverse-Status": X "Reverse Message Status"); X } X } X else { X switch (sortby) { X case SENT_DATE : return( X pad? "Date Mail Sent " : X abr? "Sent" : X "Date Mail Sent"); X case RECEIVED_DATE: return( X pad? "Date Mail Rec'vd " : X abr? "Received" : X "Date Mail Rec'vd"); X case MAILBOX_ORDER: return( X pad? "Mailbox Order " : X abr? "Mailbox" : X "Mailbox Order"); X case SENDER : return( X pad? "Message Sender " : X abr? "From" : X "Message Sender"); X case SIZE : return( X pad? "Lines in Message " : X abr? "Lines" : X "Lines in Message"); X case SUBJECT : return( X pad? "Message Subject " : X abr? "Subject" : X "Message Subject"); X case STATUS : return( X pad? "Message Status " : X abr? "Status" : X "Message Status"); X } X } X X return("*UNKNOWN-SORT-PARAMETER*"); X} X Xfind_old_current(iindex) Xint iindex; X{ X /** Set current to the message that has "index" as it's X index number. This is to track the current message X when we resync... **/ X X register int i; X X dprint(4, (debugfile, "find-old-current(%d)\n", iindex)); X X for (i = 0; i < message_count; i++) X if (headers[i]->index_number == iindex) { X current = i+1; X dprint(4, (debugfile, "\tset current to %d!\n", current)); X return; X } X X dprint(4, (debugfile, X "\tcouldn't find current index. Current left as %d\n", X current)); X return; /* can't be found. Leave it alone, then */ X} X Xchar *skip_re(string) Xchar *string; X{ X /** this routine returns the given string minus any sort of X "re:" prefix. specifically, it looks for, and will X remove, any of the pattern: X X ( [Rr][Ee][^:]:[ ] ) * X X If it doesn't find a ':' in the line it will return it X intact, just in case! X **/ X X static char buffer[SLEN]; X register int i=0; X X while (whitespace(string[i])) i++; X X do { X if (string[i] == '\0') return( (char *) string); /* forget it */ X X if (string[i] != 'r' || string[i+1] != 'e') X return( (char *) string); /* ditto */ X X i += 2; /* skip the "re" */ X X while (string[i] != ':') X if (string[i] == '\0') X return( (char *) string); /* no colon in string! */ X else X i++; X X /* now we've gotten to the colon, skip to the next non-whitespace */ X X i++; /* past the colon */ X X while (whitespace(string[i])) i++; X X } while (string[i] == 'r' && string[i+1] == 'e'); X X /* and now copy it into the buffer and sent it along... */ X X strcpy(buffer, (char *) string + i); X X return( (char *) buffer); X} SHAR_EOF chmod 0444 src/sort.c || echo "restore of src/sort.c fails" echo "x - extracting src/string2.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/string2.c && X Xstatic char rcsid[] = "@(#)$Id: string2.c,v 4.1 90/04/28 22:44:14 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: string2.c,v $ X * Revision 4.1 90/04/28 22:44:14 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This file contains string functions that are shared throughout the X various ELM utilities... X X**/ X X#include "headers.h" X#include X X#ifdef BSD X#undef tolower X#undef toupper X#endif X Xchar *shift_lower(string) Xchar *string; X{ X /** return 'string' shifted to lower case. Do NOT touch the X actual string handed to us! **/ X X static char buffer[VERY_LONG_STRING]; X register char *bufptr = buffer; X X for (; *string; string++, bufptr++) X if (isupper(*string)) X *bufptr = tolower(*string); X else X *bufptr = *string; X X *bufptr = 0; X X return( (char *) buffer); X} X X Xint Xin_list(list, target) Xchar *list, *target; X X{ X /* Returns TRUE iff target is an item in the list - case ignored. X * If target is simple (an atom of an address) match must be exact. X * If target is complex (contains a special character that separates X * address atoms), the target need only match a whole number of atoms X * at the right end of an item in the list. E.g. X * target: item: match: X * joe joe yes X * joe jojoe no (wrong logname) X * joe machine!joe no (similar logname on a perhaps X * different machine - to X * test this sort of item the X * passed target must include X * proper machine name, is X * in next two examples) X * machine!joe diffmachine!joe no " X * machine!joe diffmachine!machine!joe yes X * joe@machine jojoe@machine no (wrong logname) X * joe@machine diffmachine!joe@machine yes X */ X X register char *rest_of_list, X *next_item, X ch; X int offset; X char *shift_lower(), X lower_list[VERY_LONG_STRING], X lower_target[SLEN]; X X rest_of_list = strcpy(lower_list, shift_lower(list)); X strcpy(lower_target, shift_lower(target)); X while((next_item = strtok(rest_of_list, ", \t\n")) != NULL) { X /* see if target matches the whole item */ X if(strcmp(next_item, lower_target) == 0) X return(TRUE); X X if(strpbrk(lower_target,"!@%:") != NULL) { X X /* Target is complex */ X X if((offset = strlen(next_item) - strlen(lower_target)) > 0) { X X /* compare target against right end of next item */ X if(strcmp(&next_item[offset], lower_target) == 0) { X X /* make sure we are comparing whole atoms */ X ch=next_item[offset-1]; X if(ch == '!' || ch == '@' || ch == '%' || ch == ':') X return(TRUE); X } X } X } X rest_of_list = NULL; X } X return(FALSE); X} X X Xint Xin_string(buffer, pattern) Xchar *buffer, *pattern; X{ X /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ X X register int i = 0, j = 0; X X while (buffer[i] != '\0') { X while (buffer[i++] == pattern[j++]) X if (pattern[j] == '\0') X return(TRUE); X i = i - j + 1; X j = 0; X } X return(FALSE); X} X Xint Xchloc(string, ch) Xchar *string, ch; X{ X /** returns the index of ch in string, or -1 if not in string **/ X register int i, len; X X for (i=0, len = strlen(string); i= 0 && whitespace(string[i]); ) X /** spin backwards, semicolon intented **/ ; X X string[i+1] = '\0'; /* note that even in the worst case when there X are no trailing spaces at all, we'll simply X end up replacing the existing '\0' with X another one! No worries, as M.G. would say X */ X} SHAR_EOF chmod 0444 src/string2.c || echo "restore of src/string2.c fails" echo "x - extracting src/strings.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/strings.c && X Xstatic char rcsid[] = "@(#)$Id: strings.c,v 4.1 90/04/28 22:44:16 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: strings.c,v $ X * Revision 4.1 90/04/28 22:44:16 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This file contains all the string oriented functions for the X ELM Mailer, and lots of other generally useful string functions! X X For BSD systems, this file also includes the function "tolower" X to translate the given character from upper case to lower case. X X**/ X X#include "headers.h" X#include X X#ifdef BSD X#undef tolower X#undef toupper X#endif X X/** forward declarations **/ X Xchar *format_long(), *strip_commas(), *tail_of_string(), X *get_token(), *strip_parens(), *argv_zero(), *strcpy(), *strncpy(); X Xchar *index(); X X Xcopy_sans_escape(dest, source, len) Xchar *dest, *source; Xint len; X{ X /** this performs the same function that strncpy() does, but X also will translate any escape character to a printable X format (e.g. ^(char value + 32)) X **/ X X register int i = 0, j = 0; X X while (i < len && source[i] != '\0') { X if (iscntrl(source[i]) && source[i] != '\t') { X dest[j++] = '^'; X dest[j++] = source[i++] + 'A' - 1; X } X else X dest[j++] = source[i++]; X } X X dest[j] = '\0'; X} X X/** X This routine will return true if the "addr" contains the "user" subject X to the following contstraints: (1) either the "user" is at the front X of "addr" or it is preceded by an appropriate meta-char, and (2) X either the "user" is at the end of "addr" or it is suceeded by an X appropriate meta-char. X**/ Xint addr_matches_user(addr,user) Xregister char *addr, *user; X{ X int len = strlen(user); X static char c_before[] = "!:%"; /* these can appear before a username */ X static char c_after[] = ":%@"; /* these can appear after a username */ X X do { X if ( strncmp(addr,user,len) == 0 ) { X if ( addr[len] == '\0' || index(c_after,addr[len]) != NULL ) X return TRUE; X } X } while ( (addr=strpbrk(addr,c_before)) != NULL && *++addr != '\0' ) ; X return FALSE; X} X Xint Xtail_of(from, buffer, to) Xchar *from, *buffer, *to; X{ X /** Return last two words of 'from'. This is to allow X painless display of long return addresses as simply the X machine!username. X Or if the first word of the 'from' address is username or X full_username and 'to' is not NULL, then use the 'to' line X instead of the 'from' line. X If the 'to' line is used, return 1, else return 0. X X Also modified to know about X.400 addresses (sigh) and X that when we ask for the tail of an address similar to X a%b@c we want to get back a@b ... X **/ X X /** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes, X ':' delimits CSNet & Bitnet nodes, '%' delimits multi- X stage ARPA hops, and '/' delimits X.400 addresses... X (it is fortunate that the ASCII character set only has X so many metacharacters, as I think we're probably using X them all!!) **/ X X register int loc, i = 0, cnt = 0, using_to = 0; X X#ifndef INTERNET X X /** let's see if we have an address appropriate for hacking: X what this actually does is remove the spuriously added X local bogus Internet header if we have one and the message X has some sort of UUCP component too... X **/ X X sprintf(buffer, "@%s", hostfullname); X if (chloc(from,'!') != -1 && in_string(from, buffer)) X from[strlen(from)-strlen(buffer)] = '\0'; X X#endif X X /** X Produce a simplified version of the from into buffer. If the X from is just "username" or "Full Username" it will be preserved. X If it is an address, the rightmost "stuff!stuff", "stuff@stuff", X or "stuff:stuff" will be used. X **/ X for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) { X if (from[loc] == BANG || from[loc] == AT_SIGN || X from[loc] == COLON) cnt++; X if (cnt < 2) buffer[i++] = from[loc]; X } X buffer[i] = '\0'; X reverse(buffer); X X#ifdef MMDF X if (strlen(buffer) == 0) { X if(to && *to != '\0') { X tail_of(to, buffer, (char *)0); X using_to = 1; X } else X strcpy(buffer, full_username); X } X#endif /* MMDF */ X X if ( strcmp(buffer,full_username) == 0 || X addr_matches_user(buffer,username) ) { X X /* This message is from the user, so use the "to" header instead X * if possible, to be more informative. Otherwise be nice and X * use full_username rather than the bare username even if X * we've only matched on the bare username. X */ X X if(to && *to != '\0') { X tail_of(to, buffer, (char *)0); X using_to = 1; X } else X strcpy(buffer, full_username); X X } else { /* user%host@host? */ X X /** The logic here is that we're going to use 'loc' as a handy X flag to indicate if we've hit a '%' or not. If we have, X we'll rewrite it as an '@' sign and then when we hit the X REAL at sign (we must have one) we'll simply replace it X with a NULL character, thereby ending the string there. X **/ X X loc = 0; X X for (i=0; buffer[i] != '\0'; i++) X if (buffer[i] == '%') { X buffer[i] = AT_SIGN; X loc++; X } X else if (buffer[i] == AT_SIGN && loc) X buffer[i] = '\0'; X } X return(using_to); X X} X Xchar *format_long(inbuff, init_len) Xchar *inbuff; Xint init_len; X{ X /** Return buffer with \n\t sequences added at each point where it X would be more than 80 chars long. It only allows the breaks at X legal points (ie commas followed by white spaces). init-len is X the characters already on the first line... Changed so that if X this is called while mailing without the overhead of "elm", it'll X include "\r\n\t" instead. X Changed to use ',' as a separator and to REPLACE it after it's X found in the output stream... X **/ X X static char ret_buffer[VERY_LONG_STRING]; X register int iindex = 0, current_length = 0, depth=15, i, len; X char buffer[VERY_LONG_STRING]; X char *word, *bufptr; X X strcpy(buffer, inbuff); X X bufptr = (char *) buffer; X X current_length = init_len + 2; /* for luck */ X X while ((word = get_token(bufptr,",", depth)) != NULL) { X X /* first, decide what sort of separator we need, if any... */ X X if (strlen(word) + current_length > 80) { X if (iindex > 0) { X ret_buffer[iindex++] = ','; /* close 'er up, doctor! */ X ret_buffer[iindex++] = '\n'; X ret_buffer[iindex++] = '\t'; X } X X /* now add this pup! */ X X for (i=(word[0] == ' '? 1:0), len = strlen(word); i 0) { X ret_buffer[iindex++] = ','; /* comma added! */ X ret_buffer[iindex++] = ' '; X current_length += 2; X } X for (i=(word[0] == ' '? 1:0), len = strlen(word); i 1) X buffer[i--] = string[iindex--]; X buffer[2] = '.'; X buffer[1] = '.'; X buffer[0] = '.'; X } X X return( (char *) buffer); X} X Xreverse(string) Xchar *string; X{ X /** reverse string... pretty trivial routine, actually! **/ X X char buffer[SLEN]; X register int i, j = 0; X X for (i = strlen(string)-1; i >= 0; i--) X buffer[j++] = string[i]; X X buffer[j] = '\0'; X X strcpy(string, buffer); X} X Xint Xget_word(buffer, start, word) Xchar *buffer, *word; Xint start; X{ X /** return next word in buffer, starting at 'start'. X delimiter is space or end-of-line. Returns the X location of the next word, or -1 if returning X the last word in the buffer. -2 indicates empty X buffer! **/ X X register int loc = 0; X X while (buffer[start] == ' ' && buffer[start] != '\0') X start++; X X if (buffer[start] == '\0') return(-2); /* nothing IN buffer! */ X X while (buffer[start] != ' ' && buffer[start] != '\0') X word[loc++] = buffer[start++]; X X word[loc] = '\0'; X return(start); X} X XCenterline(line, string) Xint line; Xchar *string; X{ X /** Output 'string' on the given line, centered. **/ X X register int length, col; X X length = strlen(string); X X if (length > COLUMNS) X col = 0; X else X col = (COLUMNS - length) / 2; X X PutLine0(line, col, string); X} X Xchar *argv_zero(string) Xchar *string; X{ X /** given a string of the form "/something/name" return a X string of the form "name"... **/ X X static char buffer[NLEN]; X register int i, j=0; X X for (i=strlen(string)-1; string[i] != '/'; i--) X buffer[j++] = string[i]; X buffer[j] = '\0'; X X reverse(buffer); X X return( (char *) buffer); X} X X#define MAX_RECURSION 20 /* up to 20 deep recursion */ X Xchar *get_token(source, keys, depth) Xchar *source, *keys; Xint depth; X{ X /** This function is similar to strtok() (see "opt_utils") X but allows nesting of calls via pointers... X **/ X X register int last_ch; X static char *buffers[MAX_RECURSION]; X char *return_value, *sourceptr; X X if (depth > MAX_RECURSION) { X error1("Get_token calls nested greater than %d deep!", X MAX_RECURSION); X emergency_exit(); X } X X if (source != NULL) X buffers[depth] = source; X X sourceptr = buffers[depth]; X X if (*sourceptr == '\0') X return(NULL); /* we hit end-of-string last time!? */ X X sourceptr += strspn(sourceptr, keys); /* skip the bad.. */ X X if (*sourceptr == '\0') { X buffers[depth] = sourceptr; X return(NULL); /* we've hit end-of-string */ X } X X last_ch = strcspn(sourceptr, keys); /* end of good stuff */ X X return_value = sourceptr; /* and get the ret */ X X sourceptr += last_ch; /* ...value */ X X if (*sourceptr != '\0') /** don't forget if we're at end! **/ X sourceptr++; X X return_value[last_ch] = '\0'; /* ..ending right */ X X buffers[depth] = sourceptr; /* save this, mate! */ X X return((char *) return_value); /* and we're outta here! */ X} X X Xquote_args(out_string,in_string) Xregister char *out_string, *in_string; X{ X /** Copy from "in_string" to "out_string", collapsing multiple X white space and quoting each word. Returns a pointer to X the resulting word. X **/ X X int empty_string = TRUE; X X while ( *in_string != '\0' ) { X X /** If this is a space then advance to the start of the next word. X Otherwise, copy through the word surrounded by quotes. X **/ X X if ( isspace(*in_string) ) { X while ( isspace(*in_string) ) X ++in_string; X } else { X *out_string++ = '"'; X while ( *in_string != '\0' && !isspace(*in_string) ) X *out_string++ = *in_string++; X *out_string++ = '"'; X *out_string++ = ' '; X empty_string = FALSE; X } X X } X X if ( !empty_string ) X --out_string; X *out_string = '\0'; X} X SHAR_EOF chmod 0444 src/strings.c || echo "restore of src/strings.c fails" echo "x - extracting src/syscall.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/syscall.c && X Xstatic char rcsid[] = "@(#)$Id: syscall.c,v 4.1 90/04/28 22:44:18 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: syscall.c,v $ X * Revision 4.1 90/04/28 22:44:18 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** These routines are used for user-level system calls, including the X '!' command and the '|' commands... X X**/ X X#include "headers.h" X X#include X X#ifdef BSD X# include X#endif X Xchar *argv_zero(); Xvoid _exit(); X X#ifdef ALLOW_SUBSHELL X Xint Xsubshell() X{ X /** spawn a subshell with either the specified command X returns non-zero if screen rewrite needed X **/ X X char command[SLEN]; SHAR_EOF echo "End of part 22" echo "File src/syscall.c is continued in part 23" echo "23" > s2_seq_.tmp exit 0 exit 0 # Just in case...