/*
** wmymail.c
** email indicator tool designed as dockapp for windowmaker
** (c) 2000 josh
**
*/
/*
** wmymail version 0.1
*/
///////////////////////////////////////////////////////////////////////////////
// includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <utime.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <dockapp.h>
#include "xpm/main.xpm"
#include "xpm/numbers.xpm"
#include "xpm/unumbers.xpm"
#include "xpm/mbox_1.xpm"
#include "xpm/mbox_2.xpm"
#include "xpm/mbox_3.xpm"
///////////////////////////////////////////////////////////////////////////////
// defines
#define CHECKINTERVAL 1 // default mail check interval in seconds
#define NAME "wmymail"
#define VERSION "wmymail v0.1 June 6, 2001"
///////////////////////////////////////////////////////////////////////////////
// global data
char *displayName = "";
char *mailPath;
char *fontColor = "";
char *background = "";
char *clickcommand = "";
char *newcommand = "";
int numMessages = 0;
int lastnumMessages = 0;
int numRead = 0;
int numUnread = 0;
int lastnumUnread = 0;
int buttonpressed = 0;
/*
usefetchmail means to run "fetchmail -c" and parse the output, rather than
counting up messages in an mbox file.
It will change the interval from seconds to minutes!
*/
int usefetchmail = 0;
int flip = 1;
int checkInterval = CHECKINTERVAL;
time_t lastModifySeconds = 0;
off_t lastSize = 0;
Pixmap mainPixmap;
Pixmap numbersPixmap;
Pixmap unumbersPixmap;
Pixmap mboxonePixmap;
Pixmap mboxtwoPixmap;
Pixmap mboxthreePixmap;
Pixmap outPixmap1;
Pixmap outPixmap2;
GC defaultGC;
static DAProgramOption options[] = {
{"-display", NULL, "display to use",
DOString, False, {&displayName}},
{"-i", "--interval", "seconds between mailbox checks (default 1)",
DONatural, False, {&checkInterval} },
{"-fc", "--fontcolor", "custom font color",
DOString, False, {&fontColor} },
{"-bg", "--background", "custom background color for non-shaped window",
DOString, False, {&background} },
{"-ns", "--noshape", "make the dock app non-shaped (windowed)",
DONone, False, {NULL} },
{"-F", "--fetchmail", "check with fetchmail -c instead of the mbox",
DONone, False, {NULL} },
{"-c", "--command", "command to run when clicked",
DOString, False, {&clickcommand} },
{"-n", "--newcommand", "command to run when new mail is received",
DOString, False, {&newcommand} }
};
///////////////////////////////////////////////////////////////////////////////
// prototypes
void checkForNewMail(int dummy);
void updatePixmap(void);
void parseMailFile( struct stat *fileStat );
char *getHexColorString( char *colorName );
void putnumber (int number, Pixmap pixmap, Pixmap numbers,
int destx, int desty);
void buttonpress(int button, int state, int x, int y);
void buttonrelease(int button, int state, int x, int y);
void checkfetchmail (void);
void checkmbox (void);
void launch (const char *command);
///////////////////////////////////////////////////////////////////////////////
// functions
int main(int argc, char **argv) {
Pixmap mainPixmap_mask;
unsigned width, height;
DACallbacks callbacks = { NULL, &buttonpress, &buttonrelease,
NULL, NULL, NULL, NULL };
DAParseArguments(argc, argv, options,
sizeof(options) / sizeof(DAProgramOption),
NAME, VERSION );
DAInitialize(displayName, "Mail checker", 64, 64, argc, argv);
// simple recoloring of the raw xpms befor creating Pixmaps of them
// this works as long as you don't "touch" the images...
if (options[2].used) { // custom font color ?
char *colorLine = strdup("+ c #");
strcat(colorLine, getHexColorString(fontColor));
colorLine = strdup("+ c #");
strcat(colorLine, getHexColorString(fontColor));
numbers_xpm[3] = colorLine;
}
if (options[3].used && options[8].used) { // custom window background ?
char *colorLine = strdup(" c #");
strcat(colorLine, getHexColorString(background));
main_xpm[1] = colorLine;
}
DAMakePixmapFromData(main_xpm, &mainPixmap, &mainPixmap_mask, &width, &height);
DAMakePixmapFromData(numbers_xpm, &numbersPixmap, NULL, &width, &height);
DAMakePixmapFromData(unumbers_xpm, &unumbersPixmap, NULL, &width, &height);
DAMakePixmapFromData(mbox_1_xpm, &mboxonePixmap, NULL, &width, &height);
DAMakePixmapFromData(mbox_2_xpm, &mboxtwoPixmap, NULL, &width, &height);
DAMakePixmapFromData(mbox_3_xpm, &mboxthreePixmap, NULL, &width, &height);
if (!options[4].used) // no shape to install
DASetShape(mainPixmap_mask);
if (options[5].used) // use fetchmail
usefetchmail = 1;
else if ((mailPath = getenv("MAIL")) == NULL) {
perror("Please define your $MAIL environment-variable!\n");
exit(1);
}
DASetCallbacks( &callbacks );
DASetTimeout(-1);
outPixmap1 = DAMakePixmap();
outPixmap2 = DAMakePixmap();
defaultGC = XDefaultGC(DADisplay, 0);
signal(SIGALRM, checkForNewMail);
updatePixmap();
DAShow();
checkForNewMail(0);
DAEventLoop();
return 0;
}
char *getHexColorString(char *colorName) {
XColor color;
char *hexColorString;
if (!XParseColor(DADisplay,
DefaultColormap(DADisplay, DefaultScreen( DADisplay)),
colorName, &color))
{
printf("unknown colorname: \"%s\"\n", colorName);
exit(1);
}
hexColorString = (char *)malloc(7);
sprintf(hexColorString, "%02X%02X%02X", color.red>>8, color.green>>8,
color.blue>>8);
return hexColorString;
}
/*
*
* checkForNewMail
*
*/
void checkForNewMail(int dummy) {
struct itimerval timerVal;
if (usefetchmail) {
checkfetchmail();
} else {
checkmbox();
}
if (numMessages != lastnumMessages ||
numUnread != lastnumUnread) {
updatePixmap();
if (numUnread > lastnumUnread && strlen(newcommand) > 0)
launch(newcommand);
lastnumMessages = numMessages;
lastnumUnread = numUnread;
}
memset(&timerVal, 0, sizeof(timerVal));
if (usefetchmail) {
timerVal.it_value.tv_sec = checkInterval * 60;
} else {
timerVal.it_value.tv_sec = checkInterval;
}
setitimer(ITIMER_REAL, &timerVal, NULL);
}
/*
*
* checkfetchmail
*
*/
void checkfetchmail (void) {
int msgtotal = 0;
int msgseen = 0;
int snpret;
char tmpfile[20] = "wmymail.XXXXXX";
char syscmd[120];
char line[1024];
char *s, *t;
int fd;
FILE *f;
fd = mkstemp(tmpfile);
if (fd == -1) {
perror("wmymail: cannot get a temporay file");
return;
}
snpret = snprintf(syscmd, 120, "fetchmail -c > %s", tmpfile);
if (snpret < 0) {
perror("wmymail: error in snprintf() call (should not happen)");
return;
}
if (system(syscmd) < 0) {
perror("wmymail: error when using system() to run fetchmail -c");
return;
}
f = fdopen(fd, "r");
if (f == NULL) {
perror("wmymail: can't reread tempfile\n");
return;
}
while (fgets(line, 1024, f) != NULL) {
if (line[0] >= '0' && line[0] <= '9') {
msgtotal += atoi(line);
s = (char *)strstr(line, " ");
if (s != NULL) {
s++;
t = (char *)strstr(s, " ");
if (t != NULL && t[1] == '(' && t[2] >= '0' && t[2] <= '9') {
t += 2;
msgseen += atoi(t);
}
}
}
}
fclose(f);
remove(tmpfile);
/* Now that that's been gotten through without major errors,
move the values to the global variables */
numMessages = msgtotal;
numUnread = msgtotal - msgseen;
}
/*
*
* checkmbox
*
*/
void checkmbox (void) {
struct stat fileStat;
if (stat(mailPath, &fileStat) == -1 || fileStat.st_size == 0) {
numMessages = 0;
numUnread = 0;
} else if (lastModifySeconds != fileStat.st_mtime ||
lastSize != fileStat.st_size) {
parseMailFile(&fileStat);
lastModifySeconds = fileStat.st_mtime;
lastSize = fileStat.st_size;
}
}
/*
*
* updatePixmap
*
*/
void updatePixmap(void) {
Pixmap outPixmap = flip ? outPixmap1 : outPixmap2;
flip = !flip;
XCopyArea(DADisplay, mainPixmap, outPixmap, defaultGC,
0, 0, 64, 64, 0, 0);
if (numMessages > 998) {
putnumber(999, outPixmap, numbersPixmap, 40, 49);
} else {
putnumber(numMessages, outPixmap, numbersPixmap, 40, 49);
}
if (numUnread > 998) {
putnumber(999, outPixmap, unumbersPixmap, 6, 49);
} else if (!numUnread) {
putnumber(0, outPixmap, numbersPixmap, 6, 49);
} else {
putnumber(numUnread, outPixmap, unumbersPixmap, 6, 49);
}
if (numUnread == 0) {
// do nothing.
} else if (numUnread == 1) {
XCopyArea(DADisplay, mboxonePixmap, outPixmap, defaultGC,
0, 0, 40, 34, 14, 6);
} else if (numUnread == 2) {
XCopyArea(DADisplay, mboxtwoPixmap, outPixmap, defaultGC,
0, 0, 40, 34, 14, 6);
} else {
XCopyArea(DADisplay, mboxthreePixmap, outPixmap, defaultGC,
0, 0, 40, 34, 14, 6);
}
DASetPixmap(outPixmap);
}
/*
*
* putnumber
*
*/
void putnumber (int number, Pixmap pixmap, Pixmap numbers,
int destx, int desty) {
int digit1, digit2, digit3;
digit1 = number / 100;
digit2 = (number % 100) / 10;
digit3 = number % 10;
if (digit1) XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit1 * 5, 0, 5, 9, destx, desty);
if (digit2 || digit1) XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit2 * 5, 0, 5, 9, destx + 6, desty);
XCopyArea(DADisplay, numbers, pixmap, defaultGC,
digit3 * 5, 0, 5, 9, destx + 12, desty);
}
/*
*
* parseMailFile
*
*/
void parseMailFile(struct stat *fileStat) {
char buf[1024];
int inHeader = 0;
int statusRead = 0;
int longline = 0;
FILE *f = fopen(mailPath, "r");
numMessages = 0;
numRead = 0;
while (fgets(buf, 1024, f) != NULL) {
if (longline) {
longline = index(buf, '\n') != NULL;
} else {
if(!strncmp(buf, "From ", 5)) {
inHeader = 1;
numMessages++;
} else if (inHeader) {
if (!strcmp(buf, "\n")) {
inHeader = 0;
if (statusRead) {
numRead++;
statusRead = 0;
}
} else if (!strncmp(buf, "Status: ", 8) && strchr(buf, 'R')) {
statusRead = 1;
}
}
longline = index(buf, '\n') == NULL;
}
}
fclose(f);
numUnread = numMessages - numRead;
}
void buttonpress (int button, int state, int x, int y) {
buttonpressed = 1;
}
void buttonrelease (int button, int state, int x, int y) {
if (buttonpressed && x > 0 && x < 64 && y > 0 && y < 64 &&
strlen(clickcommand) > 0) {
launch(clickcommand);
}
buttonpressed = 0;
}
void launch (const char *command) {
int cpid;
cpid = fork();
if (cpid == -1) {
perror("can't fork");
} else if (cpid == 0) {
system(command);
exit(0);
}
}
syntax highlighted by Code2HTML, v. 0.9.1