/*
* xmail - X window system interface to the mail program
*
* Copyright 1990,1991,1992 by National Semiconductor Corporation
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of National Semiconductor Corporation not
* be used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
* SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS"
* WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO
* EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* Author: Michael C. Wagnitz - National Semiconductor Corporation
*
*/
#include "global.h"
#include "MailwatchP.h"
#include "xmailregexp.h"
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/signal.h>
#include <errno.h>
#include <pwd.h>
#ifdef vms
extern int noshare errno;
extern int noshare sys_nerr;
extern char noshare *sys_errlist[];
#else
#if !defined(__FreeBSD__)
extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];
#endif
#endif
extern char otherBuf[BUFSIZ];
#if ! defined(SIGCHLD) && defined(SIGCLD)
#define SIGCHLD SIGCLD
#endif
/*
** @(#)Autograph() - Add user's Sign or sign autograph to outgoing mail
** Then make button insensitive, to prevent multiple calls.
** If requested autograph signature does not exist, tell user.
** Because we can now be called by a translation table entry,
** check to see if already insensitive before proceeding.
*/
/* ARGSUSED */
void
Autograph(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data; /* unused */
{
int n;
String cp, autograph;
char tmp[BUFSIZ], *C = (char *) closure;
FILE *fp;
struct stat st_buf;
if (XtIsSensitive(w)) { /* if okay to proceed... */
(void) strcpy(tmp, "Sign"); /* Default action is to use Sign autograph */
if (*C == 'a') tmp[0] = 's';
autograph = GetMailEnv(tmp); /* First, see if an autograph entry exists */
if (! autograph) {
/*
** If no Sign or sign, see if the user has created a .signature file
*/
st_buf.st_size = 0;
(void) sprintf(tmp, "%s/.Signature", HOME);
if (*C == 'a')
(void) sprintf(tmp, "%s/.signature", HOME);
if (stat(tmp, &st_buf) != -1 &&
st_buf.st_size < BUFSIZ &&
(fp = fopen(tmp, "r")) != NULL) {
autograph = (String) XtMalloc((unsigned) st_buf.st_size + 1);
n = fread(autograph, sizeof(char), (int) st_buf.st_size, fp);
autograph[n] = '\0';
(void) fclose(fp);
} else {
(void) strcpy(tmp, "Cannot find a 'Sign'ature to append\n");
if (*C == 'a') tmp[15] = 's';
if (st_buf.st_size) {
(void) sprintf(tmp,"Cannot append your .Signature (exceeds %d characters)\n",
BUFSIZ - 1);
if (*C == 'a') tmp[20] = 's';
}
Bell(tmp);
return;
}
} else {
if ((int)strlen(autograph) >= BUFSIZ) {
(void) sprintf(tmp,"Cannot append your Signature (exceeds %d characters)\n",
BUFSIZ - 1);
if (*C == 'a') tmp[19] = 's';
Bell(tmp);
XtFree((String) autograph);
return;
}
}
XtSetSensitive(w, False); /* Don't let us be pressed more than once */
if (*C == 'A') /* also make other sign button inoperative */
XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), False);
else /* if this was a request for lowercase sign */
XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), False);
for (cp = autograph, n = 0; n < BUFSIZ - 1 && *cp; cp++)
if (*cp == '\\' && *(cp + 1) == 'n') {
tmp[n++] = '\n'; /* Replace newline strings with a character */
cp++;
} else tmp[n++] = *cp;
if (tmp[n - 1] != '\n') /* make sure msg ends with a newline */
tmp[n++] = '\n';
tmp[n] = '\0';
if ((fp = fopen(tmpName, "a")) != NULL) {
if (*tmp != '-' || *(tmp + 1) != '-') /* add a signature separator */
(void) fwrite("-- \n", sizeof(char), 4, fp);
(void) fwrite(tmp, sizeof(* tmp), strlen(tmp), fp);
(void) fclose(fp);
}
XtFree((String) autograph);
} /* end - if we were currently sensitive */
} /* Autograph */
/*
** @(#)endDelivery() - catch the signal when the delivery child finishes
*/
#if defined(sun)
void
#else
int
#endif
endDelivery(signum)
int signum;
{
int status;
if (signum == SIGCHLD &&
mailpid != wait(&status)) /* in case mail child was what died */
(void) signal(SIGCHLD, SIG_DFL); /* turn off the endDelivery hook */
#if !defined(sun) && !defined(SVR4)
return 1;
#endif
} /* endDelivery */
/*
** @(#)DoCopy() - send a copy of the message to the indicated folder file
*/
DoCopy(file, to, subject, inreply, cc, bcc, outfolder, edits, add_face)
char *file, *to, *subject, *inreply, *cc, *bcc;
int outfolder, edits, add_face;
{
int len, n;
time_t clock;
char *m, tmp[BUFSIZ], From[BUFSIZ], Copy[BUFSIZ];
MailwatchWidget mb = (MailwatchWidget) XtNameToWidget(toplevel,"icon.mailbox");
FILE *fp, *xf;
struct stat st_buf;
if (file[0]) {
st_buf.st_size = 0; /* (in case msg file does not exist) */
(void) stat(tmpName, &st_buf);
(void) time(&clock);
(void) sprintf(From, "From %s %24.24s\n", mb->mailbox.username, (char *) ctime(&clock));
switch (file[0]) {
case '|': /* accomodate alias with Sun pipe cmd */
(void) sprintf(Copy, "%s.pipe", tmpName);
break;
case '~': /* file with a tilde expansion name */
if (file[1] == '/')
(void) sprintf(Copy, "%s%s", HOME, &file[1]);
else {
struct passwd *pw;
for (len = 0, n = 1; file[n] && file[n] != '/';)
tmp[len++] = file[n++];
tmp[len] = '\0';
if (pw = getpwnam(tmp))
(void) sprintf(Copy, "%s%s", pw->pw_dir, &file[n]);
else (void) strcpy(Copy, file);
}
break;
case '/': /* file with an absolute path name */
(void) strcpy(Copy, file);
break;
case '+': /* file with a folder relative name */
if (! foldir[0])
(void) strcpy(Copy, file);
else
(void) sprintf(Copy, "%s%s", foldir, &file[1]);
break;
default:
if (file[0] == '.' && file[1] == '/')
(void) strcpy(Copy, file);
else if (outfolder == 0 || ! foldir[0]) {
if (strchr(file, '/') == NULL) /* no dir reference */
(void) strcpy(Copy, file);
else /* assume file with dir is relative to home */
(void) sprintf(Copy, "%s/%s", HOME, file);
} else { /* if outfolder (and folder name is included) */
(void) sprintf(Copy, "%s%s", foldir, file);
}
break;
}
if ((fp = fopen(Copy, "a")) == NULL) {
/*
** Can't use the Bell routine internally, because we're a child.
** So, just pump the message to stderr and let user deal with it.
*/
(void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
(errno < sys_nerr)? sys_errlist[errno]:"Unknown error");
(void) fprintf(stderr, tmp);
} else {
(void) fprintf(fp, From);
if (*to) (void) fprintf(fp, "To: %s\n", to);
if (*subject) (void) fprintf(fp, "Subject: %s\n", subject);
if (*inreply) (void) fprintf(fp, "%s\n", inreply);
/*
** Add support for custom header information as a resource
** and for editheaders mail option. If editheaders, find
** custom header information in message text.
*/
if (edits) {
int skip;
if (st_buf.st_size) {
xf = fopen(tmpName, "r");
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (tmp[0] == '\n') break;
if (tmp[0] != ' ' && tmp[0] != '\t') skip = 0;
if (strncmp(tmp,"To: ", 4) == 0) { skip = 1; continue; }
if (strncmp(tmp,"Subject: ", 9) == 0) { skip = 1; continue; }
if (strncmp(tmp,"In-Reply-To: ",13)==0) { skip = 1; continue; }
if (strncmp(tmp,"Forwarding: ",12)==0) { skip = 1; continue; }
if (strncmp(tmp,"Cc: ", 4) == 0) { skip = 1; continue; }
if (strncmp(tmp,"Bcc: ", 5) == 0) { skip = 1; continue; }
if (! skip) (void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
} else
if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
{
if (m[0] == '"' || m[0] == "'"[0]) {
bcopy(m + 1, m, strlen(m) - 1);
while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
LASTCH(m) = '\0';
}
if (LASTCH(m) != '\n')
(void) fprintf(fp, "%s\n", m);
else
(void) fprintf(fp, "%s", m);
}
} else
if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader")) {
if (m[0] == '"' || m[0] == "'"[0]) {
bcopy(m + 1, m, strlen(m) - 1);
while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
LASTCH(m) = '\0';
}
if (LASTCH(m) != '\n')
(void) fprintf(fp, "%s\n", m);
else
(void) fprintf(fp, "%s", m);
}
if (*cc) (void) fprintf(fp, "Cc: %s\n", cc);
if (*bcc) (void) fprintf(fp, "Bcc: %s\n", bcc);
#ifdef X_FACE
if (add_face) {
(void) sprintf(tmp, "%s/.face", HOME);
if (xf = fopen(tmp, "r")) {
n = 1;
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (n) {
n = 0;
if (strncmp(tmp, "X-Face:", 7) != 0)
(void) fprintf(fp, "X-Face:");
}
(void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
}
}
#endif /* X_FACE */
(void) fprintf(fp, "\n");
if (st_buf.st_size) {
xf = fopen(tmpName, "r");
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (edits) { /* if headers edited, drop them now */
if (tmp[0] == '\n') edits = 0;
continue;
}
if (strncmp(tmp,"From ",5) == 0) (void)fprintf(fp,">");
(void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
if (*tmp != '\n')
(void) fprintf(fp, "\n");
}
(void) fclose(fp);
if (file[0] == '|') {
(void) sprintf(tmp, "/bin/cat %s %s", Copy, file);
(void) system(tmp);
(void) unlink(Copy);
}
} /* end - if we opened the target file successfully */
} /* end - if passed file variable is not null */
} /* end - DoCopy */
/*
** @(#)Done() - Send composed message - if closure data says "Deliver"
*/
/* ARGSUSED */
void
Done(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data;
{
int outfolder, n, len, edit_headers;
int add_face = 1; /* Are we using faces.sendmail script */
String m, q, z ;
char record[BUFSIZ], Copy[BUFSIZ], tmp[BUFSIZ], addressees[BUFSIZ];
char To[BUFSIZ], Subject[BUFSIZ], Cc[BUFSIZ], Bcc[BUFSIZ];
char *c = (char *) closure;
Widget popup;
Arg args[1];
FILE *fp, *xf, *popen();
struct stat st_buf;
struct passwd *pw;
Bell(Default_Status_Info);
popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
if (! popup) return; /* SOMEthing would be VERY wrong here */
XtPopdown(popup); /* remove from view but don't destroy */
XWarpPointer(XtDisplay(toplevel), None,
XtWindow(XtNameToWidget(toplevel, "topBox.textWindow.text")),
0,0,0,0, XMail.helpX * 2, XMail.helpY);
st_buf.st_size = 0; /* (in case msg file does not exist) */
(void) stat(tmpName, &st_buf);
record[0] = Copy[0] = tmp[0] = addressees[0] = '\0';
To[0] = Subject[0] = Cc[0] = Bcc[0] = '\0';
if (strcmp(c, "Deliver") != 0) {
/*
** Restore sensitivity of the Autograph, Send, and reply for next time
*/
XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True);
XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True);
XtSetSensitive(XtParent(popup), True);
XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), True);
n = st_buf.st_size; /* the number of bytes in the message text */
if (n == 0 && *c == 'c')
Bell("No text to save in your dead letter file\n");
else {
if (n && (*c == 'c' || ! Confirm("REALLY discard this text"))) {
if (! (m = GetMailEnv("DEAD")))
(void) sprintf(Copy, "%s/dead.letter", HOME);
else {
(void) strcpy(record, m);
XtFree((String) m);
if (record[0] != '~')
(void) strcpy(Copy, record); /* take whatever is given */
else {
if (record[1] == '/')
(void) sprintf(Copy, "%s%s", HOME, &record[1]);
else {
for (len = 0, n = 1; record[n] && record[n] != '/';)
tmp[len++] = record[n++];
tmp[len] = '\0';
if (pw = getpwnam(tmp))
(void) sprintf(Copy, "%s%s", pw->pw_dir, &record[n]);
else (void) strcpy(Copy, record);
}
}
}
st_buf.st_size = -1; /* see if our target exists */
(void) stat(Copy, &st_buf);
if (fp = fopen(Copy, "a")) {
xf = fopen(tmpName, "r");
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
(void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
if (*tmp != '\n')
(void) fprintf(fp, "\n");
(void) fclose(fp);
(void) sprintf(tmp, "\"%s\" [%s] (%d bytes)\n", Copy,
(st_buf.st_size >= 0) ? "Appended" : "New file", n);
Bell(tmp);
} else {
(void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
(errno < sys_nerr)? sys_errlist[errno] : "Unknown error");
Bell(tmp);
}
}
} /* end - if some message text exists */
(void) unlink(tmpName); /* remove the message text file */
} else { /* Deliver this message text */
/*
** Call the alias() routine recursively, to de-alias the user's To:, Cc:,
** and Bcc: fields.
*/
To[0] = Subject[0] = Cc[0] = Bcc[0] = otherBuf[0] = '\0';
/*
** Retrieve current values from the header buffers
*/
m = NULL;
XtSetArg(args[0], XtNstring, &m);
XtGetValues(XtNameToWidget(popup, "*SubjCc*To"), args, 1);
if (m && *m) {
(void) strncpy(addressees, m, BUFSIZ);
(void) strncpy(To, m, BUFSIZ); /* in case there's no user recipient */
/*
** alias() adds filenames to a list and returns just user addresses
** (it also automatically wraps long header lines)
*/
for (m = alias(addressees); strcmp(m, addressees); m = alias(addressees))
(void) strncpy(addressees, m, BUFSIZ);
if (addressees[0]) /* if some real users are named... */
(void) strncpy(To, addressees, BUFSIZ);
}
m = NULL;
XtSetArg(args[0], XtNstring, &m);
XtGetValues(XtNameToWidget(popup, "*SubjCc*Subject"), args, 1);
if ((! addressees[0] && ! otherBuf[0]) || (! *m && st_buf.st_size == 0)) {
if (! addressees[0])
Bell("No recipient specified\n");
else
Bell("No subject and no message body\n");
Waiting = TRUE; /* so popup's EnterNotify won't overwrite msg */
/*
** FORCE the user to either complete the message or abort delivery
*/
XtPopup(popup, XtGrabNone);
XSync(XtDisplay(toplevel), False);
XtAddEventHandler(popup, StructureNotifyMask, False, warp_handler, (XtPointer)NULL);
} else { /* if there is a message to be delivered... */
/*
** Restore the sensitivity of the Autograph, Send, and reply buttons
*/
XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True);
XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True);
XtSetSensitive(XtParent(popup), True);
XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), True);
if (*m) {
/*
** Format the subject line to wrap on ~70 characters. In case the
** user didn't install the xmail default resources file, also look
** for imbedded newlines in the Subject text.
*/
for (n = 0, len = 9; *m && n < BUFSIZ; n++, len++) {
Subject[n] = *m++;
if (Subject[n] == '\n') {
if (! *m) Subject[n] = '\0';
else if (len < 35) Subject[n] = ' ';
else { Subject[++n] = '\t'; len = 8; }
} else if (len % 70 == 0)
if (Subject[n] == ' ') {
Subject[++n] = '\n';
Subject[++n] = '\t';
len = 8;
} else len--; /* break at a word boundary */
}
Subject[n] = '\0';
}
m = NULL;
XtSetArg(args[0], XtNstring, &m);
XtGetValues(XtNameToWidget(popup, "*SubjCc*Cc"), args, 1);
if (m && *m) {
(void) strncpy(tmp, m, BUFSIZ);
for (m = alias(tmp); strcmp(m, tmp); m = alias(tmp))
(void) strncpy(tmp, m, BUFSIZ);
if (*m) {
if (addressees[0]) (void) strcat(addressees, ", ");
(void) strcat(addressees, m);
(void) strncpy(Cc, m, BUFSIZ);
}
}
m = NULL;
XtSetArg(args[0], XtNstring, &m);
XtGetValues(XtNameToWidget(popup, "*SubjCc*Bcc"), args, 1);
if (m && *m) {
(void) strncpy(tmp, m, BUFSIZ);
for (m = alias(tmp); strcmp(m, tmp); m = alias(tmp))
(void) strncpy(tmp, m, BUFSIZ);
if (*m) {
if (addressees[0]) (void) strcat(addressees, ", ");
(void) strcat(addressees, m);
(void) strncpy(Bcc, m, BUFSIZ);
}
}
/*
** To avoid a bug in Sun's sendmail (for occasionally not being able to
** find the name of the real author of the message), strip commas from
** the address list and pass the recipient names to sendmail on the
** command line, ala Mail. Also, strip all but the actual address from
** any compound addresses present in the list.
*/
for (q = addressees; *q; q++) {
if (*q == ',') { /* remove any commas */
if (q[1] == ' ') { /* if comma is followed by a space */
for (m = q, z = q + 1; *z;) *m++ = *z++;
*m = '\0'; /* then shift string left by one */
}
else *q = ' '; /* else substitute space for comma */
q++;
}
if (*q == '\n' && *(q+1) == '\t') { /* drop any newline tabs */
for (m = q, z = q + 2; *z;) *m++ = *z++;
*m = '\0';
}
if (z = strchr(q, ',')) { /* find the end of next alias in list */
n = (int) (z - q);
for (m = tmp, z = q; *z && n--;) *m++ = *z++;
*m = '\0'; /* shorten our search to just this */
if ((m = strchr(tmp, '<')) || (m = strchr(tmp, '('))) {
if (*m == '<') { /* if its a chevroned address type */
(void) sscanf(m, "<%[^>]>", Copy);
len = strlen(Copy); /* save the address part of this only */
for (m = Copy; *m && len--;) *q++ = *m++;
for (m = q; *z;) *m++ = *z++;
*m = '\0'; /* shift rest of addressees left */
for (; *q && *q != ','; q++);
if (*q) q--;
} else { /* must be a parenthetical style */
for (n = 0; tmp[n] && strchr(" \n\t", tmp[n]); n++);
if (1 == sscanf(&tmp[n], "%*[^)]) %s", Copy)) {
bcopy(Copy, q, strlen(Copy));
m = q + strlen(Copy);
bcopy(z, m, strlen(z) + 1);
if (q = strchr(q, ',')) q--;
} else {
(void) sscanf(&tmp[n], "%s", Copy); /* address preceeds */
m = q + strlen(Copy);
bcopy(z, m, strlen(z) + 1);
if (q = strchr(q, ',')) q--;
}
}
} else q = z - 1; /* skip to alias end if not compound */
} else { /* last (or only) alias in the list */
if ((m = strchr(q, '<')) || (m = strchr(q, '('))) {
if (*m == '<') {
if (! sscanf(q, "%*[^<]<%[^>]>", Copy))
(void) sscanf(q, "<%[^>]>", Copy);
bcopy(Copy, q, strlen(Copy) + 1);
} else {
for (z = q; strchr(" \n\t", *z); z++);
if (1 == sscanf(z, "%*[^)]) %s", Copy)) {
bcopy(Copy, q, strlen(Copy) + 1);
} else {
(void) sscanf(z, "%s", Copy);
z[strlen(Copy) + 1] = '\0';
}
}
}
break; /* no more commas to be replaced */
}
}
if (! (m = GetMailEnv("sendmail")))
m = XtNewString("/usr/sbin/sendmail");
#ifdef X_FACE
else {
add_face = (strcmp(&m[strlen(m)-14], "faces.sendmail") != 0) ? 1 : 0;
}
#endif /* X_FACE */
/*
** The following arguments are passed to the sendmail command:
**
** -oi don't accept a dot on a line by itself as message termination
**
** -om send to "me" too, if I am a member of an alias expansion
*/
(void) sprintf(tmp, "exec %s -oi -om %s\n", m, addressees);
XtFree((String) m);
initfoldir();
if (m = GetMailEnv("outfolder")) {
outfolder = 1;
XtFree((String) m);
} else outfolder = 0;
if (m = GetMailEnv("record")) {
(void) strncpy(record, m, BUFSIZ);
XtFree((String) m);
} else record[0] = '\0';
if (m = GetMailEnv("editheaders")) {
XtFree((String) m);
edit_headers = 1;
} else edit_headers = 0;
/*
** Fork a child process to effect the message delivery functions.
*/
if ((n = fork()) != 0) { /* if we are not the child */
if (n == -1) { /* delivery fork failed ... */
if (errno == ENOMEM)
Bell("Not enough core for message delivery child\n");
else
Bell("No more processes - no message delivery!?!\n");
} else /* parent sets delivery hook */
(void) signal(SIGCHLD, endDelivery);
return;
}
/*
** Use this child process to effect our message delivery function.
*/
(void) close(ConnectionNumber(XtDisplay(toplevel)));
if (addressees[0]) { /* if there are primary addresses... */
/*
** First, mail the header information and message text (in temporary
** file) using sendmail. If we fail, we can't use the Bell routine
** because we are a child process, so write any complaints to stderr.
*/
if (! (fp = popen(tmp, "w")))
(void) fprintf(stderr, "xmail: Couldn't connect to sendmail.\n");
else {
if (To[0]) (void) fprintf(fp, "To: %s\n", To);
if (Subject[0]) (void) fprintf(fp, "Subject: %s\n", Subject);
if (InReply[0]) (void) fprintf(fp, "%s\n", InReply);
/*
** Add support for custom header information as a resource
** and for editheaders mail option. If editheaders, find
** custom header information in message text.
*/
if (edit_headers) {
int skip;
if (st_buf.st_size) {
xf = fopen(tmpName, "r");
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (tmp[0] == '\n') break;
if (tmp[0] != ' ' && tmp[0] != '\t') skip = 0;
if (strncmp(tmp,"To: ", 4) == 0) {skip = 1; continue;}
if (strncmp(tmp,"Subject: ", 9) == 0) {skip=1;continue;}
if (strncmp(tmp,"In-Reply-To: ",13)==0) {skip=1;continue;}
if (strncmp(tmp,"Forwarding: ",12)==0) {skip=1;continue;}
if (strncmp(tmp,"Cc: ", 4) == 0) {skip = 1; continue;}
if (strncmp(tmp,"Bcc: ", 5) == 0) {skip = 1; continue;}
if (! skip) (void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
} else
if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
{
if (m[0] == '"' || m[0] == "'"[0]) {
bcopy(m + 1, m, strlen(m) - 1);
while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
LASTCH(m) = '\0';
}
if (LASTCH(m) != '\n')
(void) fprintf(fp, "%s\n", m);
else
(void) fprintf(fp, "%s", m);
}
} else
if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
{
if (m[0] == '"' || m[0] == "'"[0]) {
bcopy(m + 1, m, strlen(m) - 1);
while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
LASTCH(m) = '\0';
}
if (LASTCH(m) != '\n')
(void) fprintf(fp, "%s\n", m);
else
(void) fprintf(fp, "%s", m);
}
if (Cc[0]) (void) fprintf(fp, "Cc: %s\n", Cc);
if (Bcc[0]) (void) fprintf(fp, "Bcc: %s\n", Bcc);
#ifdef X_FACE
/*
** Look for, and add contents of, user's ~/.face file unless
** user is already invoking the faces.sendmail script, which
** does the job itself. In that case, don't add info here.
** To accomodate both cases, look for and add header if none.
*/
if (add_face) {
(void) sprintf(tmp, "%s/.face", HOME);
if (xf = fopen(tmp, "r")) {
n = 1;
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (n) {
n = 0;
if (strncmp(tmp, "X-Face:", 7) != 0)
(void) fprintf(fp, "X-Face:");
}
(void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
}
}
#endif /* X_FACE */
(void) fprintf(fp, "\n"); /* separate the header from any text */
/*
** Now write message text (if any) to the sendmail process. ANY
** line which begins with the keyword ``From '' gets prepended
** with a greater than (>) symbol.
*/
if (st_buf.st_size) {
xf = fopen(tmpName, "r");
len = edit_headers;
while (fgets(tmp, BUFSIZ, xf) != NULL) {
if (len) { /* if headers edited, drop them now */
if (tmp[0] == '\n') len = 0;
continue;
}
if (strncmp(tmp,"From ",5) == 0) (void) fprintf(fp, ">");
(void) fprintf(fp, "%s", tmp);
}
(void) fclose(xf);
if (tmp[0] != '\n')
(void) fprintf(fp, "\n"); /* ensure a blank last line */
}
(void) pclose(fp); /* this concludes sendmail delivery */
}
/*
** If user has set ``record'' in their .mailrc,
** add a message copy to that record file.
*/
(void) DoCopy(record, To, Subject, InReply, Cc, Bcc,
outfolder, edit_headers, add_face);
} /* end - if there are any primary addresses */
/*
** If other addresses exist, send copies to those files or folders.
*/
if (*otherBuf) {
for (m = otherBuf; *m;) {
for (q = m; *q && *q != ','; q++);
if (*q == ',') {
*q = '\0';
n = 1;
} else n = 0;
(void) DoCopy(m, To, Subject, InReply, Cc, Bcc,
outfolder, edit_headers, add_face);
q += n;
m = q;
} /* end - for each record in otherBuf */
} /* end - if there were records in otherBuf */
(void) unlink(tmpName); /* remove any message text */
exit(1); /* the delivery child sub-process */
/* NOTREACHED */
} /* end - if there was something to deliver */
} /* end - if we wanted to deliver a message */
} /* Done */
/*
** @(#)DoIt() - send command - passed via client_data argument - to mail
*/
/* ARGSUSED */
void
DoIt(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data;
{
int n;
Arg args[1];
String c, buf;
SetCursor(NORMAL);
(void) sprintf(Command, "%s\n", closure);
if (mailpid) { /* If connections are okay,... */
if ((n = match(command_pattern, Command)) != XM_C_FILE && n != XM_C_NEWMAIL) {
SetCursor(WATCH); /* will be reset by parser routine */
writeMail(Command);
} else { /* check for commit of any changes */
buf = NULL;
XtSetArg(args[0], XtNlabel, &buf);
XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
c = strrchr(buf, 'l'); if (c) c -= 2;
if (! c || strncmp(c, "deleted", 7) != 0 ||
strcmp(closure, "inc") == 0 ||
Confirm("COMMIT all changes to this folder")) {
writeMail(Command);
SetCursor(WATCH);
(void) strcpy(lastFolder, buf); /* save for utimes update */
}
}
} else if (XM_C_NEWMAIL != match(command_pattern, Command))
Bell("No current mail connection\n"); /* if not 'Newmail' */
else {
SetCursor(WATCH); /* will be reset by parser routine */
if (mailargc > 2 && strcmp(mailargv[mailargc - 2], "-f") == 0) {
mailargc -= 2; /* throw away any folder argument */
mailargv[mailargc] = NULL; /* and NULL end of argument list */
}
callMail(mailargv); /* restart the mail connections */
(void) strcpy(Command, "Start"); /* Let em know we've re-started */
UnsetNewmail(w, (XtPointer) NULL, (XtPointer) NULL);
In_Bogus_Mail_File = False; /* reset this so titleBar will chg */
}
} /* DoIt */
/*
** @(#)DoPrint() - Call the PrintMsg action routine from a callback
*/
/* ARGSUSED */
void
DoPrint(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data;
{
PrintMsg(w, NULL, NULL, NULL);
} /* DoPrint */
/*
** @(#)DoQuit() - Terminate xmail after first closing mail connection
*/
/* ARGSUSED */
void
DoQuit(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data;
{
Arg args[1];
String c, buf, C = (char *) closure;
if (mailpid) { /* check for commit of any changes */
buf = NULL;
XtSetArg(args[0], XtNlabel, &buf);
XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
c = strrchr(buf, 'l'); if (c) c -= 2;
if (*C != 'q' || ! c || strncmp(c, "deleted", 7) != 0 ||
Confirm("Changes in folder. REALLY quit")) {
(void) sprintf(Command, "%s\n", C);
writeMail(Command);
} else return;
}
XCloseDisplay(XtDisplay(toplevel));
_exit(0);
} /* DoQuit */
/*
** @(#)DoSet() - send specified set request to mail and destroy current menu.
** To accommodate those systems where mail cannot handle the
** 'set no' commands, convert 'set no's to unsets.
*/
/* ARGSUSED */
void
DoSet(w, closure, call_data)
Widget w;
XtPointer closure;
XtPointer call_data;
{
char *c, buf[32];
if (! mailpid)
Bell("No current mail connection\n");
else {
SetCursor(WATCH);
c = w->core.name;
if ((int)strlen(c) > 5 && strcmp(&c[strlen(c) - 6], "expert") == 0)
if (*c == 'n')
XMail.expert = (Boolean) 0;
else XMail.expert = (Boolean) 1;
else {
if (*c == 'n')
(void) sprintf(buf, "unset %s", &c[2]);
else
(void) sprintf(buf, "set %s", c);
c = QueryMail(buf);
}
XtDestroyWidget(XtParent(XtParent(w)));
SetCursor(NORMAL);
}
} /* DoSet */
/* ARGSUSED */
/*
** @(#)DoWith() - send client_data command to mail with selected msg number
*/
void
DoWith(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
int num = 1;
char *c = (char *) client_data;
Waiting = TRUE; /* so popup's EnterNotify won't overwrite msg */
if (*c == 'n' || *c == '-')
DoSelected(w, (XEvent *)NULL, &c, (Cardinal *)&num);
else if (! mailpid) Bell("No current mail connection\n");
else {
SetCursor(WATCH);
num = SelectionNumber(*c == 'u');
if (num) (void) sprintf(Command, "%s %d\n", c, num);
else (void) sprintf(Command, "%s \n", c);
writeMail(Command);
}
} /* DoWith */
/* ARGSUSED */
/*
** @(#)DropIt() - callback to destroy the current folder popup list(s)
*/
void
DropIt(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
Widget popup = XtNameToWidget(toplevel,"topBox.commandPanel.Folder.popupList");
if (popup)
XtDestroyWidget(popup);
SetCursor(NORMAL);
} /* DropIt */
/*
** @(#)GetAliasName() - retrieve alias name from button label
*/
/* ARGSUSED */
void
GetAliasName(w, shell, call_data)
Widget w;
Widget shell;
XtPointer call_data; /* unused */
{
Arg args[1];
String alias_name;
XtSetArg(args[0], XtNlabel, &alias_name);
XtGetValues(w, (ArgList) args, 1); /* get this entry's label value */
XtPopdown(XtParent(XtParent(w))); /* aliasList<-table<-entry */
if (TextGetLastPos(shell)) /* if some alias is already in there */
writeTo(shell, ", ", APPEND); /* add comma separator between names */
writeTo(shell, alias_name, APPEND);
} /* GetAliasName */
/*
** @(#)GetFolderName() - retrieve full folder name from button labels
*/
/* ARGSUSED */
void
GetFolderName(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Arg args[1];
int k, n, x;
String folder_name;
Widget shell;
char tmp[BUFSIZ], buf[BUFSIZ];
XtSetArg(args[0], XtNlabel, &folder_name);
XtGetValues(w, (ArgList) args, 1);
if (! call_data) /* just a simple label name */
(void) sprintf(buf, "File: %s", folder_name);
else { /* multiple stack of names */
tmp[0] = '\0';
shell = w;
(void) sscanf(call_data, "%d", &n); /* using the nesting depth */
for (x = 1, k = (n * 2) + n - 1; k; k--) {
shell = shell->core.parent; /* travel up the widget tree */
if (++x == 3) { /* when we get to a label... */
x = 0;
(void) strcpy(buf, shell->core.name); /* stuff label name in */
(void) strcat(buf, tmp); /* front of previous labels */
(void) strcpy(tmp, buf); /* to build a complete path */
}
}
(void) sprintf(buf, "File: +%s%s", tmp, folder_name);
}
writeTo(XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow"),
buf, REPLACE);
} /* GetFolderName */
/*
** @(#)ReEdit() - Call the editMail routine to re-edit a message
*/
/* ARGSUSED */
void
ReEdit(w, closure, call_data)
Widget w; /* unused */
XtPointer closure; /* unused */
XtPointer call_data; /* unused */
{
Widget Popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
if (! Popup) {
XBell(XtDisplay(toplevel), 33);
return; /* SOMEthing must be VERY wrong here */
}
XtPopdown(Popup); /* pop down the send popup */
editMail(); /* re-edit the message file */
} /* ReEdit */
/*
** @(#)Reply() - send a reply to the author of the selected message
** include its text and/or copy the other recipients, if asked.
*/
/* ARGSUSED */
void
Reply(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
int n, fd, alwaysIgnore, edit_headers, erasable = 0;
String p, q, r, txt;
char *us, *getlogin(), *C = (char *) client_data;
char oldFrom[BUFSIZ], author[BUFSIZ], returnPath[BUFSIZ];
char toList[BUFSIZ], date[BUFSIZ], subject[BUFSIZ], ccList[BUFSIZ];
char Recipient[BUFSIZ];
Widget sb = XtNameToWidget(toplevel, "topBox.commandPanel.Send");
#if defined(SIGACTION) || defined(SVR4) || defined(linux)
struct sigaction outvec;
(void) sigaction(SIGCHLD, NULL, &outvec);
if (outvec.sa_handler != SIG_DFL)
#else
struct sigvec ovec;
(void) sigvec(SIGCHLD, NULL, &ovec);
if (ovec.sv_handler != SIG_DFL)
#endif
{
Bell("Still delivering your previous message. Please try again later.\n");
return;
}
XtSetSensitive(sb, False); /* Don't start more than one composition */
XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), False);
oldFrom[0] = author[0] = returnPath[0] = date[0] = subject[0] = '\0';
ccList[0] = toList[0] = '\0';
if (p = GetMailEnv("editheaders")) {
XtFree((String) p);
edit_headers = 1;
} else edit_headers = 0;
if (*C != 's' || edit_headers) {
if ((fd = open(tmpName, O_WRONLY | O_CREAT, 0600)) == -1) {
Bell("xmail: Cannot open the temp file\n");
return;
}
if (p = GetMailEnv("alwaysignore")) {
XtFree((String) p);
alwaysIgnore = (strchr("SRA", *C)) ? 1 : 0;
} else alwaysIgnore = 0;
if (alwaysIgnore) /* do we need to include a limited copy? */
(void) sprintf(Command, "p %d", SelectionNumber(False));
else
(void) sprintf(Command, "P %d", SelectionNumber(False));
if ((p = GetMailEnv("indentprefix")) != NULL)
erasable = 1;
else
p = "\t";
txt = QueryMail(Command);
switch (*C) {
case 'S':
(void) write(fd, "---------- Begin Forwarded Message ----------\n", 46);
/*
** Any lines that begin with keyword 'From ' get a leading symbol
*/
for (q = r = txt; *r;) {
for (; *r && *r != '\n'; r++);
if (*r == '\n') { /* For each line of text */
if (strncmp(q, "From ", 5) == 0)
(void) write(fd, ">", 1);
(void) write(fd, q, r - q + 1);
q = ++r;
}
}
if (*q) { /* should never happen, but. */
if (strncmp(q, "From ", 5) == 0)
(void) write(fd, ">", 1);
(void) write(fd, q, strlen(q)); /* write last line of text */
if (LASTCH(q) != '\n')
(void) write(fd, "\n", 1);
}
(void) write(fd, "----------- End Forwarded Message -----------\n", 46);
break;
case 'R':
case 'A':
n = strlen(p);
for (q = r = txt; *r;) {
for (; *r && *r != '\n'; r++);
if (*r == '\n') { /* For each line of insert */
(void) write(fd, p, n); /* write indent prefix, */
(void) write(fd, q, r - q + 1); /* followed by text */
q = ++r;
}
}
if (*q) { /* should never happen, but. */
(void) write(fd, p, n); /* write the indent prefix, */
(void) write(fd, q, strlen(q)); /* this last line of text, */
if (LASTCH(q) != '\n')
(void) write(fd, "\n", 1); /* and an ending newline. */
}
if (erasable)
XtFree((String) p);
break;
} /* end - switch on client_data */
(void) close(fd);
if (alwaysIgnore) { /* get full headers for data (top 100 lines) */
txt = QueryMail("unset alwaysignore");
(void) sprintf(Command, "top %d", SelectionNumber(False));
txt = QueryMail(Command);
}
/*
** strip header information from the original message
*/
for (p = txt; *p; p++) {
if (*p == '\n' || strncmp(p, "Status:", 7) == 0) break;
if (strncmp(p, "From ", 5) == 0 ) {
bzero(oldFrom, BUFSIZ);
p += 5;
for (q = p; *q && *q != ' ' && *q != '\n'; q++);
(void) strncpy(oldFrom, p, q - p); /* drop the date portion now */
for (; *q && *q != '\n'; q++); /* skip to end of this line */
p = q;
}
else if (strncmp(p, "Return-Path:", 12) == 0) {
bzero(returnPath, BUFSIZ);
p += 13;
for (q = p; *q && *q != '\n'; q++);
(void) strncpy(returnPath, p, q - p); /* drop trailing newline */
p = q;
}
else if (strncmp(p, "Date:", 5) == 0) {
bzero(date, BUFSIZ);
p += 6;
for (q = p; *q && *q != '\n'; q++);
(void) strncpy(date, p, q - p);
p = q;
}
else if (strncmp(p, "From:", 5) == 0) {
bzero(author, BUFSIZ);
p += 6;
for (q = p; *q && *q != '\n'; q++);
while (*(q+1) && strchr(" \t", *(q+1))) {
*q = ' '; /* change this newline to a space */
*(q+1) = ' '; /* change possible tab to a space */
for (q++; *q && *q != '\n'; q++);
}
(void) strncpy(author, p, q - p);
p = q;
}
else if (strncmp(p, "To:", 3) == 0) {
bzero(toList, BUFSIZ);
p += 4;
for (q = p; *q && *q != '\n'; q++);
while (*(q+1) && strchr(" \t", *(q+1))) {
*q = ' '; /* change this newline to a space */
*(q+1) = ' '; /* change possible tab to a space */
for (q++; *q && *q != '\n'; q++);
}
if (*C == 'a' || *C == 'A')
(void) strncpy(toList, p, q - p);
p = q;
}
else if (strncmp(p, "Subject:", 8) == 0) {
bzero(subject, BUFSIZ);
p += 9;
for (q = p; *q && *q != '\n'; q++);
while (*(q+1) && strchr(" \t", *(q+1))) {
*q = ' '; /* change this newline to a space */
*(q+1) = ' '; /* change possible tab to a space */
for (q++; *q && *q != '\n'; q++);
}
(void) strncpy(subject, p, q - p);
p = q;
}
else if (strncmp(p, "Cc:", 3) == 0) {
bzero(ccList, BUFSIZ);
p += 4;
for (q = p; *q && *q != '\n'; q++);
while (*(q+1) && strchr(" \t", *(q+1))) {
*q = ' '; /* change this newline to a space */
*(q+1) = ' '; /* change possible tab to a space */
for (q++; *q && *q != '\n'; q++);
}
if (*C == 'a' || *C == 'A')
(void) strncpy(ccList, p, q - p);
p = q;
}
else for (; *p && *p != '\n'; p++);
} /* end - for all of message body */
if (alwaysIgnore) /* restore this if originally set */
p = QueryMail("set alwaysignore");
if (toList[0] != '\0') { /* remove ourself from the list */
if (! (us = getlogin())) {
struct passwd *pw = getpwuid((uid_t) getuid());
if (pw)
us = pw->pw_name;
else
us = "no_name";
}
for (p = toList; *us && *p; p++) {
if (strncmp(p, us, strlen(us)) == 0) {
for (q = p + strlen(us); *q && *q != ',' && *q != ' '; q++);
for (; *q && (*q == ',' || *q == ' '); q++);
bcopy(q, p, strlen(q) + 1);
continue;
}
while (*p && *p != ',' && *p != ' ') p++;
while (*p && (*p == ',' || *p == ' ')) p++;
p--;
}
}
} /* end - if client_data does not equal 's' */
InReply[0] = Recipient[0] = '\0';
/*
** If message did not have a 'From:', use 'Return-Path:' for reply recipient.
** If message also did not have a 'Return-Path', use the older style 'From '.
*/
if (*C != 'S' && *C != 's') {
p = author;
if (! *p && returnPath[0])
p = returnPath;
if (! *p && oldFrom[0])
p = oldFrom;
(void) strcpy(Recipient, p);
/*
** If author's name consists of a compound address (i.e. name <address>,
** (Name) address, or equivalents...) strip off the real address portion
** (i.e. that portion not in parens, but possibly between chevrons).
*/
if ((p = strchr(Recipient, '<')) || (p = strchr(Recipient, '(')))
switch (*p) {
case '<': q = strchr(p++, '>');
*q = '\0'; /* '<address> Name' or 'Name <address>' */
bcopy(p, Recipient, strlen(p) + 1);
break;
case '(': q = strchr(p, ')'); /* skipping past the parens */
if (p == Recipient) { /* '(Name) address' format */
for (q++; *q && (*q == ' ' || *q == '\t'); q++);
bcopy(p, Recipient, strlen(p) + 1);
} else { /* 'address (Name)' format */
for (; (p-1) > Recipient &&
(*(p-1) == ' ' || *(p-1) == '\t'); p--);
*p = '\0';
}
break;
}
/*
** If this sender wishes to include all recipients of the original message in
** this response, include all others except this sender in that address list.
*/
if (toList[0] && (*C == 'a' || *C == 'A')) {
if (LASTCH(Recipient) && LASTCH(Recipient) != ',' &&
(int)strlen(Recipient) + 2 < BUFSIZ)
(void) strcat(Recipient, ", ");
if ((int)strlen(Recipient) + (int)strlen(toList) < BUFSIZ)
(void) strcat(Recipient, toList);
for (p = Recipient + strlen(Recipient) - 1; *p == ' ' || *p == ','; p--);
*++p = '\0'; /* drop any trailing ", " garbage */
}
}
if (*C != 's' && author[0] && date[0]) {
r = (*C == 'S') ? "Forwarding" : "In-Reply-To";
(void) sprintf(InReply, "%s: Mail from '%s'\n%*sdated: %s", r, author,
strlen(r) - 5, " ", date);
}
sendMail(sb);
fd = -1;
if (edit_headers) {
(void) sprintf(Command, "%s_", tmpName);
if (rename(tmpName, Command))
Bell("xmail: Cannot rename edit file for editheaders\n");
else if ((fd = open(tmpName, O_WRONLY | O_CREAT, 0600)) < 0) {
Bell("xmail: Cannot reopen the edit file for editheaders\n");
return;
}
}
if (! Recipient[0]) {
writeTo(XtNameToWidget(sb, "*To"), "", REPLACE);
if (fd >= 0) (void) write(fd, "To: \n", 5);
} else {
writeTo(XtNameToWidget(sb, "*To"), Recipient, REPLACE);
if (fd >= 0) {
if (*C == 's' && edit_headers)
(void) write(fd, "To: \n", 5);
else {
(void) write(fd, "To: ", 4);
(void) write(fd, Recipient, strlen(Recipient));
(void) write(fd, "\n", 1);
}
}
}
if (! subject[0]) {
writeTo(XtNameToWidget(sb, "*Subject"), "", REPLACE);
if (fd >= 0) (void) write(fd, "Subject: \n", 10);
} else {
n = ((strchr("Rr", subject[0]) != NULL) &&
(strchr("Ee", subject[1]) != NULL) &&
(strchr(":;", subject[2]) != NULL));
if (n)
writeTo(XtNameToWidget(sb, "*Subject"), subject, REPLACE);
else {
writeTo(XtNameToWidget(sb, "*Subject"), "Re: ", REPLACE);
writeTo(XtNameToWidget(sb, "*Subject"), subject, APPEND);
}
if (fd >= 0) {
if (*C == 's' && edit_headers)
(void) write(fd, "Subject: \n", 10);
else {
(void) write(fd, "Subject: ", 9);
if (! n) (void) write(fd, "Re: ", 4);
(void) write(fd, subject, strlen(subject));
(void) write(fd, "\n", 1);
if (InReply[0]) {
(void) write(fd, InReply, strlen(InReply));
(void) write(fd, "\n", 1);
}
}
if (p = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader")) {
if (p[0] == '"' || p[0] == "'"[0]) {
bcopy(p + 1, p, strlen(p) - 1);
while (LASTCH(p) == '"' || LASTCH(p) == "'"[0])
LASTCH(p) = '\0';
}
(void) write(fd, p, strlen(p));
if (LASTCH(p) != '\n')
(void) write(fd, "\n", 1);
}
}
}
if (! ccList[0]) {
writeTo(XtNameToWidget(sb, "*Cc"), "", REPLACE);
if (fd >= 0 && edit_headers)
(void) write(fd, "Cc: \n", 5);
} else {
writeTo(XtNameToWidget(sb, "*Cc"), ccList, REPLACE);
if (fd >= 0) {
(void) write(fd, "Cc: ", 4);
(void) write(fd, ccList, strlen(ccList));
(void) write(fd, "\n", 1);
}
}
writeTo(XtNameToWidget(sb, "*Bcc"), "", REPLACE);
if (fd >= 0 && edit_headers)
(void) write(fd, "Bcc: \n", 6);
if (fd >= 0) {
(void) write(fd, "\n", 1);
if ((erasable = open(Command, O_RDONLY)) < 0) {
Bell("xmail: Cannot reread the edit file for editheaders\n");
return;
}
(void) unlink(Command);
while (n = read(erasable, Command, BUFSIZ))
(void) write(fd, Command, n);
(void) close(erasable);
(void) close(fd);
}
editMail();
} /* Reply */
/*
** @(#)Save() - (or copy) a message to specified folder or mbox
*/
/* ARGSUSED */
void
Save(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
int num;
String p, r, FBuf;
XawTextPosition pos;
Arg args[1];
Widget fileWindow;
char *cmd = (char *) client_data;
if (! mailpid) Bell("No current mail connection\n");
else {
SetCursor(WATCH); /* reset by parser routines */
num = SelectionNumber(False); /* no current message returns zero */
if (*cmd == 'C' || *cmd == 'S' || num == 0) {
if (num) {
(void) sprintf(Command, "%s %d\n", cmd, num);
Bell(""); /* Reset bell worthyness flag */
} else {
(void) sprintf(Command, "%s \n", cmd);
}
} else {
fileWindow = XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow");
pos = TextGetLastPos(fileWindow);
if (pos - StartPos > 0) {
XtSetArg(args[0], XtNstring, &FBuf);
XtGetValues(fileWindow, args, 1);
if (FBuf[pos] != '\0') FBuf[pos] = '\0';
p = XtNewString(&FBuf[StartPos]);
(void) sprintf(Command, "%s %d %s\n", cmd, num, p);
XtFree((String) p);
} else {
/*
** If no specified filename, use the mbox pointer. We MUST include
** it here, because specifying the message number for the action
** would be interpreted as a filename, if we didn't append one.
*/
if (! (p = GetMailEnv("MBOX")))
(void) sprintf(Command, "%s %d %s/mbox\n", cmd, num, HOME);
else {
initfoldir();
if (*p != '+' && (*p == '/' || (*p == '.' && *(p+1) == '/') ||
foldir[0] == '\0')) {
(void) sprintf(Command, "%s %d %s\n", cmd, num, p);
} else {
(void) sprintf(Command, "%s %d %s%s\n", cmd, num, foldir, (*p == '+') ? &p[1] : p);
}
XtFree((String) p);
}
}
}
writeMail(Command);
}
} /* Save */
/*
** @(#)SetNewmail - Highlight Newmail button to attract user attention
*/
/* ARGSUSED */
void
SetNewmail(w, client_data, call_data)
Widget w; /* unused */
XtPointer client_data; /* unused */
XtPointer call_data; /* unused */
{
Widget cw;
if (! Highlighted) {
cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
XSetWindowBackgroundPixmap(XtDisplay(toplevel), XtWindow(cw), hatch);
XtUnmapWidget(cw);
XtMapWidget(cw);
Highlighted = 1;
reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 0);
}
} /* SetNewmail */
/*
** @(#)UnsetNewmail - Remove Newmail button highlighting
*/
/* ARGSUSED */
void
UnsetNewmail(w, client_data, call_data)
Widget w; /* unused */
XtPointer client_data; /* unused */
XtPointer call_data; /* unused */
{
Widget cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
if (Highlighted) {
XSetWindowBackground(XtDisplay(toplevel), XtWindow(cw), cw->core.background_pixel);
XtUnmapWidget(cw);
XtMapWidget(cw);
Highlighted = 0;
reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 1);
}
} /* UnsetNewmail */
syntax highlighted by Code2HTML, v. 0.9.1