/* * 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. markIndex: * 2. LastNumber: * 3. SelectionNumber: * 4. SetCursor: and * 5. SetXY. * * Author: Michael C. Wagnitz - National Semiconductor Corporation * */ #include #include "global.h" #include "patchlevel.h" #include "revtable.h" /* ** @(#)Bell() - write a status message and (optionally) ring the terminal bell */ void Bell(String msg) { Arg args[1]; char *p; char buf[BUFSIZ]; int size; static int worthy = 0; /* only msgs with ending newline are */ size = (int)strlen(msg); if (size >= BUFSIZ) size = BUFSIZ - 1; (void) strncpy(buf, msg, size); buf[size] = '\0'; p = strchr(buf, '\n'); /* messages with newline get a bell */ /* ** Because we have now added enter/leave window event information messages, ** we must play a slight game with incoming messages, to prevent any error ** messages from a menu selection failure or status messages from a command ** button being overwritten by the subsequent event info messages produced ** when the menu popup is dismissed or the command completes. To do this, ** we make the bell worthy-ness flag static, and only replace a message after ** first seeing a non-default status message, which will reset the worthy-ness ** flag, but otherwise be ignored. When the first non-default, non-error ** message comes in, simply reset our bell worthy-ness flag and return, leaving ** the previous error message still intact. This means, to ensure seeing the ** default message, first send a blank line to reset the worthy-ness flag. */ if (! XMail.Show_Info) /* if NOT showing info flags always */ worthy = 0; /* reset the bell worthy-ness flag */ else { if (worthy && p == NULL) { /* if last was but this ain't urgent */ if (strcmp(buf, Default_Status_Info)) /* and not the default info */ worthy = 0; /* reset the bell worthy-ness flag */ return; /* ignore event info if menu errored */ } /* by leaving previous error message */ } if (size == 0) /* if intent was just to reset flag */ return; if (p != NULL) { /* Only display first line of output */ *p = '\0'; /* (no new line at end of label) */ worthy = 1; /* this message is worthy of a bell */ } if (worthy && XMail.bellRing) /* ring bell if not silenced by user */ XBell(XtDisplay (toplevel), 33); XtSetArg(args[0], XtNlabel, (XtArgVal) buf); /* show this message text */ XtSetValues(XtNameToWidget(toplevel, "topBox.statusWindow"), args, 1); XFlush(XtDisplay(toplevel)); } /* Bell */ /* ** @(#)figureWidth() - determine the figure width of the specified font */ int figureWidth(XFontStruct *font) { Atom _XA_FIGURE_WIDTH; unsigned long width = 0; _XA_FIGURE_WIDTH = XInternAtom(XtDisplay(toplevel), "FIGURE_WIDTH", FALSE); if ((_XA_FIGURE_WIDTH != (Atom)NULL) && ((! XGetFontProperty(font, _XA_FIGURE_WIDTH, &width)) || (width == 0))) if (font->per_char && font->min_char_or_byte2 <= '$' && font->max_char_or_byte2 >= '$') width = font->per_char['$' - font->min_char_or_byte2].width; else width = font->max_bounds.width; return(width); } /* end - figureWidth */ /* ** @(#)markIndex() - add or remove a tag from the start of a mail header line ** May be invoked by button press, which sets the insertion ** pointer for the text to the current mouse cursor location. */ void markIndex(char *s) { int size; XawTextPosition pos, old; String c, p = NULL; char buf[3]; Widget iw = XtNameToWidget(toplevel, "topBox.indexWindow"); Arg args[1]; XawTextBlock text; (void) strcpy(buf, s); /* make a copy of our marker string */ XtSetArg(args[0], XtNstring, &p); /* retrieve the current index buffer */ XtGetValues(iw, args, 1); for (pos = XawTextGetInsertionPoint(iw); pos > 0 && p[pos-1] != '\n'; pos--); if (buf[0] == '>') { /* if mark is for 'current' pointer */ XtSetArg(args[0], XtNstring, &p); /* retrieve the current index buffer */ XtGetValues(iw, args, 1); if ((int)strlen(p) < 3) /* trap for case of no index at all */ return; if ((int)strlen(p) > pos + 1) if (p[pos + 1] == 'S') /* keep the Save marker if it exists */ if ((int)strlen(buf) > 1) buf[1] = '\0'; for (c = p; *c; c++) if (*c == '>' && (c == p || *(c - 1) == '\n')) { old = c - p; /* if found, remove the old '>' mark */ text.firstPos = 0; text.length = 1; text.ptr = " "; text.format = FMT8BIT; XawTextReplace(iw, (XawTextPosition) old, (XawTextPosition) old + 1, &text); break; } } size = (int)strlen(buf); /* now write the specified marker */ old = (buf[0] == '>') ? pos : pos + 1; text.firstPos = 0; text.length = size; text.ptr = buf; text.format = FMT8BIT; XawTextReplace(iw, (XawTextPosition) old, (XawTextPosition) old + size, &text); XawTextSetInsertionPoint(iw, pos); /* reset our actual insertion point */ } /* markIndex */ /* ** @(#)LastNumber() - Get mail index number for last message in folder */ int LastNumber(void) { int last_number; Arg args[1]; String c, ep, str = NULL; Widget iw = XtNameToWidget(toplevel, "topBox.indexWindow"); XtSetArg(args[0], XtNstring, &str); XtGetValues(iw, args, 1); ep = &str[(int)strlen(str) - 1]; for (c = ep - 1; c > str; c--) if (*(c - 1) == '\n' && *(c + 1) != 'D') break; for (; c < ep && !isdigit(*c); c++); (void) sscanf(c, "%d", &last_number); return(last_number); } /* LastNumber */ /* ** @(#)SelectionNumber() - Get mail index number from line position */ int SelectionNumber(int undeleting) { Arg args[1]; String c, str = NULL; Widget iw = XtNameToWidget(toplevel, "topBox.indexWindow"); XawTextPosition pos; int selection_number = 0; XtSetArg(args[0], XtNstring, &str); XtGetValues(iw, args, 1); for (pos = XawTextGetInsertionPoint(iw); pos > 0 && str[pos] != '\n'; pos--); pos++; if (! undeleting || str[pos + 1] == 'D') { for (c = &str[pos]; *c && !isdigit(*c); c++); (void) sscanf(c, "%d", &selection_number); } return(selection_number); } /* SelectionNumber */ /* ARGSUSED */ /* ** @(#)SetCursor() - sets the wait cursor or restores the default */ void SetCursor(int waiting) /* a non-zero value sets the busy cursor */ { if (! waiting) XUnmapWindow(XtDisplay(toplevel), WaitCursorWindow); else { XMapWindow(XtDisplay(toplevel), WaitCursorWindow); Waiting = TRUE; /* to prevent overwrite of important info */ } XFlush(XtDisplay(toplevel)); } /* SetCursor */ /* ** @(#)SetXY() - Set relative window coordinates including specified offset */ void SetXY(Widget target, Widget reference, int X_offset, int Y_offset) { Arg args[2]; Display *dpy = XtDisplay(reference); Window dumy; int x, y; XTranslateCoordinates(dpy, XtWindow(reference), RootWindow(dpy, DefaultScreen(dpy)), X_offset, Y_offset, &x, &y, &dumy); /* ** Keep window within root window borders (don't place it off-screen) */ if (! XtIsRealized(target)) XtRealizeWidget(target); /* to get width and height values */ if (x + (int) target->core.width > RootWidth) x = RootWidth - target->core.width - 2; if (y + (int)target->core.height > RootHeight) y = RootHeight - target->core.height - 2; XtSetArg(args[0], XtNx, x); XtSetArg(args[1], XtNy, y); XtSetValues(target, args, 2); } /* end - SetXY */ /* ** @(#)TextGetLastPos() - return position of last text character */ XawTextPosition TextGetLastPos(Widget w) { TextWidget ctx = (TextWidget) w; if (ctx->text.source) return (XawTextSourceScan(ctx->text.source,0,XawstAll,XawsdRight,1,TRUE)); else return( (XawTextPosition) 0); } /* ** @(#)UpdateTitleBar() - replace information in the title bar title */ void UpdateTitleBar(char *msg) { char message[BUFSIZ]; Arg args[1]; Widget w; (void) sprintf(message, "%s%d - %s", TITLE, PATCHLEVEL, msg); w = XtNameToWidget(toplevel, "topBox.titleBar.title"); XtSetArg(args[0], XtNlabel, (XtArgVal) message); XtSetValues(w, args, 1); w = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail.Newmail_menu.menu.inc"); if (w) XtSetSensitive(w, In_System_Folder()); } /* UpdateTitleBar */ /* ** @(#)writeTo() - write data to the specified text widget */ void writeTo(Widget w, char *data, int do_append) { XawTextBlock text; XawTextPosition startPos, endPos; int l, n; endPos = TextGetLastPos(w) + (do_append ? 0 : 1); startPos = (do_append ? endPos : 0); text.firstPos = 0; text.length = (int)strlen(data); text.ptr = data; text.format = FMT8BIT; XawTextReplace(w, (XawTextPosition) startPos, (XawTextPosition) endPos, &text); XawTextSetInsertionPoint(w, (XawTextPosition) TextGetLastPos(w)); XawTextInvalidate(w, (XawTextPosition) 0, (XawTextPosition) endPos); } /* writeTo */ /* ** @(#)writeText() - replace the current text string in the text window. ** Also look for an X-Face: header and if found, display. */ void writeText(char *buf) { Arg args[2]; Widget w = XtNameToWidget(toplevel, "topBox.textWindow.text"); #ifdef X_FACE Pixmap bits; Dimension rWidth; Display *dpy = XtDisplay(w); Widget fw; Window rw; char cb[1024], fb[2048], *ptr, *xface; int i, n, x, y; #endif if (buf && *buf) { #ifndef X_FACE XtSetArg(args[0], XtNstring, buf); XtSetValues(w, args, 1); #else if (! (fw = XtNameToWidget(XtParent(w), "face"))) { XtSetArg(args[0], XtNstring, buf); XtSetValues(w, args, 1); return; } /* ** First, unmap any current picture. ** ** Look for a line containing an 'X-Face:' header, followed by 72 ** characters of compressed data. The second and any subsequent lines ** will contain an initial space (which is ignored), followed by 79 ** characters of compressed data. The last line may contain fewer than 79 ** characters. ** ** The X-Face: header and any immediate whitespace (tabs or spaces) will be ** removed, and the remaining line placed in the internal buffer (minus ** any trailing newline). On subsequent lines, initial whitespace will be ** removed, and the remainder of the data appended to the buffer (minus any ** trailing newline). ** ** A blank line, a line without an initial whitespace character,or the ** end of the input buffer will signify the end of the X-Face data. That ** buffer will then be uncompressed, and if the data was valid, displayed. */ if (XtIsManaged(fw)) XtUnmanageChild(fw); for (ptr = buf; *ptr; ptr++) { if (*ptr == '\n' || strncmp(ptr, "Status:", 7) == 0 || strncmp(ptr, "X-Face:", 7) == 0) break; for (; *ptr && *ptr != '\n'; ptr++); } if (! *ptr || strncmp(ptr, "X-Face:", 7) != 0) { XtSetArg(args[0], XtNstring, buf); XtSetValues(w, args, 1); return; } xface = ptr; /* keep track of the start position of X-Face header */ bzero(fb, 2048); for (i = 0, ptr += 7; *ptr; ptr++) { if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') fb[i++] = *ptr; if (*ptr == '\n' && *(ptr+1) && *(ptr+1) != ' ' && *(ptr+1) != '\t') break; } if (XMail.No_X_Hdr) { if (*ptr) ptr++; bcopy(ptr, xface, (int)strlen(ptr) + 1); /* suppress the X-Face header */ } XtSetArg(args[0], XtNstring, buf); XtSetValues(w, args, 1); if (uncompface(fb) >= 0) { bzero(cb, 1024); for (i = n = 0;i < 1024;) { if (! sscanf(&fb[n], "%i%n", &x, &y)) break; cb[i++] = revtable[(x >> 8) & 0xFF]; cb[i++] = revtable[x & 0xFF]; n += y; while (fb[n] && (fb[n]==',' || fb[n]=='\n')) n++; } XtSetArg(args[0], XtNwidth, &rWidth); XtGetValues(XtParent(w), args, 1); if ( (int)rWidth > 0 ) n = (int) rWidth - 52; /* the width of the face minus 4 pixel inset */ else n = 0; XtSetArg(args[0], XtNbitmap, &bits); XtGetValues(fw, args, 1); if (bits != None) XFreePixmap(dpy, bits ); rw = RootWindow(dpy, DefaultScreen(dpy)); bits = XCreateBitmapFromData(dpy, rw, cb, 48, 48); XtSetArg(args[0], XtNbitmap, bits ); XtSetArg(args[1], XtNhorizDistance, n); XtSetValues(fw, args, 2); XtManageChild(fw); } #endif } } /* writeText */