/*******************************************************************************
Copyright (c) 1994,1995 William Pemberton (wfp5p@virginia.edu)
The X Consortium, and any party obtaining a copy of these files from
the X Consortium, directly or indirectly, is granted, free of charge, a
full and unrestricted irrevocable, world-wide, paid up, royalty-free,
nonexclusive right and license to deal in this software and
documentation files (the "Software"), including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons who receive
copies from any such party to do so. This license includes without
limitation a license to do the foregoing actions under any patents of
the party supplying this software to the X Consortium.
*******************************************************************************/
/*
xbuffy - Bill's version of the multiple mailbox biff
Author: Bill Pemberton, wfp5p@virginia.edu
This is a modified version of xmultibiff 2.0 by:
John Reardon, Midnight Networks, badger@midnight.com, 1993.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <dirent.h>
#include <limits.h>
#ifndef SUN
#include <sys/types.h>
#include <sys/stat.h>
#endif /* SYSV */
#include "xbuffy.h"
#ifndef USE_MOTIF
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Paned.h>
#else
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/Text.h>
#include <Xm/PushB.h>
/*
#define XtNbackground XmNbackground
#define XtNforeground XmNforeground
#define XtNwidth XmNwidth
#define XtNheight XmNheight
#define XtNlabel XmNvalue
*/
#endif
#ifdef USE_LED
#include <signal.h>
#endif
#include "xbuffy.xbm"
#ifdef WFP_DEBUG
#include "/home/wfp5p/bin/debug_include/malloc.h"
#endif
void CheckBox();
void TimerBreakPopup();
int CountUnixMail();
void ParseMailPath();
int makeBoxTitle();
void initBox();
Pixel convertColor();
void ButtonDownHandler();
void ButtonUpHandler();
void BreakPopup();
void ExecuteCommand();
void setBoxColor();
void PopupHeader();
char *EliminatePath();
void UpdateBoxNumber();
/** globals **/
char versionString[MAX_STRING];
char *programName;
Widget toplevel;
Widget *header;
ApplicationData_t data;
XtAppContext app;
DynObject DynBoxObj;
BoxInfo_t *boxInfo;
int *headerUp;
int nBoxes = 0;
int envPolltime = 0;
int envPriority = 0;
int envHeadertime = 0;
int NNTPinit = 0;
int maxBoxSize = 0;
FILE *NNTP_fIn, *NNTP_fOut;
extern char **environ;
XtResource resources[] = {
{"mailboxes", "Mailboxes", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, mailBoxes), XtRString, 0},
{"nobeep", "Nobeep", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, nobeep), XtRString, "FALSE"},
{"horiz", "Horiz", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, horiz), XtRString, "FALSE"},
{"command", "Command", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, command), XtRString, 0},
{"names", "Names", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, longNames), XtRString, "FALSE"},
{"shortnames", "Shortnames", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, shortNames), XtRString, "FALSE"},
{"polltime", "Polltime", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, pollTime), XtRString, "60"},
{"priority", "Priority", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, priority), XtRString, "15"},
{"headertime", "Headertime", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, headerTime), XtRString, 0},
{"orig", "Orig", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, origMode), XtRString, "FALSE"},
{"audiocmd", "Audiocmd", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, audioCmd), XtRString, 0},
{"boxfile", "Boxfile", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, boxFile), XtRString, 0},
{"center", "Center", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, center), XtRString, "FALSE"},
{"fill", "Fill", XtRBoolean, sizeof(int),
XtOffset(ApplicationData_t *, fill), XtRString, "FALSE"},
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
XtOffset(ApplicationData_t *, fg), XtRString, XtDefaultForeground},
{XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
XtOffset(ApplicationData_t *, bg), XtRString, XtDefaultBackground},
#ifdef USE_NNTP
{"newsboxes", "Newsboxes", XtRString, sizeof(String),
XtOffset(ApplicationData_t *, newsBoxes), XtRString, 0},
#endif /* USE_NNTP */
};
XrmOptionDescRec options[] = {
{"-nobeep", "*nobeep", XrmoptionNoArg, "TRUE"},
{"-center", "*center", XrmoptionNoArg, "TRUE"},
{"-fill", "*fill", XrmoptionNoArg, "TRUE"},
{"-horiz", "*horiz", XrmoptionNoArg, "TRUE"},
{"-names", "*names", XrmoptionNoArg, "TRUE"},
{"-shortnames", "*shortnames", XrmoptionNoArg, "TRUE"},
{"-acmd", "*audiocmd", XrmoptionSepArg, 0},
{"-poll", "*polltime", XrmoptionSepArg, 0},
{"-priority", "*priority", XrmoptionSepArg, 0},
{"-header", "*headertime", XrmoptionSepArg, 0},
{"-orig", "*orig", XrmoptionNoArg, "TRUE"},
{"-boxfile", "*boxfile", XrmoptionSepArg, 0},
{"-command", "*command", XrmoptionSepArg, 0},
};
void CheckBox(i)
int i;
{
int num = 0;
Arg args[5];
int nargs;
BoxInfo_t *currentBox;
Boolean beenTouched;
Boolean isIcon = FALSE;
currentBox = &boxInfo[i];
#ifdef USE_NNTP
if (boxInfo[i].type == NNTPBOX)
{
num = CountNNTP(currentBox, NULL, &beenTouched);
}
#endif /* USE_NNTP */
if ((boxInfo[i].type == MAILBOX) || (boxInfo[i].type == MAILDIR) ||
(boxInfo[i].type == MHDIR))
{
num = CountUnixMail(currentBox, NULL, &beenTouched);
}
nargs = 0;
XtSetArg(args[nargs], XtNiconic, &isIcon);
if ((num > currentBox->n) ||
((!currentBox->origMode) && ((num != currentBox->n) || (beenTouched))))
{
if ((currentBox->headerTime != 0) && (!isIcon) && (num > 0))
{
PopupHeader(currentBox->w, currentBox->boxNum, 0, 0);
}
if ((!currentBox->nobeep) && (num > 0))
{
if (currentBox->audioCmd != NULL)
{
system(currentBox->audioCmd);
}
else
{
XBell(XtDisplay(currentBox->w), 0);
}
}
}
if (currentBox->n != num)
{
currentBox->n = num;
UpdateBoxNumber(currentBox);
}
XtAppAddTimeOut(app, (currentBox->pollTime * 1000), CheckBox, (XtPointer) i);
}
void setBoxColor(box,status)
BoxInfo_t *box;
int status;
{
Arg args[5];
int nargs;
nargs = 0;
if (status)
{
XtSetArg(args[nargs], XtNbackground, box->fg);
nargs++;
XtSetArg(args[nargs], XtNforeground, box->bg);
nargs++;
}
else
{
XtSetArg(args[nargs], XtNbackground, box->bg);
nargs++;
XtSetArg(args[nargs], XtNforeground, box->fg);
nargs++;
}
XtSetValues(box->w, args, nargs);
}
void UpdateBoxNumber(box)
BoxInfo_t *box;
{
char amt[MAX_STRING];
char fmtString[MAX_STRING];
char *ptr;
int offset;
Arg args[5];
int nargs;
#ifdef USE_MOTIF
XmString label;
#endif
#ifdef USE_LED
if (box->led != -1)
{
char l[17];
if (box->n > 0)
{
if (box->pid > 1) {
if (!kill(box->pid, SIGINT))
waitpid(box->pid, NULL, 0);
/*
else
perror("Failing to kill led");
*/
}
switch (box->pid = fork()) {
case -1:
perror("Fork failure");
break;
case 0:
sprintf(amt, "%d", box->n);
sprintf(l, "%d", box->led);
if (execlp("led", "led", l, amt, (char*)NULL) == -1) {
fprintf(stderr, "Error executing led\n");
_exit(1);
}
default:
}
}
else
{
if (box->pid > 1)
if (!kill(box->pid, SIGINT))
{
waitpid(box->pid, NULL, 0);
box->pid = 0;
}
else
perror("Failing to kill led");
}
}
#endif
if (box->boxTitle != NULL)
{
sprintf(amt, "%s: %d", box->boxTitle, box->n);
}
else
{
sprintf(amt, "%d", box->n);
}
memset(fmtString, ' ',MAX_STRING);
if (data.center) /* center implies fill */
{
offset = ((maxBoxSize+4) - NEWstrlen(amt))/2;
if (offset < 0) offset = 0;
if (offset > MAX_STRING) offset = 0;
ptr = fmtString+ offset;
strcpy(ptr,amt);
ptr = fmtString+NEWstrlen(fmtString);
*ptr = ' ';
*(ptr+offset+1-(offset%2))='\0';
}
else if (data.fill)
{
offset = maxBoxSize+4-NEWstrlen(amt);
if (offset < 0) offset = 0;
strcpy(fmtString,amt);
ptr = fmtString+NEWstrlen(fmtString);
while (offset-- >0)
*ptr++ = ' ';
*ptr = '\0';
}
else
{
strcpy(fmtString, amt);
}
nargs = 0;
if (!box->origMode)
{
if (box->n > 0)
{
setBoxColor(box,1);
}
else
{
setBoxColor(box,0);
}
}
#ifdef USE_MOTIF
label = XmStringCreateSimple(amt);
XtSetArg(args[nargs], XmNlabelString, label);
nargs++;
#else
XtSetArg(args[nargs], XtNlabel, fmtString);
nargs++;
#endif
XtSetValues(box->w, args, nargs);
#ifdef USE_MOTIF
XmStringFree(label);
#endif
}
#ifdef USE_MOTIF
static void dimension_text(char *hdrPtr, int *rows, int *cols)
{
int curwidth;
*rows = 0;
*cols = 0;
curwidth = 0;
while (*hdrPtr != '\0')
{
if (*hdrPtr == '\n')
{
(*rows)++;
if (curwidth > *cols)
*cols = curwidth;
curwidth = 0;
}
else
curwidth++;
hdrPtr++;
}
}
#endif
/* event handlers that decides what to do with button clicks */
void ButtonDownHandler(w, i, event, cont)
Widget w;
int *i;
XEvent *event;
Boolean *cont;
{
if (event->xbutton.button == 1)
{
PopupHeader(w, *i, event, cont);
}
/* don't do anything else for other button clicks */
}
void ButtonUpHandler(w, i, event, cont)
Widget w;
int *i;
XEvent *event;
Boolean *cont;
{
if (event->xbutton.button == 1)
{
BreakPopup(w, *i, event, cont);
}
else if (event->xbutton.button == 2)
{
ExecuteCommand(w, *i, event, cont);
}
else if (event->xbutton.button == 3)
{
BoxInfo_t *currentBox;
currentBox = &boxInfo[*i];
setBoxColor(currentBox,0);
#ifdef USE_LED
if (currentBox->led != -1)
if (currentBox->pid > 1)
if (!kill(currentBox->pid, SIGINT))
{
waitpid(currentBox->pid, NULL, 0);
currentBox->pid = 0;
}
else
perror("Failing to kill led");
#endif
}
}
void PopupHeader(w, i, event, cont)
Widget w;
int i;
XEvent *event;
Boolean *cont;
{
Arg args[5];
int nargs;
Widget tmpCommand;
Position biff_x, biff_y, root_x, root_y;
static XtIntervalId timerID;
static int rootH = 0;
static int rootW = 0;
int number = 0;
static Boolean firstTime = TRUE;
static DynObject mailHeaders;
static char *hdrPtr;
Dimension headerW, headerH;
BoxInfo_t *currentBox;
Boolean beenTouched;
#ifdef USE_MOTIF
int rows, cols;
#endif
currentBox = &boxInfo[i];
if (rootH == 0)
{
rootH = DisplayHeight(XtDisplay(w), DefaultScreen(XtDisplay(w)));
rootW = DisplayWidth(XtDisplay(w), DefaultScreen(XtDisplay(w)));
}
if ((!firstTime) && (DynSize(mailHeaders) != 0))
{
DynDestroy(mailHeaders);
}
firstTime = FALSE;
mailHeaders = DynCreate(sizeof(char), MAX_STRING);
#ifdef DEBUG
DynDebug(mailHeaders, 1);
DynParanoid(mailHeaders, 1);
#endif
#ifdef USE_NNTP
/* check to see if there is any news before proceeding */
if (boxInfo[i].type == NNTPBOX)
{
number = CountNNTP(&boxInfo[i], mailHeaders, &beenTouched);
DynAdd(mailHeaders, "\0");
hdrPtr = (char *) DynGet(mailHeaders, 0);
}
#endif
/* update the number on the box (in case there are new articles) */
if ((currentBox->type == MAILBOX) || (currentBox->type == MAILDIR) ||
(currentBox->type == MHDIR))
{
number = CountUnixMail(currentBox, mailHeaders, &beenTouched);
DynAdd(mailHeaders, "\0");
hdrPtr = (char *) DynGet(mailHeaders, 0);
}
/* if the number is different, update it */
currentBox->n = number;
UpdateBoxNumber(&boxInfo[i]);
/* if the number is zero, there's no header, so leave */
if (boxInfo[i].n == 0)
{
return;
}
/* if its already up, pop it down, because we must update it */
if (headerUp[i] == TRUE)
{
XtRemoveTimeOut(timerID);
BreakPopup(0, i, 0, 0);
}
/* Calculate Relative position -> Root absolute position */
nargs = 0;
XtSetArg(args[nargs], XtNwidth, &biff_x);
nargs++;
XtSetArg(args[nargs], XtNheight, &biff_y);
nargs++;
XtGetValues(w, args, nargs);
XtTranslateCoords(w, biff_x, biff_y, &root_x, &root_y);
header[i] = XtCreatePopupShell(currentBox->boxTitle, transientShellWidgetClass,
currentBox->w, 0, 0);
nargs = 0;
#ifndef USE_MOTIF
XtSetArg(args[nargs], XtNlabel, hdrPtr);
nargs++;
XtSetArg(args[nargs], XtNhighlightThickness, 0);
nargs++;
tmpCommand = XtCreateManagedWidget("popup", commandWidgetClass, header[i], args, nargs);
XtAddCallback(tmpCommand, XtNcallback, BreakPopup, (XtPointer) i);
#else
dimension_text((char *) hdrPtr, &rows, &cols);
XtSetArg(args[nargs], XmNvalue, hdrPtr);
nargs++;
XtSetArg(args[nargs], XmNeditMode, XmMULTI_LINE_EDIT);
nargs++;
XtSetArg(args[nargs], XmNeditable, False);
nargs++;
XtSetArg(args[nargs], XmNrows, (short) rows);
nargs++;
XtSetArg(args[nargs], XmNcolumns, (short) cols);
nargs++;
tmpCommand = XmCreateText(header[i], "popup", args, nargs);
XtManageChild(tmpCommand);
XtAddCallback(tmpCommand, XmNactivateCallback, BreakPopup, (XtPointer) i);
#endif
if (!XtIsRealized(header[i]))
{
XtRealizeWidget(header[i]);
}
/* see where we should put this thing so its on the screen */
/* i.e. make sure we can see it */
nargs = 0;
XtSetArg(args[nargs], XtNwidth, &headerW);
nargs++;
XtSetArg(args[nargs], XtNheight, &headerH);
nargs++;
XtGetValues(header[i], args, nargs);
if (((int) root_x + (int) headerW) >= (rootW - 20))
{
root_x = (Position) rootW - ((Position) headerW + 5);
}
if (((int) root_y + (int) headerH) >= (rootH - 20))
{
root_y = (Position) rootH - ((Position) headerH + 40);
}
nargs = 0;
XtSetArg(args[nargs], XtNx, root_x);
nargs++;
XtSetArg(args[nargs], XtNy, root_y);
nargs++;
XtSetValues(header[i], args, nargs);
XtPopup(header[i], XtGrabNone);
headerUp[i] = TRUE;
/* free alloc'ed string */
/* register a routine to pop it down if it was invoked from a routine */
if (event == 0)
{
timerID = XtAppAddTimeOut(app, (currentBox->headerTime * 1000),
TimerBreakPopup, (XtPointer) i);
}
}
void TimerBreakPopup(i)
int i;
{
BreakPopup(0, i, 0, 0);
}
void BreakPopup(w, i, event, cont)
Widget w;
int i;
XEvent *event;
Boolean *cont;
{
if (headerUp[i] != TRUE)
{
return;
}
XtPopdown(header[i]);
XtDestroyWidget(header[i]);
headerUp[i] = FALSE;
}
void ExecuteCommand(w, i, event, cont)
Widget w;
int i;
XEvent *event;
Boolean *cont;
{
BoxInfo_t *currentBox;
currentBox = &boxInfo[i];
#ifdef USE_LED
if (currentBox->led != -1)
if (currentBox->pid > 1)
if (!kill(currentBox->pid, SIGINT))
{
waitpid(currentBox->pid, NULL, 0);
currentBox->pid = 0;
}
else
perror("Failing to kill led");
#endif
if (currentBox->command != NULL)
{
system(currentBox->command);
}
}
int isLocked(mbox)
char *mbox;
{
/* right now this is a REAL stupid function, it just looks for a .lock file */
char *lockfile;
int retVal;
lockfile = (char *) malloc( (NEWstrlen(mbox)+15)*sizeof(char));
strcpy(lockfile, mbox);
strcat(lockfile, ".lock");
retVal = exists(lockfile);
free(lockfile);
return(retVal);
}
int CountMBoxMail(mailBox, headerString)
BoxInfo_t *mailBox;
DynObject headerString;
{
FILE *fp = 0;
char buffer[MAX_STRING];
char From[MAX_STRING], Subject[MAX_STRING];
register int count = 0;
int status = UNKNOWN;
register Boolean in_header = FALSE;
fp = fopen(mailBox->box, "r");
if (fp == NULL)
return 0;
From[0] = Subject[0] = '\0';
while (fgets(buffer, MAX_STRING - 2, fp) != 0)
{
long CL = 0L;
int has_CL = FALSE;
buffer[MAX_STRING - 1] = '\0'; /* just in case */
if ((strchr(buffer, '\n') == NULL) && (!feof(fp)))
{
int c;
while ((c = getc(fp)) != EOF && c != '\n'); /* keep reading */
}
if ((!in_header) && (real_from(buffer)))
{
has_CL = FALSE;
in_header = TRUE;
status = NEW_MSG;
}
else if (in_header)
{
if (header_cmp(buffer, "From", NULL))
{
strcpy(From, buffer);
}
if (header_cmp(buffer, "Content-Length", NULL))
{
has_CL = TRUE;
CL = atol(buffer+15);
}
if (header_cmp(buffer, "Subject", NULL))
{
strcpy(Subject, buffer);
}
if (header_cmp(buffer, "Status", NULL))
{
remove_header_keyword(buffer);
if (*buffer == 'N')
status = NEW_MSG;
else
status = READ_MSG;
}
else if (buffer[0] == LINEFEED)
{
#ifdef USE_CONTENT_LENGTH
if (has_CL)
fseek(fp,CL,SEEK_CUR);
#endif
in_header = FALSE;
if ((status == NEW_MSG) || (mailBox->origMode))
{
count++;
if (headerString != NULL)
{
if (NEWstrlen(From) != 0)
DynInsert(headerString, ((DynHigh(headerString) > 0) ? (DynSize(headerString)) : 0), From, NEWstrlen(From));
if (NEWstrlen(Subject) != 0)
DynInsert(headerString, ((DynHigh(headerString) > 0) ? (DynSize(headerString)) : 0), Subject, NEWstrlen(Subject));
}
}
From[0] = Subject[0] = '\0';
}
}
}
fclose(fp);
return count;
}
int CountDirMail(mailBox, headerString)
BoxInfo_t *mailBox;
DynObject headerString;
{
DIR *dp = 0;
FILE *fp = 0;
char buffer[MAX_STRING];
char From[MAX_STRING], Subject[MAX_STRING];
char path[_POSIX_PATH_MAX];
int status;
register Boolean found = FALSE;
register Boolean mailfile = TRUE;
struct dirent *de;
register int count = 0;
if (mailBox->type == MAILDIR) {
sprintf(path, "%s/new", mailBox->box);
} else {
strcpy(path,mailBox->box);
}
dp = opendir(path);
if (dp == NULL)
return 0;
while ((de = readdir (dp)) != NULL)
{
mailfile = TRUE;
if (mailBox->type == MHDIR) {
char *p;
p = de->d_name;
while (*p && mailfile)
{
if (!isdigit (*p)) mailfile = FALSE;
p++;
}
} else if (mailBox->type == MAILDIR) {
if (*de->d_name == '.') mailfile = FALSE;
}
if (mailfile)
{
if (mailBox->type == MAILDIR) count++;
if (headerString != NULL || mailBox->type == MHDIR) {
/* Ok, we need to get the From: and Subject: lines */
From[0] = Subject[0] = '\0';
found = FALSE;
status = NEW_MSG;
if (mailBox->type == MAILDIR) {
sprintf(path, "%s/new/%s",mailBox->box,de->d_name);
} else {
sprintf(path, "%s/%s",mailBox->box,de->d_name);
}
fp = fopen(path, "r");
if (fp != NULL) {
while (!found && fgets(buffer, MAX_STRING - 2, fp) != 0)
{
long CL;
int has_CL;
buffer[MAX_STRING - 1] = '\0'; /* just in case */
if ((strchr(buffer, '\n') == NULL) && (!feof(fp)))
{ /* read to end of line */
int c;
while ((c = getc(fp)) != EOF && c != '\n'); /* keep reading */
}
if (headerString != NULL &&
header_cmp(buffer, "From", NULL))
{
strcpy(From, buffer);
}
else if (headerString != NULL &&
header_cmp(buffer, "Subject", NULL))
{
strcpy(Subject, buffer);
}
else if (mailBox->type == MHDIR &&
header_cmp(buffer, "Status", NULL))
{
remove_header_keyword(buffer);
if (*buffer == 'N')
status = NEW_MSG;
else
status = READ_MSG;
}
else if (buffer[0] == LINEFEED && (mailBox->type == MAILDIR ||
status == NEW_MSG))
{
if (mailBox->type == MHDIR) count++;
if (strlen(From) != 0)
DynInsert(headerString,
((DynHigh(headerString) > 0) ? (DynSize(headerString)) : 0),
From, strlen(From));
if (strlen(Subject) != 0)
DynInsert(headerString,
((DynHigh(headerString) > 0) ? (DynSize(headerString)) : 0),
Subject, strlen(Subject));
found = TRUE;
}
}
fclose(fp);
}
}
}
}
closedir(dp);
return count;
}
int CountUnixMail(mailBox, headerString, beenTouched)
BoxInfo_t *mailBox;
DynObject headerString;
Boolean *beenTouched;
{
struct stat f_stat;
struct timeval t[2];
register int count = 0;
char path[_POSIX_PATH_MAX];
*beenTouched = FALSE;
if (mailBox->type == MAILBOX) {
if (isLocked(mailBox->box))
return (mailBox->n);
}
if (mailBox->type == MAILDIR) {
sprintf(path,"%s/new",mailBox->box);
} else {
strcpy(path,mailBox->box);
}
if (stat(path, &f_stat))
{
mailBox->st_size = 0;
mailBox->box_mtime = 0;
return (0);
}
if ((f_stat.st_size != mailBox->st_size) ||
(f_stat.st_mtime > mailBox->box_mtime))
{
mailBox->st_size = f_stat.st_size;
mailBox->box_mtime = f_stat.st_mtime;
*beenTouched = TRUE;
}
if ((!*beenTouched) && (headerString == NULL))
return (mailBox->n);
switch (mailBox->type) {
case MAILBOX:
count = CountMBoxMail(mailBox, headerString);
break;
case MAILDIR:
case MHDIR:
count = CountDirMail(mailBox, headerString);
break;
}
/* Restore access time of mailbox. */
t[0].tv_sec = f_stat.st_atime;
t[0].tv_usec = 0;
t[1].tv_sec = f_stat.st_mtime;
t[1].tv_usec = 0;
utimes(mailBox->box, t);
return count;
}
Pixel convertColor(colorname, defValue)
char *colorname;
Pixel defValue;
{
XrmValue namein, pixelout;
namein.addr = colorname;
namein.size = NEWstrlen(colorname) + 1;
pixelout.size = 0;
XtConvert(toplevel, XtRString, &namein, XtRPixel, &pixelout);
if (pixelout.size == 0) /* it failed */
return(defValue);
else
return(*(Pixel *)pixelout.addr);
}
#ifdef USE_LED
void initBox(box, BoxType, pollTime, headerTime, BoxNameType, command, audioCmd,
title, origMode, nobeep, bgName, fgName, led)
#else
void initBox(box, BoxType, pollTime, headerTime, BoxNameType, command, audioCmd,
title, origMode, nobeep, bgName, fgName)
#endif
char *box;
BoxType_t BoxType;
int pollTime;
int headerTime;
BoxNameType_t BoxNameType;
char *command;
char *audioCmd;
char *title;
Boolean origMode;
Boolean nobeep;
char *bgName;
char *fgName;
#ifdef USE_LED
int led;
#endif
{
BoxInfo_t tempBox;
int boxSize;
char *ptr;
/* get rid of trailing whitespace in box */
ptr = box + NEWstrlen(box) - 1;
while (isspace(*ptr))
*ptr-- = '\0';
#ifdef DEBUG
fprintf(stderr, "Init Box = *%s*\n", box);
fprintf(stderr, "nboxes = %i\n", nBoxes);
fprintf(stderr, "type = %i\n", BoxType);
fprintf(stderr, "command = *%s*\n", command);
fprintf(stderr, "audio = *%s*\n", audioCmd);
fprintf(stderr, "boxTitle = *%s*\n", title);
fprintf(stderr, "pollTime = %i headerTime = %i\n", pollTime, headerTime);
fprintf(stderr, "nobeep = %i origMode = %i \n", nobeep, origMode);
fprintf(stderr, "nametype = %i\n\n", BoxNameType);
#endif
tempBox.box = NEWstrdup(box);
tempBox.type = BoxType;
tempBox.boxNum = nBoxes;
if (BoxType == NNTPBOX)
{
tempBox.articles = DynCreate(sizeof(Articles_t), 2);
#ifdef DEBUG
/* DynDebug(tempBox.articles, 1);
DynParanoid(tempBox.articles, 1);*/
#endif
} else if (BoxType == MAILBOX)
{
struct stat st;
char tmp[_POSIX_PATH_MAX];
if (stat (box, &st) != -1) {
if (S_ISDIR (st.st_mode)) {
/* check for maildir mailbox */
sprintf(tmp, "%s/cur", box);
if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode)) {
tempBox.type = MAILDIR;
} else {
/* check for mh mailbox */
sprintf(tmp, "%s/.mh_sequences", box);
if (access (tmp, F_OK) == 0) {
tempBox.type = MHDIR;
} else {
sprintf(tmp, "%s/.xmhcache", box);
if (access (tmp, F_OK) == 0) {
tempBox.type = MHDIR;
}
}
}
}
}
}
if ((pollTime <= 0) || (pollTime >= 3600))
tempBox.pollTime = envPolltime;
else
tempBox.pollTime = pollTime;
if ((tempBox.type == NNTPBOX) && (tempBox.pollTime < 180))
tempBox.pollTime = 180;
if ((headerTime < 0) || (headerTime >= 60))
tempBox.headerTime = envHeadertime;
else
tempBox.headerTime = headerTime;
tempBox.BoxNameType = BoxNameType;
tempBox.boxTitle = NEWstrdup(title);
if (tempBox.BoxNameType == UNDEF)
{
if (data.shortNames)
tempBox.BoxNameType = SHORT;
if (data.longNames)
tempBox.BoxNameType = LONG;
}
boxSize = makeBoxTitle(&tempBox);
if (boxSize > maxBoxSize)
maxBoxSize = boxSize;
tempBox.command = NEWstrdup(command);
tempBox.audioCmd = NEWstrdup(audioCmd);
tempBox.origMode = origMode;
tempBox.nobeep = nobeep;
if (bgName != NULL)
tempBox.bg = convertColor(bgName,data.bg);
else
tempBox.bg = data.bg;
if (fgName != NULL)
tempBox.fg = convertColor(fgName,data.fg);
else
tempBox.fg = data.fg;
#ifdef USE_LED
if (led < 1 || led > 3)
tempBox.led = -1;
else
tempBox.led = led;
#endif
tempBox.box_mtime = tempBox.st_size = 0;
DynAdd(DynBoxObj, &tempBox);
boxInfo = (BoxInfo_t *) DynGet(DynBoxObj, 0);
nBoxes++;
}
void ParseMailPath()
{
char *mailPath = 0;
char *boxes = 0;
char *str = 0;
/* get mail path */
if ((mailPath = getenv("MAILPATH")) != 0)
{
boxes = mailPath;
}
else if ((mailPath = getenv("MAIL")) != 0)
{
boxes = mailPath;
}
else if (data.mailBoxes != 0)
{
boxes = data.mailBoxes;
}
else
{
return;
}
str = (char *) strtok(boxes, ":, ");
while (str != NULL)
{
#ifdef USE_LED
initBox(NEWstrdup(str), MAILBOX, envPolltime, envHeadertime, UNDEF, data.command,
data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL,-1);
#else
initBox(NEWstrdup(str), MAILBOX, envPolltime, envHeadertime, UNDEF, data.command,
data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL);
#endif
str = (char *) strtok(NULL, ":, ");
}
}
char *EliminatePath(path)
char *path;
{
char *file = 0;
file = (char *) strrchr(path, '/');
file = (file ? ++file : path);
return (file);
}
#ifdef USE_NNTP
void ParseNewsPath()
{
char *newsPath = 0;
char *boxes = 0;
char *str = 0;
/* get nntp path */
if ((newsPath = getenv("NEWSPATH")) != 0)
{
boxes = newsPath;
}
else if (data.newsBoxes != 0)
{
boxes = data.newsBoxes;
}
else
{
return;
}
str = strtok(boxes, ":, ");
while (str != NULL)
{
initBox(NEWstrdup(str), NNTPBOX, envPolltime, envHeadertime, UNDEF,
data.command, data.audioCmd, NULL, data.origMode, data.nobeep,
NULL,NULL);
str = strtok(NULL, ":, ");
}
}
#endif /* USE_NNTP */
/* the the icon if it is not already loaded */
void LoadIcon(w)
Widget w;
{
Display *display = XtDisplay(w);
int screen;
Pixmap icon_pixmap = (Pixmap) 0;
Arg arg;
screen = DefaultScreen(display);
/* User sets iconPixmap resource, converter does the right thing.. */
XtSetArg(arg, XtNiconPixmap, &icon_pixmap);
XtGetValues(w, &arg, 1);
if (icon_pixmap == (Pixmap) 0)
{
XtSetArg(arg, XtNiconPixmap,
XCreateBitmapFromData(display,
RootWindow(display, screen),
xbuffy_bits, xbuffy_width,
xbuffy_height));
XtSetValues(w, &arg, 1);
}
}
int makeBoxTitle(currentBox)
BoxInfo_t *currentBox;
{
char line[MAX_STRING];
line[0] = '\0';
if ((currentBox->type == MAILBOX) || (currentBox->type == MAILDIR) ||
(currentBox->type == MHDIR))
{
switch (currentBox->BoxNameType)
{
case SHORT:
strcpy(line, EliminatePath(currentBox->box));
break;
case LONG:
strcpy(line, currentBox->box);
break;
case NONE:
case USR:
case UNDEF:
break;
}
if (line[0] != '\0')
currentBox->boxTitle = NEWstrdup(line);
}
else
{
switch (currentBox->BoxNameType)
{
case SHORT:
case LONG:
strcpy(line, currentBox->box);
break;
case NONE:
case USR:
case UNDEF:
break;
}
if (line[0] != '\0')
currentBox->boxTitle = NEWstrdup(line);
}
if ( currentBox->boxTitle != NULL)
return(NEWstrlen(currentBox->boxTitle));
else
return(0);
}
void Usage()
{
printf("Usage: %s [toolkit options] [options] <file> ...\n\n", programName);
printf("Options are:\n");
printf(" -help print this message\n");
printf(" -version print the version number\n");
printf(" -poll <secs> how often to poll the file(s); default: 60\n");
printf(" -header <secs> popup header when mail is received\n");
printf(" (use '0' for mouse press only)\n");
printf(" -acmd <command> command for audio instead of <bell>\n");
printf(" -boxfile <file> filename containing names of mailboxes\n");
printf(" -horiz place the boxes horizontally; default: vertical\n");
printf(" -nobeep don't ring bell when mail is received\n");
printf(" -names display full path of mail files in the boxes\n");
printf(" -shortnames display names of mail files in the boxes\n");
printf(" -center center the names of the boxes\n");
printf(" -fill make all the boxes the same size\n");
printf(" -orig original mode - display all messages in the boxes\n");
printf(" -command <cmd> system command to execute when middle button is pushed\n");
printf(" -mail <files> specify a mailbox(s) to watch\n");
#ifdef USE_NNTP
printf(" -news <groups> specify a newsgroup(s) to watch\n");
#endif /* USE_NNTP */
printf("\n");
printf("If there are any files specified on the command line, it will\n");
printf("monitor those mail files, otherwise it will use your MAILPATH\n");
printf("environment variable.\n");
printf("\n");
}
int main(argc, argv)
int argc;
char *argv[];
{
#ifdef USE_MOTIF
static String fallback_resources[] = {
"*.popup.translations: <Btn1Up>:Activate()",
"*XmPushButton.translations: #override \
<Btn2Down>:Arm()\n\
<Btn2Up>:Disarm()",
(String) NULL
};
#endif
static Boolean mailArgs;
Widget form;
int i;
char *check;
char name[MAX_STRING];
Arg args[5];
int nargs;
int pid;
#ifdef DEBUG
char pause_string[10];
/* gets(pause_string);*/
#endif
/* initialize program name and version string */
programName = EliminatePath(argv[0]);
sprintf(versionString, "%s v%s", programName, VERSION);
mailArgs = TRUE;
nBoxes = 0;
DynBoxObj = DynCreate(sizeof(BoxInfo_t), 1);
#ifdef DEBUG
DynDebug(DynBoxObj, 1);
DynParanoid(DynBoxObj, 1);
#endif
boxInfo = (BoxInfo_t *) DynGet(DynBoxObj, 0);
nargs = 0;
XtSetArg(args[nargs], XtNallowShellResize, TRUE);
nargs++;
#ifdef USE_MOTIF
toplevel = XtAppInitialize(&app, X_RESOURCE_CLASS, options,
XtNumber(options), &argc, argv, fallback_resources, args, nargs);
#else
toplevel = XtAppInitialize(&app, X_RESOURCE_CLASS, options,
XtNumber(options), &argc, argv, 0, args, nargs);
#endif
XtGetApplicationResources(toplevel, &data, resources, XtNumber(resources),
0, 0);
/* initialize some values */
if (data.pollTime != NULL)
envPolltime = atoi(data.pollTime);
if ((data.pollTime == NULL) && ((check = getenv("MAILCHECK")) != 0))
{
if ((envPolltime = atoi(check)) < 0)
{
fprintf(stderr, "MAILCHECK has illegal value\n");
}
}
if ((envPolltime <= 0) || (envPolltime >= 3600))
envPolltime = 60;
if (data.priority != NULL)
envPriority = atoi(data.priority);
if ((envPriority < 0) || (envPriority >= 20))
envPriority = 15;
if (data.headerTime != NULL)
envHeadertime = atoi(data.headerTime);
if (envHeadertime <= 0)
envHeadertime = 0;
if (envHeadertime >= 60)
envHeadertime = 60;
argc--;
++argv;
while (argc)
{
if (strcmp("-help", *argv) == 0)
{
Usage();
exit(0);
}
else if (strcmp("-version", *argv) == 0)
{
printf("%s\n", versionString);
exit(0);
}
else if (strcmp("-news", *argv) == 0)
{
#ifndef USE_NNTP
fprintf(stderr, "program not compiled with -DUSE_NNTP ignoring %s\n", *argv);
#else
mailArgs = FALSE;
#endif /* !USE_NNTP */
}
else if (strcmp("-mail", *argv) == 0)
{
mailArgs = TRUE;
}
else
{
if (*argv[0] == '-')
{
fprintf(stderr, "Bad option: %s\n\n", *argv);
Usage();
exit(-1);
}
if (mailArgs)
{
#ifdef USE_LED
initBox(NEWstrdup(*argv), MAILBOX, envPolltime, envHeadertime,
UNDEF, data.command, data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL,-1);
#else
initBox(NEWstrdup(*argv), MAILBOX, envPolltime, envHeadertime,
UNDEF, data.command, data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL);
#endif
}
#ifdef USE_NNTP
else
{
#ifdef USE_LED
initBox(NEWstrdup(*argv), NNTPBOX, envPolltime, envHeadertime,
UNDEF, data.command, data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL,-1);
#else
initBox(NEWstrdup(*argv), NNTPBOX, envPolltime, envHeadertime,
UNDEF, data.command, data.audioCmd, NULL, data.origMode, data.nobeep,NULL,NULL);
#endif
}
#endif /* USE_NNTP */
}
argc--;
++argv;
}
if ((data.boxFile != 0) && (nBoxes == 0))
{
readBoxfile(data.boxFile);
}
if (nBoxes == 0)
{
ParseMailPath();
#ifdef USE_NNTP
ParseNewsPath();
#endif /* USE_NNTP */
}
/* if there are still no boxes, what's the point? */
if (nBoxes == 0)
{
fprintf(stderr, "nothing to watch is specified\n");
fprintf(stderr, "check $MAILPATH / XBuffy.mailboxes\n");
#ifdef USE_NNTP
fprintf(stderr, "check $NEWSPATH / XBuffy.newsboxes\n");
#endif /* USE_NNTP */
Usage();
exit(-1);
}
LoadIcon(toplevel);
nargs = 0;
#ifndef USE_MOTIF
if (data.horiz)
{
XtSetArg(args[nargs], XtNorientation, XtorientHorizontal);
nargs++;
}
form = XtCreateManagedWidget("box", boxWidgetClass, toplevel, args, nargs);
/* form = XtCreateManagedWidget("box", panedWidgetClass, toplevel, args, nargs);*/
#else
if (data.horiz)
{
XtSetArg(args[nargs], XmNorientation, XmHORIZONTAL);
nargs++;
XtSetArg(args[nargs], XmNpacking, XmPACK_COLUMN);
nargs++;
}
else
{
XtSetArg(args[nargs], XmNorientation, XmVERTICAL);
nargs++;
XtSetArg(args[nargs], XmNpacking, XmPACK_TIGHT);
nargs++;
}
XtSetArg(args[nargs], XmNisAligned, True);
nargs++;
XtSetArg(args[nargs], XmNentryVerticalAlignment, XmALIGNMENT_CENTER);
nargs++;
form = XmCreateRowColumn(toplevel, "box", args, nargs);
XtManageChild(form);
#endif
if ((header = (Widget *) malloc(nBoxes * sizeof(Widget))) == 0)
{
fprintf(stderr, "Can't malloc header widgets\n");
exit(-1);
}
if ((headerUp = (int *) malloc(nBoxes * sizeof(int))) == 0)
{
fprintf(stderr, "Can't malloc header flags\n");
exit(-1);
}
for (i = 0; i < nBoxes; i++)
{
Boolean dummy;
headerUp[i] = FALSE;
if ((boxInfo[i].type == MAILBOX) || (boxInfo[i].type == MAILDIR) ||
(boxInfo[i].type == MHDIR))
boxInfo[i].n = CountUnixMail(&boxInfo[i], NULL, &dummy);
#ifdef USE_NNTP
if (boxInfo[i].type == NNTPBOX)
boxInfo[i].n = CountNNTP(&boxInfo[i], NULL, &dummy);
#endif
sprintf(name, "box%d", i);
#ifndef USE_MOTIF
nargs = 0;
XtSetArg(args[nargs], XtNleft, XtChainLeft);
nargs++;
XtSetArg(args[nargs], XtNright, XtChainLeft);
nargs++;
XtSetArg(args[nargs], XtNresizable, True);
nargs++;
/*7!*/ XtSetArg(args[nargs], XtNshowGrip, False);
nargs++;
XtSetArg(args[nargs], XtNallowResize, True);
nargs++;
boxInfo[i].w = XtCreateManagedWidget(name, commandWidgetClass, form, args, nargs);
XtAddEventHandler(boxInfo[i].w, ButtonPressMask, True,
ButtonDownHandler, &boxInfo[i].boxNum);
XtAddEventHandler(boxInfo[i].w, ButtonReleaseMask, True,
ButtonUpHandler, &boxInfo[i].boxNum);
#else
nargs = 0;
XtSetArg(args[nargs], XmNresizable, TRUE);
nargs++;
boxInfo[i].w = XmCreatePushButton(form, name, args, nargs);
XtManageChild(boxInfo[i].w);
XtAddEventHandler(boxInfo[i].w, ButtonPressMask, True,
ButtonDownHandler, &boxInfo[i].boxNum);
XtAddEventHandler(boxInfo[i].w, ButtonReleaseMask, True,
ButtonUpHandler, &boxInfo[i].boxNum);
#endif
UpdateBoxNumber(&boxInfo[i]);
CheckBox(i);
}
#ifdef DEBUG
fprintf(stderr, "bg = %i, fg = %i maxSize = %i\n", data.bg, data.fg,maxBoxSize);
for (i = 0; i < nBoxes; i++)
{
fprintf(stderr, "box = %s\n", boxInfo[i].box);
fprintf(stderr, "pollTime = %i\n", boxInfo[i].pollTime);
fprintf(stderr, "headerTime = %i\n", boxInfo[i].headerTime);
fprintf(stderr, "origMode = %i\n", boxInfo[i].origMode);
fprintf(stderr, "nobeep = %i\n", boxInfo[i].nobeep);
#ifdef USE_LED
fprintf(stderr, "led = %i\n", boxInfo[i].led);
#endif
fprintf(stderr, "command = %s\n", boxInfo[i].command);
fprintf(stderr, "nameType = %i\n", boxInfo[i].BoxNameType);
}
#endif
XtRealizeWidget(toplevel);
#ifndef DEBUG
#ifdef HAVE_SETPRIORITY
if (setpriority(PRIO_PROCESS, 0, envPriority) == -1)
perror("Proirity change Failed");
#endif
/* put ourself in the background */
switch (pid = fork())
{
case 0:
XtAppMainLoop(app); /* in child do the stuff */
break;
case -1:
perror("Fork failure");
XtAppMainLoop(app); /* fork failed - carry on in the parent instead */
break;
default:
exit(0); /* ok its going we can stop now */
break;
}
#else
XtAppMainLoop(app);
#endif
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1