/* * 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. initialize: and * 2. SetHints. * * Author: Michael C. Wagnitz - National Semiconductor Corporation * */ #include "global.h" #include "Mailwatch.h" /* use as icon and watch for newmail */ #include #include #include /* use watch cursor for busy notify */ #include /* background use in Newmail notify */ #include /* for getting user's home directory */ #ifdef linux #include #include #endif #ifndef lint static char what[] = "@(#)xmail.c 1.6 94/12/04 Copyright 1989,1990,1991,1992,1993,1994 National Semiconductor Corp."; #endif #define Offset(field) (XtOffset(XmailResources *, field)) static XtResource resrcs[] = { {"textFont", XtCFont, XtRFontStruct, sizeof (XFontStruct *), Offset(textFont), XtRString, XtDefaultFont}, {"helpFont", XtCFont, XtRFontStruct, sizeof (XFontStruct *), Offset(helpFont), XtRString, XtDefaultFont}, {"buttonFont", XtCFont, XtRFontStruct, sizeof (XFontStruct *), Offset(buttonFont), XtRString, XtDefaultFont}, {"iconGeometry", "IconGeometry", XtRString, sizeof(char *), Offset(iconGeometry), XtRString, (caddr_t) NULL}, {"mFileName", "MFileName", XtRString, sizeof(char *), Offset(MFileName), XtRString, (caddr_t) NULL}, {"editorCommand", "EditorCommand", XtRString, sizeof(char *), Offset(editorCommand), XtRString, (caddr_t) NULL}, {"bellRing", "BellRing", XtRBoolean, sizeof(Boolean), Offset(bellRing), XtRImmediate, (caddr_t) True}, {"expert", "Expert", XtRBoolean, sizeof(Boolean), Offset(expert), XtRImmediate, (caddr_t) False}, {"iconic", "Iconic", XtRBoolean, sizeof(Boolean), Offset(iconic), XtRImmediate, (caddr_t) False}, {"mailopt_n", "Mailopt_n", XtRBoolean, sizeof(Boolean), Offset(mailopt_n), XtRImmediate, (caddr_t) False}, {"mailopt_U", "Mailopt_U", XtRBoolean, sizeof(Boolean), Offset(mailopt_U), XtRImmediate, (caddr_t) False}, {"show_Last", "Show_Last", XtRBoolean, sizeof(Boolean), Offset(Show_Last), XtRImmediate, (caddr_t) True}, {"show_Info", "Show_Info", XtRBoolean, sizeof(Boolean), Offset(Show_Info), XtRImmediate, (caddr_t) True}, {"no_X_Hdr", "No_X_Hdr", XtRBoolean, sizeof(Boolean), Offset(No_X_Hdr), XtRImmediate, (caddr_t) False}, { XtNborderWidth, XtCBorderWidth, XtRInt, sizeof (int), Offset(borderWidth), XtRString, "1"}, }; #undef Offset static XrmOptionDescRec Opts[] = { {"-borderwidth", ".TopLevelShell.borderWidth", XrmoptionSepArg, (caddr_t) NULL}, {"-buttonfont", "*buttonFont", XrmoptionSepArg, (caddr_t) NULL}, {"-buttonFont", "*buttonFont", XrmoptionSepArg, (caddr_t) NULL}, {"-bw", ".TopLevelShell.borderWidth", XrmoptionSepArg, (caddr_t) NULL}, {"-editorcommand", "*editorCommand", XrmoptionSepArg, (caddr_t) NULL}, {"-editorCommand", "*editorCommand", XrmoptionSepArg, (caddr_t) NULL}, {"-e", "*expert", XrmoptionNoArg, (caddr_t) "True"}, {"-f", "*MFileName", XrmoptionSepArg, (caddr_t) NULL}, {"-fn", "*Font", XrmoptionSepArg, (caddr_t) NULL}, {"-font", "*Font", XrmoptionSepArg, (caddr_t) NULL}, {"-geometry", ".geometry", XrmoptionSepArg, (caddr_t) NULL}, {"-h", "*icon*useHost", XrmoptionNoArg, (caddr_t) "True"}, {"-helpfont", "*helpFont", XrmoptionSepArg, (caddr_t) NULL}, {"-helpFont", "*helpFont", XrmoptionSepArg, (caddr_t) NULL}, {"-iconGeometry", "*iconGeometry", XrmoptionSepArg, (caddr_t) NULL}, {"-iconic", "*iconic", XrmoptionNoArg, (caddr_t) "True"}, {"-ls", "*show_Last", XrmoptionNoArg, (caddr_t) "False"}, {"-n", "*mailopt_n", XrmoptionNoArg, (caddr_t) "True"}, {"-nb", "*bellRing", XrmoptionNoArg, (caddr_t) "False"}, {"-noinfo", "*show_Info", XrmoptionNoArg, (caddr_t) "False"}, {"-nx", "*no_X_Hdr", XrmoptionNoArg, (caddr_t) "True"}, {"-rv", "*icon*reverseVideo", XrmoptionNoArg, (caddr_t) "True"}, {"-textfont", "*textFont", XrmoptionSepArg, (caddr_t) NULL}, {"-textFont", "*textFont", XrmoptionSepArg, (caddr_t) NULL}, {"-U", "*mailopt_U", XrmoptionNoArg, (caddr_t) "True"}, {"-u", "*icon*useName", XrmoptionNoArg, (caddr_t) "True"}, {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL}, }; Atom wmDeleteWindow; /* for WM_DELETE_WINDOW property */ Boolean In_Bogus_Mail_File; /* in bogus folder when we're iconic */ Boolean Waiting; /* TRUE when we set the busy cursor */ Pixmap hatch; /* cross_weave, to indicate new mail */ Widget toplevel; /* top level shell widget */ Window WaitCursorWindow; AliasRecPtr *aliases = NULL; /* array of mail alias strings */ helpText *HelpList = NULL; /* list of help text objects */ XmailResources XMail; /* application resources of xmail */ int mailargc; /* counter passed to mail child */ int RootWidth, RootHeight; int Highlighted; /* state of 'Newmail' highlighting */ char HOME[BUFSIZ]; /* home directory of user */ char Command[BUFSIZ]; /* xmail command string */ char InReply[BUFSIZ]; /* reply reference string */ char tmpName[BUFSIZ]; /* message temporary filename */ char otherBuf[BUFSIZ]; /* bucket for non-addressee names */ char foldir[BUFSIZ]; /* name of the folder directory */ char lastFolder[BUFSIZ]; /* previous folder's title-bar */ char *mailargv[8]; /* array passed to mail child */ /* ** @(#)mailoptions() - construct command line arguments for calling mail. ** Return the argument list for mail and new value of argc. */ int mailoptions(void) { XWMHints *wm_hints; int i; char *cp; if ((cp = (char *)getenv("XMAILER")) == NULL) /* first looks up env var */ cp = DEFAULT_MAILER; wm_hints = XGetWMHints(XtDisplay(toplevel), XtWindow(toplevel)); i = 0; mailargv[i++] = cp; /* Argv[0] is the name of the program */ mailargv[i++] = "-N"; /* no version or header info at start */ if (XMail.mailopt_n) mailargv[i++] = "-n"; /* don't initialize from Mail.rc file */ if (XMail.mailopt_U) mailargv[i++] = "-U"; /* Change uucp to Internet addresses */ if (wm_hints->initial_state == IconicState) { /* start iconic in bogus */ FILE *fp; (void) sprintf(InReply, "%s+", tmpName); if (fp = fopen(InReply, "w")) { /* create our bogus mail file */ (void) fprintf(fp, "\n"); (void) fclose(fp); mailargv[i++] = "-f"; /* start in our bogus mail folder */ mailargv[i++] = InReply; In_Bogus_Mail_File = True; } } else if (XMail.MFileName) { mailargv[i++] = "-f"; /* start from mail folder MFileName */ mailargv[i++] = XMail.MFileName; } mailargv[i] = NULL; XFree((XWMHints *)wm_hints); return (i); } /* mailoptions */ /* ** @(#)initialize() - establish xmail program defaults and setups */ void initialize(void) { long buttonSpace, i; String disp, file, str_type[20]; Display *dpy = XtDisplay(toplevel); XrmValue value; struct passwd *pw; if (XrmGetResource(XrmGetDatabase(dpy), "command.borderWidth", "Command.BorderWidth", str_type, &value)) { if ((i = atoi(value.addr)) > XMail.borderWidth) XMail.borderWidth = i; } if (XrmGetResource(XrmGetDatabase(dpy), "send.borderWidth", "Send.BorderWidth", str_type, &value)) { if ((i = atoi(value.addr)) > XMail.borderWidth) XMail.borderWidth = i; } lastFolder[0] = foldir[0] = '\0'; (void) strcpy(Command, "Start"); /* let parser know we've started */ (void) sprintf(tmpName, "/tmp/xmail%d", getpid()); pw = getpwuid((uid_t) getuid()); /* get the user's home directory */ (void) strcpy(HOME, pw->pw_dir); /* ** TRAP any stupid attempt to set the border width of this application to less ** than the allowed minimum (0) or greater than an acceptable maximum. This ** to prevent a really wierd reaction to a negative number for border width. */ if (XMail.borderWidth < 0) XMail.borderWidth = 1; if (XMail.borderWidth > 6) XMail.borderWidth = 6; /* ** Compute all window dimensions based on extents of the specified fonts. ** Make shell wide enough to hold eight buttons on a row. Total button width ** includes width of text area plus width of separation plus width of border. */ XMail.commandHSpace = 10; XMail.commandVSpace = 10; XMail.buttonHeight = CHARHEIGHT(XMail.buttonFont) + (XMail.buttonFont->ascent / 2); XMail.buttonWidth = figureWidth(XMail.buttonFont) * 9; /* ' NewMail ' */ buttonSpace = XMail.borderWidth * 2; buttonSpace += XMail.buttonWidth + XMail.commandHSpace; XMail.shellWidth = (8 * buttonSpace) + 26; /* 8 buttons per row */ XMail.fileBoxWidth = (4 * buttonSpace) + XMail.buttonWidth; XMail.helpHeight = CHARHEIGHT(XMail.helpFont) * 15 + 5; XMail.helpWidth = figureWidth(XMail.helpFont) * 62 + 5; XMail.helpX = ((int)XMail.shellWidth - (int)XMail.helpWidth) / 2; XMail.helpY = 70; buttonSpace = CHARHEIGHT(XMail.textFont) + (XMail.textFont->ascent / 2); XMail.indexHeight = 12 * buttonSpace; XMail.textHeight = 23 * buttonSpace; XMail.commandHeight = (XMail.buttonHeight*2) + (XMail.commandVSpace*3) + (4 * XMail.borderWidth); XMail.menuX = 15; XMail.menuY = 7; RootWidth = XDisplayWidth(XtDisplay(toplevel), DefaultScreen(XtDisplay(toplevel))) - 1; RootHeight = XDisplayHeight(XtDisplay(toplevel), DefaultScreen(XtDisplay(toplevel))) - 1; /* ** Ensure xmail shell height does not exceed the height of the root window. */ buttonSpace = (2 * XMail.buttonHeight) + XMail.indexHeight + XMail.commandHeight + XMail.textHeight + (6 * XMail.borderWidth); for (i = 0, buttonSpace -= RootHeight; buttonSpace > 0; i++) { buttonSpace -= CHARHEIGHT(XMail.textFont); if (i % 2) XMail.indexHeight -= CHARHEIGHT(XMail.textFont); else XMail.textHeight -= CHARHEIGHT(XMail.textFont); } /* ** If editorCommand resource exists, warn if it doesn't have two %s entries. */ if (XMail.editorCommand) if (! (disp = strchr(XMail.editorCommand, '%')) || *(disp + 1) != 's' || ! (file = strrchr(XMail.editorCommand, '%')) || *(file + 1) != 's' || disp == file) { XtWarning("xmail editorCommand resource improperly defined... ignoring"); XtFree((String) XMail.editorCommand); XMail.editorCommand = NULL; } parser_init(); } /* initialize */ /* ** @(#)SetHints() - Sets hatching, cursor, icon and size hints, and wm protocol */ SetHints(void) { Cardinal x, y; unsigned long valuemask; Window win = XtWindow(toplevel); CommandWidget nm = (CommandWidget)XtNameToWidget(toplevel, "topBox.commandPanel.Newmail"); Display *dpy = XtDisplay(toplevel); Screen *scn = XtScreen(toplevel); XSetWindowAttributes attributes; XSizeHints size_hints; XWMHints wm_hints; /* ** Hatch will be used to indicate new mail arrival on command & folder buttons */ hatch = XCreatePixmapFromBitmapData(dpy, XtScreen(toplevel)->root, cross_weave_bits, cross_weave_width, cross_weave_height, nm->label.foreground, nm->core.background_pixel, DefaultDepth(dpy, DefaultScreen(dpy))); /* ** Notify the window manager about our icon window */ wm_hints.input = True; wm_hints.initial_state = (XMail.iconic) ? IconicState : NormalState; wm_hints.flags = InputHint | StateHint; if (XMail.iconGeometry) { ParseIconGeometry(XMail.iconGeometry, &x, &y); wm_hints.icon_x = x; wm_hints.icon_y = y; wm_hints.flags |= IconPositionHint; } wm_hints.flags |= IconWindowHint; wm_hints.icon_window = XtWindow(XtNameToWidget(toplevel, "icon")); XSetWMHints(dpy, win, &wm_hints); /* ** Set starting position and default geometry */ if (! XGetNormalHints(dpy, win, &size_hints)) { size_hints.x = 56; size_hints.y = 56; /* slightly off from top left corner */ } size_hints.width = XMail.shellWidth; size_hints.height = (2 * XMail.buttonHeight) + XMail.indexHeight + XMail.commandHeight + XMail.textHeight + (6 * XMail.borderWidth); size_hints.min_width = size_hints.max_width = size_hints.width; size_hints.min_height = size_hints.max_height = size_hints.height; size_hints.flags = USPosition | USSize | PMinSize; XSetNormalHints(dpy, win, &size_hints); /* ** Add a protocol flag indicating we wish to handle WM_DELETE_WINDOW requests */ wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(dpy, win, &wmDeleteWindow, 1); /* ** Create a WaitCursor window, ala FAQ to Ignore device events while ** the busy cursor is displayed. The window will be as big as the ** display screen, and clipped by its own parent window, so we never ** have to worry about resizing. */ valuemask = CWDontPropagate | CWCursor; attributes.do_not_propagate_mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); attributes.cursor = XCreateFontCursor(dpy, XC_watch); WaitCursorWindow = XCreateWindow(dpy, win, 0, 0, WidthOfScreen(scn), HeightOfScreen(scn), (unsigned int) 0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); } /* SetHints */ /* ** @(#)main() - main routine for the x11 interface to the mail utility */ main(int argc, String *argv) { int indx, value, aC; String cp, *aV; static XtActionsRec actionTable[] = { {"CheckInsert", (XtActionProc) CheckInsert}, {"DeleteChar", (XtActionProc) DeleteChar}, {"DeleteLine", (XtActionProc) DeleteLine}, {"DeleteWord", (XtActionProc) DeleteWord}, {"DoCmd", (XtActionProc) DoCmd}, {"DoDone", (XtActionProc) DoDone}, {"DoNothing", (XtActionProc) DoNothing}, {"DoReply", (XtActionProc) DoReply}, {"DoSave", (XtActionProc) DoSave}, {"DoSelected", (XtActionProc) DoSelected}, {"Iconify", (XtActionProc) Iconify}, {"Folder", (XtActionProc) Folder}, {"MyNotify", (XtActionProc) MyNotify}, {"NextField", (XtActionProc) NextField}, {"PrintMsg", (XtActionProc) PrintMsg}, {"Quit", (XtActionProc) Quit}, {"SetAliases", (XtActionProc) SetAliases}, {"SetDirectory", (XtActionProc) SetDirectory}, {"SetFolders", (XtActionProc) SetFolders}, {"SetMenu", (XtActionProc) SetMenu}, {"SetPopup", (XtActionProc) SetPopup}, {"SetSelect", (XtActionProc) SetSelect}, {"ShowHelp", (XtActionProc) ShowHelp}, {NULL, NULL} }; #ifdef linux /* ** Some distributions of Linux come with a window manager which leaves ** SIGCHLD ignored. Since we use the state of SIGCHLD to verify an active ** delivery, we had better set it back to the default. */ signal(SIGCHLD, SIG_DFL); #endif /* ** First, examine our command line arguments and Class resources for bogus ** values which would cause the application to operate incorrectly. Drop ** command lines arguments and/or change the resource values before we ** initialize our widgets. */ aV = (String *) XtMalloc((unsigned) (argc + 1) * sizeof(String *)); aC = 0; for (value = indx = 0; indx < argc; indx++) value += strlen(argv[indx]) + 1; aV[aC] = (String) XtMalloc((unsigned) value); (void) strcpy(aV[aC++], *argv); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; for (indx = 1; indx < argc; indx++) switch (argv[indx][0]) { /* look for, -xrm *[Bb]orderWidth or */ case '-': /* -bw, w/ negative valued arguments */ if ((argv[indx][1] != 'b' || argv[indx][2] != 'w') && (argv[indx][1] != 'x' || argv[indx][2] != 'r' || argv[indx][3] != 'm') || (indx + 1) >= argc) { (void) strcpy(aV[aC++], argv[indx]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; } else if (sscanf(argv[indx+1], "%d", &value) == 1) { if (value < 0) indx++; /* skip the value argument too */ else if (value < 7) { (void) strcpy(aV[aC++], argv[indx]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; } else { (void) strcpy(aV[aC++], argv[indx++]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; (void) strcpy(aV[aC++], "6"); aV[aC] = aV[aC - 1] + 2; } } else if ((cp = strchr(argv[indx + 1], 'o')) == NULL || strncmp(cp, "orderWidth:", 11) != 0 || sscanf(cp + 11, "%d", &value) != 1) { (void) strcpy(aV[aC++], argv[indx]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; } else if (value >= 0) { if (value < 7) { (void) strcpy(aV[aC++], argv[indx]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; } else { (void) strcpy(aV[aC++], argv[indx++]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; (void) strcpy(aV[aC], argv[indx]); cp = strchr(aV[aC], ':'); *++cp = '\0'; (void) strcat(aV[aC], " 6"); /* max allowed value */ aV[aC + 1] = aV[aC] + strlen(aV[aC]) + 1; aC++; } } else indx++; /* skip the value argument too */ break; /* if negative, it is not included */ default : (void) strcpy(aV[aC++], argv[indx]); aV[aC] = aV[aC - 1] + strlen(aV[aC - 1]) + 1; break; } aV[aC] = NULL; /* array MUST end with a null */ /* ** Now, initialize our toplevel widget and parse the command line */ toplevel = XtInitialize(*aV, "XMail", Opts, XtNumber(Opts), &aC, aV); if (aC > 1) { (void) fprintf(stderr,"Usage: %s [-toolkitoptions] [-xmailoptions]\n",*aV); exit(-1); /*NOTREACHED*/ } /* ** Next, add xmail specific as well as Athena text widget actions */ XtAddActions(actionTable, XtNumber(actionTable)); XtAddActions(_XawTextActionsTable, _XawTextActionsTableCount); XtGetApplicationResources(toplevel, &XMail, resrcs, XtNumber(resrcs), NULL, 0); XtOverrideTranslations(toplevel, XtParseTranslationTable("WM_PROTOCOLS: Quit(q)")); initialize(); /* set window sizes based on font */ CreateSubWindows(toplevel); /* and build our widget hierarchy */ XSync(XtDisplay(toplevel), False); /* ensure everyone's on the same page */ XtRealizeWidget(toplevel); /* initialize widgets for our hints */ SetHints(); /* tell WM about our icon and size */ mailargc = mailoptions(); /* set up the mail pgm argv and argc */ callMail(mailargv); /* attempt to start Mail connection */ SetCursor(WATCH); XtMainLoop(); /* NOTREACHED */ } /* main */