michael@uunet.UU.NET (Michael Wagnitz) (06/16/91)
Submitted-by: stratus!voder!nsc!berlioz.nsc.com!michael@uunet.UU.NET (Michael Wagnitz) Posting-number: Volume 13, Issue 51 Archive-name: xmail/part09 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 9 (of 11)." # Contents: callbacks.c # Wrapped by michael@harley on Fri May 3 13:35:53 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'callbacks.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'callbacks.c'\" else echo shar: Extracting \"'callbacks.c'\" \(32817 characters\) sed "s/^X//" >'callbacks.c' <<'END_OF_FILE' X/* X * xmail - X window system interface to the mail program X * X * Copyright 1990 by National Semiconductor Corporation X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose is hereby granted without fee, provided that X * the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of National Semiconductor Corporation not X * be used in advertising or publicity pertaining to distribution of the X * software without specific, written prior permission. X * X * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE X * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" X * WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION X * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO X * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL, X * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM X * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE X * OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR X * PERFORMANCE OF THIS SOFTWARE. X * X * Author: Michael C. Wagnitz - National Semiconductor Corporation X * X */ X X X#include "global.h" X#include "xmailregex.h" X#include <sys/wait.h> X#include <sys/stat.h> X#include <sys/types.h> X#include <sys/time.h> X#include <pwd.h> X Xextern char otherBuf[BUFSIZ]; X X/* X** @(#)Autograph() - Add user's Sign or sign autograph to outgoing mail X** Then make button insensitive, to prevent multiple calls. X** If requested autograph signature does not exist, tell user. X*/ X/* ARGSUSED */ XXtCallbackProc XAutograph(w, C, call_data) XWidget w; Xcaddr_t C; Xcaddr_t call_data; X{ X FILE *fp; X String autograph; X char tmp[BUFSIZ]; X int n; X X X strcpy(tmp, "Sign"); /* Default action is to use Sign autograph */ X if (*C == 'a') tmp[0] = 's'; X autograph = GetMailEnv(tmp); /* First, see if an autograph exists */ X X if (! autograph) { X strcpy(tmp, "Cannot find a 'Sign'ature in your .mailrc file\n"); X if (*C == 'a') tmp[15] = 's'; X Bell(tmp); X } else { X XtSetSensitive(w, False); /* Don't let us be pressed more than once */ X if (*C == 'A') /* also make other sign button inoperative */ X XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), False); X else /* if this was a request for lowercase sign */ X XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), False); X X for (n = 0; n < BUFSIZ - 2 && *autograph; autograph++) X if (*autograph == '\\' && *(autograph + 1) == 'n') { X tmp[n++] = '\n'; /* Replace newline strings with a character */ X autograph++; X } else tmp[n++] = *autograph; X X if (tmp[n - 1] != '\n') /* make sure msg ends with a newline */ X tmp[n++] = '\n'; X tmp[n] = '\0'; X X if ((fp = fopen(tmpName, "a")) != NULL) { X fwrite(tmp, sizeof(* tmp), strlen(tmp), fp); X fclose(fp); X } X XtFree(autograph); X } X} /* Autograph */ X X X/* X** @(#)Done() - Send composed message - if closure data says "Deliver" X** Attempt to do the task as a forked child. Failing that, X** deliver the message by system call(s). X*/ X/* ARGSUSED */ XXtCallbackProc XDone(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X Widget shell; X FILE *fp, *xf; X char *ARGV[3]; X char *p, *q, *record, *folder, *getenv(); X char From[BUFSIZ], Copy[BUFSIZ], s[BUFSIZ], addressees[BUFSIZ]; X int n; X struct stat st_buf; X X X Bell(Default_Status_Info); X X shell = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup"); X if (! shell) return; /* SOMEthing would be VERY wrong here */ X X SetCursor(1); X XtPopdown(shell); /* remove from use but don't destroy */ X/* X** Restore the sensitivity of the Autograph buttons X*/ X XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True); X XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True); X X st_buf.st_size = 0; /* (in case msg file does not exist) */ X stat(tmpName, &st_buf); X X if (strcmp(closure, "Deliver") == 0) { X otherBuf[0] = '\0'; /* remove names from any previous act */ X/* X** Prepare header information (in a second temporary file). Call the alias() X** routine recursively, to de-alias the user's To:, Cc:, and Bcc: fields. X*/ X if ((fp = fopen(tmpName, "a+")) != NULL) { /* (give cat something to do) */ X fprintf(fp, "\n"); /* ensure the last line is a blank */ X fclose(fp); X if (st_buf.st_size) /* don't count unless text was there */ X st_buf.st_size += 1; /* but try to be accurate for cancel */ X } X X sprintf(s, "%s_", tmpName); X if ((fp = fopen(s, "w")) != NULL) { X if (*Recipient) { X strcpy(addressees, Recipient); /* alias() adds file names to a list */ X for (p = alias(addressees); X strcmp(p, addressees); X p = alias(addressees)) X strcpy(addressees, p); /* and returns just user addresses, */ X X if (*addressees) /* for case if user has mix of both */ X fprintf(fp, "To: %s\n", addressees); X } X X if (*SubjBuf) X fprintf(fp, "Subject: %s\n", SubjBuf); X X if (*InReply) X fprintf(fp, "%s\n", InReply); X X if (*CcBuf) { X strcpy(s, CcBuf); X for (p = alias(s); strcmp(p, s); p = alias(s)) X strcpy(s, p); X X if (*p) { X fprintf(fp, "Cc: %s\n", p); X strcat(addressees, " "); X strcat(addressees, p); X } X } X X if (*BccBuf) { X strcpy(s, BccBuf); X for (p = alias(s); strcmp(p, s); p = alias(s)) X strcpy(s, p); X X if (*p) { X fprintf(fp, "Bcc: %s\n", p); X strcat(addressees, " "); X strcat(addressees, p); X } X } X X#ifdef X_FACE X/* X** Look in user's home directory for, and add contents of, their .face file X*/ X sprintf(s, "%s/.face", getenv("HOME")); X if (xf = fopen(s, "r")) { X while (fgets(s, BUFSIZ, xf) != NULL) X fprintf(fp, "%s", s); X fclose(xf); X } X#endif X_FACE X X if ((*Recipient || *SubjBuf) && st_buf.st_size) X fprintf(fp, "\n"); /* separate the header from any text */ X fclose(fp); X } X X sprintf(s, "%s=", tmpName); X fp = fopen(s, "w"); X if (fp) { /* try to keep user from overwriting these */ X fprintf(fp,"mv %s_ %s#_ 2> /dev/null\n", tmpName, tmpName); X fprintf(fp,"mv %s %s# 2> /dev/null\n", tmpName, tmpName); X } X/* X** mail the header information and text in temporary files using sendmail X*/ X if (*addressees && (*SubjBuf || st_buf.st_size)) { X if ((p = GetMailEnv("sendmail")) == NULL) X p = XtNewString("/usr/lib/sendmail"); X/* X** To avoid a bug in Sun's sendmail (for occasionally not being able to find X** the name of the real author of the message), strip commas from the address X** list and pass the recipient names to sendmail on the command line, ala Mail. X*/ X for (q = addressees; *q; q++) if (*q == ',') *q = ' '; X q = addressees; X/* X** The following arguments are passed to the sendmail command: X** X** -oi don't accept a dot on a line by itself as message termination X** X** -om send to "me" too, if I am a member of an alias expansion X*/ X if (fp) X fprintf(fp, "cat %s#_ %s# | %s -oi -om %s\n", tmpName, tmpName, p, q); X else { X sprintf(s, "cat %s_ %s | %s -oi -om %s", tmpName, tmpName, p, q); X system(s); X } X X XtFree(p); X/* X** If user has set "record" in their .mailrc, add a message copy to that file. X** Try to faithfully follow the description of the "outfolder" variable, even X** if Berkeley Mail doesn't appear to do so. To whit, if "outfolder" is set, X** ``locate files used to record outgoing messages (the "record" variable, X** for one) in the directory specified by the "folder" variable, unless the X** pathname is absolute.'' (Quoted from Mail man page outfolder description.) X** Consider both absolute and relative addressing (i.e. /* and ./*) X*/ X if (record = GetMailEnv("record")) { X long *clock; X X p = GetMailEnv("outfolder"); X folder = GetMailEnv("folder"); X if (*record != '+' && X (*record == '/' || (*record == '.' && *(record+1) == '/') || X p == NULL || folder == NULL)) { X strcpy(Copy, record); X } else { X if (*folder == '/') X sprintf(Copy, "%s/%s", folder, X (*record == '+') ? &record[1] : record); X else X sprintf(Copy, "%s/%s/%s", getenv("HOME"), folder, X (*record == '+') ? &record[1] : record); X } X if (folder) XtFree(folder); X if (p) XtFree(p); X XtFree(record); X X (void) time(&clock); X sprintf(From, "From %s %24.24s", getenv("USER"), ctime(&clock)); X if (fp) X fprintf(fp,"echo \"%s\" >> %s\ncat %s#_ %s# >> %s 2> /dev/null\n", X From, Copy, tmpName, tmpName, Copy); X else { X sprintf(s, "echo \"%s\" >> %s;cat %s_ %s >> %s 2> /dev/null", X From, Copy, tmpName, tmpName, Copy); X system(s); X } X } /* end - if record variable is set */ X/* X** If there are other addresses, add copies to those files and or folders X*/ X if (*otherBuf) { X FILE *fp1; X long *clock; X /* X ** Prepare (aliased) header information (in a third temporary file) X */ X sprintf(s, "%s$", tmpName); X if ((fp1 = fopen(s, "w"))) { X (void) time(&clock); X sprintf(fp1, "From %s %s", getenv("USER"), ctime(&clock)); X fprintf(fp1, "To: %s\n", Recipient); X X if (*SubjBuf) X fprintf(fp1, "Subject: %s\n", SubjBuf); X X if (*InReply) X fprintf(fp1, "%s\n", InReply); X X if (*CcBuf) X fprintf(fp1, "Cc: %s\n", CcBuf); X X fprintf(fp1, "\n"); /* separate header from text */ X fclose(fp1); X } X p = GetMailEnv("outfolder"); X folder = GetMailEnv("folder"); X for (record = otherBuf; *record;) { X for (q = record; *q && *q != ','; q++); X n = 0; X if (*q == ',') { X *q = '\0'; X n = 1; X } X if (*record != '+' && X (*record == '/' || (*record == '.' && *(record+1) == '/') || X p == NULL || folder == NULL)) { X strcpy(Copy, record); /* same rules as for 'record' */ X } else { X if (*folder == '/') X sprintf(Copy, "%s/%s", folder, X (*record == '+') ? &record[1] : record); X else X sprintf(Copy, "%s/%s/%s", getenv("HOME"), folder, X (*record == '+') ? &record[1] : record); X } X X if (fp) X fprintf(fp, "cat %s$ %s# >>%s 2>/dev/null\n", tmpName, tmpName, Copy); X else { X sprintf(s, "cat %s$ %s >> %s 2> /dev/null", tmpName, tmpName, Copy); X system(s); X } X if (n) *q++ = ','; X record = q; X } /* end - for each record in otherBuf */ X if (p) XtFree(p); X if (folder) XtFree(folder); X } /* end - if records in otherBuf */ X } else { /* end - if something is there to deliver */ X if (! *Recipient) X Bell("No recipient specified\n"); X else X Bell("No subject and no message\n"); X } X } else { /* do we want to save the message text in dead file */ X sprintf(s, "%s=", tmpName); /* name of the command script file */ X fp = fopen(s, "w"); /* try to run commands in a child */ X n = st_buf.st_size; /* remember num bytes in msg text */ X if (n == 0 && *closure == 'c') X Bell("No text to save in your dead letter box\n"); X else { X if (n && (*closure == 'c' || ! Confirm("REALLY discard this text"))) { X if ((record = GetMailEnv("DEAD")) == NULL) X sprintf(Copy, "%s/dead.letter", getenv("HOME")); X else { X strcpy(Copy, record); /* take whatever is given */ X XtFree(record); X } X st_buf.st_size = -1; /* see if our target exists */ X stat(Copy, &st_buf); X sprintf(s, "\"%s\" [%s] (%d bytes)\n", Copy, X (st_buf.st_size >= 0) ? "Appended" : "New file", n); X Bell(s); X if (fp) X fprintf(fp,"cat %s# >> %s 2> /dev/null\n", tmpName, Copy); X else { X sprintf(s, "cat %s >> %s 2> /dev/null", tmpName, Copy); X system(s); X } X } X } X } X/* X** remove any message text that may have been created X*/ X SetCursor(0); X if (! fp) { /* if we failed to make temp file */ X sprintf(s, "rm -f %s_ %s %s$ &", tmpName, tmpName, tmpName); X system(s); X } else { /* try to fork this off to a child process */ X fprintf(fp, "rm -f %s#_ %s# %s= %s$\n", tmpName,tmpName,tmpName,tmpName); X fclose(fp); X switch (fork()) { X case -1: /* failed, so use old fashioned way */ X sprintf(s, "/bin/sh %s= &", tmpName); X system(s); X break; X case 0: /* fork succeeded - we are the child */ X sprintf(s, "%s=", tmpName); X ARGV[0] = "/bin/sh"; X ARGV[1] = s; X ARGV[2] = NULL; X execv("/bin/sh", ARGV); X break; X } X } X} /* Done */ X X X/* X** @(#)DoIt() - send command - passed via client_data argument - to mail X*/ X/* ARGSUSED */ XXtCallbackProc XDoIt(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X int n; X char buf[BUFSIZ]; X Arg args[1]; X LabelWidget lw = (LabelWidget) XtNameToWidget(toplevel, "topBox.titleBar.title"); X X X SetCursor(1); X sprintf(Command, "%s\n", closure); X if (mailpid) { /* If connections are okay,... */ X if ((n = match(&command_pattern, Command)) != C_FILE && n != C_NEWMAIL) X writeMail(Command); X else { /* check for commit of any changes */ X XtSetArg(args[0], XtNlabel, (XtArgVal) NULL); X XtGetValues(lw, args, ONE); X strcpy(buf, (char *)args[0].value); X X if (strcmp(&buf[strlen(buf) - 7], "deleted") || X strcmp(closure, "inc") == 0 || X Confirm("COMMIT all changes to this folder")) X writeMail(Command); X } X } else if (C_NEWMAIL != match(&command_pattern, Command)) X Bell("No current mail connection\n"); /* if not 'Newmail' */ X else { X if (strcmp(mailargv[mailargc - 2], "-f") == 0) { X mailargc -= 2; /* throw away any folder argument */ X mailargv[mailargc] = NULL; /* and NULL end of argument list */ X } X callMail(mailargc, mailargv); /* restart the mail connections */ X strcpy(Command, "Start"); /* Let em know we've re-started */ X UnsetNewmail(w, NULL, NULL); X } X} /* DoIt */ X X X/* X** @(#)DoPrint() - Call the PrintMsg action routine from a callback X*/ X/* ARGSUSED */ XXtCallbackProc XDoPrint(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X PrintMsg(w, NULL, NULL, NULL); X} /* DoPrint */ X X X/* X** @(#)DoQuit() - Terminate xmail after first closing mail connection X*/ X/* ARGSUSED */ XXtCallbackProc XDoQuit(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X Arg args[1]; X Display *dpy = XtDisplay(toplevel); X LabelWidget lw = (LabelWidget) XtNameToWidget(toplevel, "topBox.titleBar.title"); X char buf[BUFSIZ]; X int status; X X if (mailpid) { /* check for commit of any changes */ X XtSetArg(args[0], XtNlabel, (XtArgVal) NULL); X XtGetValues(lw, args, ONE); X strcpy(buf, (char *)args[0].value); X X if (*closure != 'q' || strcmp(&buf[strlen(buf) - 7], "deleted") || X Confirm("Changes in folder. REALLY quit")) { X sprintf(Command, "%s\n", closure); X writeMail(Command); X wait3(&status, WNOHANG, NULL); X } else return; X } X X XtDestroyWidget(toplevel); X XCloseDisplay(dpy); X _exit(0); X} /* DoQuit */ X X X/* X** @(#)DoSet() - send specified set request to mail and destroy current menu. X** To accommodate those systems (Sony?) whose mail cannot handle X** 'set no' commands, convert 'set no's to unsets. X*/ X/* ARGSUSED */ XXtCallbackProc XDoSet(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X char *c, buf[32]; X X X SetCursor(1); X if (! mailpid) X Bell("No current mail connection\n"); X else { X c = w->core.name; X if (strcmp(&c[strlen(c) - 6], "expert") == 0) X if (*c == 'n') X XMail.expert = (Boolean) 0; X else XMail.expert = (Boolean) 1; X else { X if (*c == 'n') X sprintf(buf, "unset %s", &c[2]); X else X sprintf(buf, "set %s", c); X X c = QueryMail(buf); X XtFree(c); X } X X XtDestroyWidget(XtParent(XtParent(w))); X SetCursor(0); X } X} /* DoSet */ X X X/* ARGSUSED */ X/* X** @(#)DoWith() - send client_data command to mail with selected msg number X*/ XXtCallbackProc XDoWith(w, client_data, call_data) XWidget w; Xcaddr_t client_data; Xcaddr_t call_data; X{ X int num = 0; X X X SetCursor(1); X if (! mailpid) Bell("No current mail connection\n"); X else { X num = SelectionNumber(*client_data == 'u'); X X if (num) sprintf(Command, "%s %d\n", client_data, num); X else sprintf(Command, "%s \n", client_data); X X writeMail(Command); X } X} /* DoWith */ X X X/* ARGSUSED */ X/* X** @(#)DropIt() - callback to destroy the current folder popup list(s) X*/ XXtCallbackProc XDropIt(w, client_data, call_data) XWidget w; Xcaddr_t client_data; Xcaddr_t call_data; X{ X Widget popup = XtNameToWidget(toplevel,"topBox.commandPanel.Folder.popupList"); X if (popup) X XtDestroyWidget(popup); X} /* DropIt */ X X X/* X** @(#)GetAliasName() - retrieve alias name from button label X*/ X/* ARGSUSED */ XXtCallbackProc XGetAliasName(w, client_data, call_data) XWidget w; Xcaddr_t client_data; /* unused */ Xcaddr_t call_data; /* unused */ X{ X Arg args[1]; X String alias_name; X Widget shell; X X X XtSetArg(args[0], XtNlabel, &alias_name); X XtGetValues(w, (ArgList) args, 1); /* get this entry's label value */ X X shell = XtParent(XtParent(w)); /* aliasList<-table<-entry */ X XtPopdown(shell); X X shell = XtParent(shell); /* (To|Cc|Bcc)<-aliasList */ X X if (TextGetLastPos(shell)) /* if some alias is already in there */ X writeText(shell, ", ", 1); /* add comma separator between names */ X X writeText(shell, alias_name, 1); X} /* GetAliasName */ X X X/* X** @(#)GetFolderName() - retrieve full folder name from button labels X*/ X/* ARGSUSED */ XXtCallbackProc XGetFolderName(w, client_data, call_data) XWidget w; Xcaddr_t client_data, call_data; X{ X Arg args[1]; X Cardinal k, n, x; X String folder_name; X Widget shell; X char tmp[BUFSIZ], buf[BUFSIZ]; X X X XtSetArg(args[0], XtNlabel, &folder_name); X XtGetValues(w, (ArgList) args, 1); X X if (! call_data) /* just a simple label name */ X sprintf(buf, "File: %s", folder_name); X else { /* multiple stack of names */ X tmp[0] = '\0'; X shell = w; X sscanf(call_data, "%d", &n); /* using the nesting depth */ X X for (x = 1, k = (n * 2) + n - 1; k; k--) { X shell = shell->core.parent; /* travel up the widget tree */ X if (++x == 3) { /* when we get to a label... */ X x = 0; X strcpy(buf, shell->core.name); /* stuff each label name in */ X strcat(buf, tmp); /* front of previous labels */ X strcpy(tmp, buf); /* to build a complete path */ X } X } X sprintf(buf, "File: +%s%s", tmp, folder_name); X } X writeText(XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow"), buf, 0); X} /* GetFolderName */ X X X/* X** @(#)ReEdit() - Call the editMail routine to re-edit a message X*/ X/* ARGSUSED */ XXtCallbackProc XReEdit(w, closure, call_data) XWidget w; Xcaddr_t closure; Xcaddr_t call_data; X{ X Widget Popup, To; X X X Popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup"); X X if (! Popup) { X XBell(XtDisplay(toplevel), 33); X return; /* SOMEthing must be VERY wrong here */ X } X X To = XtNameToWidget(Popup, "SubjCc.To"); X X XtPopdown(Popup); /* pop down the send popup */ X X editMail(); /* re-edit the message file */ X X XtPopup(Popup, XtGrabNone); /* pop back the send popup */ X XWarpPointer(XtDisplay(toplevel), None, XtWindow(To), 0, 0, 0, 0, 10, 5); X} /* ReEdit */ X X X/* X** @(#)Reply() - send a reply to the author of the selected message X** include its text and/or copy the other recipients, if asked. X*/ X/* ARGSUSED */ XXtCallbackProc XReply(w, client_data, call_data) XWidget w; Xcaddr_t client_data; Xcaddr_t call_data; X{ X FILE *fp; X String p, q, r, old_From; X String txt, ccList, author, subject, others, date, reference, empty; X Widget sb = XtNameToWidget(toplevel, "topBox.commandPanel.Send"); X char *us, *getlogin(); X int erasable = 0; X int alwaysIgnore; X X X SetCursor(1); X txt = ccList = author = subject = others = date = reference = empty = old_From = ""; X if (*client_data != 's') { X if ((fp = fopen(tmpName, "w")) == NULL) X Bell("xmail: Cannot open temp file for writing\n"); X X if (p = GetMailEnv("alwaysignore")) { X XtFree(p); X alwaysIgnore = (strchr("SRA", *client_data)) ? 1 : 0; X } else alwaysIgnore = 0; X X if (alwaysIgnore) /* do we need to include a limited copy? */ X sprintf(Command, "p %d", SelectionNumber(False)); X else X sprintf(Command, "P %d", SelectionNumber(False)); X X txt = QueryMail(Command); X if (fp) { X switch (*client_data) { X case 'S': X fputs("---------- Begin Forwarded Message ----------\n", fp); X if (! fwrite(txt, sizeof(*txt), strlen(txt), fp)) X Bell("xmail: Could not write to temp file\n"); X fputs("----------- End Forwarded Message -----------\n", fp); X break; X case 'R': X case 'A': X if ((p = GetMailEnv("indentprefix")) != NULL) X erasable = 1; X else X p = "\t"; X for (q = r = txt; *r;) { X for (; *r && *r != '\n'; r++); X if (*r == '\n') { /* For each line of insert */ X *r = '\0'; /* temporarily mark off eos, */ X fputs(p, fp); /* write our indent prefix, */ X fputs(q, fp); /* this line of insert text, */ X fputs("\n", fp); /* and our missing newline, */ X *r = '\n'; /* and replace for later use */ X q = ++r; X } X } X if (erasable) X XtFree(p); X break; X } /* end - switch on client_data */ X } /* end - if file is open */ X/* X** strip author, subject, and Carbon copy information from the selected message X*/ X if (alwaysIgnore) { /* get full headers for data (top 100 lines) */ X XtFree(txt); X txt = QueryMail("unset alwaysignore"); X XtFree(txt); X sprintf(Command, "top %d", SelectionNumber(False)); X txt = QueryMail(Command); X p = QueryMail("set alwaysignore"); X XtFree(p); X } X for (p = txt; *p; p++) { X if (strcmp(p, empty) == 0 || strncmp(p, "Status:", 7) == 0) break; X X if (strncmp(p, "From ", 5) == 0 ) { X old_From = p + 5; X for (p = old_From; *p && *p != ' ' && *p != '\n'; p++); X if (*p) *p++ = '\0'; /* drop the date portion now */ X for (; *p && *p != '\n'; p++); /* skip to end of this line */ X } X X else if (strncmp(p, "Return-Path:", 12) == 0) { X reference = p + 14; /* step over the opening '<' chevron */ X for (p = reference; *p && *p != '>'; p++); X if (*p) *p++ = '\0'; /* drop the trailing chevron */ X for (; *p && *p != '\n'; p++); /* skip to end of this line */ X } X X else if (strncmp(p, "Date:", 5) == 0) { X date = p + 6; X for (p = date; *p && *p != '\n'; p++); X if (*p) *p = '\0'; X } X X else if (strncmp(p, "From:", 5) == 0) { X author = p + 6; X for (p = author; *p && *p != '\n'; p++); X while (*(p+1) && strchr(" \t", *(p+1))) { X *p = ' '; /* change this newline to a space */ X *(p+1) = ' '; /* change possible tab to a space */ X for (p++; *p && *p != '\n'; p++); X } X if (*p) *p = '\0'; X } X X else if (strncmp(p, "To:", 3) == 0) { X others = p + 4; X for (p = others; *p && *p != '\n'; p++); X while (*(p+1) && strchr(" \t", *(p+1))) { X *p = ' '; /* change this newline to a space */ X *(p+1) = ' '; /* change possible tab to a space */ X for (p++; *p && *p != '\n'; p++); X } X if (*p) *p = '\0'; X } X X else if (strncmp(p, "Subject:", 8) == 0) { X subject = p + 9; X for (p = subject; *p && *p != '\n'; p++); X while (*(p+1) && strchr(" \t", *(p+1))) { X *p = ' '; /* change this newline to a space */ X *(p+1) = ' '; /* change possible tab to a space */ X for (p++; *p && *p != '\n'; p++); X } X if (*p) *p = '\0'; X } X X else if (strncmp(p, "Cc:", 3) == 0) { X ccList = p + 4; X for (p = ccList; *p && *p != '\n'; p++); X while (*(p+1) && strchr(" \t", *(p+1))) { X *p = ' '; /* change this newline to a space */ X *(p+1) = ' '; /* change possible tab to a space */ X for (p++; *p && *p != '\n'; p++); X } X if (*p) *p = '\0'; X } X else for (; *p && *p != '\n'; p++); X } /* end - for all of message body */ X X if (*client_data != 'a' && *client_data != 'A') { X ccList = empty; /* If not [rR]eplyall, make sender enter any Cc: */ X others = empty; X } else { /* otherwise, remove ourself from the others list */ X us = getlogin(); X if (! us) { X struct passwd *pw = getpwuid(getuid()); X X if (pw) X us = pw->pw_name; X } X for (p = others; *us && *p; p++) { X if (strncmp(p, us, strlen(us)) == 0) { X for (us = p + strlen(us); *us && *us != ',' && *us != ' ';) us++; X for (; *us && (*us == ',' || *us == ' ');) us++; X for (; *us;) *p++ = *us++; X *p = '\0'; X break; X } X while (*p && *p != ',' && *p != ' ') p++; X while (*p && (*p == ',' || *p == ' ')) p++; X p--; X } X } X X if (fp) fclose(fp); X X } /* end - if client_data does not equal 's' */ X X Recipient[0] = InReply[0] = SubjBuf[0] = CcBuf[0] = BccBuf[0] = '\0'; X/* X** If message did not have a 'From:', use 'Return-Path:' for reply recipient. X** If message also did not have a 'Return-Path', use the older style 'From '. X*/ X if (*client_data != 'S' && *client_data != 's') { X if (! *author && *reference) X author = reference; X if (! *author && *old_From) X author = old_From; X strcpy(Recipient, author); X/* X** If author's name consists of a compound address (i.e. name <address>, X** (Name) address, or equivalents...) strip off the real address portion X** (i.e. that portion not in parens, but possibly between chevrons). X*/ X if ((p = strchr(Recipient, '(')) || (p = strchr(Recipient, '<'))) X switch (*p) { X case '(': q = strchr(p, ')'); /* skipping past the parens */ X if (p == Recipient) { /* '(Name) address' format */ X for (q++; *q && (*q == ' ' || *q == '\t'); q++); X bcopy(p, Recipient, strlen(p) + 1); X } else { /* 'address (Name)' format */ X for (; (p-1) > Recipient && X (*(p-1) == ' ' || *(p-1) == '\t'); p--); X *++p = '\0'; X } X break; X X case '<': q = strchr(p++, '>'); X *q = '\0'; /* '<address> Name' or 'Name <address>' */ X bcopy(p, Recipient, strlen(p) + 1); X break; X } X/* X** If the user wishes to include all recipients of the original X** message in this message, include those others in the address. X*/ X if (*others && (*client_data == 'a' || *client_data == 'A')) { X if (LASTCH(Recipient) && LASTCH(Recipient) != ',') X strcat(Recipient, ", "); X strcat(Recipient, others); X for (p = Recipient + strlen(Recipient) - 1; *p == ' ' || *p == ','; p--); X *++p = '\0'; /* drop any trailing ", " garbage */ X } X } X X if (*client_data != 's' && *reference && *date) { X r = (*client_data == 'S') ? "Forwarding" : "In-Reply-To"; X sprintf(InReply, "%s: Mail from '%s'\n dated: %s", r, reference, date); X } X X if (*subject) { X if (strncmp(subject, "Re:", 3) != 0 && X strncmp(subject, "Re;", 3) != 0 && X strncmp(subject, "RE:", 3) != 0 && X strncmp(subject, "RE;", 3) != 0 && X strncmp(subject, "re:", 3) != 0 && X strncmp(subject, "re;", 3) != 0) X strcpy(SubjBuf, "Re: "); X strcat(SubjBuf, subject); X } X X strcpy(CcBuf, ccList); X X XtFree(txt); X X SetCursor(0); X X sendMail(sb); X} /* Reply */ X X X/* X** @(#)Save() - (or copy) a message to specified folder or mbox X*/ X/* ARGSUSED */ XXtCallbackProc XSave(w, cmd, call_data) XWidget w; Xcaddr_t cmd; Xcaddr_t call_data; X{ X char *p, *q, *r, *getenv(); X Cardinal num, n; X X X SetCursor(1); X if (! mailpid) Bell("No current mail connection\n"); X else { X num = SelectionNumber(False); /* no current message returns zero */ X if (*cmd == 'C' || *cmd == 'S' || num == 0) { X if (num) { X sprintf(Command, "%s %d\n", cmd, num); X } else { X sprintf(Command, "%s \n", cmd); X } X } else { X if ((n = TextGetLastPos(XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow")) - StartPos) > 0) { X FileBuf[StartPos + n] = '\0'; X p = FileBuf + StartPos; X sprintf(Command, "%s %d %s\n", cmd, num, p); X } else { X/* X** If no specified filename, use the mbox pointer. We MUST include it here, X** because specifying the message number for the action would be interpreted X** as a filename, if we don't append one. X*/ X if ((p = GetMailEnv("MBOX"))) { X q = GetMailEnv("outfolder"); X r = GetMailEnv("folder"); X if (*p != '+' && (*p == '/' || (*p == '.' && *(p+1) == '/') || X q == NULL || r == NULL)) { X sprintf(Command, "%s %d %s\n", cmd, num, p); X } else { X if (*r == '/') X sprintf(Command, "%s %d %s/%s\n", cmd, num, r, (*p == '+') ? &p[1] : p); X else X sprintf(Command, "%s %d %s/%s/%s\n", cmd, num, X getenv("HOME"), r, (*p == '+') ? &p[1] : p); X } X if (r) XtFree(r); X if (q) XtFree(q); X XtFree(p); X } X } X } X writeMail(Command); X } X} /* Save */ X X X/* X** @(#)SetNewmail - Highlight Newmail button to attract user attention X*/ X/* ARGSUSED */ XXtCallbackProc XSetNewmail(w, client_data, call_data) XWidget w; /* unused */ Xcaddr_t client_data; /* unused */ Xcaddr_t call_data; /* unused */ X{ X Widget cw; X X if (! Highlighted) { X cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail"); X XSetWindowBackgroundPixmap(XtDisplay(toplevel), XtWindow(cw), hatch); X XtUnmapWidget(cw); X XtMapWidget(cw); X Highlighted = 1; X } X} /* SetNewmail */ X X X/* X** @(#)UnsetNewmail - Remove Newmail button highlighting X*/ X/* ARGSUSED */ XXtCallbackProc XUnsetNewmail(w, client_data, call_data) XWidget w; /* unused */ Xcaddr_t client_data; /* unused */ Xcaddr_t call_data; /* unused */ X{ X Widget cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail"); X X if (Highlighted) { X XSetWindowBackground(XtDisplay(toplevel), XtWindow(cw), cw->core.background_pixel); X XtUnmapWidget(cw); X XtMapWidget(cw); X Highlighted = 0; X reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox")); X } X} /* UnsetNewmail */ END_OF_FILE if test 32817 -ne `wc -c <'callbacks.c'`; then echo shar: \"'callbacks.c'\" unpacked with wrong size! fi # end of 'callbacks.c' fi echo shar: End of archive 9 \(of 11\). cp /dev/null ark9isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 11 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Dan Heller O'Reilly && Associates Z-Code Software Comp-sources-x: Senior Writer President comp-sources-x@uunet.uu.net argv@ora.com argv@zipcode.com