about summary refs log tree commit diff stats
path: root/src/LYMail.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYMail.c')
-rw-r--r--src/LYMail.c1122
1 files changed, 880 insertions, 242 deletions
diff --git a/src/LYMail.c b/src/LYMail.c
index 59d8deb6..e56c0ec6 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -35,6 +35,8 @@ PUBLIC void mailform ARGS4(
 {
     FILE *fd;
     char *address = NULL;
+    char *ccaddr = NULL;
+    char *keywords = NULL;
     char *searchpart = NULL;
     char *cp = NULL, *cp0 = NULL, *cp1 = NULL;
     char subject[80];
@@ -42,9 +44,17 @@ PUBLIC void mailform ARGS4(
     char cmd[512];
     int len, i, ch;
 #if defined(VMS) || defined(DOSPATH)
-    char my_tempfile[256];
+    char my_tmpfile[256];
     char *address_ptr1, *address_ptr2;
+    char *command = NULL;
     BOOLEAN first = TRUE;
+    BOOLEAN isPMDF = FALSE;
+    char hdrfile[256];
+    FILE *hfd;
+
+    if (!strncasecomp(system_mail, "PMDF SEND", 9)) {
+	isPMDF = TRUE;
+    }
 #endif /* VMS */
 
     if (!mailto_address || !mailto_content) {
@@ -63,17 +73,17 @@ PUBLIC void mailform ARGS4(
      */
     if ((cp = strchr(address, '?')) != NULL) {
 	StrAllocCopy(searchpart, cp);
-        *cp = '\0';
+	*cp = '\0';
 	cp = (searchpart + 1);
 	if (*cp != '\0') {
 	    /*
 	     *  Seek and handle a subject=foo. - FM
 	     */
 	    while (*cp != '\0') {
-	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
 		    !strncasecomp(cp, "subject=", 8))
 		    break;
-	        cp++;
+		cp++;
 	    }
 	    if (*cp) {
 		cp += 8;
@@ -81,9 +91,8 @@ PUBLIC void mailform ARGS4(
 		    *cp1 = '\0';
 		}
 		if (*cp) {
-		    strncpy(subject, cp, 70);
-		    subject[70] = '\0';
 		    HTUnEscape(subject);
+		    LYstrncpy(subject, cp, 70);
 		}
 		if (cp1) {
 		    *cp1 = '&';
@@ -92,33 +101,107 @@ PUBLIC void mailform ARGS4(
 	    }
 
 	    /*
-	     *  Seek and handle cc=foo fields.  Excludes Bcc=foo
-	     *  and appends to address, so we can use our own cc
-	     *  field for the actual mailing. - FM
+	     *  Seek and handle to=address(es) fields.
+	     *  Appends to address. - FM
 	     */
 	    cp = (searchpart + 1);
 	    while (*cp != '\0') {
-	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
-		    !strncasecomp(cp, "cc=", 3)) {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "to=", 3)) {
 		    cp += 3;
 		    if ((cp1 = strchr(cp, '&')) != NULL) {
-		        *cp1 = '\0';
+			*cp1 = '\0';
 		    }
-		    while (*cp == ',')
-		        cp++;
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
 		    if (*cp) {
-			StrAllocCat(address, ",");
+			if (*address) {
+			    StrAllocCat(address, ",");
+			}
 			StrAllocCat(address, cp);
 		    }
 		    if (cp1) {
-		        *cp1 = '&';
+			*cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+			break;
+		    }
+		}
+		cp++;
+	    }
+
+	    /*
+	     *  Seek and handle cc=address(es) fields.  Excludes
+	     *  Bcc=address(es) as unsafe.  We may append our own
+	     *  cc (below) as a list for the actual mailing. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "cc=", 3)) {
+		    cp += 3;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+			*cp1 = '\0';
+		    }
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp) {
+			if (ccaddr == NULL) {
+			    StrAllocCopy(ccaddr, cp);
+			} else {
+			    StrAllocCat(ccaddr, ",");
+			    StrAllocCat(ccaddr, cp);
+			}
+		    }
+		    if (cp1) {
+			*cp1 = '&';
 			cp = cp1;
 			cp1 = NULL;
 		    } else {
-		        break;
+			break;
 		    }
 		}
-	        cp++;
+		cp++;
+	    }
+
+	    /*
+	     *  Seek and handle keywords=term(s) fields. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "keywords=", 9)) {
+		    cp += 9;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+			*cp1 = '\0';
+		    }
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp) {
+			if (keywords == NULL) {
+			    StrAllocCopy(keywords, cp);
+			} else {
+			    StrAllocCat(keywords, cp);
+			    StrAllocCat(keywords, ", ");
+			}
+		    }
+		    if (cp1) {
+			*cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+			break;
+		    }
+		}
+		cp++;
+	    }
+	    if (keywords != NULL) {
+		if (*keywords != '\0') {
+		    HTUnEscape(keywords);
+		} else {
+		    FREE(keywords);
+		}
 	    }
 
 	    FREE(searchpart);
@@ -126,11 +209,6 @@ PUBLIC void mailform ARGS4(
     }
 
     /*
-     *  Unescape the address field. - FM
-     */
-    HTUnEscape(address);
-
-    /*
      * Convert any Explorer semi-colon Internet address
      * separators to commas. - FM
      */
@@ -143,18 +221,51 @@ PUBLIC void mailform ARGS4(
 	}
 	cp = cp1;
     }
+    if (address[(strlen(address) - 1)] == ',')
+	address[(strlen(address) - 1)] = '\0';
+    if (*address == '\0') {
+	FREE(address);
+	FREE(ccaddr);
+	FREE(keywords);
+	HTAlert(BAD_FORM_MAILTO);
+	return;
+    }
+    if (ccaddr != NULL) {
+	cp = ccaddr;
+	while ((cp1 = strchr(cp, '@')) != NULL) {
+	    cp1++;
+	    if ((cp0 = strchr(cp1, ';')) != NULL) {
+		*cp0 = ',';
+		cp1 = cp0 + 1;
+	    }
+	    cp = cp1;
+	}
+	if (ccaddr[(strlen(ccaddr) - 1)] == ',') {
+	    ccaddr[(strlen(ccaddr) - 1)] = '\0';
+	}
+	if (*ccaddr == '\0') {
+	    FREE(ccaddr);
+	}
+    }
+
+    /*
+     *  Unescape the address and ccaddr fields. - FM
+     */
+    HTUnEscape(address);
+    if (ccaddr != NULL) {
+	HTUnEscape(ccaddr);
+    }
 
     /*
      *  Allow user to edit the default Subject - FM
      */
     if (subject[0] == '\0') {
-        if (mailto_subject && *mailto_subject) {
-	    strncpy(subject, mailto_subject, 70);
+	if (mailto_subject && *mailto_subject) {
+	    LYstrncpy(subject, mailto_subject, 70);
 	} else {
 	    strcpy(subject, "mailto:");
-	    strncpy((char*)&subject[7], address, 63);
+	    LYstrncpy((char*)&subject[7], address, 63);
 	}
-	subject[70] = '\0';
     }
     _statusline(SUBJECT_PROMPT);
     if ((ch = LYgetstr(subject, VISIBLE, 71, NORECALL)) < 0) {
@@ -164,6 +275,8 @@ PUBLIC void mailform ARGS4(
 	_statusline(FORM_MAILTO_CANCELLED);
 	sleep(InfoSecs);
 	FREE(address);
+	FREE(ccaddr);
+	FREE(keywords);
 	return;
     }
 
@@ -172,8 +285,8 @@ PUBLIC void mailform ARGS4(
      *  entry, if permitted. - FM
      */
     if (!LYNoCc) {
-	sprintf(self,"%.79s", (personal_mail_address ? 
-			       personal_mail_address : ""));
+	sprintf(self, "%.79s", (personal_mail_address ?
+				personal_mail_address : ""));
 	self[79] = '\0';
 	_statusline("Cc: ");
 	if ((ch = LYgetstr(self, VISIBLE, sizeof(self), NORECALL)) < 0) {
@@ -183,29 +296,60 @@ PUBLIC void mailform ARGS4(
 	    _statusline(FORM_MAILTO_CANCELLED);
 	    sleep(InfoSecs);
 	    FREE(address);
+	    FREE(ccaddr);
+	    FREE(keywords);
 	    return;
 	}
+	remove_tildes(self);
+	if (ccaddr == NULL) {
+	    StrAllocCopy(ccaddr, self);
+	} else {
+	    StrAllocCat(ccaddr, ",");
+	    StrAllocCat(ccaddr, self);
+	}
     }
 
 #if defined(VMS) || defined(DOSPATH)
-    sprintf(my_tempfile, "%s%s", lynx_temp_space, "temp_mail.txt");
-    if ((fd = LYNewTxtFile(my_tempfile)) == NULL) {
+    tempname(my_tmpfile, NEW_FILE);
+    if (((cp = strrchr(my_tmpfile, '.')) != NULL) &&
+	NULL == strchr(cp, ']') &&
+	NULL == strchr(cp, '/')) {
+	*cp = '\0';
+	strcat(my_tmpfile, ".txt");
+    }
+    if ((fd = LYNewTxtFile(my_tmpfile)) == NULL) {
 	HTAlert(FORM_MAILTO_FAILED);
 	FREE(address);
+	FREE(ccaddr);
+	FREE(keywords);
 	return;
     }
-    if (*self) {
-        cp = self;
-	while (*cp == ' ' || *cp == ',')
-	    cp++;
-	if (*cp) {
-	    StrAllocCat(address, ",");
-	    StrAllocCat(address, cp);
+    if (isPMDF) {
+	tempname(hdrfile, NEW_FILE);
+	if (((cp = strrchr(hdrfile, '.')) != NULL) &&
+	    NULL == strchr(cp, ']') &&
+	    NULL == strchr(cp, '/')) {
+	    *cp = '\0';
+	    strcat(hdrfile, ".txt");
+	}
+	if ((hfd = LYNewTxtFile(hdrfile)) == NULL) {
+	    HTAlert(FORM_MAILTO_FAILED);
+	    FREE(address);
+	    FREE(ccaddr);
+	    FREE(keywords);
+	    return;
 	}
     }
 #ifdef VMS
-    if (mailto_type &&
-        !strncasecomp(mailto_type, "multipart/form-data", 19)) {
+    if (isPMDF) {
+	if (mailto_type && *mailto_type) {
+	    fprintf(hfd, "Mime-Version: 1.0\n");
+	    fprintf(hfd, "Content-Type: %s\n", mailto_type);
+	    if (personal_mail_address && *personal_mail_address)
+		fprintf(hfd, "From: %s\n", personal_mail_address);
+	    }
+    } else if (mailto_type &&
+	       !strncasecomp(mailto_type, "multipart/form-data", 19)) {
 	/*
 	 *  Ugh!  There's no good way to include headers while
 	 *  we're still using "generic" VMS MAIL, so we'll put
@@ -227,10 +371,11 @@ PUBLIC void mailform ARGS4(
 
 #else
     sprintf(cmd, "%s %s", system_mail, system_mail_flags);
-
     if ((fd = popen(cmd, "w")) == NULL) {
 	HTAlert(FORM_MAILTO_FAILED);
 	FREE(address);
+	FREE(ccaddr);
+	FREE(keywords);
 	return;
     }
 
@@ -238,13 +383,14 @@ PUBLIC void mailform ARGS4(
 	fprintf(fd, "Mime-Version: 1.0\n");
 	fprintf(fd, "Content-Type: %s\n", mailto_type);
     }
-    fprintf(fd,"To: %s\n", address);
+    fprintf(fd, "To: %s\n", address);
     if (personal_mail_address && *personal_mail_address)
-	fprintf(fd,"From: %s\n", personal_mail_address);
-    remove_tildes(self);
-    if (*self)
-	fprintf(fd,"Cc: %s\n", self);
-    fprintf(fd,"Subject: %.70s\n\n", subject);
+	fprintf(fd, "From: %s\n", personal_mail_address);
+    if (ccaddr != NULL && *ccaddr != '\0')
+	fprintf(fd, "Cc: %s\n", ccaddr);
+    fprintf(fd, "Subject: %s\n\n", subject);
+    if (keywords != NULL && *keywords != '\0')
+	fprintf(fd, "Keywords: %s\n", keywords);
     _statusline(SENDING_FORM_CONTENT);
 #endif /* VMS */
 
@@ -256,7 +402,7 @@ PUBLIC void mailform ARGS4(
      */
     while((cp = strchr(mailto_content, '\n')) != NULL) {
 	*cp = '\0';
-        i = 0;
+	i = 0;
 	len = strlen(mailto_content);
 	while (len > 78) {
 	    strncpy(cmd, (char *)&mailto_content[i], 78);
@@ -287,40 +433,125 @@ PUBLIC void mailform ARGS4(
 #if defined(VMS) || defined(DOSPATH)
     fclose(fd);
 #ifdef VMS
-    sprintf(cmd, "%s %s/subject=\"%.70s\" %s ",
-    		 system_mail,
-		 (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
-		 subject, my_tempfile);
+    /*
+     *  Set the mail command. - FM
+     */
+    if (isPMDF) {
+	/*
+	 *  For PMDF, put any keywords and the subject
+	 *  in the header file and close it. - FM
+	 */
+	if (keywords != NULL && *keywords != '\0') {
+	    fprintf(hfd, "Keywords: %s\n", keywords);
+	}
+	fprintf(hfd, "Subject: %s\n\n", subject);
+	fclose(hfd);
+	/*
+	 *  Now set up the command. - FM
+	 */
+	sprintf(cmd,
+		"%s %s %s,%s ",
+		system_mail,
+		system_mail_flags,
+		hdrfile,
+		my_tmpfile);
+    } else {
+	/*
+	 *  For "generic" VMS MAIL, include the subject in the
+	 *  command, and ignore any keywords to minimize risk
+	 *  of them making the line too long or having problem
+	 *  characters. - FM
+	 */
+	sprintf(cmd,
+		"%s %s%s/subject=\"%s\" %s ",
+		system_mail,
+		system_mail_flags,
+		(strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
+		subject,
+		my_tmpfile);
+    }
+    StrAllocCopy(command, cmd);
 
+    /*
+     *  Now add all the people in the address field. - FM
+     */
     address_ptr1 = address;
     do {
 	if ((cp = strchr(address_ptr1, ',')) != NULL) {
 	    address_ptr2 = (cp+1);
 	    *cp = '\0';
-	} else
+	} else {
 	    address_ptr2 = NULL;
+	}
 
-	if (strlen(address) > 3) {
-	    if (!first)
-		strcat(cmd, ",");  /* add a comma */
-	    sprintf( &cmd[strlen(cmd)], mail_adrs, address_ptr1);
+	/*
+	 *  4 letters is arbitrarily the smallest posible mail
+	 *  address, at least for lynx.  That way extra spaces
+	 *  won't confuse the mailer and give a blank address.
+	 */
+	if (strlen(address_ptr1) > 3) {
+	    if (!first) {
+		StrAllocCat(command, ",");
+	    }
+	    sprintf(cmd, mail_adrs, address_ptr1);
+	    StrAllocCat(command, cmd);
 	    first = FALSE;
 	}
-
 	address_ptr1 = address_ptr2;
     } while (address_ptr1 != NULL);
-#else
-	 sprintf(cmd, "%s -t \"%s\" -F %s", system_mail, address, my_tempfile);
-#endif
+
+    /*
+     *  Now add all the people in the CC field. - FM
+     */
+    if (ccaddr != NULL && *ccaddr != '\0') {
+	address_ptr1 = ccaddr;
+	do {
+	    if ((cp = strchr(address_ptr1, ',')) != NULL) {
+		address_ptr2 = (cp+1);
+		*cp = '\0';
+	    } else {
+		address_ptr2 = NULL;
+	    }
+
+	    /*
+	     *  4 letters is arbitrarily the smallest possible mail
+	     *  address, at least for lynx.  That way extra spaces
+	     *  won't confuse the mailer and give a blank address.
+	     */
+	    if (strlen(address_ptr1) > 3) {
+		StrAllocCat(command, ",");
+		sprintf(cmd, mail_adrs, address_ptr1);
+		if (isPMDF) {
+		    strcat(cmd, "/CC");
+		}
+		StrAllocCat(command, cmd);
+	    }
+	    address_ptr1 = address_ptr2;
+	} while (address_ptr1 != NULL);
+    }
+
+    stop_curses();
+    printf("Sending form content:\n\n$ %s\n\nPlease wait...", command);
+    system(command);
+    FREE(command);
+    sleep(AlertSecs);
+    start_curses();
+    remove(my_tmpfile);
+    remove(hdrfile);
+#else /* DOSPATH */
+    sprintf(cmd, "%s -t \"%s\" -F %s", system_mail, address, my_tmpfile);
     stop_curses();
     printf("Sending form content:\n\n$ %s\n\nPlease wait...", cmd);
     system(cmd);
     sleep(MessageSecs);
     start_curses();
-    remove(my_tempfile);
+    remove(my_tmpfile);
+#endif
 #endif /* VMS */
 
     FREE(address);
+    FREE(ccaddr);
+    FREE(keywords);
     return;
 }
 
@@ -328,34 +559,80 @@ PUBLIC void mailform ARGS4(
 **  mailmsg() sends a message to the owner of the file, if one is defined,
 **  telling of errors (i.e., link not available).
 */
-PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, 
-		char *,filename, char *,linkname)
+PUBLIC void mailmsg ARGS4(
+	int,		cur,
+	char *,		owner_address,
+	char *,		filename,
+	char *,		linkname)
 {
     FILE *fd, *fp;
     char *address = NULL;
+    char *searchpart = NULL;
     char cmd[512], *cp, *cp0, *cp1;
 #if defined(VMS) || defined(DOSPATH)
-    char my_tempfile[256];
+    char my_tmpfile[256];
     char *address_ptr1, *address_ptr2;
+    char *command = NULL;
     BOOLEAN first = TRUE;
+    BOOLEAN isPMDF = FALSE;
+    char hdrfile[256];
+    FILE *hfd;
+
+    if (!strncasecomp(system_mail, "PMDF SEND", 9)) {
+	isPMDF = TRUE;
+    }
 #endif /* VMS */
 
+    if (owner_address == NULL || *owner_address == '\0') {
+	return;
+    }
     if ((cp = (char *)strchr(owner_address,'\n')) != NULL)
 	*cp = '\0';
     StrAllocCopy(address, owner_address);
 
     /*
-     *  Check for a ?searchpart and trim it. - FM
+     *  Check for a ?searchpart. - FM
      */
-    if ((cp = strchr(address, '?')) != NULL)
+    if ((cp = strchr(address, '?')) != NULL) {
+	StrAllocCopy(searchpart, cp);
 	*cp = '\0';
+	cp = (searchpart + 1);
+	if (*cp != '\0') {
+	    /*
+	     *  Seek and handle to=address(es) fields.
+	     *  Appends to address.  We ignore any other
+	     *  headers in the ?searchpart. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "to=", 3)) {
+		    cp += 3;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+			*cp1 = '\0';
+		    }
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp) {
+			if (*address) {
+			    StrAllocCat(address, ",");
+			}
+			StrAllocCat(address, cp);
+		    }
+		    if (cp1) {
+			*cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+			break;
+		    }
+		}
+		cp++;
+	    }
+	}
+    }
 
     /*
-     *  Unescape the address field. - FM
-     */
-    HTUnEscape(address);
-	
-    /*
      *  Convert any Explorer semi-colon Internet address
      *  separators to commas. - FM
      */
@@ -369,39 +646,97 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 	cp = cp1;
     }
 
+    /*
+     *  Unescape the address field. - FM
+     */
+    HTUnEscape(address);
+    if (address[(strlen(address) - 1)] == ',')
+	address[(strlen(address) - 1)] = '\0';
+    if (*address == '\0') {
+	FREE(address);
+	if (TRACE) {
+	    fprintf(stderr,
+		    "mailmsg: No address in '%s'.\n",
+		    owner_address);
+	}
+	return;
+    }
+
 #ifdef UNIX
     sprintf(cmd, "%s %s", system_mail, system_mail_flags);
-
     if ((fd = popen(cmd, "w")) == NULL) {
 	FREE(address);
+	if (TRACE) {
+	    fprintf(stderr,
+		    "mailmsg: '%s' failed.\n",
+		    cmd);
+	}
 	return;
     }
 
-    fprintf(fd,"To: %s\n", address);
-    fprintf(fd,"Subject: Lynx Error in %s\n", filename);
-    fprintf(fd,"X-URL: %s\n", filename);
-    fprintf(fd,"X-Mailer: Lynx, Version %s\n\n", LYNX_VERSION);
+    fprintf(fd, "To: %s\n", address);
+    fprintf(fd, "Subject: Lynx Error in %s\n", filename);
+    if (personal_mail_address != NULL && *personal_mail_address != '\0') {
+	fprintf(fd, "Cc: %s\n", personal_mail_address);
+    }
+    fprintf(fd, "X-URL: %s\n", filename);
+    fprintf(fd, "X-Mailer: Lynx, Version %s\n\n", LYNX_VERSION);
 #endif /* UNIX */
 #if defined(VMS) || defined(DOSPATH)
-    sprintf(my_tempfile, "%s%s", lynx_temp_space, "temp_mail.txt");
-    if ((fd = LYNewTxtFile(my_tempfile)) == NULL) {
+    tempname(my_tmpfile, NEW_FILE);
+    if (((cp = strrchr(my_tmpfile, '.')) != NULL) &&
+	NULL == strchr(cp, ']') &&
+	NULL == strchr(cp, '/')) {
+	*cp = '\0';
+	strcat(my_tmpfile, ".txt");
+    }
+    if ((fd = LYNewTxtFile(my_tmpfile)) == NULL) {
+	if (TRACE) {
+	    fprintf(stderr,
+		    "mailmsg: Could not fopen '%s'.\n",
+		    my_tmpfile);
+	}
 	FREE(address);
 	return;
     }
+    if (isPMDF) {
+	tempname(hdrfile, NEW_FILE);
+	if (((cp = strrchr(hdrfile, '.')) != NULL) &&
+	    NULL == strchr(cp, ']') &&
+	    NULL == strchr(cp, '/')) {
+	    *cp = '\0';
+	    strcat(hdrfile, ".txt");
+	}
+	if ((hfd = LYNewTxtFile(hdrfile)) == NULL) {
+	    if (TRACE) {
+		fprintf(stderr,
+			"mailmsg: Could not fopen '%s'.\n",
+			hdrfile);
+	    }
+	    FREE(address);
+	    return;
+	}
+
+	if (personal_mail_address != NULL && *personal_mail_address != '\0') {
+	    fprintf(fd, "Cc: %s\n", personal_mail_address);
+	}
+	fprintf(fd, "X-URL: %s\n", filename);
+	fprintf(fd, "X-Mailer: Lynx, Version %s\n\n", LYNX_VERSION);
+    }
 #endif /* VMS */
 
     fprintf(fd, "The link   %s :?: %s \n",
-    		links[cur].lname, links[cur].target);
+		links[cur].lname, links[cur].target);
     fprintf(fd, "called \"%s\"\n", links[cur].hightext);
     fprintf(fd, "in the file \"%s\" called \"%s\"", filename, linkname);
 
-    fputs("\nwas requested but was not available.",fd);
-    fputs("\n\nThought you might want to know.",fd);
+    fputs("\nwas requested but was not available.", fd);
+    fputs("\n\nThought you might want to know.", fd);
 
     fputs("\n\nThis message was automatically generated by\n", fd);
     fprintf(fd, "Lynx ver. %s", LYNX_VERSION);
     if ((LynxSigFile != NULL) &&
-        (fp = fopen(LynxSigFile, "r")) != NULL) {
+	(fp = fopen(LynxSigFile, "r")) != NULL) {
 	fputs("-- \n", fd);
 	while (fgets(cmd, sizeof(cmd), fp) != NULL)
 	    fputs(cmd, fd);
@@ -413,9 +748,35 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 #if defined(VMS) || defined(DOSPATH)
     fclose(fd);
 #ifdef VMS
-    sprintf(cmd, "%s /subject=\"Lynx Error in %s\" %s ",
-    		 system_mail, filename, my_tempfile);
-
+    if (isPMDF) {
+	/*
+	 *  For PMDF, put the subject in the
+	 *  header file and close it. - FM
+	 */
+	fprintf(hfd, "Subject: Lynx Error in %.56s\n\n", filename);
+	fclose(hfd);
+	/*
+	 *  Now set up the command. - FM
+	 */
+	sprintf(cmd,
+		"%s %s %s,%s ",
+		system_mail,
+		system_mail_flags,
+		hdrfile,
+		my_tmpfile);
+    } else {
+	/*
+	 *  For "generic" VMS MAIL, include the
+	 *  subject in the command. - FM
+	 */
+	sprintf(cmd,
+		"%s %s/self/subject=\"Lynx Error in %.56s\" %s ",
+		system_mail,
+		system_mail_flags,
+		filename,
+		my_tmpfile);
+    }
+    StrAllocCopy(command, cmd);
     address_ptr1 = address;
     do {
 	if ((cp = strchr(address_ptr1, ',')) != NULL) {
@@ -425,20 +786,27 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 	    address_ptr2 = NULL;
 
 	if (strlen(address) > 3) {
-	    if (!first)
-		strcat(cmd, ",");  /* add a comma */
-	    sprintf(&cmd[strlen(cmd)], mail_adrs, address_ptr1);
+	    if (!first) {
+		StrAllocCat(command, ",");
+	    }
+	    sprintf(cmd, mail_adrs, address_ptr1);
+	    StrAllocCat(command, cmd);
 	    first = FALSE;
 	}
-
 	address_ptr1 = address_ptr2;
     } while (address_ptr1 != NULL);
 
-#else
-	 sprintf(cmd, "%s -t \"%s\" -F %s", system_mail, address, my_tempfile);
-#endif
+    system(command);
+    FREE(command);
+    remove(my_tmpfile);
+    if (isPMDF) {
+	remove(hdrfile);
+    }
+#else /* DOSPATH */
+    sprintf(cmd, "%s -t \"%s\" -F %s", system_mail, address, my_tmpfile);
     system(cmd);
-    remove(my_tempfile);
+    remove(my_tmpfile);
+#endif
 #endif /* VMS */
 
     if (traversal) {
@@ -459,7 +827,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 		    (void) signal(SIGTSTP,SIG_DFL);
 #endif /* SIGTSTP */
 		exit(-1);
-            }
+	    }
 	}
 
 	fprintf(ofp, "%s\t%s \tin %s\n",
@@ -473,7 +841,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 
 /*
 **  reply_by_mail() invokes sendmail on Unix or mail on VMS to send
-**  a comment  from the users to the owner 
+**  a comment  from the users to the owner
 */
 PUBLIC void reply_by_mail ARGS3(
 	char *,		mail_address,
@@ -483,21 +851,31 @@ PUBLIC void reply_by_mail ARGS3(
     char user_input[1000];
     FILE *fd, *fp;
     char *address = NULL;
+    char *ccaddr = NULL;
+    char *keywords = NULL;
     char *searchpart = NULL;
     char *body = NULL;
     char *cp = NULL, *cp0 = NULL, *cp1 = NULL;
     char *temp = NULL;
     int i, len;
     int c = 0;  /* user input */
-    char my_tempfile[256], cmd[512];
+    char my_tmpfile[256], cmd[512];
 #ifdef DOSPATH
-	 char tmpfile2[256];
+    char tmpfile2[256];
 #endif
     static char *personal_name = NULL;
     char subject[80];
 #ifdef VMS
     char *address_ptr1 = NULL, *address_ptr2 = NULL;
+    char *command = NULL;
     BOOLEAN first = TRUE;
+    BOOLEAN isPMDF = FALSE;
+    char hdrfile[256];
+    FILE *hfd;
+
+    if (!strncasecomp(system_mail, "PMDF SEND", 9)) {
+	isPMDF = TRUE;
+    }
 #else
     char buf[512];
     char *header = NULL;
@@ -513,19 +891,34 @@ PUBLIC void reply_by_mail ARGS3(
 	return;
     }
 
-    tempname(my_tempfile,NEW_FILE);
-    if (((cp = strrchr(my_tempfile, '.')) != NULL) &&
+    tempname(my_tmpfile, NEW_FILE);
+    if (((cp = strrchr(my_tmpfile, '.')) != NULL) &&
 #ifdef VMS
 	NULL == strchr(cp, ']') &&
 #endif /* VMS */
 	NULL == strchr(cp, '/')) {
 	*cp = '\0';
-	strcat(my_tempfile, ".txt");
+	strcat(my_tmpfile, ".txt");
     }
-    if ((fd = LYNewTxtFile(my_tempfile)) == NULL) {
+    if ((fd = LYNewTxtFile(my_tmpfile)) == NULL) {
 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
 	return;
     }
+#ifdef VMS
+    if (isPMDF) {
+	tempname(hdrfile, NEW_FILE);
+	if (((cp = strrchr(hdrfile, '.')) != NULL) &&
+	    NULL == strchr(cp, ']') &&
+	    NULL == strchr(cp, '/')) {
+	    *cp = '\0';
+	    strcat(hdrfile, ".txt");
+	}
+	if ((hfd = LYNewTxtFile(hdrfile)) == NULL) {
+	    HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
+	    return;
+	}
+    }
+#endif /* VMS */
     subject[0] = '\0';
 
     /*
@@ -540,10 +933,10 @@ PUBLIC void reply_by_mail ARGS3(
 	     *  Seek and handle a subject=foo. - FM
 	     */
 	    while (*cp != '\0') {
-	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
 		    !strncasecomp(cp, "subject=", 8))
 		    break;
-	        cp++;
+		cp++;
 	    }
 	    if (*cp) {
 		cp += 8;
@@ -562,33 +955,108 @@ PUBLIC void reply_by_mail ARGS3(
 	    }
 
 	    /*
-	     *  Seek and handle cc=foo fields.  Excludes Bcc=foo
-	     *  and appends to address, so we can use our own cc
-	     *  field for the actual mailing. - FM
+	     *  Seek and handle to=address(es) fields.
+	     *  Appends to address. - FM
 	     */
 	    cp = (searchpart + 1);
 	    while (*cp != '\0') {
-	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
-		    !strncasecomp(cp, "cc=", 3)) {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "to=", 3)) {
 		    cp += 3;
 		    if ((cp1 = strchr(cp, '&')) != NULL) {
-		        *cp1 = '\0';
+			*cp1 = '\0';
 		    }
-		    while (*cp == ',')
-		        cp++;
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
 		    if (*cp) {
-		        StrAllocCat(address, ",");
+			if (*address) {
+			    StrAllocCat(address, ",");
+			}
 			StrAllocCat(address, cp);
 		    }
 		    if (cp1) {
-		        *cp1 = '&';
+			*cp1 = '&';
 			cp = cp1;
 			cp1 = NULL;
 		    } else {
-		        break;
+			break;
 		    }
 		}
-	        cp++;
+		cp++;
+	    }
+
+	    /*
+	     *  Seek and handle cc=address(es) fields.  Excludes
+	     *  Bcc=address(es) as unsafe.  We may append our own
+	     *  cc (below) as a list for the actual mailing. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "cc=", 3)) {
+		    cp += 3;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+			*cp1 = '\0';
+		    }
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp) {
+			if (ccaddr == NULL) {
+			    StrAllocCopy(ccaddr, cp);
+			} else {
+			    StrAllocCat(ccaddr, ",");
+			    StrAllocCat(ccaddr, cp);
+			}
+		    }
+		    if (cp1) {
+			*cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+			break;
+		    }
+		}
+		cp++;
+	    }
+
+	    /*
+	     *  Seek and handle keywords=term(s) fields. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "keywords=", 9)) {
+		    cp += 9;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+			*cp1 = '\0';
+		    }
+		    while (*cp == ',' || isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp) {
+			if (keywords == NULL) {
+			    StrAllocCopy(keywords, cp);
+			} else {
+			    StrAllocCat(keywords, cp);
+			    StrAllocCat(keywords, ", ");
+			}
+			StrAllocCat(keywords, cp);
+		    }
+		    if (cp1) {
+			*cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+			break;
+		    }
+		}
+		cp++;
+	    }
+	    if (keywords != NULL) {
+		if (*keywords != '\0') {
+		    HTUnEscape(keywords);
+		} else {
+		    FREE(keywords);
+		}
 	    }
 
 	    /*
@@ -596,24 +1064,24 @@ PUBLIC void reply_by_mail ARGS3(
 	     */
 	    cp = (searchpart + 1);
 	    while (*cp != '\0') {
-	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
 		    !strncasecomp(cp, "body=", 5)) {
 		    cp += 5;
 		    if ((cp1 = strchr(cp, '&')) != NULL) {
-		        *cp1 = '\0';
+			*cp1 = '\0';
 		    }
 		    if (*cp) {
 			/*
 			 *  Break up the value into lines with
 			 *  a maximimum length of 78. - FM
 			 */
-		        StrAllocCopy(temp, cp);
+			StrAllocCopy(temp, cp);
 			HTUnEscape(temp);
 			cp0 = temp;
 			while((cp = strchr(cp0, '\n')) != NULL) {
 			    *cp = '\0';
 			    if (cp > cp0) {
-			        if (*(cp - 1) == '\r') {
+				if (*(cp - 1) == '\r') {
 				    *(cp - 1) = '\0';
 				}
 			    }
@@ -648,28 +1116,19 @@ PUBLIC void reply_by_mail ARGS3(
 			FREE(temp);
 		    }
 		    if (cp1) {
-		        *cp1 = '&';
+			*cp1 = '&';
 			cp = cp1;
 			cp1 = NULL;
 		    } else {
-		        break;
+			break;
 		    }
 		}
-	        cp++;
+		cp++;
 	    }
 
 	    FREE(searchpart);
 	}
     }
-    if (subject[0] == '\0' && title && *title) {
-	strncpy(subject, title, 70);
-	subject[70] = '\0';
-    }
-
-    /*
-     *  Unescape the address field. - FM
-     */
-    HTUnEscape(address);
 
     /*
      *  Convert any Explorer semi-colon Internet address
@@ -685,15 +1144,50 @@ PUBLIC void reply_by_mail ARGS3(
 	cp = cp1;
     }
     if (address[(strlen(address) - 1)] == ',')
-        address[(strlen(address) - 1)] = '\0';
+	address[(strlen(address) - 1)] = '\0';
     if (*address == '\0') {
-        FREE(address);
+	FREE(address);
+	FREE(ccaddr);
+	FREE(keywords);
 	FREE(body);
 	fclose(fd);		/* Close the tmpfile.  */
-	remove(my_tempfile);	/* Delete the tmpfile. */
+	remove(my_tmpfile);	/* Delete the tmpfile. */
 	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
 	return;
     }
+    if (ccaddr != NULL) {
+	cp = ccaddr;
+	while ((cp1 = strchr(cp, '@')) != NULL) {
+	    cp1++;
+	    if ((cp0 = strchr(cp1, ';')) != NULL) {
+		*cp0 = ',';
+		cp1 = cp0 + 1;
+	    }
+	    cp = cp1;
+	}
+	if (ccaddr[(strlen(ccaddr) - 1)] == ',') {
+	    ccaddr[(strlen(ccaddr) - 1)] = '\0';
+	}
+	if (*ccaddr == '\0') {
+	    FREE(ccaddr);
+	}
+    }
+
+    /*
+     *  Unescape the address and ccaddr fields. - FM
+     */
+    HTUnEscape(address);
+    if (ccaddr != NULL) {
+	HTUnEscape(ccaddr);
+    }
+
+    /*
+     *  Set the default subject. - FM
+     */
+    if (subject[0] == '\0' && title && *title) {
+	strncpy(subject, title, 70);
+	subject[70] = '\0';
+    }
 
     /*
      *  Use ^G to cancel mailing of comment
@@ -701,18 +1195,23 @@ PUBLIC void reply_by_mail ARGS3(
      */
     signal(SIGINT, terminate_letter);
 
-    
+
 #ifdef VMS
-    if (!body) {
+    if (isPMDF || !body) {
 	/*
-	 *  Put the X-URL and X-Mailer lines in the tmpfile.
+	 *  Put the X-URL and X-Mailer lines in the hdrfile
+	 *  for PMDF or my_tmpfile for VMS MAIL. - FM
 	 */
-	fprintf(fd, "X-URL: %s%s\n",
-		    (filename && *filename) ? filename : "mailto:",
-		    (filename && *filename) ? "" : address);
-	fprintf(fd,"X-Mailer: Lynx, Version %s\n",LYNX_VERSION);
+	fprintf((isPMDF ? hfd : fd),
+		"X-URL: %s%s\n",
+		(filename && *filename) ? filename : "mailto:",
+		(filename && *filename) ? "" : address);
+	fprintf((isPMDF ? hfd : fd),
+		"X-Mailer: Lynx, Version %s\n",LYNX_VERSION);
 #ifdef NO_ANONYMOUS_MAIL
-	fprintf(fd,"\n");
+	if (!isPMDF) {
+	    fprintf(fd, "\n");
+	}
 #endif /* NO_ANONYMOUS_MAIL */
     }
 #else /* Unix: */
@@ -720,7 +1219,7 @@ PUBLIC void reply_by_mail ARGS3(
      *  Put the To: line in the header.
      */
 #ifndef DOSPATH
-    sprintf(buf,"To: %s\n", address);
+    sprintf(buf, "To: %s\n", address);
     StrAllocCopy(header, buf);
 #endif
 
@@ -753,11 +1252,12 @@ PUBLIC void reply_by_mail ARGS3(
     /*
      *  Put the X-URL and X-Mailer lines in the header.
      */
-    sprintf(buf, "X-URL: %s%s\n",
-    		 (filename && *filename) ? filename : "mailto:",
-		 (filename && *filename) ? "" : address);
+    sprintf(buf,
+	    "X-URL: %s%s\n",
+	    (filename && *filename) ? filename : "mailto:",
+	    (filename && *filename) ? "" : address);
     StrAllocCat(header, buf);
-    sprintf(buf,"X-Mailer: Lynx, Version %s\n",LYNX_VERSION);
+    sprintf(buf, "X-Mailer: Lynx, Version %s\n", LYNX_VERSION);
     StrAllocCat(header, buf);
 #endif /* VMS */
 
@@ -773,7 +1273,7 @@ PUBLIC void reply_by_mail ARGS3(
 	addstr(SENDING_COMMENT_TO);
     cp = address;
     while ((cp1 = strchr(cp, ',')) != NULL) {
-        *cp1 = '\0';
+	*cp1 = '\0';
 	while (*cp == ' ')
 	    cp++;
 	if (*cp) {
@@ -783,12 +1283,40 @@ PUBLIC void reply_by_mail ARGS3(
 	*cp1 = ',';
 	cp = (cp1 + 1);
     }
-    if (*cp)
-        addstr(cp);
+    if (*cp) {
+	addstr(cp);
+    }
+#ifdef VMS
+    if ((isPMDF == TRUE) &&
+	(cp = ccaddr) != NULL)
+#else
+    if ((cp = ccaddr) != NULL)
+#endif /* VMS */
+    {
+	if (strchr(cp, ',') != NULL) {
+	    addstr(WITH_COPIES_TO);
+	} else {
+	    addstr(WITH_COPY_TO);
+	}
+	while ((cp1 = strchr(cp, ',')) != NULL) {
+	    *cp1 = '\0';
+	    while (*cp == ' ')
+		cp++;
+	    if (*cp) {
+		addstr(cp);
+		addstr(",\n  ");
+	    }
+	    *cp1 = ',';
+	    cp = (cp1 + 1);
+	}
+	if (*cp) {
+	    addstr(cp);
+	}
+    }
     addstr(CTRL_G_TO_CANCEL_SEND);
 
 #ifdef VMS
-    if (!body) {
+    if (isPMDF || !body) {
 #endif /* VMS */
 #ifndef NO_ANONYMOUS_EMAIL
     /*
@@ -802,7 +1330,11 @@ PUBLIC void reply_by_mail ARGS3(
 	strcpy(user_input, personal_name);
     }
 #ifdef VMS
-    addstr("X_Personal_name: ");
+    if (isPMDF) {
+	addstr("Personal_name: ");
+    } else {
+	addstr("X_Personal_name: ");
+    }
 #else
     addstr("Personal Name: ");
 #endif /* VMS */
@@ -821,9 +1353,10 @@ PUBLIC void reply_by_mail ARGS3(
     term_letter = FALSE;
     if (*user_input) {
 #ifdef VMS
-	fprintf(fd,"X-Personal_name: %s\n",user_input);
+	fprintf((isPMDF ? hfd : fd),
+		"X-Personal_name: %s\n",user_input);
 #else
-	sprintf(buf,"X-Personal_name: %s\n",user_input);
+	sprintf(buf, "X-Personal_name: %s\n", user_input);
 	StrAllocCat(header, buf);
 #endif /* VMS */
     }
@@ -836,13 +1369,17 @@ PUBLIC void reply_by_mail ARGS3(
     if (personal_mail_address)
 	addstr(CTRL_U_TO_ERASE);
 #ifdef VMS
-    addstr("X-From: ");
+    if (isPMDF) {
+	addstr("From: ");
+    } else {
+	addstr("X-From: ");
+    }
 #else
     addstr("From: ");
 #endif /* VMS */
     /* Add the personal mail address if there is one. */
-    sprintf(user_input,"%s", (personal_mail_address ? 
-			      personal_mail_address : ""));
+    sprintf(user_input, "%s", (personal_mail_address ?
+			       personal_mail_address : ""));
     if (LYgetstr(user_input, VISIBLE, sizeof(user_input), NORECALL) < 0 ||
 	term_letter) {
 	addstr("\n");
@@ -855,12 +1392,17 @@ PUBLIC void reply_by_mail ARGS3(
     addstr("\n");
     remove_tildes(user_input);
 #ifdef VMS
-    if (*user_input)
-	fprintf(fd,"X-From: %s\n\n",user_input);
-    else
+    if (*user_input) {
+	if (isPMDF) {
+	    fprintf(hfd, "From: %s\n", user_input);
+	} else {
+	    fprintf(fd, "X-From: %s\n\n", user_input);
+	}
+    } else if (!isPMDF) {
 	fprintf(fd, "\n");
+    }
 #else
-    sprintf(buf,"From: %s\n",user_input);
+    sprintf(buf, "From: %s\n", user_input);
     StrAllocCat(header, buf);
 #endif /* VMS */
 #endif /* !NO_ANONYMOUS_EMAIL */
@@ -876,7 +1418,7 @@ PUBLIC void reply_by_mail ARGS3(
     addstr("Subject: ");
     /* Add the default subject. */
     sprintf(user_input, "%.70s%.63s",
-    			(subject[0] != '\0') ?
+			(subject[0] != '\0') ?
 				     subject :
 		    ((filename && *filename) ?
 				    filename : "mailto:"),
@@ -898,7 +1440,7 @@ PUBLIC void reply_by_mail ARGS3(
 #ifdef VMS
     sprintf(subject, "%.70s", user_input);
 #else
-    sprintf(buf,"Subject: %s\n",user_input);
+    sprintf(buf, "Subject: %s\n", user_input);
     StrAllocCat(header, buf);
 #endif /* VMS */
 
@@ -915,15 +1457,15 @@ PUBLIC void reply_by_mail ARGS3(
 	/*
 	 *  Add the mail address if there is one.
 	 */
-	sprintf(user_input,"%s", (personal_mail_address ? 
-				  personal_mail_address : ""));
+	sprintf(user_input, "%s", (personal_mail_address ?
+				   personal_mail_address : ""));
 	if (LYgetstr(user_input, VISIBLE, sizeof(user_input), NORECALL) < 0 ||
 	    term_letter) {
 	    addstr("\n");
 	    _statusline(COMMENT_REQUEST_CANCELLED);
 	    sleep(InfoSecs);
 	    fclose(fd);			/* Close the tmpfile. */
-	    scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+	    scrollok(stdscr, FALSE);	/* Stop scrolling.    */
 	    goto cleanup;
 	}
 	addstr("\n");
@@ -931,36 +1473,54 @@ PUBLIC void reply_by_mail ARGS3(
     remove_tildes(user_input);
 #if defined (VMS) || defined (DOSPATH)
     if (*user_input) {
-        cp = user_input;
-	while (*cp == ' ' || *cp == ',')
+	cp = user_input;
+	while (*cp == ',' || isspace((unsigned char)*cp))
 	    cp++;
 	if (*cp) {
-	    StrAllocCat(address, ",");
-	    StrAllocCat(address, cp);
+	    if (ccaddr == NULL) {
+		StrAllocCopy(ccaddr, cp);
+	    } else {
+		StrAllocCat(ccaddr, ",");
+		StrAllocCat(ccaddr, cp);
+	    }
 	}
     }
+#endif
 #ifdef DOSPATH
-	 if (*address) {
-		sprintf(buf,"To: %s\n",address);
-		StrAllocCat(header, buf);
-	 }
+    if (*address) {
+	sprintf(buf, "To: %s\n", address);
+	StrAllocCat(header, buf);
+    }
 #endif
 
-#else
-    if (*user_input) {
-	sprintf(buf,"Cc: %s\n",user_input);
-	StrAllocCat(header, buf);
+#ifndef VMS
+    /*
+    **  Add the Cc: header. - FM
+    */
+    if (ccaddr != NULL && *ccaddr != '\0') {
+	StrAllocCat(header, "Cc: ");
+	StrAllocCat(header, ccaddr);
+	StrAllocCat(header, "\n");
+    }
+
+    /*
+    **  Add the Keywords: header. - FM
+    */
+    if (keywords != NULL && *keywords != '\0') {
+	StrAllocCat(header, "Keywords: ");
+	StrAllocCat(header, keywords);
+	StrAllocCat(header, "\n");
     }
 
     /*
      *  Terminate the header.
      */
-    sprintf(buf,"\n");
+    sprintf(buf, "\n");
     StrAllocCat(header, buf);
-#endif /* VMS */
+#endif /* !VMS */
 
     if (!no_editor && editor && *editor != '\0') {
-        /*
+	/*
 	 *  Use an external editor for the message.
 	 */
 	char *editor_arg = "";
@@ -968,12 +1528,12 @@ PUBLIC void reply_by_mail ARGS3(
 	if (body) {
 	    cp1 = body;
 	    while((cp = strchr(cp1, '\n')) != NULL) {
-	        *cp++ = '\0';
+		*cp++ = '\0';
 		fprintf(fd, "%s\n", cp1);
 		cp1 = cp;
 	    }
 	} else if (strcmp(HTLoadedDocumentURL(), "")) {
-            /*
+	    /*
 	     *  Ask if the user wants to include the original message.
 	     */
 	    BOOLEAN is_preparsed = (LYPreparsedSource &&
@@ -982,12 +1542,12 @@ PUBLIC void reply_by_mail ARGS3(
 		_statusline(INC_PREPARSED_MSG_PROMPT);
 	    else
 		_statusline(INC_ORIG_MSG_PROMPT);
-            c = 0;
-            while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
-	           !term_letter && c != 7   && c != 3)
-                c = LYgetch();
-            if (TOUPPER(c) == 'Y') {
-                /*
+	    c = 0;
+	    while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
+		   !term_letter && c != 7   && c != 3)
+		c = LYgetch();
+	    if (TOUPPER(c) == 'Y') {
+		/*
 		 *  The 1 will add the reply "> " in front of every line.
 		 */
 		if (is_preparsed)
@@ -995,7 +1555,7 @@ PUBLIC void reply_by_mail ARGS3(
 		else
 		    print_wwwfile_to_fd(fd, 1);
 	    }
-        }
+	}
 	fclose(fd);		/* Close the tmpfile. */
 	scrollok(stdscr,FALSE);	/* Stop scrolling.    */
 
@@ -1008,7 +1568,7 @@ PUBLIC void reply_by_mail ARGS3(
 	if (strstr(editor, "pico")) {
 	    editor_arg = " -t"; /* No prompt for filename to use */
 	}
-	sprintf(user_input,"%s%s %s",editor,editor_arg,my_tempfile);
+	sprintf(user_input, "%s%s %s", editor, editor_arg, my_tmpfile);
 	_statusline(SPAWNING_EDITOR_FOR_MAIL);
 	stop_curses();
 	if (system(user_input)) {
@@ -1031,7 +1591,7 @@ PUBLIC void reply_by_mail ARGS3(
 	i = (LYlines - 5);
 	while((cp = strchr(cp1, '\n')) != NULL) {
 	    if (i <= 0) {
-	        addstr(RETURN_TO_CONTINUE);
+		addstr(RETURN_TO_CONTINUE);
 		refresh();
 		c = LYgetch();
 		addstr("\n");
@@ -1060,7 +1620,7 @@ PUBLIC void reply_by_mail ARGS3(
 	scrollok(stdscr,FALSE);	/* Stop scrolling.	  */
 
     } else {
-        /*
+	/*
 	 *  Use the internal line editor for the message.
 	 */
 	addstr(ENTER_MESSAGE_BELOW);
@@ -1068,9 +1628,9 @@ PUBLIC void reply_by_mail ARGS3(
 	addstr(ENTER_PERIOD_WHEN_DONE_B);
 	addstr("\n\n");
 	refresh();
-    	*user_input = '\0';
+	*user_input = '\0';
 	if (LYgetstr(user_input, VISIBLE, sizeof(user_input), NORECALL) < 0 ||
-	    term_letter || STREQ(user_input,".")) {
+	    term_letter || STREQ(user_input, ".")) {
 	    _statusline(COMMENT_REQUEST_CANCELLED);
 	    sleep(InfoSecs);
 	    fclose(fd);			/* Close the tmpfile. */
@@ -1078,13 +1638,13 @@ PUBLIC void reply_by_mail ARGS3(
 	    goto cleanup;
 	}
 
-	while (!STREQ(user_input,".") && !term_letter) { 
+	while (!STREQ(user_input, ".") && !term_letter) {
 	    addstr("\n");
 	    remove_tildes(user_input);
-	    fprintf(fd,"%s\n",user_input);
+	    fprintf(fd, "%s\n", user_input);
 	    *user_input = '\0';
 	    if (LYgetstr(user_input, VISIBLE,
-	    		 sizeof(user_input), NORECALL) < 0) {
+			 sizeof(user_input), NORECALL) < 0) {
 		_statusline(COMMENT_REQUEST_CANCELLED);
 		sleep(InfoSecs);
 		fclose(fd);		/* Close the tmpfile. */
@@ -1093,7 +1653,7 @@ PUBLIC void reply_by_mail ARGS3(
 	    }
 	}
 
-	fprintf(fd,"\n");	/* Terminate the message. */
+	fprintf(fd, "\n");	/* Terminate the message. */
 	fclose(fd);		/* Close the tmpfile.	  */
 	scrollok(stdscr,FALSE);	/* Stop scrolling.	  */
     }
@@ -1106,31 +1666,31 @@ PUBLIC void reply_by_mail ARGS3(
 #endif /* !VMS */
     LYStatusLine = (LYlines - 1);
     if (body)
-        _statusline(SEND_MESSAGE_PROMPT);
+	_statusline(SEND_MESSAGE_PROMPT);
     else
-        _statusline(SEND_COMMENT_PROMPT);
+	_statusline(SEND_COMMENT_PROMPT);
     LYStatusLine = -1;
     c = 0;
     while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
 	   !term_letter && c != 7   && c != 3)
 	c = LYgetch();
     if (TOUPPER(c) != 'Y') {
-        clear();  /* clear the screen */
+	clear();  /* clear the screen */
 	goto cleanup;
     }
     if ((body == NULL && LynxSigFile != NULL) &&
-        (fp = fopen(LynxSigFile, "r")) != NULL) {
+	(fp = fopen(LynxSigFile, "r")) != NULL) {
 	LYStatusLine = (LYlines - 1);
 	_user_message(APPEND_SIG_FILE, LynxSigFile);
 	c = 0;
-        LYStatusLine = -1;
+	LYStatusLine = -1;
 	while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
 	       !term_letter && c != 7   && c != 3)
 	    c = LYgetch();
 	if (TOUPPER(c) == 'Y') {
-	    if ((fd = fopen(my_tempfile, "a")) != NULL) {
-	        fputs("-- \n", fd);
-	        while (fgets(user_input, sizeof(user_input), fp) != NULL) {
+	    if ((fd = fopen(my_tmpfile, "a")) != NULL) {
+		fputs("-- \n", fd);
+		while (fgets(user_input, sizeof(user_input), fp) != NULL) {
 		    fputs(user_input, fd);
 		}
 		fclose(fd);
@@ -1145,62 +1705,126 @@ PUBLIC void reply_by_mail ARGS3(
      */
 #ifdef VMS
     /*
-     *  Set the mail command.
+     *  Set the mail command. - FM
      */
-    sprintf(cmd, "%s %s/subject=\"%s\" %s ",
-    		 system_mail,
-		 (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
-		 subject, my_tempfile);
+    if (isPMDF) {
+	/*
+	 *  For PMDF, put any keywords and the subject
+	 *  in the header file and close it. - FM
+	 */
+	if (keywords != NULL && *keywords != '\0') {
+	    fprintf(hfd, "Keywords: %s\n", keywords);
+	}
+	fprintf(hfd, "Subject: %s\n\n", subject);
+	fclose(hfd);
+	/*
+	 *  Now set up the command. - FM
+	 */
+	sprintf(cmd,
+		"%s %s %s,%s ",
+		system_mail,
+		system_mail_flags,
+		hdrfile,
+		my_tmpfile);
+    } else {
+	/*
+	 *  For "generic" VMS MAIL, include the subject in the
+	 *  command, and ignore any keywords to minimize risk
+	 *  of them making the line too long or having problem
+	 *  characters. - FM
+	 */
+	sprintf(cmd,
+		"%s %s%s/subject=\"%s\" %s ",
+		system_mail,
+		system_mail_flags,
+		(strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
+		subject,
+		my_tmpfile);
+    }
+    StrAllocCopy(command, cmd);
 
     /*
-     *  Now add all the people in the address field.
+     *  Now add all the people in the address field. - FM
      */
     address_ptr1 = address;
     do {
 	if ((cp = strchr(address_ptr1, ',')) != NULL) {
 	    address_ptr2 = (cp+1);
 	    *cp = '\0';
-	} else
+	} else {
 	    address_ptr2 = NULL;
+	}
 
 	/*
 	 *  4 letters is arbitrarily the smallest posible mail
 	 *  address, at least for lynx.  That way extra spaces
 	 *  won't confuse the mailer and give a blank address.
 	 */
-	if (strlen(address_ptr1) > 3) {	
-	    if (!first)
-		strcat(cmd, ",");  /* add a comma */
-	    sprintf( &cmd[strlen(cmd)], mail_adrs, address_ptr1);
+	if (strlen(address_ptr1) > 3) {
+	    if (!first) {
+		StrAllocCat(command, ",");
+	    }
+	    sprintf(cmd, mail_adrs, address_ptr1);
+	    StrAllocCat(command, cmd);
 	    first = FALSE;
 	}
-
 	address_ptr1 = address_ptr2;
     } while (address_ptr1 != NULL);
 
+    /*
+     *  Now add all the people in the CC field. - FM
+     */
+    if (ccaddr != NULL && *ccaddr != '\0') {
+	address_ptr1 = ccaddr;
+	do {
+	    if ((cp = strchr(address_ptr1, ',')) != NULL) {
+		address_ptr2 = (cp+1);
+		*cp = '\0';
+	    } else {
+		address_ptr2 = NULL;
+	    }
+
+	    /*
+	     *  4 letters is arbitrarily the smallest posible mail
+	     *  address, at least for lynx.  That way extra spaces
+	     *  won't confuse the mailer and give a blank address.
+	     */
+	    if (strlen(address_ptr1) > 3) {
+		StrAllocCat(command, ",");
+		sprintf(cmd, mail_adrs, address_ptr1);
+		if (isPMDF) {
+		    strcat(cmd, "/CC");
+		}
+		StrAllocCat(command, cmd);
+	    }
+	    address_ptr1 = address_ptr2;
+	} while (address_ptr1 != NULL);
+    }
+
     stop_curses();
-    printf("Sending your comment:\n\n$ %s\n\nPlease wait...", cmd);
-    system(cmd);
-    sleep(MessageSecs);
+    printf("Sending your comment:\n\n$ %s\n\nPlease wait...", command);
+    system(command);
+    FREE(command);
+    sleep(AlertSecs);
     start_curses();
     goto cleandown;
 #else /* Unix: */
     /*
-     *  Send the tmpfile into sendmail.  
+     *  Send the tmpfile into sendmail.
      */
     _statusline(SENDING_YOUR_MSG);
     sprintf(cmd, "%s %s", system_mail, system_mail_flags);
 #ifdef DOSPATH
-	 tempname(tmpfile2,NEW_FILE);
-	 if (((cp = strrchr(tmpfile2, '.')) != NULL) &&
-		NULL == strchr(cp, '/')) {
-			*cp = '\0';
-			strcat(tmpfile2, ".txt");
-	 }
-	 if ((fp = fopen(tmpfile2,"w")) == NULL) {
-		HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
-		return;
-	 }
+    tempname(tmpfile2, NEW_FILE);
+    if (((cp = strrchr(tmpfile2, '.')) != NULL) &&
+	NULL == strchr(cp, '/')) {
+	*cp = '\0';
+	strcat(tmpfile2, ".txt");
+    }
+    if ((fp = LYNewTxtFile(tmpfile2)) == NULL) {
+	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
+	return;
+    }
 #else
     signal(SIGINT, SIG_IGN);
     fp = popen(cmd, "w");
@@ -1210,7 +1834,7 @@ PUBLIC void reply_by_mail ARGS3(
 	goto cleanup;
     }
 #endif /* DOSPATH */
-    fd = fopen(my_tempfile, "r");
+    fd = fopen(my_tmpfile, "r");
     if (fd == NULL) {
 	_statusline(COMMENT_REQUEST_CANCELLED);
 	sleep(InfoSecs);
@@ -1235,7 +1859,7 @@ PUBLIC void reply_by_mail ARGS3(
     fclose(fd);	/* Close the tmpfile. */
 
     if (TRACE)
-	printf("%s\n",cmd);
+	printf("%s\n", cmd);
 #endif /* VMS */
 
     /*
@@ -1251,8 +1875,19 @@ cleanup:
 cleandown:
 #endif /* VMS */
     term_letter = FALSE;
-    remove(my_tempfile);	/* Delete the tmpfile. */
+#ifdef VMS
+    FREE(command);
+    while (remove(my_tmpfile) == 0)
+	;		 /* Delete the tmpfile(s). */
+    if (isPMDF) {
+	remove(hdrfile); /* Delete the hdrfile. */
+    }
+#else
+    remove(my_tmpfile);	 /* Delete the tmpfile. */
+#endif /* VMS */
     FREE(address);
+    FREE(ccaddr);
+    FREE(keywords);
     FREE(body);
     return;
 }
@@ -1263,7 +1898,9 @@ PRIVATE void terminate_letter ARGS1(int,sig)
     /* Reassert the AST */
     signal(SIGINT, terminate_letter);
 #if defined(VMS) || defined(DOSPATH)
-    /* Refresh the screen to get rid of the "interrupt" message */
+    /*
+     *  Refresh the screen to get rid of the "interrupt" message.
+     */
     if (!dump_output_immediately) {
 	lynx_force_repaint();
 	refresh();
@@ -1273,9 +1910,10 @@ PRIVATE void terminate_letter ARGS1(int,sig)
 
 PRIVATE void remove_tildes ARGS1(char *,string)
 {
-       /* change the first character to a space if
-	* it is a '~'
-	*/
-    if(*string == '~')
+   /*
+    *  Change the first character to
+    *  a space if it is a '~'.
+    */
+    if (*string == '~')
 	*string = ' ';
 }