/*
* 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 <X11/Xaw/CommandP.h>
#include <X11/Xaw/TextP.h>
#include <X11/cursorfont.h> /* use watch cursor for busy notify */
#include <X11/bitmaps/cross_weave> /* background use in Newmail notify */
#include <pwd.h> /* for getting user's home directory */
#ifdef linux
#include <sys/types.h>
#include <signal.h>
#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("<Message>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 */
syntax highlighted by Code2HTML, v. 0.9.1