This is hdrconfg.c in view mode; [Download] [Up]
static char rcsid[] = "@(#)$Id: hdrconfg.c,v 5.2 1992/11/22 01:15:15 syd Exp $"; /******************************************************************************* * The Elm Mail System - $Revision: 5.2 $ $State: Exp $ * * Copyright (c) 1988-1992 USENET Community Trust * Copyright (c) 1986,1987 Dave Taylor ******************************************************************************* * Bug reports, patches, comments, suggestions should be sent to: * * Syd Weinstein, Elm Coordinator * elm@DSI.COM dsinc!elm * ******************************************************************************* * $Log: hdrconfg.c,v $ * Revision 5.2 1992/11/22 01:15:15 syd * Add on initial display or display where the entire screen is being * drawn, we should not output the trailing blanks that clear the old * value. * From: chip@chinacat.unicom.com (Chip Rosenthal) * * Revision 5.1 1992/10/03 22:58:40 syd * Initial checkin as of 2.4 Release at PL0 * * ******************************************************************************/ /** This file contains the routines necessary to be able to modify the mail headers of messages on the way off the machine. The headers currently supported for modification are: Subject: To: Cc: Bcc: Reply-To: Expires: Priority: Precedence: In-Reply-To: Action: <user defined> **/ #include "headers.h" #include "s_elm.h" #include <ctype.h> #ifdef BSD #undef toupper #undef tolower #endif /* * Placement of prompts and messages at the bottom of the screen. */ #define INSTRUCT_LINE (LINES-4) #define INPUT_LINE (LINES-2) #define ERROR_LINE (LINES-1) #define TOPMOST_PROMPTAREA_LINE INSTRUCT_LINE /* * Option flags for the fields in a (struct hdr_menu_item). */ #define HF_DISP_1ROW 0001 /* field is displayed on one line */ #define HF_DISP_2ROW 0002 /* field display spans two lines */ #define HF_DISP_3ROW 0003 /* field display spans three lines */ #define HF_DISP_LEFT 0004 /* field occupies left half of a line */ #define HF_DISP_RIGHT 0005 /* field occupies right half of a line */ #define HF_DISP_MASK 0007 /* -- mask to pull out display option */ #define HF_PROMPT_EXP 0010 /* prompt for expires data entry */ #define HF_PROMPT_USR 0020 /* prompt for user defined hdr entry */ #define HF_PROMPT_MASK 0070 /* -- mask to pull out prompt option */ #define HF_APPENDENTRY 0100 /* append user entry to existing value */ /* * Structure to describe a header which can be edited in this menu. */ struct hdr_menu_item { int menucmd; /* The single keystroke (lower-case letter) the */ /* user strikes to edit this menu item. */ char *hdrname; /* Header name to display in the menu. Parens */ /* should be used to bracket the "menucmd" */ /* char in the name, e.g. "S)ubject". This */ /* will be NULL for the user-defined header. */ int lineno; /* Screen line at which the field is displayed. */ int flags; /* Various flags which effect the display and */ /* user entry of this item. */ char *inpval; /* Pointer to the buffer to hold the value */ /* entered by the user. */ char *expval; /* Pointer to the expanded header value to */ /* display. If no special expansions are */ /* required then this will point to "inpval". */ int (*hdrproc)(); /* Pointer to a procedure which verifies the */ /* user data entry, and if required converts */ /* the "inpval" value to "expval" value. If */ /* no verification or expansion is needed */ /* then this will be NULL. */ }; /* * These are all defined in the mailmsg file. */ extern char subject[SLEN], in_reply_to[SLEN], expires[SLEN], action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], expanded_reply_to[LONG_STRING], expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN], bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING], precedence[SLEN], expires_days[SLEN]; /* * Local procedures. */ static void hdrmenu_clear_promptarea(); static int hdrmenu_get(); static void hdrmenu_put(); static int hdrproc_addr(); static int hdrproc_expires(); static int hdrproc_precedence(); static int hdrproc_userhdr(); static int domainize_submenu(); static void domainize(); static void domainize_addr(); /* * Definition of all the header editing menu fields. */ struct hdr_menu_item hmenu_item_list[] = { { 't', "T)o", 2, HF_DISP_3ROW|HF_APPENDENTRY, to, expanded_to, hdrproc_addr }, { 'c', "C)c", 5, HF_DISP_3ROW|HF_APPENDENTRY, cc, expanded_cc, hdrproc_addr }, { 'b', "B)cc", 8, HF_DISP_2ROW|HF_APPENDENTRY, bcc, expanded_bcc, hdrproc_addr }, { 's', "S)ubject", 10, HF_DISP_2ROW, subject, subject, NULL }, { 'r', "R)eply-to", 12, HF_DISP_1ROW, reply_to, expanded_reply_to, hdrproc_addr }, { 'a', "A)ction", 13, HF_DISP_LEFT, action, action, NULL }, { 'e', "E)xpires", 13, HF_DISP_RIGHT|HF_PROMPT_EXP, expires_days, expires, hdrproc_expires }, { 'p', "P)riority", 14, HF_DISP_LEFT, priority, priority, NULL }, { 'n', "Precede(n)ce", 14, HF_DISP_RIGHT, precedence, precedence, hdrproc_precedence }, { 'i', "I)n-reply-to", 15, HF_DISP_2ROW, in_reply_to, in_reply_to, NULL }, { 'u', NULL, 17, HF_DISP_1ROW|HF_PROMPT_USR, user_defined_header, user_defined_header, hdrproc_userhdr }, { -1, NULL, -1, -1, NULL, NULL, NULL }, }; /* * Selection of individual fields. The indices *must* correspond * to the above "hmenu_item_list[]" list. */ #define hmenu_to (hmenu_item_list[0]) #define hmenu_cc (hmenu_item_list[1]) #define hmenu_bcc (hmenu_item_list[2]) #define hmenu_subject (hmenu_item_list[3]) #define hmenu_replyto (hmenu_item_list[4]) #define hmenu_action (hmenu_item_list[5]) #define hmenu_expires (hmenu_item_list[6]) #define hmenu_priority (hmenu_item_list[7]) #define hmenu_precedence (hmenu_item_list[8]) #define hmenu_inreplyto (hmenu_item_list[9]) #define hmenu_userdef (hmenu_item_list[10]) edit_headers() { int c, i, do_redraw; struct hdr_menu_item *h; /* expand out all of the header values */ /* menu displays expanded values, user edits unexpended versions */ for (h = hmenu_item_list ; h->menucmd > 0 ; ++h) { if (h->hdrproc != NULL) (*h->hdrproc)(h); } clearerr(stdin); do_redraw = TRUE; while (TRUE) { /* forever */ /* redraw the entire display if required */ if (do_redraw) { ClearScreen(); Centerline(0, catgets(elm_msg_cat, ElmSet, ElmHdrmenuScreenTitle, "Message Header Edit Screen")); for (h = hmenu_item_list ; h->menucmd > 0 ; ++h) hdrmenu_put(h, TRUE); do_redraw = FALSE; } /* display the instructions */ #ifdef ALLOW_SUBSHELL Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuInstruct, "Choose header, u)ser defined header, d)omainize, !)shell, or <return>.")); #else Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuInstructNoShell, "Choose header, u)ser defined header, d)omainize, or <return>.")); #endif /* prompt for command */ PutLine0(INPUT_LINE, 0, catgets(elm_msg_cat, ElmSet, ElmHdrmenuPrompt, "Choice: ")); c = getchar(); if (isupper(c)) c = tolower(c); hdrmenu_clear_promptarea(); /* execute the command */ switch (c) { case EOF: case RETURN: case LINE_FEED: case 'q': return 0; case 'd': if (domainize_submenu() != 0) return 0; break; #ifdef ALLOW_SUBSHELL case '!': if (subshell()) do_redraw = TRUE; break; #endif case ctrl('L'): do_redraw = TRUE; break; default: for (h = hmenu_item_list ; h->menucmd > 0 ; ++h) { if (h->menucmd == c) { if (hdrmenu_get(h) != 0) return 0; hdrmenu_put(h, FALSE); break; } } if (h->menucmd <= 0) { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuBadChoice, "No such header!")); Writechar('\007'); } break; } } /*NOTREACHED*/ } /* * Erase instructions, user input, left-over errors, etc. * This should be run after every user input command in this module. */ static void hdrmenu_clear_promptarea() { clear_error(); MoveCursor(TOPMOST_PROMPTAREA_LINE, 0); CleartoEOS(); } /* * Prompt the user for a header value, and do any required post-processing. */ static int hdrmenu_get(h) struct hdr_menu_item *h; { char *s; int plen, ret, do_append; /* display the instructions */ switch (h->flags & HF_PROMPT_MASK) { case HF_PROMPT_EXP: Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuGetExpiresInstruct, "In how many days should this message expire? ")); break; case HF_PROMPT_USR: Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuGetUserdefInstruct, "Enter in the format \"HeaderName: HeaderValue\".")); break; default: Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuGetInstruct, "Enter value for the header.")); break; } /* display a prompt */ plen = 0; if (h->hdrname != NULL) { MoveCursor(INPUT_LINE, 0); for (s = h->hdrname ; *s != '\0' ; ++s) { if (*s != '(' && *s != ')') { Writechar(*s); ++plen; } } Writechar(':'); Writechar(' '); plen += 2; } /* get input from the user */ do_append = ((h->flags & HF_APPENDENTRY) != 0); ret = optionally_enter(h->inpval, INPUT_LINE, plen, do_append, FALSE); hdrmenu_clear_promptarea(); /* bail out on error */ if (ret < 0) return -1; /* see if there is some processing required on this value */ if (h->hdrproc != NULL) (void) (*h->hdrproc)(h); return 0; } /* * Dispay a header and its value in the appropriate field. */ static void hdrmenu_put(h, already_clear) struct hdr_menu_item *h; int already_clear; { char *p; int start_row, max_row, start_col, max_col, row, col; /* figure out the dimensions of the field */ switch (h->flags & HF_DISP_MASK) { case HF_DISP_LEFT: start_row = h->lineno; max_row = h->lineno; start_col = 0; max_col = COLUMNS/2 - 2; break; case HF_DISP_RIGHT: start_row = h->lineno; max_row = h->lineno; start_col = COLUMNS/2 + 1; max_col = COLUMNS-1; break; case HF_DISP_3ROW: start_row = h->lineno; max_row = h->lineno+2; start_col = 0; max_col = COLUMNS-1; break; case HF_DISP_2ROW: start_row = h->lineno; max_row = h->lineno+1; start_col = 0; max_col = COLUMNS-1; break; default: start_row = h->lineno; max_row = h->lineno; start_col = 0; max_col = COLUMNS-1; break; } /* display the header name */ MoveCursor(start_row, start_col); if (h->hdrname != NULL) { for (p = h->hdrname ; *p != '\0' ; ++p) Writechar(*p); Writechar(':'); Writechar(' '); } /* display the header value */ GetXYLocation(&row, &col); for (p = h->expval ; *p != '\0' && row <= max_row ; ++p) { if (row == max_row && col == max_col-4 && strlen(p) > 4) p = " ..."; /* neat hack alert */ Writechar(*p); if (!isprint(*p) || ++col > max_col) GetXYLocation(&row, &col); } /* save some drawing if we know the screen is already empty */ if (!already_clear) { /* clear out remaining space in this line of the field */ if (max_col == COLUMNS-1) { /* people on slow terminals might appreciate doing it this way */ CleartoEOLN(); } else { while (col++ <= max_col) Writechar(' '); } /* for multi-line fields, clear out any unused lines */ /* this assumes that multi-line fields span the entire screen width */ while (++row <= max_row) { /* grrrrrr -- this is a multi-statement macro */ ClearLine(row); } } } /* * Process the to, cc, and bcc headers. The value entered by the * user is expanded. A successful status is always returned. */ static int hdrproc_addr(h) struct hdr_menu_item *h; { (void) build_address(strip_commas(h->inpval), h->expval); return 0; } /* * Process the expires header. The value entered by the user is interpreted * as a number of days, and is expanded out to a date specification. If * an error occurs a message is printed, the expanded value is cleared * out, and a -1 is returned. */ static int hdrproc_expires(h) struct hdr_menu_item *h; { int days; /* initialize expanded date spec to empty */ h->expval[0] = '\0'; /* blank is ok */ if (h->inpval[0] == '\0') return 0; /* verify the number of days is valid and in range */ days = atoi(h->inpval); if (days < 1) { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuExpiresNotNumber, "Expiration must be specified as a number of days.")); return -1; } if (days > 8*7) { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuExpiresOutOfRange, "Expiration date must be within eight weeks of today.")); return -1; } /* convert number of days to a date */ days_ahead(days, h->expval); return 0; } /* * Process the precedence header. The value entered by the user is * checked against the list of allowed precedences, if one exists. If * the precedence has a priority assigned to it, then an empty priority * field will be filled in with that value. If an error occurs a message * is printed, the precedence value is cleared out, and a -1 is returned. */ static int hdrproc_precedence(h) struct hdr_menu_item *h; { char buf[SLEN]; /* assumes sizeof(allowed_precedences) <= SLEN */ char *bp, *prec, *prio; /* empty is ok */ if (h->inpval[0] == '\0') return 0; /* if there are no restrictions on precedence then anything is ok */ if (allowed_precedences[0] == '\0') return 0; /* the "allowed_precedences[]" format is: */ /* precedence[:priority-value] precedence[:priority-value] ... */ bp = strcpy(buf, allowed_precedences); while ((prec = strtok(bp, " \t\n")) != NULL) { bp = NULL; if ((prio = index(prec, ':')) != NULL) *prio++ = '\0'; if (istrcmp(prec, h->inpval) == 0) break; } /* see if we reached the end of the list without a match */ if (prec == NULL) { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuPrecedenceBadValue, "Unknown precedence value specified.")); h->inpval[0] = '\0'; return -1; } /* see if this precedence has an associated priority */ if (prio != NULL && hmenu_priority.inpval[0] == '\0') { (void) strcpy(hmenu_priority.inpval, prio); hdrmenu_put(&hmenu_priority, FALSE); } return 0; } /* * Process the user-defined header. The value entered by the user is * verified for proper format. If an error occurs a message is printed, * the expanded value is cleared out, and a -1 is returned. */ static int hdrproc_userhdr(h) struct hdr_menu_item *h; { char *s; /* empty is ok */ if (h->inpval[0] == '\0') return 0; /* make sure the header name doesn't begin with some strange character */ if (!isalnum(h->inpval[0])) { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuUserdefNotAlnum, "The user-defined header must begin with a letter or number.")); h->inpval[0] = '\0'; return -1; } /* locate the end of the header name */ for (s = h->inpval ; *s != ':' && isprint(*s) && !isspace(*s) ; ++s) ; /* there needs to be a colon at the end of the header name */ if (*s != ':') { Centerline(ERROR_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuUserdefMissingColon, "The user-defined header must have a colon after the field name.")); h->inpval[0] = '\0'; return -1; } return 0; } /* * Prompt the user to domainize a header. */ static int domainize_submenu() { int c; struct hdr_menu_item *h; Centerline(INSTRUCT_LINE, catgets(elm_msg_cat, ElmSet, ElmHdrmenuDomInstruct, "Select header to domainize: T)o, C)c, B)cc, or <return>.")); PutLine0(INPUT_LINE, 0, catgets(elm_msg_cat, ElmSet, ElmHdrmenuDomPrompt, "Domainize choice: ")); for (;;) { c = getchar(); switch ((int)(isupper(c) ? tolower(c) : c)) { case 't': h = &hmenu_to; break; case 'c': h = &hmenu_cc; break; case 'b': h = &hmenu_bcc; break; case '\r': case '\n': case EOF: h = NULL; break; default: Writechar('\007'); continue; } if (h != NULL) { domainize(h->expval); hdrmenu_put(h, FALSE); } hdrmenu_clear_promptarea(); return (c == EOF ? -1 : 0); } /*NOTREACHED*/ } static void domainize(addresses) char *addresses; { /*** Convert the given addresses from bang paths to domain format. This policy amounts to Rabid Rerouting. However, since it's under the sender's control, I don't mind. ***/ char buffer[VERY_LONG_STRING]; char *a, *d; int how_many; strcpy(buffer, addresses); a = buffer; d = addresses; how_many = 0; for (;;) { while (*a == ' ' || *a == ',') ++a; if (*a == '\0') break; if (*a == '(' || *a == '"') { int endch; if (d != addresses) *d++ = ' '; endch = (*a == '(') ? ')' : '"'; while (*a && *a != endch) { if (*a == '\\' && *(a + 1)) *d++ = *a++; *d++ = *a++; } if (*a) *d++ = *a++; } else { char *addr; if (how_many) { *d++ = ','; *d++ = ' '; } ++how_many; if (*a == '<') { *d++ = *a++; addr = a; while (*a && *a != '>') { if (*a == '\\' && *(a + 1)) ++a; ++a; } if (*a) *a++ = '\0'; domainize_addr(addr, d); d += strlen(d); *d++ = '>'; } else { addr = a; while (*a && *a != ' ' && *a != ',') ++a; if (*a) *a++ = '\0'; domainize_addr(addr, d); d += strlen(d); } } } *d = '\0'; } static void domainize_addr(src, dest) char *src, *dest; { /*** Convert one address to domain form. ***/ char *locpart, *host; if (index(src, '@') != NULL || (locpart = rindex(src, '!')) == NULL) { strcpy(dest, src); return; } *locpart++ = '\0'; if ((host = rindex(src, '!')) != NULL) ++host; else host = src; sprintf(dest, "%s@%s", locpart, host); if (!index(host, '.')) strcat(dest, ".uucp"); *--locpart = '!'; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.