home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume15 / xmail / part02 / Mailwatch.c < prev    next >
C/C++ Source or Header  |  1991-10-29  |  29KB  |  967 lines

  1. /*
  2.  * @(#)Mailwatch.c - MODIFIED for use as an active icon in the xmail program.
  3.  *
  4.  * Author:  Dan Heller <island!argv@sun.com>
  5.  * This code was stolen from Mailbox.c --the widget which supports "xbiff"
  6.  * written by Jim Fulton which was apparently stolen from Clock.c, the widget
  7.  * which supports "xclock."  Note, you are witnessing the big bang theory of
  8.  * software development (everything is a subclass of universeWidgetClass).
  9.  *
  10.  * Major changes:
  11.  * XtRemoveTimeOut() is called before calling XtAddTimeOut().  The original
  12.  * xbiff would eventually timeout all the time rather than every 30 seconds
  13.  * because the old timer was never removed.
  14.  *
  15.  * User can specify any icon he chooses for either the up flag or the down
  16.  * flag.  Icons don't need to be the same size (defaults to flagup/flagdown).
  17.  *
  18.  * When new mail comes in, a user supplied callback function is invoked.
  19.  *
  20.  * The mailbox flag goes up when there is new mail _and_ the user hasn't
  21.  * read it yet.  As soon as the user updates the access time on the mailbox,
  22.  * the flag goes down.  This removes the incredibly annoying habit xbiff
  23.  * had where you read some mail but not delete it from the mailbox and the
  24.  * flag would remain up.
  25.  *
  26.  * Destroy() will now destroy the flagup and flagdown pixmaps.
  27.  *
  28. ** July 1991 - Michael C. Wagnitz - National Semiconductor Corporation
  29. ** The following modifications were made for use in xmail.
  30. **
  31. ** Added support for colored icons via the XPixMap format library libXpm.a
  32. **
  33. ** November 1990 - Michael C. Wagnitz - National Semiconductor Corporation
  34. ** The following modifications were made for use in xmail.
  35. **
  36. ** Added options to display username or host name in icon window.
  37. **
  38. ** November 1989 - Michael C. Wagnitz - National Semiconductor Corporation
  39. **
  40. ** Removed button handler, custom cursor, and 'from()' reader functions.
  41. ** Added reset_mailbox() function, my own icons (56x56 bits), and also
  42. ** added timer initialization to Initialize() routine (we might not ever be
  43. ** Realized, if the user never iconifies my parent).  This also fixes a Sun4
  44. ** bug for trying to remove an initial interval_id with a garbage address.
  45. ** Also changed check_mailbox() to test access time vs. modified and zero size
  46. ** of file, rather than trying to track our last access or increase in size.
  47. **
  48. ** Copyright 1990,1991 by National Semiconductor Corporation
  49. **
  50. ** Permission to use, copy, modify, and distribute this software and its
  51. ** documentation for any purpose is hereby granted without fee, provided that
  52. ** the above copyright notice appear in all copies and that both that
  53. ** copyright notice and this permission notice appear in supporting
  54. ** documentation, and that the name of National Semiconductor Corporation not
  55. ** be used in advertising or publicity pertaining to distribution of the
  56. ** software without specific, written prior permission.
  57. **
  58. ** NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  59. ** SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  60. ** WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  61. ** DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  62. ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  63. ** EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  64. ** INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  65. ** LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  66. ** OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  67. ** PERFORMANCE OF THIS SOFTWARE.
  68. **
  69. ** The following software modules were created and are Copyrighted by National
  70. ** Semiconductor Corporation:
  71. **
  72. ** 1. reset_mailbox,
  73. ** 2. set_host,
  74. ** 3. set_user,
  75. ** 4. set_none,
  76. ** 5. GetHostName, and
  77. ** 6. XMyLocateXPixmapFile.
  78. **
  79. ** Author:  Michael C. Wagnitz - National Semiconductor Corporation
  80. */
  81.  
  82.  
  83. #include <X11/Xos.h>
  84. #include <X11/IntrinsicP.h>        /* for toolkit stuff */
  85. #include <X11/cursorfont.h>        /* for cursor constants */
  86. #include <X11/StringDefs.h>        /* for useful atom names */
  87. #include <X11/Xaw/XawInit.h>
  88. #include "MailwatchP.h"            /* for implementation mailbox stuff */
  89. #include <stdio.h>            /* for printing error messages */
  90. #include <sys/stat.h>            /* for stat() */
  91. #include <sys/param.h>            /* for MAXHOSTNAMELEN */
  92. #include <pwd.h>            /* for getting username */
  93. #include <errno.h>
  94.  
  95. #ifndef    XPM
  96. #include <X11/Xmu/Converters.h>        /* for XmuCvtStringToBitmap */
  97. #include "icon.mail"            /* for flag up (mail present) bits */
  98. #include "icon.nomail"            /* for flag down (mail not here) */
  99. #else
  100. #include <X11/xpm.h>            /* for XPixMap colored icons */
  101. #include <X11/Xmu/CvtCache.h>
  102. #include "mail.xpm"            /* for flag up (mail present) bits */
  103. #include "nomail.xpm"            /* for flag down (mail not here) */
  104.  
  105. #define    mail_width    64
  106. #define    mail_height    64
  107. #define    nomail_width    64
  108. #define    nomail_height    64
  109. #endif
  110.  
  111. #ifndef    MAXHOSTNAMELEN
  112. #define    MAXHOSTNAMELEN    64
  113. #endif
  114.  
  115. #define between(x, i, y)   ((i) < (x) ? (x) : (i) > (y) ? (y) : (i))
  116.  
  117. #define REMOVE_TIMEOUT(id) if (!id) ; else XtRemoveTimeOut(id)
  118.  
  119. static struct stat    stbuf;
  120. static Boolean        SetValues();
  121. static Pixmap        make_pixmap();
  122. static GC        GetNormalGC(), GetInvertGC();
  123. static void        GetMailFile(), GetUserName(), GetHostName(),
  124.             CloseDown(), check_mailbox(), redraw_mailbox(),
  125.             ClassInitialize(), Initialize(), Destroy(),
  126.             Realize(), Redisplay(), clock_tic(), set_title();
  127. extern void        reset_mailbox(), set_host(), set_user(), set_none();
  128. extern Widget        toplevel;
  129.  
  130. extern    int        RootWidth;
  131. extern    int        RootHeight;
  132.  
  133. #define min(a,b) ((a) < (b) ? (a) : (b))
  134. #define max(a,b) ((a) > (b) ? (a) : (b))
  135.  
  136. static char defaultTranslations[] =
  137.     "<Key>h:        set-host()    \n\
  138.      <Key>u:        set-user()    \n\
  139.      <Key>space:    set-none()";
  140.  
  141. static XtActionsRec actionsList[] = {
  142.     { "set-host",    set_host    },
  143.     { "set-user",    set_user    },
  144.     { "set-none",    set_none    },
  145. };
  146.  
  147. /* Initialization of defaults */
  148. #define offset(field) XtOffset(MailwatchWidget,mailbox.field)
  149. #define goffset(field) XtOffset(Widget,core.field)
  150.  
  151. static XtResource resources[] = {
  152.     {XtNupdate, XtCInterval, XtRInt, sizeof(int),
  153.     offset(update), XtRImmediate, (caddr_t) 30 },
  154.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  155.     offset(foreground_pixel), XtRString, XtDefaultForeground },
  156.     {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
  157.     goffset(background_pixel), XtRString, XtDefaultBackground },
  158.     {XtNreverseVideo, XtCBoolean, XtRBoolean, sizeof(Boolean),
  159.     offset(reverseVideo), XtRImmediate, (caddr_t) False },
  160.     {XtNbell, XtCBoolean, XtRBoolean, sizeof(Boolean),
  161.     offset(bell), XtRImmediate, (caddr_t) True },
  162.     {XtNfile, XtCFile, XtRString, sizeof(String),
  163.     offset(filename), XtRString, NULL},
  164. #ifndef    XPM
  165.     {XtNmailFlag, XtCMailFlag, XtRBitmap, sizeof(Pixmap),
  166.     offset(mail.bitmap), XtRString, NULL},
  167.     {XtNnoMailFlag, XtCNoMailFlag, XtRBitmap, sizeof(Pixmap),
  168.     offset(nomail.bitmap), XtRString, NULL},
  169. #else
  170.     {XtNmailFlag, XtCMailFlag, XtRString, sizeof(String),
  171.     offset(mail.bitmap), XtRString, NULL},
  172.     {XtNnoMailFlag, XtCNoMailFlag, XtRString, sizeof(String),
  173.       offset(nomail.bitmap), XtRString, NULL},
  174. #endif
  175.     {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  176.     offset(callback), XtRCallback, NULL},
  177.     {"useName", XtCBoolean, XtRBoolean, sizeof(Boolean),
  178.     offset(useName), XtRString, "FALSE" },
  179.     {"useHost", XtCBoolean, XtRBoolean, sizeof(Boolean),
  180.     offset(useHost), XtRString, "FALSE" },
  181.     { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
  182.     offset(font), XtRString, XtDefaultFont},
  183. };
  184.  
  185. #undef offset
  186. #undef goffset
  187.  
  188. MailwatchClassRec mailwatchClassRec = {
  189.     {    /* core fields */
  190.     /* superclass        */ &widgetClassRec,
  191.     /* class_name        */ "Mailwatch",
  192.     /* widget_size        */ sizeof(MailwatchRec),
  193.     /* class_initialize    */ ClassInitialize,
  194.     /* class_part_initialize*/ NULL,
  195.     /* class_inited     */ FALSE,
  196.     /* initialize        */ Initialize,
  197.     /* initialize_hook    */ NULL,
  198.     /* realize        */ Realize,
  199.     /* actions        */ actionsList,
  200.     /* num_actions        */ XtNumber(actionsList),
  201.     /* resources        */ resources,
  202.     /* resource_count    */ XtNumber(resources),
  203.     /* xrm_class        */ NULL,
  204.     /* compress_motion    */ TRUE,
  205.     /* compress_exposure    */ TRUE,
  206.     /* compress_enterleave    */ TRUE,
  207.     /* visible_interest    */ FALSE,
  208.     /* destroy        */ Destroy,
  209.     /* resize        */ NULL,
  210.     /* expose        */ Redisplay,
  211.     /* set_values        */ SetValues,
  212.     /* set_values_hook    */ NULL,
  213.     /* set_values_almost    */ XtInheritSetValuesAlmost,
  214.     /* get_values_hook    */ NULL,
  215.     /* accept_focus        */ NULL,
  216.     /* version        */ XtVersion,
  217.     /* callback_private    */ NULL,
  218.     /* tm_table        */ defaultTranslations,
  219.     /* query_geometry    */ NULL,
  220.     }
  221. };
  222.  
  223. WidgetClass mailwatchWidgetClass = (WidgetClass) & mailwatchClassRec;
  224.  
  225. /*
  226.  * private procedures
  227.  */
  228. static Pixmap
  229. make_pixmap (dpy, w, bitmap, depth, widthp, heightp)
  230. Display        *dpy;
  231. MailwatchWidget    w;
  232. Pixmap        bitmap;
  233. int        depth;
  234. int        *widthp, *heightp;
  235. {
  236.  Window root;
  237.  int x, y;
  238.  unsigned int width, height, bw, dep;
  239.  unsigned long fore, back;
  240.  
  241.  
  242.  if (bitmap == 0 ||
  243.      ! XGetGeometry(dpy, bitmap, &root, &x, &y, &width, &height, &bw, &dep))
  244.     return None;
  245.  
  246.  *widthp = (int) width;
  247.  *heightp = (int) height;
  248.  fore = w->mailbox.foreground_pixel;
  249.  back = w->core.background_pixel;
  250.  return XmuCreatePixmapFromBitmap(dpy, w->core.window, bitmap, 
  251.                       width, height, depth, fore, back);
  252. }
  253.  
  254.  
  255. static void
  256. ClassInitialize()
  257. {
  258. #ifndef XPM
  259.  static XtConvertArgRec screenConvertArg[] = {
  260.     { XtWidgetBaseOffset, (caddr_t) XtOffset(Widget, core.screen), sizeof(Screen *) }
  261.     };
  262. #endif
  263.  
  264.  XawInitializeWidgetSet();
  265.  
  266. #ifndef XPM
  267.  XtAddConverter (XtRString, XtRBitmap, XmuCvtStringToBitmap,
  268.             screenConvertArg, XtNumber(screenConvertArg));
  269. #endif
  270.  
  271.  return;
  272. } /* ClassInitialize */
  273.  
  274.  
  275. /* ARGSUSED */
  276. static void
  277. Initialize(request, new)
  278. Widget request, new;
  279. {
  280.     MailwatchWidget w = (MailwatchWidget) new;
  281.  
  282.     GetUserName(w);
  283.  
  284.     GetHostName(w);
  285.  
  286.     if (!w->mailbox.filename)
  287.     GetMailFile(w);
  288.  
  289.     if (w->mailbox.reverseVideo) {
  290.     Pixel tmp;
  291.  
  292.     tmp = w->mailbox.foreground_pixel;
  293.     w->mailbox.foreground_pixel = w->core.background_pixel;
  294.     w->core.background_pixel = tmp;
  295.     }
  296.  
  297.     GetNormalGC(w);
  298.  
  299.     GetInvertGC(w);
  300.  
  301.     w->mailbox.flag_up = FALSE;        /* because it hasn't been shown yet */
  302.     w->mailbox.mail.pixmap = None;
  303.     w->mailbox.nomail.pixmap = None;
  304.  
  305.     w->mailbox.last_access = (stat(w->mailbox.filename, &stbuf) == 0) ?
  306.                              stbuf.st_atime : 0 ;    /* last accessed */
  307.     return;
  308. }
  309.  
  310.  
  311. /* ARGSUSED */
  312. static void
  313. clock_tic(client_data, id)
  314. caddr_t client_data;
  315. XtIntervalId *id;
  316. {
  317.     MailwatchWidget w = (MailwatchWidget) client_data;
  318.  
  319.     check_mailbox(w, FALSE);
  320. }
  321.  
  322.  
  323. static void
  324. set_title(str)
  325. String    str;
  326. {
  327.  Display    *dpy = XtDisplay(toplevel);
  328.  Window        win  = XtWindow(toplevel);
  329.  String        c, name, title;
  330.  
  331.  
  332.  XFetchName(dpy, win, &name);
  333.  if (! name)
  334.     name = XtNewString("xmail");
  335.  else
  336.     if ((c = (char *)strrchr(name, '_')) != NULL)
  337.         *c = '\0';
  338.  
  339.  if (! *str)
  340.     title = XtMalloc((unsigned) strlen(name) + 1);
  341.  else
  342.     title = XtMalloc((unsigned) strlen(name) + strlen(str) + 2);
  343.  
  344.  if (! title)
  345.     XtError("xmail: Insufficient memory to allocate title space");
  346.  
  347.  if (! *str)
  348.     (void) sprintf(title, "%s", name);
  349.  else
  350.     (void) sprintf(title, "%s_%s", name, str);
  351.  
  352.  XStoreName(dpy, win, title);
  353.  
  354.  XtFree((char *)name);
  355.  XtFree((char *)title);
  356. } /* end - set_title */
  357.  
  358.  
  359. void
  360. set_host(m)
  361. MailwatchWidget        m;
  362. {
  363.  register Display    *dpy = XtDisplay(m);
  364.  register Window    win = XtWindow(m);
  365.  register int        x, y, h, w;
  366.  
  367.  
  368.  set_title(m->mailbox.mailhost);
  369.  
  370.  m->mailbox.useHost = True;
  371.  m->mailbox.useName = False;
  372.  h = m->mailbox.font->max_bounds.width - m->mailbox.font->max_bounds.lbearing;
  373.  w = strlen(m->mailbox.mailhost);
  374.  h = (h * w) - 2;
  375.  x = max(m->core.width - h, 2);            /* if (x < 2) x = 2; */
  376.  x /= 2;
  377.  y = m->core.height - m->mailbox.font->descent;
  378.  
  379.  XFillRectangle(dpy, win, m->mailbox.invert_GC,
  380.                       0, y - m->mailbox.font->ascent, m->core.width,
  381.                       m->mailbox.font->ascent + m->mailbox.font->descent);
  382.  
  383.  XDrawString(dpy, win, m->mailbox.normal_GC, x, y, m->mailbox.mailhost, w);
  384. } /* end - set_host */
  385.  
  386.  
  387. void
  388. set_user(m)
  389. MailwatchWidget        m;
  390. {
  391.  register Display    *dpy = XtDisplay(m);
  392.  register Window    win = XtWindow(m);
  393.  register int        x, y, h, w;
  394.  
  395.  
  396.  set_title(m->mailbox.username);
  397.  
  398.  m->mailbox.useHost = False;
  399.  m->mailbox.useName = True;
  400.  h = m->mailbox.font->max_bounds.width - m->mailbox.font->max_bounds.lbearing;
  401.  w = strlen(m->mailbox.username);
  402.  h = (h * w) - 2;
  403.  x = max(m->core.width - h, 2);            /* if (x < 2) x = 2; */
  404.  x /= 2;
  405.  y = m->core.height - m->mailbox.font->descent;
  406.  
  407.  XFillRectangle(dpy, win, m->mailbox.invert_GC,
  408.                       0, y - m->mailbox.font->ascent, m->core.width,
  409.                       m->mailbox.font->ascent + m->mailbox.font->descent);
  410.  
  411.  XDrawString(dpy, win, m->mailbox.normal_GC, x, y, m->mailbox.username, w);
  412. } /* end - set_user */
  413.  
  414.  
  415. void
  416. set_none(m)
  417. MailwatchWidget        m;
  418. {
  419.  set_title("");
  420.  m->mailbox.useHost = m->mailbox.useName = False;
  421.  redraw_mailbox(m);
  422. } /* end - set_none */
  423.  
  424.  
  425. static GC
  426. GetNormalGC(w)
  427. MailwatchWidget w;
  428. {
  429.     XtGCMask valuemask;
  430.     XGCValues xgcv;
  431.  
  432.     valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
  433.     xgcv.foreground = w->mailbox.foreground_pixel;
  434.     xgcv.background = w->core.background_pixel;
  435.     xgcv.function = GXcopy;
  436.     xgcv.graphics_exposures = False;
  437.     w->mailbox.normal_GC = XtGetGC((Widget) w, valuemask, &xgcv);
  438. }
  439.  
  440. static GC
  441. GetInvertGC(w)
  442. MailwatchWidget w;
  443. {
  444.     XtGCMask valuemask;
  445.     XGCValues xgcv;
  446.  
  447.     valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
  448.     xgcv.foreground = w->core.background_pixel;
  449.     xgcv.background = w->mailbox.foreground_pixel;
  450.     xgcv.function = GXcopy;
  451.     xgcv.graphics_exposures = False;    /* this is Bool, not Boolean */
  452.     w->mailbox.invert_GC = XtGetGC((Widget) w, valuemask, &xgcv);
  453. }
  454.  
  455.  
  456. #ifdef XPM
  457. /*
  458.  * split_path_string - split a colon-separated list into its constituent
  459.  * parts; to release, free list[0] and list.  From libXmu LocBitmap.c
  460.  */
  461. static char **
  462. split_path_string (src)
  463. register char *src;
  464. {
  465.  int nelems = 1;
  466.  register char *dst;
  467.  char **elemlist, **elem;
  468.  
  469.  /* count the number of elements */
  470.  for (dst = src; *dst; dst++) if (*dst == ':') nelems++;
  471.  
  472.  /* get memory for everything */
  473.  dst = (char *) XtMalloc ((unsigned) (dst - src) + 1);
  474.  if (!dst) return NULL;
  475.  elemlist = (char **) XtCalloc ((unsigned) (nelems + 1), sizeof (char *));
  476.  if (!elemlist) {
  477.     XtFree (dst);
  478.     return NULL;
  479.    }
  480.  
  481.  /* copy to new list and walk up nulling colons and setting list pointers */
  482.  (void) strcpy (dst, src);
  483.  for (elem = elemlist, src = dst; *src; src++) {
  484.      if (*src == ':') {
  485.         *elem++ = dst;
  486.         *src = '\0';
  487.         dst = src + 1;
  488.        }
  489.     }
  490.  *elem = dst;
  491.  
  492.  return elemlist;
  493. }
  494.  
  495. char            **bitmap_file_paths = NULL;
  496.  
  497. #ifndef MAXPATHLEN
  498. #define MAXPATHLEN    256
  499. #endif
  500.  
  501. #ifndef BITMAPDIR
  502. #define BITMAPDIR    "/usr/include/X11/bitmaps"
  503. #endif
  504.  
  505.  
  506. /*
  507. ** @(#)XMyLocateXPixmapFile() - Cloned from libXmu LocBitmap.c for use in XPM
  508. */
  509. static Pixmap
  510. XMyLocateXPixmapFile(w, depth, name, widthp, heightp)
  511. Widget    w;
  512. int    depth;
  513. char    *name;
  514. int    *widthp, *heightp;    /* RETURN */
  515. {
  516.  Bool            try_plain_name = True;
  517.  Display        *dpy = XtDisplay(w);
  518.  int            screen = DefaultScreen(dpy);
  519.  Colormap        cmap = DefaultColormap(dpy, screen);
  520.  Pixmap            pixmap;                    /* RETURN */
  521.  Visual            *visual    = DefaultVisual(dpy, screen);
  522.  XrmName        xrm_name[2];
  523.  XrmClass        xrm_class[2];
  524.  XrmRepresentation    rep_type;
  525.  XrmValue        value;
  526.  int            i;
  527.  char            filename[MAXPATHLEN];
  528.  char            **file_paths = NULL;
  529. /*
  530. ** look for bitmap path (only once, because we're going to call this twice)
  531. */
  532.  if (bitmap_file_paths == NULL) {
  533.     xrm_name[0] = XrmStringToName ("bitmapFilePath");
  534.     xrm_name[1] = NULL;
  535.     xrm_class[0] = XrmStringToClass ("BitmapFilePath");
  536.     xrm_class[1] = NULL;
  537.     /*
  538.     ** XXX - warning, derefing Display * until XDisplayDatabase
  539.     */
  540.     if (!dpy->db)
  541.        (void) XGetDefault (dpy, "", "");
  542.  
  543.     if (XrmQGetResource (dpy->db, xrm_name, xrm_class, &rep_type, &value) &&
  544.         rep_type == XrmStringToQuark(XtRString)) {
  545.        bitmap_file_paths = split_path_string(value.addr);
  546.       }
  547.    }
  548.  file_paths = bitmap_file_paths;
  549. /*
  550. ** Search order:
  551. **    1.  name if it begins with / or ./
  552. **    2.  "each prefix in file_paths"/name
  553. **    3.  BITMAPDIR/name
  554. **    4.  name if didn't begin with / or .
  555. */
  556.  for (i = 1; i <= 4; i++) {
  557.      char *fn = filename;
  558.  
  559.      switch (i) {
  560.        case 1:
  561.             if (!(name[0] == '/' || (name[0] == '.') && name[1] == '/'))
  562.               continue;
  563.             fn = name;
  564.             try_plain_name = False;
  565.             break;
  566.        case 2:
  567.             if (file_paths && *file_paths) {
  568.                 (void) sprintf (filename, "%s/%s", *file_paths, name);
  569.                 file_paths++;
  570.                 i--;
  571.                 break;
  572.             }
  573.             continue;
  574.        case 3:
  575.             (void) sprintf (filename, "%s/%s", BITMAPDIR, name);
  576.             break;
  577.        case 4:
  578.             if (!try_plain_name) continue;
  579.             fn = name;
  580.             break;
  581.        }
  582.  
  583.      if (PixmapSuccess == XReadPixmapFile(dpy, visual, w->core.window, cmap, fn,
  584.                          depth, &pixmap, widthp, heightp, 0, 0, NULL, 0, NULL))
  585.        {
  586.         return pixmap;
  587.        }
  588.     }
  589.  return None;
  590. }
  591. #endif
  592.  
  593.  
  594.  
  595. static void
  596. Realize(gw, valuemaskp, attr)
  597. Widget gw;
  598. XtValueMask *valuemaskp;
  599. XSetWindowAttributes *attr;
  600. {
  601.  Arg            args[2];
  602.  MailwatchWidget    w = (MailwatchWidget) gw;
  603.  register Display    *dpy = XtDisplay(w);
  604.  int            depth = w->core.depth;
  605. #ifdef XPM
  606.  int            x, y, screen = DefaultScreen(dpy);
  607.  Colormap        cmap = DefaultColormap(dpy, screen);
  608.  Visual            *visual    = DefaultVisual(dpy, screen);
  609.  Pixmap            bitmap, XmuLocateBitmapFile();
  610. #endif
  611.  
  612.  
  613.  XtCreateWindow(gw, InputOutput, (Visual *) CopyFromParent, *valuemaskp, attr);
  614. /*
  615. ** build up the pixmaps that we'll put into the icon image
  616. */
  617.  if (w->mailbox.mail.bitmap == None) {    /* if user failed to specify an icon */
  618. #ifndef    XPM            /* Non-XPM uses [no]mail.bitmap as a pixmap */
  619.     w->mailbox.mail.bitmap = XCreateBitmapFromData(dpy, w->core.window,
  620.                     mail_bits, mail_width, mail_height);
  621.  
  622.     w->mailbox.mail.pixmap = make_pixmap(dpy, w, w->mailbox.mail.bitmap, depth,
  623.                      &w->mailbox.mail.width,
  624.                      &w->mailbox.mail.height);
  625.    } else {            /* non-XPM used XmuConvertStringToPixmap */
  626.     w->mailbox.mail.pixmap = make_pixmap(dpy, w, w->mailbox.mail.bitmap, depth,
  627.                      &w->mailbox.mail.width,
  628.                      &w->mailbox.mail.height);
  629. #else
  630.     XCreatePixmapFromData(dpy, visual, w->core.window, cmap, mail_xpm, depth,
  631.                           &w->mailbox.mail.pixmap, &w->mailbox.mail.width, 
  632.                           &w->mailbox.mail.height, 0, 0, NULL, 0, NULL);
  633.    } else {
  634.     /*
  635.     ** Because for XPM we define mailbox.[no]mail.bitmap as a string,
  636.     ** we must do the file conversion ourselves.  First, see if it is
  637.     ** a plain old bitmap file.  Failing that, try for an XPM format
  638.     ** file.  Failing that, default to our internally defined xpm icon.
  639.     */
  640.     if (bitmap = XmuLocateBitmapFile(w->core.screen, w->mailbox.mail.bitmap,
  641.                                      NULL, 0, &w->mailbox.mail.width,
  642.                                               &w->mailbox.mail.height, &x, &y))
  643.        w->mailbox.mail.pixmap = make_pixmap(dpy, w, bitmap, depth,
  644.                                             &w->mailbox.mail.width,
  645.                         &w->mailbox.mail.height);
  646.  
  647.     else if (! (w->mailbox.mail.pixmap = XMyLocateXPixmapFile((Widget) w, depth,
  648.                                                      w->mailbox.mail.bitmap,
  649.                                                     &w->mailbox.mail.width,
  650.                                                     &w->mailbox.mail.height)))
  651.             XCreatePixmapFromData(dpy, visual, w->core.window, cmap,
  652.                                   mail_xpm, depth, &w->mailbox.mail.pixmap,
  653.                                                    &w->mailbox.mail.width, 
  654.                                                    &w->mailbox.mail.height,
  655.                                   0, 0, NULL, 0, NULL);
  656. #endif
  657.    }
  658.  
  659.  if (w->mailbox.nomail.bitmap == None) {
  660. #ifndef    XPM
  661.     w->mailbox.nomail.bitmap = XCreateBitmapFromData(dpy, w->core.window,
  662.                                  no_mail_bits, no_mail_width, no_mail_height);
  663.  
  664.     w->mailbox.nomail.pixmap = make_pixmap(dpy, w, w->mailbox.nomail.bitmap,
  665.                      depth, &w->mailbox.nomail.width,
  666.                      &w->mailbox.nomail.height);
  667.    } else {
  668.     w->mailbox.nomail.pixmap = make_pixmap(dpy, w, w->mailbox.nomail.bitmap,
  669.                      depth, &w->mailbox.nomail.width,
  670.                      &w->mailbox.nomail.height);
  671. #else
  672.     XCreatePixmapFromData(dpy, visual, w->core.window, cmap, nomail_xpm, depth,
  673.                           &w->mailbox.nomail.pixmap, &w->mailbox.nomail.width, 
  674.                           &w->mailbox.nomail.height, 0, 0, NULL, 0, NULL);
  675.    } else {
  676.     if (bitmap = XmuLocateBitmapFile(w->core.screen, w->mailbox.nomail.bitmap,
  677.                                         NULL, 0, &w->mailbox.nomail.width,
  678.                                         &w->mailbox.nomail.height, &x, &y))
  679.        w->mailbox.nomail.pixmap = make_pixmap(dpy, w, bitmap, depth,
  680.                           &w->mailbox.nomail.width,
  681.                           &w->mailbox.nomail.height);
  682.  
  683.     else if (! (w->mailbox.nomail.pixmap = XMyLocateXPixmapFile((Widget) w, depth,
  684.                                                    w->mailbox.nomail.bitmap,
  685.                                                   &w->mailbox.nomail.width,
  686.                                                   &w->mailbox.nomail.height)))
  687.             XCreatePixmapFromData(dpy, visual, w->core.window, cmap, nomail_xpm,
  688.                                   depth, &w->mailbox.nomail.pixmap,
  689.                                          &w->mailbox.nomail.width, 
  690.                                          &w->mailbox.nomail.height,
  691.                                   0, 0, NULL, 0, NULL);
  692. #endif
  693.    }
  694. /*
  695. ** the size of the icon should be the size of the larger icon image.
  696. */
  697.  w->core.width  = max(w->mailbox.mail.width, w->mailbox.nomail.width);
  698.  w->core.height = max(w->mailbox.mail.height, w->mailbox.nomail.height);
  699.  
  700.  XtSetArg(args[0], XtNwidth,  (XtArgVal) w->core.width);
  701.  XtSetArg(args[1], XtNheight, (XtArgVal) w->core.height);
  702.  XtSetValues(XtNameToWidget(toplevel, "icon"), args, 2);
  703.  
  704. /* set status check timer */
  705.  w->mailbox.interval_id = XtAddTimeOut(w->mailbox.update * 1000,
  706.                                             clock_tic, (caddr_t) w);
  707. #ifdef XPM
  708.  if (bitmap_file_paths) {
  709.     XtFree((char *)bitmap_file_paths[0]);
  710.     XtFree((char *)bitmap_file_paths);
  711.    }
  712. #endif
  713. }
  714.  
  715. static void
  716. Destroy(gw)
  717. Widget gw;
  718. {
  719.  MailwatchWidget w = (MailwatchWidget) gw;
  720.  Display    *dpy = XtDisplay(gw);
  721.  
  722.  XtFree(w->mailbox.filename);
  723.  XtFree(w->mailbox.username);
  724.  XtFree(w->mailbox.mailhost);
  725.  REMOVE_TIMEOUT(w->mailbox.interval_id);
  726.  XtReleaseGC(w, w->mailbox.normal_GC);
  727. #ifndef    XPM
  728.  XFreePixmap(dpy, w->mailbox.mail.bitmap);
  729.  XFreePixmap(dpy, w->mailbox.nomail.bitmap);
  730. #endif
  731.  XFreePixmap(dpy, w->mailbox.mail.pixmap);
  732.  XFreePixmap(dpy, w->mailbox.nomail.pixmap);
  733. }
  734.  
  735. static void
  736. Redisplay(gw)
  737. Widget gw;
  738. {
  739.     MailwatchWidget w = (MailwatchWidget) gw;
  740.  
  741.     REMOVE_TIMEOUT(w->mailbox.interval_id);
  742.     check_mailbox(w, TRUE);
  743. }
  744.  
  745.  
  746. /*
  747. ** Modified to NOT update the mail file timestamp via utimes(), and to
  748. ** ignore state change where mail adds a status record to the message.
  749. ** The first eliminates collisions with mail during delivery, and the
  750. ** second eliminates false triggers for new mail.  The number of times
  751. ** the terminal bell is rung is controlled by the same .mailrc resource
  752. ** (bell) used by Sunview's mailtool.
  753. */
  754. static void
  755. check_mailbox(w, force_redraw)
  756. MailwatchWidget w;
  757. Boolean force_redraw;
  758. {
  759.  int        i, redraw = 0;
  760.  char        *p = NULL;
  761.  
  762.  
  763.  if (stat(w->mailbox.filename, &stbuf) < 0) {        /* no mail file */
  764.     if (w->mailbox.flag_up == TRUE) {
  765.        force_redraw = 0;
  766.        UnsetNewmail(w, NULL, NULL);
  767.       }
  768.    } else {
  769.     if (stbuf.st_atime > stbuf.st_mtime &&
  770.         stbuf.st_atime >= w->mailbox.last_access) {    /* mail was seen */
  771.        w->mailbox.last_access = stbuf.st_atime;
  772.        if (w->mailbox.flag_up == TRUE) {
  773.           force_redraw = 0;
  774.           UnsetNewmail(w, NULL, NULL);
  775.          }
  776.       } else {
  777.        if (stbuf.st_size != 0 && 
  778.            stbuf.st_mtime > w->mailbox.last_access) {    /* got new mail */
  779.           w->mailbox.last_access = stbuf.st_mtime;
  780.           if (w->mailbox.flag_up == FALSE) {
  781.              if (w->mailbox.bell) {
  782.                 i = 1;
  783.                 if (p = (char *)GetMailrc("bell"))
  784.                    (void) sscanf(p, "%d", &i);
  785.                 i = between(1, i, 5);
  786.                 for (; i > 0; i--)
  787.                     XBell(XtDisplay(w), MAILBOX_VOLUME);
  788.                }
  789.              w->mailbox.flag_up = TRUE;
  790.              redraw = TRUE;
  791.              XtCallCallbacks(w, XtNcallback, NULL);
  792.             }
  793.          }
  794.       }
  795.    }
  796.  
  797.  if (redraw || force_redraw)
  798.     redraw_mailbox(w);
  799.  
  800.  /* reset timer */
  801.  w->mailbox.interval_id = XtAddTimeOut(w->mailbox.update * 1000,
  802.     clock_tic, (caddr_t) w);
  803. } /* check_mailbox */
  804.  
  805. /*
  806. ** Retrieve the user's mailbox filename - use MAIL environment value, if set
  807. */
  808. static void
  809. GetMailFile(w)
  810. MailwatchWidget w;
  811. {
  812.  if (! (w->mailbox.filename = (char *) GetMailEnv("MAIL"))) {
  813.     if (! (w->mailbox.filename = XtMalloc((unsigned) strlen(MAILBOX_DIRECTORY)
  814.        + 1 + strlen(w->mailbox.username) + 1))) {
  815.        (void) fprintf(stderr, "Mailbox widget: can't allocate enough memory.\n");
  816.        CloseDown(w, 1);
  817.       }
  818.     (void) sprintf(w->mailbox.filename, "%s/%s\0", MAILBOX_DIRECTORY, w->mailbox.username);
  819.    }
  820. } /* GetMailFile */
  821.  
  822.  
  823. /*
  824. ** Retrieve the mailbox user's name
  825. */
  826. static void
  827. GetUserName(w)
  828. MailwatchWidget w;
  829. {
  830.  char *username = (char *)getlogin();
  831.  
  832.  if (! username) {
  833.     struct passwd *pw = getpwuid(getuid());
  834.  
  835.     if (! pw) {
  836.        (void) fprintf(stderr, "Mailbox widget: can't find your username.\n");
  837.        CloseDown(w, 1);
  838.       }
  839.     username = pw->pw_name;
  840.    }
  841.  
  842.  if (! (w->mailbox.username = XtNewString(username))) {
  843.     XtWarning("Mailbox widget: can't allocate space for username.\n");
  844.     CloseDown(w, 1);
  845.    }
  846. } /* GetUserName */
  847.  
  848.  
  849. /*
  850. ** Retrieve the process host name
  851. */
  852. static void
  853. GetHostName(w)
  854. MailwatchWidget w;
  855. {
  856.  char    hostname[MAXHOSTNAMELEN];
  857.  
  858.  
  859.  (void) gethostname(hostname, MAXHOSTNAMELEN);
  860.  
  861.  if (! (w->mailbox.mailhost = XtNewString(hostname))) {
  862.     XtWarning("Mailbox widget: can't allocate space for hostname.\n");
  863.     CloseDown(w, 1);
  864.    }
  865. } /* GetHostName */
  866.  
  867.  
  868. static void
  869. CloseDown(w, status)
  870. MailwatchWidget w;
  871. int status;
  872. {
  873.     Display *dpy = XtDisplay(w);
  874.  
  875.     XtDestroyWidget(w);
  876.     XCloseDisplay(dpy);
  877.     _exit(status);
  878. }
  879.  
  880. /* ARGSUSED */
  881. static Boolean
  882. SetValues(gcurrent, grequest, gnew)
  883. Widget gcurrent, grequest, gnew;
  884. {
  885.     MailwatchWidget current = (MailwatchWidget) gcurrent;
  886.     MailwatchWidget new = (MailwatchWidget) gnew;
  887.     Boolean redisplay = FALSE;
  888.  
  889.     if (current->mailbox.update != new->mailbox.update) {
  890.     REMOVE_TIMEOUT(current->mailbox.interval_id);
  891.     new->mailbox.interval_id = XtAddTimeOut(new->mailbox.update * 1000,
  892.         clock_tic,
  893.         (caddr_t) gnew);
  894.     }
  895.     if (current->mailbox.foreground_pixel != new->mailbox.foreground_pixel ||
  896.     current->core.background_pixel != new->core.background_pixel) {
  897.     XtReleaseGC(current, current->mailbox.normal_GC);
  898.     GetNormalGC(new);
  899.     redisplay = TRUE;
  900.     }
  901.     return (redisplay);
  902. }
  903.  
  904. /*
  905.  * drawing code
  906.  */
  907. static void
  908. redraw_mailbox(m)
  909. MailwatchWidget m;
  910. {
  911.     register Display    *dpy = XtDisplay(m);
  912.     register Window    win = XtWindow(m);
  913.     register int    x, y;
  914.     Pixel        back = m->core.background_pixel;
  915.     GC            gc = m->mailbox.normal_GC;
  916.     struct _mbimage    *im;
  917.  
  918.  
  919.     if (m->mailbox.flag_up)            /* paint the "up" position */
  920.     im = &m->mailbox.mail;
  921.     else                    /* paint the "down" position */
  922.     im = &m->mailbox.nomail;
  923.  
  924.     /* center the picture in the window */
  925.     x = ((int)m->core.width - im->width) / 2;
  926.     y = ((int)m->core.height - im->height) / 2;
  927.  
  928.     XSetWindowBackground(dpy, win, back);
  929.     XClearWindow(dpy, win);
  930.     XCopyArea(dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, x, y);
  931.  
  932.     if (m->mailbox.useHost || m->mailbox.useName) {
  933.        if (m->mailbox.useHost) set_host(m);
  934.        else set_user(m);
  935.       }
  936. }
  937.  
  938.  
  939. void
  940. reset_mailbox(gw, down)
  941. Widget    gw;
  942. int    down;
  943. {
  944.  MailwatchWidget w = (MailwatchWidget) gw;
  945.  char    *p;
  946.  int    i;
  947.  
  948.  
  949.  if (down)
  950.     w->mailbox.flag_up = FALSE;
  951.  else {
  952.     if (w->mailbox.flag_up == FALSE) {
  953.        if (w->mailbox.bell) {
  954.           i = 1;
  955.           if (p = (char *)GetMailrc("bell"))
  956.              (void) sscanf(p, "%d", &i);
  957.           i = between(1, i, 5);
  958.           for (; i > 0; i--)
  959.               XBell(XtDisplay(w), MAILBOX_VOLUME);
  960.          }
  961.       }
  962.     w->mailbox.flag_up = TRUE;
  963.    }
  964.  
  965.  redraw_mailbox(w);
  966. } /* reset_mailbox */
  967.