/* * 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 #include #include #include #include #include #include #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
, ** (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'; /* '
Name' or 'Name
' */ 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 */