/* * 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. * * The following software modules were created and are Copyrighted by National * Semiconductor Corporation: * * 1. warp_handler: * 2. extract_of: * 3. endEdits: * 4. editMail: * 5. makeHeading: * 6. makeButton: * 7. sendMail: * * Author: Michael C. Wagnitz - National Semiconductor Corporation * */ #include "global.h" #include #include #include #include #ifdef vms extern int noshare errno; #else extern int errno; #endif #if ! defined(SIGCHLD) && defined(SIGCLD) #define SIGCHLD SIGCLD #endif #ifndef DEFAULT_VISUAL #ifndef linux #define DEFAULT_VISUAL "/usr/ucb/vi" #else #define DEFAULT_VISUAL "/usr/bin/vi" #endif #endif static int editMail_pid; /* ARGSUSED */ void warp_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *continueToDispatch) { Widget Popup = XtNameToWidget(toplevel,"topBox.commandPanel.Send.popup"); Widget To = XtNameToWidget(Popup, "SubjCc.To"); if (event->type == MapNotify) { XWarpPointer(XtDisplay(toplevel), None, XtWindow(To), 0,0,0,0, 15, 10); XtRemoveEventHandler(Popup, StructureNotifyMask, False, warp_handler, NULL); } } /* ** @(#)extract_of - strip off header information from a buffer and return ** the extracted information and the incremented pointer */ char * extract_of(char **p) { int n; static char tmp[BUFSIZ]; for (n = 0; *(*p); (*p)++) { if (*(*p) == '\n' && *((*p) + 1) != ' ' && *((*p) + 1) != '\t') break; if (*(*p) == '\n') { if (tmp[n - 1] != ' ' && tmp[n - 1] != '\t') tmp[n++] = ' '; for ((*p)++; *(*p) && (*(*p) == ' ' || *(*p) == '\t');) (*p)++; } if (*(*p) != '\n') tmp[n++] = *(*p); } tmp[n] = '\0'; return((char *)tmp); } /* ** @(#)endEdits() - catch the signal when the edit child finishes ** (The idea for this was ``borrowed'' from xrn.) ** If editheaders is set, extract selected header ** information from the message text file and ** install it in the appropriate header windows. ** Then, popup the completion window with header ** edit windows and completion control buttons. */ #if defined(sun) || defined(SVR4) void #else int #endif endEdits(int signum) { int fd, status; String p, q; char buf[BUFSIZ]; Widget sb, Popup; if (signum != SIGCHLD) #if defined(sun) || defined(SVR4) return ; #else return 1; #endif if (editMail_pid != wait(&status)) #if defined(sun) || defined(SVR4) return ; /* the mail child could die too */ #else return 1; #endif (void) signal(SIGCHLD, SIG_DFL); /* turn off the endEdits hook */ sb = XtNameToWidget(toplevel, "topBox.commandPanel.Send"); if (p = GetMailEnv("editheaders")) { XtFree((String) p); if ((fd = open(tmpName, O_RDONLY)) >= 0) { while (1) { bzero(Command, BUFSIZ); status = read(fd, Command, BUFSIZ); for (p = Command; *p; p++) { if (*p == '\n' && *(p - 1) == '\n') { status = 0; break; } if (strncmp(p, "To: ", 4) == 0) { p += 4; writeTo(XtNameToWidget(sb, "*To"), extract_of(&p), REPLACE); } else if (strncmp(p, "Subject: ", 9) == 0) { p += 9; writeTo(XtNameToWidget(sb,"*Subject"),extract_of(&p),REPLACE); } else if (strncmp(p, "In-Reply-To: ", 13) == 0) { p += 13; (void) strcpy(buf, extract_of(&p)); if (! (q = strchr(buf, ':'))) (void) sprintf(InReply, "In-Reply-To: %s", buf); else { q -= 5; if (strncmp(q, "dated: ", 7) != 0) (void) sprintf(InReply, "In-Reply-To: %s", buf); else { *(q - 1) = '\0'; (void) sprintf(InReply, "In-Reply-To: %s\n ", buf); (void) strcat(InReply, q); } } } else if (strncmp(p, "Forwarding: ", 12) == 0) { p += 12; (void) strcpy(buf, extract_of(&p)); if (! (q = strchr(buf, ':'))) (void) sprintf(InReply, "Forwarding: %s", buf); else { q -= 5; if (strncmp(q, "dated: ", 7) != 0) (void) sprintf(InReply, "Forwarding: %s", buf); else { *(q - 1) = '\0'; (void) sprintf(InReply, "Forwarding: %s\n ", buf); (void) strcat(InReply, q); } } } else if (strncmp(p, "Cc: ", 4) == 0) { p += 4; writeTo(XtNameToWidget(sb, "*Cc"), extract_of(&p), REPLACE); } else if (strncmp(p, "Bcc: ", 5) == 0) { p += 5; writeTo(XtNameToWidget(sb, "*Bcc"), extract_of(&p), REPLACE); } else { for (;*p && *p != '\n';) p++; } } if (status < BUFSIZ) break; } (void) close(fd); } } Popup = XtNameToWidget(sb, ".popup"); SetXY(Popup, XtNameToWidget(toplevel, "topBox.commandPanel"), 0, 0); XtPopup(Popup, XtGrabNone); XSync(XtDisplay(toplevel), False); XtAddEventHandler(Popup, StructureNotifyMask, False, warp_handler, NULL); #if defined(sun) || defined(SVR4) return ; #else return 1; #endif } /* ** @(#)editMail() - edit a mail message using the preferred editor ** ** Support is now provided for declaring the editor command as an xmail ** resource, ala xrn. If the resource ``xmail.editorCommand'' is defined, ** it must contain an `sprintf'-able format string that provides for the ** inclusion of both a display name and the name of the file to be edited. ** If the resource declaration is not included, or does not contain the two ** required percent-s (%s) formatting strings, xmail will use the VISUAL ** resource. If VISUAL is used, try to accommodate those editors (emacs, ** xedit...) which start their own window in X11. We know for a fact that ** vi and ed variants do not invoke windows. We assume any other editor ** specification does. */ void editMail(void) { String edit, cp; char cmd[BUFSIZ]; Display *ad; bzero(cmd, BUFSIZ); ad = XtDisplay(XtNameToWidget(toplevel, "topBox.statusWindow")); /* ** If editorCommand resource exists, use it (format validated during initialize) */ if (XMail.editorCommand) (void) sprintf(cmd, XMail.editorCommand, DisplayString(ad), tmpName); else { /* ** Otherwise, default to the VISUAL method of starting things */ if (! (edit = GetMailEnv("VISUAL"))) edit = XtNewString(DEFAULT_VISUAL); if ((cp = strrchr(edit, '/')) == NULL) cp = edit; else cp++; if (strcmp(cp, "ed") == 0 || strcmp(cp,"red") == 0 || strcmp(cp, "ex") == 0 || strcmp(cp, "vi") == 0) { (void) sprintf(cmd, "exec xterm -display %s -name XMail -title 'Message entry' -e %s %s", DisplayString(ad), edit, tmpName); } else (void) sprintf(cmd, "exec %s -display %s %s", edit, DisplayString(ad), tmpName); XtFree((String) edit); } editMail_pid = fork(); switch (editMail_pid) { case -1: /* fork failed ... */ if (errno == ENOMEM) Bell("Not enough core for edits\n"); else Bell("No more processes - no edits\n"); break; case 0: /* child starts the message entry session */ (void) close(ConnectionNumber(XtDisplay(toplevel))); (void) execl("/bin/sh", "sh", "-c", cmd, 0); perror("editMail: Failed to start the text editor"); (void) _exit(127); break; default: /* parent waits for editing to conclude */ (void) signal(SIGCHLD, endEdits); break; } } /* editMail */ /* ** @(#)readMail() - callback invoked every time input is pending on mail fd ** ** Calls QueryMail() to read all available data from mail file descriptor, ** and passes output to parse() for analysis and appropriate action. */ /* ARGSUSED */ void readMail(XtPointer client_data, int *source, XtInputId *id) /* unused */ /* unused */ /* unused */ { SetCursor(WATCH); parse(QueryMail("")); } /* readMail */ /* ** @(#)makeHeading() - Create the specified message header windows */ void makeHeading(Widget parent, String label_string, Widget *left, Widget *above, String info, String help_text) { Arg args[11]; char resource_name[10]; Widget input_window; XtSetArg(args[0], XtNfromVert, *left); XtSetArg(args[1], XtNfromHoriz, NULL); XtSetArg(args[2], XtNlabel, label_string); XtSetArg(args[3], XtNborderWidth, 0); XtSetArg(args[4], XtNfont, XMail.buttonFont); XtSetArg(args[5], XtNheight, XMail.buttonHeight + XMail.borderWidth + 7); XtSetArg(args[6], XtNwidth, XMail.buttonWidth); XtSetArg(args[7], XtNjustify, XtJustifyLeft); XtSetArg(args[8], XtNinternalHeight, 0); XtSetArg(args[9], XtNinternalWidth, 1); *left = XtCreateManagedWidget("SubjCc", labelWidgetClass, parent, args, 10); bzero(resource_name, 9); (void) strncpy(resource_name, label_string, strlen(label_string) - 1); input_window = CreateInputWindow(parent, resource_name); XtSetArg(args[0], XtNfromVert, *above); XtSetArg(args[1], XtNfromHoriz, *left); XtSetValues(input_window, args, 2); AddInfoHandler(input_window, info); AddHelpText(input_window, help_text); *above = input_window; } /* makeHeading */ /* ** @(#)makeButton() - Create the specified command button with callback */ void makeButton(Widget parent, String label, XtCallbackProc CBProc, String CBData, String info, String help_text) { Arg args[3]; Widget button; int width = ((((int)XMail.shellWidth-2)/6) - (int)XMail.borderWidth*2) - 4; XtSetArg(args[0], XtNfont, XMail.buttonFont); XtSetArg(args[1], XtNheight, XMail.buttonHeight); XtSetArg(args[2], XtNwidth, width); button = XtCreateManagedWidget(label, commandWidgetClass, parent, args, 3); XtAddCallback(button, XtNcallback, CBProc, CBData); AddInfoHandler(button, info); AddHelpText(button, help_text); } /* makeButton */ /* ** @(#)sendMail() - Create the send window popup for message headers */ void sendMail(Widget parent) { Arg args[11]; Widget Popup, Layout, Box, left, above; Popup = XtNameToWidget(parent, "popup"); if (! Popup) { XtSetArg(args[0], XtNinput, True); XtSetArg(args[1], XtNwidth, XMail.shellWidth - 2); XtSetArg(args[2], XtNheight, XMail.borderWidth*3 + XMail.buttonHeight*5 + 44); Popup = XtCreatePopupShell("popup",transientShellWidgetClass,parent,args,3); XtSetArg(args[0], XtNdefaultDistance, 2); Layout = XtCreateManagedWidget("SubjCc", formWidgetClass, Popup, args, 1); left = above = NULL; makeHeading(Layout, "To:",&left,&above,SendMail_Info[0],To_Help); makeHeading(Layout, "Subject:",&left,&above,SendMail_Info[1],Subject_Help); makeHeading(Layout, "Cc:",&left,&above,SendMail_Info[2],Cc_Help); makeHeading(Layout, "Bcc:",&left,&above,SendMail_Info[3],Bcc_Help); XtRegisterGrabAction(SetAliases, True, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync); XtSetArg(args[0], XtNfont, XMail.buttonFont); XtSetArg(args[1], XtNheight, XMail.buttonHeight + XMail.borderWidth*2 + 4); XtSetArg(args[2], XtNwidth, XMail.shellWidth - 2); XtSetArg(args[3], XtNfromVert, left); XtSetArg(args[4], XtNfromHoriz, NULL); XtSetArg(args[5], XtNborderWidth, 0); XtSetArg(args[6], XtNresize, False); XtSetArg(args[7], XtNmin, args[1].value); XtSetArg(args[8], XtNmax, args[1].value); XtSetArg(args[9], XtNhSpace, 2); XtSetArg(args[10],XtNvSpace, 2); Box = XtCreateManagedWidget("Box", boxWidgetClass, Layout, args, 11); makeButton(Box, "Autograph", (XtCallbackProc) Autograph, "A", Autograph_Info[0], Sign_Help); makeButton(Box, "autograph", (XtCallbackProc) Autograph, "a", Autograph_Info[1], sign_Help); makeButton(Box, "ReEdit", (XtCallbackProc) ReEdit, "ReEdit", Deliver_Info[1], ReEdit_Help); makeButton(Box, "Cancel", (XtCallbackProc) Done, "cancel", Deliver_Info[2], Cancel_Help); makeButton(Box, "Abort", (XtCallbackProc) Done, "Cancel", Deliver_Info[3], Abort_Help); makeButton(Box, "Deliver", (XtCallbackProc) Done, "Deliver", Deliver_Info[0], Deliver_Help); } } /* sendMail */ /* ** @(#)writeMail() - Write command s to the mail process. */ void writeMail(char *s) { (void) write(mail_fd, s, strlen(s)); } /* writeMail */