home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / system / xmailbox.2-s / xmailbox / xmailbox-2.2 / Mailbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-17  |  27.3 KB  |  1,031 lines

  1. /*
  2.  * Copyright (c) 1994,1995  Dimitrios P. Bouras and William K. W. Cheung
  3.  * 
  4.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  5.  * of this software and associated documentation files (the "Software"), to deal
  6.  * in the Software without restriction, including without limitation the rights
  7.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8.  * copies of the Software, and to permit persons to whom the Software is
  9.  * furnished to do so, subject to the following conditions:
  10.  * 
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  17.  * X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  18.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20.  * 
  21.  * Except as contained in this notice, the name of the X Consortium shall not be
  22.  * used in advertising or otherwise to promote the sale, use or other dealings
  23.  * in this Software without prior written authorization from the X Consortium.
  24.  * 
  25.  * Derived from the MIT X11R5 xbiff, written by Jim Fulton, which is
  26.  * copyrighted (c) 1988 X Consortium.
  27.  *
  28.  * Mailbox XPM additions-modifications:  Dimitrios P. Bouras
  29.  * Audio support and XPM icon animation: William K. W. Cheung
  30.  */
  31.  
  32. #include <X11/IntrinsicP.h>        /* for toolkit stuff */
  33. #include <X11/StringDefs.h>        /* for useful atom names */
  34. #include <X11/cursorfont.h>        /* for cursor constants */
  35. #include <X11/Xosdefs.h>        /* for X_NOT_POSIX def */
  36. #include <sys/stat.h>            /* for stat() ** needs types.h ***/
  37. #include <sys/signal.h>            /* for signal() */
  38. #include <stdio.h>                /* for printing error messages */
  39. #include <pwd.h>                /* for getting username */
  40. #include <stdlib.h>                /* for getenv() */
  41. #include <string.h>
  42.  
  43. #ifndef NO_AUDIO
  44. #ifdef NCD_AUDIO
  45. #include <audio/audiolib.h>
  46. #include <audio/soundlib.h>
  47.  
  48. static AuServer *aud;            /* Audio server handler */
  49. #elif defined(RPLAY_AUDIO)
  50. #include <rplay.h>
  51. #endif
  52. #endif
  53.  
  54. #include <sys/file.h>
  55. #include <sys/fcntl.h>
  56. #include <sys/ioctl.h>
  57.  
  58. #ifndef NO_AUDIO
  59. #ifdef SUN_AUDIO
  60.  
  61. /* Adapted from <multimedia/audio_filehdr.h> */
  62.  
  63. typedef unsigned     u_32;    /* we assume sizeof(unsigned) = 4 */
  64.  
  65. typedef struct {
  66.     u_32        magic;        /* magic number */
  67.     u_32        hdr_size;    /* size of this header */
  68.     u_32        data_size;    /* length of data (optional) */
  69.     u_32        encoding;    /* data encoding format */
  70.     u_32        sample_rate;    /* samples per second */
  71.     u_32        channels;    /* number of interleaved channels */
  72. } Audio_filehdr;
  73.  
  74. #ifdef linux
  75. #include <linux/soundcard.h>
  76.  
  77. #define DEV_MIXER        "/dev/mixer"
  78. #define MAX_VOLUME        100
  79. #define MIN_VOLUME        1
  80. #define RIGHT            0x01
  81. #define LEFT            0x02
  82.  
  83. typedef struct stereovolume
  84. {
  85.     unsigned char left;
  86.     unsigned char right;
  87.     unsigned char pad[2];
  88. } StereoVolume;
  89.  
  90. void setvolume(int which, unsigned char setting, StereoVolume *volptr)
  91. {
  92.     if ( setting < MIN_VOLUME )
  93.         setting=MIN_VOLUME;
  94.     if ( setting > MAX_VOLUME )
  95.         setting=MAX_VOLUME;
  96.  
  97.     if ( which&RIGHT )
  98.         volptr->right=setting;
  99.     if ( which&LEFT )
  100.         volptr->left=setting;
  101. }
  102. #else
  103. #include <sun/audioio.h>
  104. #endif
  105. #endif
  106. #endif
  107.  
  108. #ifndef X_NOT_POSIX
  109. #ifdef _POSIX_SOURCE
  110. # include <sys/wait.h>
  111. #else
  112. #define _POSIX_SOURCE
  113. # include <sys/wait.h>
  114. #undef _POSIX_SOURCE
  115. #endif
  116. # define waitCode(w)    WEXITSTATUS(w)
  117. # define waitSig(w)    WIFSIGNALED(w)
  118. typedef int        waitType;
  119. # define INTWAITTYPE
  120. #else /* ! X_NOT_POSIX */
  121. #ifdef SYSV
  122. # define waitCode(w)    (((w) >> 8) & 0x7f)
  123. # define waitSig(w)    ((w) & 0xff)
  124. typedef int        waitType;
  125. # define INTWAITTYPE
  126. #else
  127. # include    <sys/wait.h>
  128. # define waitCode(w)    ((w).w_T.w_Retcode)
  129. # define waitSig(w)    ((w).w_T.w_Termsig)
  130. typedef union wait    waitType;
  131. #endif /* SYSV else */
  132. #endif /* ! X_NOT_POSIX else */
  133.  
  134. #include "xmail.xpm"        /* for flag up (mail present) bits */
  135. #include "xnomail.xpm"        /* for flag down (mail not here) */
  136.  
  137. #ifndef min
  138. #define min(x,y)    ((x) < (y)? (x): (y))
  139. #endif
  140.  
  141. #include <X11/Xaw/XawInit.h>
  142. #include "MailboxP.h"            /* for implementation mailbox stuff */
  143. #include <X11/Xmu/Drawing.h>
  144. #include <X11/extensions/shape.h>
  145.  
  146. /*
  147.  * The default user interface is to have the mailbox turn itself off whenever
  148.  * the user presses a button in it.  Expert users might want to make this 
  149.  * happen on EnterWindow.  It might be nice to provide support for some sort of
  150.  * exit callback so that you can do things like press q to quit.
  151.  */
  152.  
  153. static char defaultTranslations[] = 
  154.   "<ButtonPress>:  unset()";
  155.  
  156. static void Check(), Set(), Unset();
  157.  
  158. static XtActionsRec actionsList[] = { 
  159.     { "check",    Check },
  160.     { "unset",    Unset },
  161.     { "set",    Set },
  162. };
  163.  
  164. /*
  165.  * Storage for the XPM images for the two mailbox states.
  166.  */
  167. static XpmImage mail_xpmimg[MAX_ANIM_IMAGE];
  168. static XpmImage nomail_xpmimg;
  169.  
  170. /* Initialization of defaults */
  171.  
  172. #define offset(field) XtOffsetOf(Mailbox_XPM_Rec, mailbox.field)
  173. #define goffset(field) XtOffsetOf(WidgetRec, core.field)
  174.  
  175. static XtResource resources[] = {
  176.     { XtNupdate, XtCInterval, XtRInt, sizeof (int),
  177.     offset (update), XtRImmediate, (XtPointer)30 },
  178.     { XtNfile, XtCFile, XtRString, sizeof (String),
  179.     offset (filename), XtRString, NULL },
  180.     { XtNcheckCommand, XtCCheckCommand, XtRString, sizeof(char*),
  181.     offset (check_command), XtRString, NULL },
  182.     { XtNvolume, XtCVolume, XtRInt, sizeof(int),
  183.     offset (volume), XtRImmediate, (XtPointer)33 },
  184.     { XtNonceOnly, XtCBoolean, XtRBoolean, sizeof(Boolean),
  185.     offset (once_only), XtRImmediate, (XtPointer)False },
  186.     { Nmailtool, CMailTool, XtRString, sizeof (String),
  187.     offset (mail_tool), XtRString, NULL },
  188.     { XtNmailAnimUpdate, XtCMailAnimUpdate, XtRInt, sizeof (int),
  189.     offset (mail_animupdate), XtRImmediate, (XtPointer)1000 },
  190.     { XtNmailAnimOnce, XtCMailAnimOnce, XtRBoolean, sizeof (Boolean),
  191.     offset (mail_animonce), XtRImmediate, (XtPointer)False },
  192.     { XtNmailNumOfXpmFile, XtCMailNumOfXpmFile, XtRInt, sizeof (int),
  193.     offset (mail_numofxpmfile), XtRImmediate, (XtPointer)1 },
  194.     { NmailXpmFile, CMailXpmFile, XtRString, sizeof (String),
  195.     offset (mail_xpmfile), XtRString, NULL },
  196.     { NnomailXpmFile, CNomailXpmFile, XtRString, sizeof (String),
  197.     offset (nomail_xpmfile), XtRString, NULL },
  198.     { NmailSndFile, CMailSndFile, XtRString, sizeof (String),
  199.     offset (mail_sndfile), XtRString, NULL },
  200. };
  201.  
  202. #undef offset
  203.  
  204. static void GetMailFile(), CloseDown(), ReadIconFile(), DefaultXpmImage();
  205. static void check_mailbox(), redraw_mailbox(), beep();
  206. static void Initialize(), Realize(), Destroy(), Redisplay();
  207. static Boolean SetValues();
  208.  
  209. Mailbox_XPM_ClassRec mailboxClassRec = {
  210.     { /* core fields */
  211.     /* superclass                */    (WidgetClass) &simpleClassRec,
  212.     /* class_name                */    "Mailbox",
  213.     /* widget_size                */    sizeof(Mailbox_XPM_Rec),
  214.     /* class_initialize            */    XawInitializeWidgetSet,
  215.     /* class_part_initialize    */    NULL,
  216.     /* class_inited                */    FALSE,
  217.     /* initialize                */    Initialize,
  218.     /* initialize_hook            */    NULL,
  219.     /* realize                    */    Realize,
  220.     /* actions                    */    actionsList,
  221.     /* num_actions                */    XtNumber(actionsList),
  222.     /* resources                */    resources,
  223.     /* resource_count            */    XtNumber(resources),
  224.     /* xrm_class                */    NULLQUARK,
  225.     /* compress_motion            */    TRUE,
  226.     /* compress_exposure        */    TRUE,
  227.     /* compress_enterleave        */    TRUE,
  228.     /* visible_interest            */    FALSE,
  229.     /* destroy                    */    Destroy,
  230.     /* resize                    */    NULL,
  231.     /* expose                    */    Redisplay,
  232.     /* set_values                */    SetValues,
  233.     /* set_values_hook            */    NULL,
  234.     /* set_values_almost        */    XtInheritSetValuesAlmost,
  235.     /* get_values_hook            */    NULL,
  236.     /* accept_focus                */    NULL,
  237.     /* version                    */    XtVersion,
  238.     /* callback_private            */    NULL,
  239.     /* tm_table                    */    defaultTranslations,
  240.     /* query_geometry            */    XtInheritQueryGeometry,
  241.     /* display_accelerator        */    XtInheritDisplayAccelerator,
  242.     /* extension                */    NULL
  243.     },
  244.     { /* simple fields */
  245.     /* change_sensitive         */    XtInheritChangeSensitive
  246.     },
  247.     { /* mailbox fields */
  248.     /* ignore                   */    0
  249.     }
  250. };
  251.  
  252. WidgetClass mailboxWidgetClass = (WidgetClass) &mailboxClassRec;
  253.  
  254.  
  255. /*
  256.  * widget initialization
  257.  */
  258.  
  259. static GC get_mailbox_gc (w)
  260.     MailboxWidget w;
  261. {
  262.     XtGCMask valuemask;
  263.     XGCValues xgcv;
  264.  
  265.     valuemask = GCFunction | GCGraphicsExposures;
  266.     xgcv.function = GXcopy;
  267.     xgcv.graphics_exposures = False;    /* this is Bool, not Boolean */
  268.     return (XtGetGC ((Widget) w, valuemask, &xgcv));
  269. }
  270.  
  271. int zombiekiller()
  272. {
  273.     int    status;
  274.  
  275.     while (wait3(&status, WNOHANG, 0) >= 0);
  276. }
  277.  
  278. /* ARGSUSED */
  279. static void Initialize (request, new)
  280.     Widget request, new;
  281. {
  282.     MailboxWidget w = (MailboxWidget) new;
  283.     int shape_event_base, shape_error_base;
  284.  
  285. #ifdef SYSV
  286.     signal(SIGCLD, zombiekiller);
  287. #else
  288.     signal(SIGCHLD, zombiekiller);
  289. #endif
  290.  
  291.     if ( !XShapeQueryExtension (XtDisplay (w), &shape_event_base,
  292.                                                &shape_error_base)) {
  293.     fprintf (stderr, "%s:  shape extensions not supported!\n",
  294.          "Mailbox widget");
  295.     CloseDown (w, 1);
  296.     }
  297.  
  298.     w->mailbox.shape_cache.mask = None;
  299.     w->mailbox.gc = get_mailbox_gc (w);
  300.     w->mailbox.interval_id = (XtIntervalId) 0;
  301.     w->mailbox.anim_int_id = (XtIntervalId) -1;
  302.     w->mailbox.first_trig = 1;
  303.     w->mailbox.flag_up = FALSE;
  304.     w->mailbox.last_size = 0;
  305.     w->mailbox.anim_id = 0;
  306.  
  307.     if ((w->mailbox.mail_numofxpmfile < 1) 
  308.         || (w->mailbox.mail_numofxpmfile > MAX_ANIM_IMAGE)) {
  309.         fprintf (stderr,
  310.                  "%s:  Number of Xpm Images must be between 1 and 8 !\n",
  311.                  "Mailbox widget");
  312.         CloseDown (w, 1);
  313.     }
  314.  
  315.     if (!w->mailbox.filename) GetMailFile (w);
  316.  
  317.     /*
  318.      * read the XPM files from the resources, if any, and create
  319.      * XpmImages, or create XpmImages from default image data
  320.      */
  321.  
  322.     w->mailbox.full[0].xpmimg = None;
  323.     if (w->mailbox.mail_xpmfile) ReadIconFile(w, True);
  324.     if (w->mailbox.full[0].xpmimg == None) DefaultXpmImage(w, True);
  325.  
  326.     w->mailbox.empty.xpmimg = None;
  327.     if (w->mailbox.nomail_xpmfile) ReadIconFile(w, False);
  328.     if (w->mailbox.empty.xpmimg == None) DefaultXpmImage(w, False);
  329.  
  330. #define _MAX(x,y) ((x>y)?x:y)
  331.     w->core.width = _MAX( w->mailbox.full[0].width, w->mailbox.empty.width);
  332.     w->core.height = _MAX( w->mailbox.full[0].height, w->mailbox.empty.height);
  333. #undef _MAX
  334.  
  335.     return;
  336. }
  337.  
  338.  
  339. /*
  340.  * action procedures
  341.  */
  342.  
  343. /*
  344.  * pretend there is new mail; put widget in flagup state
  345.  */
  346.  
  347. /* ARGSUSED */
  348. static void Set (gw, event, params, nparams)
  349.     Widget gw;
  350.     XEvent *event;
  351.     String *params;
  352.     Cardinal *nparams;
  353. {
  354.     MailboxWidget w = (MailboxWidget) gw;
  355.  
  356.     w->mailbox.last_size = -1;
  357.  
  358.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  359.  
  360.     return;
  361. }
  362.  
  363.  
  364. /*
  365.  * ack the existing mail; put widget in flagdown state
  366.  */
  367.  
  368. /* ARGSUSED */
  369. static void Unset (gw, event, params, nparams)
  370.     Widget gw;
  371.     XEvent *event;
  372.     String *params;
  373.     Cardinal *nparams;
  374. {
  375.     MailboxWidget w = (MailboxWidget) gw;
  376.  
  377.     check_mailbox (w, TRUE, TRUE);    /* redraw, reset */
  378.  
  379.     return;
  380. }
  381.  
  382.  
  383. /*
  384.  * look to see if there is new mail; if so, Set, else Unset
  385.  */
  386.  
  387. /* ARGSUSED */
  388. static void Check (gw, event, params, nparams)
  389.     Widget gw;
  390.     XEvent *event;
  391.     String *params;
  392.     Cardinal *nparams;
  393. {
  394.     MailboxWidget w = (MailboxWidget) gw;
  395.  
  396.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  397.  
  398.     return;
  399. }
  400.  
  401.  
  402. /* ARGSUSED */
  403. static void clock_tic_anim (client_data, id)
  404.     XtPointer client_data;
  405.     XtIntervalId *id;
  406. {
  407.     MailboxWidget w = (MailboxWidget) client_data;
  408.  
  409.     redraw_mailbox(w);
  410.     /*
  411.      * and reset the timer
  412.      */
  413.  
  414.     w->mailbox.anim_int_id =
  415.         XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  416.                  w->mailbox.mail_animupdate, clock_tic_anim, client_data);
  417.  
  418.     return;
  419. }
  420.  
  421. /* ARGSUSED */
  422. static void clock_tic (client_data, id)
  423.     XtPointer client_data;
  424.     XtIntervalId *id;
  425. {
  426.     MailboxWidget w = (MailboxWidget) client_data;
  427.  
  428.     check_mailbox (w, FALSE, FALSE);    /* no redraw, no reset */
  429.  
  430.     /*
  431.      * and reset the timer
  432.      */
  433.  
  434.     w->mailbox.interval_id =
  435.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  436.              w->mailbox.update * 1000, clock_tic, client_data);
  437.  
  438.     return;
  439. }
  440.  
  441. static void Realize (gw, valuemaskp, attr)
  442.     Widget                    gw;
  443.     XtValueMask                *valuemaskp;
  444.     XSetWindowAttributes    *attr;
  445. {
  446.     MailboxWidget        w = (MailboxWidget) gw;
  447.     register Display    *dpy = XtDisplay (w);
  448.     XpmAttributes        xpm_attr;
  449.     int                    i;
  450.  
  451.     *valuemaskp |= (CWBitGravity | CWCursor);
  452.     attr->bit_gravity = ForgetGravity;
  453.     attr->cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
  454.  
  455.     (*mailboxWidgetClass->core_class.superclass->core_class.realize)
  456.     (gw, valuemaskp, attr);
  457.  
  458.     /*
  459.      * build the pixmaps for the two mailbox
  460.      * states from the saved XpmImages
  461.      */
  462.     xpm_attr.valuemask = 0;
  463.  
  464.     for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {    
  465.         XpmCreatePixmapFromXpmImage (dpy, w->core.window,
  466.                                      w->mailbox.full[i].xpmimg,
  467.                                      &w->mailbox.full[i].pixmap,
  468.                                      &w->mailbox.full[i].bitmap, &xpm_attr);
  469.     }
  470.  
  471.     xpm_attr.valuemask = 0;
  472.     XpmCreatePixmapFromXpmImage (dpy, w->core.window, w->mailbox.empty.xpmimg,
  473.                                  &w->mailbox.empty.pixmap,
  474.                                  &w->mailbox.empty.bitmap, &xpm_attr);
  475.  
  476.     w->mailbox.interval_id = 
  477.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  478.                      w->mailbox.update * 1000, clock_tic, (XtPointer) w);
  479.  
  480.     w->mailbox.shape_cache.mask = None;
  481.  
  482.     check_mailbox (w, TRUE, FALSE);
  483.  
  484.     return;
  485. }
  486.  
  487.  
  488. static void Destroy (gw)
  489.     Widget gw;
  490. {
  491.     MailboxWidget w = (MailboxWidget) gw;
  492.     Display *dpy = XtDisplay (gw);
  493.     int    i;
  494.  
  495.     XtFree (w->mailbox.filename);
  496.     if (w->mailbox.interval_id) XtRemoveTimeOut (w->mailbox.interval_id);
  497.     if (w->mailbox.anim_int_id != -1) XtRemoveTimeOut (w->mailbox.anim_int_id);
  498.     XtReleaseGC(gw, w->mailbox.gc);
  499. #define freepix(p) if (p) XFreePixmap (dpy, p)
  500.     for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  501.         freepix (w->mailbox.full[i].bitmap);    /* until cvter does ref cnt */
  502.         freepix (w->mailbox.full[i].pixmap);
  503.     }
  504.     freepix (w->mailbox.empty.bitmap);            /* until cvter does ref cnt */
  505.     freepix (w->mailbox.empty.pixmap);
  506.     freepix (w->mailbox.shape_cache.mask);
  507. #undef freepix
  508.     return;
  509. }
  510.  
  511.  
  512. static void Redisplay (gw)
  513.     Widget gw;
  514. {
  515.     MailboxWidget w = (MailboxWidget) gw;
  516.  
  517.     check_mailbox (w, TRUE, FALSE);
  518. }
  519.  
  520.  
  521. static void check_mailbox (w, force_redraw, reset)
  522.     MailboxWidget w;
  523.     Boolean force_redraw, reset;
  524. {
  525.     long mailboxsize = 0;
  526.     Boolean readSinceLastWrite = FALSE;
  527.     int pid;
  528.  
  529.     if (w->mailbox.check_command != NULL) {
  530.         waitType wait_status;
  531.         int    check_status;
  532. #ifdef INTWAITTYPE
  533.         wait_status = system(w->mailbox.check_command);
  534. #else
  535.         wait_status.w_status = system(w->mailbox.check_command);
  536. #endif
  537.         check_status = waitCode(wait_status);
  538.  
  539.         /* error in sh checkCommand execution */
  540.         if (waitSig(wait_status))
  541.             check_status = 2;        /* act as if there is no mail */
  542.  
  543.         switch (check_status) {
  544.           case 0:
  545.             mailboxsize = w->mailbox.last_size + 1;
  546.             break;
  547.           case 2:
  548.             mailboxsize = 0;
  549.             break;
  550.           default:        /* treat everything else as no change */
  551.                         /* case 1 is no change */
  552.             mailboxsize = w->mailbox.last_size;
  553.         }
  554.     } else {
  555.         struct stat st;
  556.         if (stat (w->mailbox.filename, &st) == 0) {
  557.             mailboxsize = st.st_size;
  558.             readSinceLastWrite = (st.st_atime > st.st_mtime);
  559.         }
  560.     }
  561.  
  562.     /*
  563.      * Now check for changes.  If reset is set then we want to pretent that
  564.      * there is no mail.  If the mailbox is empty then we want to turn off
  565.      * the flag.  Otherwise if the mailbox has changed size then we want to
  566.      * put the flag up, unless the mailbox has been read since the last 
  567.      * write.
  568.      *
  569.      * The cases are:
  570.      *    o  forced reset by user                        DOWN
  571.      *    o  no mailbox or empty (zero-sized) mailbox    DOWN
  572.      *    o  if read after most recent write              DOWN
  573.      *    o  same size as last time                      no change
  574.      *    o  bigger than last time                       UP
  575.      *    o  smaller than last time but non-zero         UP
  576.      *
  577.      * The last two cases can be expressed as different from last
  578.      * time and non-zero.
  579.      */
  580.  
  581.     if (reset) {                        /* forced reset */
  582.         w->mailbox.flag_up = FALSE;
  583.         force_redraw = TRUE;
  584.         if (w->mailbox.mail_tool) {
  585.             pid = fork();
  586.             if (pid == 0) {                /* Child process */
  587.                 system(w->mailbox.mail_tool);
  588.                 _exit(0);
  589.             }
  590.         }
  591.     } else if (mailboxsize == 0) {        /* no mailbox or empty */
  592.         w->mailbox.flag_up = FALSE;
  593.         if (w->mailbox.last_size > 0)
  594.             force_redraw = TRUE;        /* if change */
  595.     } else if (readSinceLastWrite) {     /* only when checkCommand is NULL */
  596.     /* mailbox has been read after most recent write */
  597.         if (w->mailbox.flag_up) {
  598.             w->mailbox.flag_up = FALSE;
  599.             force_redraw = TRUE;
  600.         }
  601.     } else if (mailboxsize != w->mailbox.last_size) {  /* different size */
  602.         if (!w->mailbox.once_only || !w->mailbox.flag_up)
  603.             beep(w); 
  604.         if (!w->mailbox.flag_up)
  605.             force_redraw = w->mailbox.flag_up = TRUE;
  606.     } 
  607.     w->mailbox.last_size = mailboxsize;
  608.     if (force_redraw) redraw_mailbox (w);
  609.     return;
  610. }
  611.  
  612. /*
  613.  * get user name for building mailbox
  614.  */
  615.  
  616. static void GetMailFile (w)
  617.     MailboxWidget w;
  618. {
  619.     char *getlogin();
  620.     char *username;
  621.  
  622.     /* MAIL env var overrides any hard-coded mail dir */
  623.     username = getenv( "MAIL" );
  624.     if (username!=(char *)NULL) {
  625.         w->mailbox.filename = (String) XtMalloc (strlen (username) + 1);
  626.         strcpy (w->mailbox.filename, username);
  627.         return;
  628.     }
  629.  
  630.     username = getlogin();
  631.     if (!username) {
  632.         struct passwd *pw = getpwuid (getuid ());
  633.  
  634.         if (!pw) {
  635.             fprintf (stderr, "%s:  unable to find a username for you.\n",
  636.                  "Mailbox widget");
  637.             CloseDown (w, 1);
  638.         }
  639.         username = pw->pw_name;
  640.     }
  641.     w->mailbox.filename = (String) XtMalloc (strlen (MAILBOX_DIRECTORY) + 1 +
  642.                                              strlen (username) + 1);
  643.     strcpy (w->mailbox.filename, MAILBOX_DIRECTORY);
  644.     strcat (w->mailbox.filename, "/");
  645.     strcat (w->mailbox.filename, username);
  646.     return;
  647. }
  648.  
  649. static void CloseDown (w, status)
  650.     MailboxWidget w;
  651.     int status;
  652. {
  653.     Display *dpy = XtDisplay (w);
  654.  
  655.     XtDestroyWidget ((Widget)w);
  656.     XCloseDisplay (dpy);
  657.     exit (status);
  658. }
  659.  
  660. /*
  661.  * Called by Initialize() to read XPM icon files
  662.  * and create XPM image data from their contents
  663.  */
  664. static void ReadIconFile (w, flag)
  665.     MailboxWidget w;
  666.     Bool flag;
  667. {
  668.     String            name;
  669.     char            aname[255], *ch=NULL;
  670.     int                code;
  671.     struct _mbimage    *im;
  672.     XpmImage        *imp;
  673.     int                i;
  674.  
  675.     if ( flag ) {
  676.         if (w->mailbox.mail_numofxpmfile > 1) {
  677.             /* append a number before a file name */
  678.             ch = strrchr(w->mailbox.mail_xpmfile, '/');
  679.             if (ch) *ch = '\0';
  680.         }
  681.         for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  682.             if (w->mailbox.mail_numofxpmfile > 1)
  683.                 sprintf(aname, "%s/%d%s", w->mailbox.mail_xpmfile, i, ch+1);
  684.             else
  685.                 strcpy(aname, w->mailbox.mail_xpmfile);    /* 1: file for "mail" */
  686.             im = &w->mailbox.full[i];
  687.             imp = &mail_xpmimg[i];
  688.             code = XpmReadFileToXpmImage( aname, imp, (XpmInfo *)NULL );
  689.             if ( code == XpmSuccess ) {
  690.                 im->xpmimg = imp;
  691.                 im->width = imp->width;
  692.                 im->height = imp->height;
  693.             }
  694.             else
  695.             {
  696.                 fprintf (stderr, "%s: ReadIconFile(%s): %s\n",
  697.                          "Mailbox widget", aname, XpmGetErrorString(code));
  698.                 w->mailbox.mail_numofxpmfile = i;
  699.                 if (w->mailbox.mail_numofxpmfile == 0)
  700.                     w->mailbox.mail_numofxpmfile = 1;
  701.                 break;
  702.             }
  703.         }
  704.     }
  705.     else {
  706.         name = w->mailbox.nomail_xpmfile; /* False: file for no "mail" */
  707.         im = &w->mailbox.empty;
  708.         imp = &nomail_xpmimg;
  709.         code = XpmReadFileToXpmImage( name, imp, (XpmInfo *)NULL );
  710.         if ( code == XpmSuccess ) {
  711.             im->xpmimg = imp;
  712.             im->width = imp->width;
  713.             im->height = imp->height;
  714.         }
  715.         else
  716.             fprintf (stderr, "%s: ReadIconFile(%s): %s\n",
  717.                  "Mailbox widget", name, XpmGetErrorString(code));
  718.     }
  719. }
  720.  
  721. /*
  722.  * Called by Initialize() to create XPM image
  723.  * data from the default (hard-coded) XPM icons
  724.  */
  725. static void DefaultXpmImage(w, flag)
  726.     MailboxWidget w;
  727.     Bool flag;
  728. {
  729. #define MakeXpmImage()    { \
  730.         code = XpmCreateXpmImageFromData (datap, imp, (XpmInfo *)NULL); \
  731.         if ( code == XpmSuccess ) { \
  732.             im->xpmimg = imp; \
  733.             im->width = imp->width; \
  734.             im->height = imp->height; \
  735.         } \
  736.         else { \
  737.             fprintf (stderr, "%s: DefaultXpmImage(): %s\n", \
  738.                      "Mailbox widget", XpmGetErrorString(code)); \
  739.             CloseDown (w, 1); \
  740.         } \
  741.     }
  742.  
  743.     char            **datap;
  744.     int                code;
  745.     struct _mbimage    *im;
  746.     XpmImage        *imp;
  747.     int                i;
  748.  
  749.     if ( flag ) {
  750.         for(i = 0; i < w->mailbox.mail_numofxpmfile; i++) {
  751.             datap = (i % 2)? xnomail_xpm: xmail_xpm; /* 1: data for "mail" */
  752.             im = &w->mailbox.full[i];
  753.             imp = &mail_xpmimg[i];
  754.             MakeXpmImage();
  755.         }
  756.     }
  757.     else {
  758.         datap = xnomail_xpm; /* False: data for "no mail" */
  759.         im = &w->mailbox.empty;
  760.         imp = &nomail_xpmimg;
  761.         MakeXpmImage();
  762.     }
  763. #undef MakeXpmImage
  764. }
  765.  
  766. /* ARGSUSED */
  767. static Boolean SetValues (gcurrent, grequest, gnew)
  768.     Widget gcurrent, grequest, gnew;
  769. {
  770.     MailboxWidget current = (MailboxWidget) gcurrent;
  771.     MailboxWidget new = (MailboxWidget) gnew;
  772.     Boolean redisplay = FALSE;
  773.  
  774.     if (current->mailbox.update != new->mailbox.update) {
  775.         if (current->mailbox.interval_id) 
  776.         XtRemoveTimeOut (current->mailbox.interval_id);
  777.         new->mailbox.interval_id =
  778.             XtAppAddTimeOut (XtWidgetToApplicationContext(gnew),
  779.                              new->mailbox.update * 1000, clock_tic,
  780.                              (XtPointer) gnew);
  781.     }
  782.  
  783.     return (redisplay);
  784. }
  785.  
  786.  
  787. /*
  788.  * drawing code
  789.  */
  790.  
  791. static void redraw_mailbox (w)
  792.     MailboxWidget w;
  793. {
  794.     static                int ctrig=0;
  795.     register Display    *dpy = XtDisplay (w);
  796.     register Window        win = XtWindow (w);
  797.     GC                    gc = w->mailbox.gc;
  798.     struct _mbimage        *im;
  799.     Widget                parent;
  800.  
  801.     if (w->mailbox.flag_up) {        /* draw the "mail" icon */
  802.         if (w->mailbox.mail_numofxpmfile > 1) {
  803.             if (w->mailbox.first_trig) {
  804.                 w->mailbox.anim_int_id = XtAppAddTimeOut (
  805.                             XtWidgetToApplicationContext((Widget) w),
  806.                             w->mailbox.mail_animupdate, clock_tic_anim, 
  807.                             (XtPointer) w);
  808.                 w->mailbox.anim_id = 0;
  809.                 w->mailbox.first_trig = 0;
  810.                 ctrig = 0;
  811.             } else {
  812.                 /* This route called twice (The second one from ReDisplay()) */
  813.                 if ((++ctrig % 2) == 0) {
  814.                     w->mailbox.anim_id = (w->mailbox.anim_id + 1) 
  815.                                             % (w->mailbox.mail_numofxpmfile);
  816.                     if (w->mailbox.mail_animonce && (w->mailbox.anim_id == 0)) {
  817.                         if (w->mailbox.anim_int_id != -1) {
  818.                             XtRemoveTimeOut(w->mailbox.anim_int_id);
  819.                             w->mailbox.anim_int_id = -1;
  820.                         }
  821.                         w->mailbox.anim_id = w->mailbox.mail_numofxpmfile - 1;
  822.                     }
  823.                     ctrig = 0;
  824.                 }
  825.     
  826.                 if (w->mailbox.anim_int_id == -1)
  827.                     return;
  828.             }
  829.             im = &(w->mailbox.full[w->mailbox.anim_id]);
  830.         }
  831.         else im = &(w->mailbox.full[0]);
  832.     } else {                        /* draw the "no mail" icon */
  833.         im = &w->mailbox.empty;
  834.         w->mailbox.first_trig = 1;
  835.         if (w->mailbox.anim_int_id != -1) {
  836.             XtRemoveTimeOut(w->mailbox.anim_int_id);
  837.             w->mailbox.anim_int_id = -1;
  838.         }
  839.     }
  840.     XClearWindow (dpy, win);
  841.     XCopyArea (dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, 0, 0);
  842.  
  843.     /*
  844.      * XXX - temporary hack; walk up widget tree to find top most parent (which
  845.      * will be a shell) and mash it to have our shape.  This will be replaced
  846.      * by a special shell widget.
  847.      */
  848.  
  849.     for (parent = (Widget) w; XtParent(parent);
  850.         parent = XtParent(parent));
  851.  
  852.     if (im->bitmap != w->mailbox.shape_cache.mask) {
  853.         XShapeCombineMask (XtDisplay(parent), XtWindow(parent),
  854.                            ShapeBounding, 0, 0, im->bitmap, ShapeSet);
  855.         w->mailbox.shape_cache.mask = im->bitmap;
  856.     }
  857.  
  858.     return;
  859. }
  860.  
  861. #ifndef NO_AUDIO
  862. #define CLOSE_FD(afd)    { if (afd > -1) close(afd); afd = -1; }
  863.  
  864. #ifdef linux
  865. #define INIT_FD    { audiofd = filefd = mixer_fd = -1; }
  866. #define END_FD    { CLOSE_FD(audiofd); CLOSE_FD(filefd); CLOSE_FD(mixer_fd); return; }
  867. #else
  868. #define INIT_FD    { audiofd = filefd = 0; }
  869. #define END_FD    { CLOSE_FD(audiofd); CLOSE_FD(filefd); return; }
  870. #endif
  871. #endif
  872.  
  873. static void beep (w)
  874.     MailboxWidget w;
  875. {
  876. #ifndef NO_AUDIO
  877. #ifdef NCD_AUDIO
  878.     char    *auservername = NULL;
  879. #elif defined(RPLAY_AUDIO)
  880.     char    *rplay_name;
  881. #endif
  882.     int        audiofd, filefd;
  883.     int        rn, wn, len;
  884.     unsigned char    buf[256];
  885. #ifdef SUN_AUDIO
  886.     Audio_filehdr    *au_hdr;
  887. #ifdef linux
  888.     StereoVolume origVol, volume;
  889.     int                mixer_fd;
  890. #else
  891.     audio_info_t     ais;
  892.     int                origVol;    
  893. #endif
  894. #endif
  895.  
  896.     if (w->mailbox.mail_sndfile) {
  897. #ifdef NCD_AUDIO
  898.         aud = AuOpenServer(auservername, 0, NULL, 0, NULL, NULL);
  899.         if (aud) {
  900.             if (!AuSoundPlaySynchronousFromFile(aud, w->mailbox.mail_sndfile, 
  901.                                                 w->mailbox.volume))
  902.                 fprintf(stderr, "%s: Couldn't play file \"%s\"\n", 
  903.                         "Mailbox widget", w->mailbox.mail_sndfile);
  904.  
  905.             AuCloseServer(aud);
  906.             return;
  907.         }
  908. #elif defined(RPLAY_AUDIO)
  909.         rplay_name = rplay_default_host();
  910.         if (rplay_host_volume(rplay_name, w->mailbox.mail_sndfile,
  911.                               (int)(w->mailbox.volume*2.55)) < 0)
  912.             fprintf(stderr, "%s: Rplay couldn't play file \"%s\"\n", 
  913.                     "Mailbox widget", w->mailbox.mail_sndfile);
  914.         else
  915.             return;
  916. #endif
  917. #ifdef SUN_AUDIO
  918.         INIT_FD;
  919.         audiofd = open( "/dev/audio", O_WRONLY | O_NDELAY ); 
  920.         if (audiofd < 0) {
  921.             fprintf(stderr, "%s: Problem opening /dev/audio.\n",
  922.                     "Mailbox widget");
  923.             END_FD;
  924.         }
  925. #ifdef linux
  926.         if ( (mixer_fd=open(DEV_MIXER, O_RDWR, 0)) < 0 ) {
  927.             fprintf(stderr, "Can't open %s: ", DEV_MIXER);
  928.             END_FD;
  929.         }
  930.  
  931.         if ( ioctl(mixer_fd, SOUND_MIXER_READ_PCM, &origVol) < 0 ) {
  932.             perror("Can't obtain current volume settings");
  933.             END_FD;
  934.         }
  935.  
  936.         setvolume(LEFT|RIGHT, (unsigned char)w->mailbox.volume, &volume);
  937.  
  938.         if ( ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &volume) < 0 ) {
  939.             fprintf(stderr, "Can't set current volume settings");
  940.             END_FD;
  941.         }
  942.  
  943.         /* The following is required for the setting to take into effect
  944.         CLOSE_FD(mixer_fd); */
  945. #else
  946.         if( ioctl( audiofd, AUDIO_GETINFO, &ais ) ) {
  947.             fprintf(stderr, "%s: Problem retrieving /dev/audio info.\n",
  948.                     "Mailbox widget");
  949.             END_FD;
  950.         }
  951.         origVol = ais.play.gain;
  952.         ais.play.gain = w->mailbox.volume;
  953.         if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
  954.             fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
  955.                     "Mailbox widget");
  956.             END_FD;
  957.         }
  958. #endif
  959.         filefd = open(w->mailbox.mail_sndfile, O_RDONLY);
  960.         if (filefd < 0) {
  961.             fprintf(stderr, "%s: Couldn't play file \"%s\"\n", 
  962.                 "Mailbox widget", w->mailbox.mail_sndfile);
  963.             END_FD;
  964.         }
  965.  
  966.         /* Read in the audio header */
  967.         rn = read(filefd, buf, sizeof(Audio_filehdr)); 
  968.  
  969.         if (rn > 0 && strncmp(buf, ".snd", 4) != 0) {
  970.             fprintf(stderr, "%s: Invalid audio file format.\n",
  971.                     "Mailbox widget");
  972.             END_FD;
  973.         }
  974.  
  975.         /* Strip the header */
  976.         au_hdr = (Audio_filehdr *)buf;
  977. #ifdef linux
  978.         rn = ntohl(au_hdr->hdr_size) - sizeof(Audio_filehdr);     
  979. #else
  980.         rn = au_hdr->hdr_size - sizeof(Audio_filehdr);
  981. #endif
  982.         for( ; rn > 0; ) {
  983.             len = min(rn, sizeof(buf));
  984.             len = read(filefd, buf, len); 
  985.             rn -= len;    
  986.         }
  987.  
  988.         while(1) {
  989.             rn = read(filefd, buf, sizeof(buf));
  990.             if (rn < 0) {
  991.                 fprintf(stderr, "%s: Error reading from file \"%s\"\n", 
  992.                     "Mailbox widget", w->mailbox.mail_sndfile);
  993.                 END_FD;
  994.             }
  995.             if (rn == 0)
  996.                 break;
  997.             while(1) {
  998.                 wn = write(audiofd, buf, rn);
  999.                 if ( wn < 0 ) {
  1000.                     fprintf(stderr, "%s: Error writing to /dev/audio.\n", 
  1001.                         "Mailbox widget");
  1002.                     END_FD;
  1003.                 }
  1004.                 if ( wn != 0 )
  1005.                     break;
  1006.                 usleep(1000);
  1007.             }
  1008.         }
  1009. #ifdef linux
  1010.         CLOSE_FD(audiofd);
  1011.  
  1012.         if ( ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &origVol) < 0 ) {
  1013.             fprintf(stderr, "Can't reset volume settings");
  1014.         }
  1015. #else
  1016.         ais.play.gain = origVol;
  1017.         if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
  1018.             fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
  1019.                     "Mailbox widget");
  1020.         }
  1021. #endif
  1022.         END_FD;
  1023. #endif /* #ifdef SUN_AUDIO */
  1024.     }
  1025.     else
  1026. #endif /* #ifndef NO_AUDIO */
  1027.         XBell (XtDisplay (w), w->mailbox.volume);
  1028.     return;
  1029. }
  1030.  
  1031.