/*
* WMMail - Window Maker Mail
*
* Copyright (c) 1996, 1997, 1998 Per Liden
* Copyright (c) 1997, 1998 Bryan Chan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* wmmail.c: essential routines
*
* $Id: wmmail.c,v 1.1 2000/07/02 20:38:01 bryan.chan Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/extensions/shape.h>
#include "wmmail.h"
#include "wmutil.h"
#include "properties.h"
#include "std_icons.h"
int end_of_cycle = False;
#ifdef MBOX_SUPPORT
# include "mbox.h"
#endif
#ifdef MH_SUPPORT
# include "mh.h"
#endif
#ifdef MAILDIR_SUPPORT
# include "maildir.h"
#endif
#ifdef POP3_SUPPORT
# include "pop3.h"
#endif
#ifdef IMAP_SUPPORT
# include "imap.h"
#endif
/* function prototypes */
int main(int, char **);
void help(void);
void read_configuration_data(void);
void initialize(int, char **);
void create_appicon(void);
void redraw_appicon(void);
void animate(XtPointer, XtIntervalId *);
Pixel get_pixel_by_color(char *);
void update_status(XtPointer, XtIntervalId *);
void handle_expose(Widget, XtPointer, XEvent *);
void handle_button(Widget, XtPointer, XEvent *);
int main(int argc, char **argv)
{
initialize(argc, argv);
create_appicon();
update_status(NULL, NULL);
animate(NULL, NULL);
XtAppMainLoop(wmmail_context);
return 0;
}
void help(void)
{
fprintf(stderr,
"WMMail version %s%s by Bryan Chan (bryan.chan@utoronto.ca)\n"
"based on asmail version 0.50, by Per Liden (per@rsn.hk-r.se)\n"
"\n"
"usage: \t%s [options ...] [<pathname>]\n"
"\n"
"<pathname>:\tfull path of defaults domain to use\n"
"\n"
"options:\t-help, -h display this message\n"
" \t-quiet, -q suppress all error messages\n"
" \t-swallowed, -s show window as well as appicon;\n"
" \t good for swallowing with AfterStep\n"
"\n",
VERSION,
#ifdef DEBUG
"(with debug support),",
#else
",",
#endif
app_name);
exit(1);
}
void read_configuration_data(void)
{
char *domain;
if (user_specified_domain)
{
if (!parse_gnustep_domain(user_specified_domain))
exit(-1);
}
else if (domain = find_resource(WMMAIL_CLASS, "Defaults"))
{
if (!parse_gnustep_domain(domain))
exit(-1);
}
else
croak("cannot find any configuration data, using default values...");
}
/* SIGCHLD handler */
void sig_chld(int signo)
{
waitpid((pid_t) -1, NULL, WNOHANG);
signal(SIGCHLD, sig_chld);
}
/* handle command line options, open the configuration file for reading */
void initialize(int argc, char **argv)
{
/* determine how this program was invoked */
if ((char *) rindex(argv[0], '/') != NULL)
app_name = (char *) rindex(argv[0], '/') + 1;
else
app_name = argv[0];
wmmail_widget = XtAppInitialize(&wmmail_context, WMMAIL_CLASS,
(XrmOptionDescRec *) NULL, 0, &argc, argv,
(String *) NULL, (ArgList) NULL, 0);
disp = XtDisplay(wmmail_widget);
root = RootWindow(disp, DefaultScreen(disp));
wmmail_font = XLoadFont(disp, DEFAULT_FONT);
if (argc > 1)
{
int i;
for (i = 1; i < argc; i++)
if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-h"))
{
help();
exit(0);
}
else if (!strcmp(argv[i], "-quiet") || !strcmp(argv[i], "-q"))
{
keep_quiet = True;
}
else if (!strcmp(argv[i], "-swallowed") || !strcmp(argv[i], "-s"))
{
use_appicon_only = False;
}
else if (argv[i][0] == '-')
{
croak("no such option '%s'", argv[i]);
exit(-1);
}
else if (user_specified_domain != NULL)
{
croak("cannot use more than one defaults domain");
exit(-1);
}
else
user_specified_domain = wstrdup(argv[i]);
}
read_configuration_data();
/* if we're cycling text, set up for animation of mailbox names */
if (display_names) {
int i;
for (i = 0; i < 3; i++) {
animations[i]->text_cycle = 0;
}
}
/* if no mailbox is specified, assume $MAIL is a UNIX mbox */
#ifdef MBOX_SUPPORT
if (mailbox_list == NULL && getenv("MAIL") != NULL)
{
proplist_t key, path;
Mailbox *mailbox;
char *mailbox_path;
struct stat t;
mailbox_path = getenv("MAIL");
if (mailbox_path && !stat(mailbox_path, &t))
{
if (S_ISREG(t.st_mode))
{
mailbox = (Mailbox *) wmalloc(sizeof(Mailbox));
mailbox->name = wstrdup("Inbox");
mailbox->type = TYPE_MBOX;
mailbox->status = NO_MAIL;
mailbox->total_mail_count = 0;
mailbox->new_mail_count = 0;
mailbox->update_interval = DEFAULT_INTERVAL;
mailbox->last_update = 0;
mailbox->size = t.st_size;
key = PLMakeString("Path");
path = PLMakeString(mailbox_path);
mailbox->options = PLMakeDictionaryFromEntries(key, path, NULL);
PLRelease(key);
PLRelease(path);
mailbox_list = list_cons(mailbox, mailbox_list);
}
else
{
croak("default mailbox %s not a UNIX mbox; aborting", mailbox_path);
exit(-1);
}
}
else
{
croak("cannot stat default mailbox %s", mailbox_path ? mailbox_path : "");
exit(-1);
}
}
else
#endif
if (mailbox_list == NULL)
{
croak("no usable mailbox (already tried $MAIL)");
exit(-1);
}
/* zombie children are dealt with in the SIG_CHLD handler */
signal(SIGCHLD, sig_chld);
}
void create_appicon(void)
{
Arg args[4];
XGCValues gc_values;
load_std_icons();
wmmail_appicon = XtCreateWidget("AppIcon", topLevelShellWidgetClass,
wmmail_widget, NULL, 0);
XtAddEventHandler(wmmail_appicon, ExposureMask, False,
(XtEventHandler) handle_expose, NULL);
XtAddEventHandler(wmmail_appicon, ButtonPressMask, False,
(XtEventHandler) handle_button, NULL);
XtResizeWidget(wmmail_appicon, animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height, 1);
XtRealizeWidget(wmmail_appicon);
XtSetArg(args[0], XtNiconName, app_name);
XtSetArg(args[1], XtNiconWindow, XtWindow(wmmail_appicon));
if (!use_appicon_only)
XtSetArg(args[2], XtNinitialState, NormalState);
else
XtSetArg(args[2], XtNinitialState, WithdrawnState);
XtSetValues(wmmail_widget, args, 3);
if (!use_appicon_only)
{
XtAddEventHandler(wmmail_widget, ExposureMask, False,
(XtEventHandler) handle_expose, NULL);
XtAddEventHandler(wmmail_widget, ButtonPressMask, False,
(XtEventHandler) handle_button, NULL);
}
XtResizeWidget(wmmail_widget, animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height, 1);
XtRealizeWidget(wmmail_widget);
XtMapWidget(wmmail_widget);
shape_mask = XCreatePixmap(disp, XtWindow(wmmail_widget),
animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height, 1);
shape_mask_gc = XCreateGC(disp, shape_mask, 0, &gc_values);
XSetGraphicsExposures(disp, shape_mask_gc, False);
XSetBackground(disp, shape_mask_gc, 0);
XSetForeground(disp, shape_mask_gc, 1);
wmmail_gc = XCreateGC(disp, root, 0, &gc_values);
XSetGraphicsExposures(disp, wmmail_gc, False);
XSetBackground(disp, wmmail_gc, get_pixel_by_color("black"));
XSetForeground(disp, wmmail_gc, get_pixel_by_color(wmmail_color));
redraw_appicon();
}
void redraw_appicon(void)
{
char buf[30];
XTextItem num_of_msg;
/* create shape mask from the mask of the XPM animation frame */
XFillRectangle(disp, shape_mask, shape_mask_gc, 0, 0,
animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height);
XCopyArea(disp, animations[wmmail_status]->mask, shape_mask,
shape_mask_gc, 0, 0,
animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height,
0, 0);
/* generate NumOfMsg if NumOfMsgMode is used */
if (num_of_msg_mode != SHOW_NONE || display_names)
{
Mailbox *mailbox;
int i, j, sum_new_mail, sum_total_mail;
static char *box_name = NULL;
static int box_new = 0;
static int box_total = 0;
j = animations[wmmail_status]->text_cycle;
if (j != -1) {
box_name = NULL;
}
for (i = 0, sum_new_mail = 0, sum_total_mail = 0; i < mailbox_count; i++)
{
mailbox = list_nth(i, mailbox_list);
sum_new_mail += mailbox->new_mail_count;
sum_total_mail += mailbox->total_mail_count;
if (j > -1 && mailbox->status == NEW_MAIL) {
j--;
if (j <= 0) {
box_name = mailbox->name;
box_new = mailbox->new_mail_count;
box_total = mailbox->total_mail_count;
#ifdef DEBUG
croak("box_name: %s box_new: %d box_total: %d",
box_name, box_new, box_total);
#endif
}
}
}
if (j >= 0) {
end_of_cycle = True;
box_name = NULL;
box_new = box_total = 0;
}
if (display_names && box_name) {
switch(num_of_msg_mode) {
case SHOW_NEW_OVER_TOTAL:
sprintf(buf, "%s %d/%d", box_name, box_new, box_total);
break;
case SHOW_NEW_ONLY:
sprintf(buf, "%s %d", box_name, box_new);
break;
case SHOW_TOTAL_ONLY:
sprintf(buf, "%s %d", box_name, box_total);
break;
case SHOW_NONE:
sprintf(buf, "%s", box_name);
break;
}
} else {
switch(num_of_msg_mode) {
case SHOW_NEW_OVER_TOTAL:
sprintf(buf, "%d/%d", sum_new_mail, sum_total_mail);
break;
case SHOW_NEW_ONLY:
sprintf(buf, "%d", sum_new_mail);
break;
case SHOW_TOTAL_ONLY:
sprintf(buf, "%d", sum_total_mail);
break;
}
}
num_of_msg.chars = buf;
num_of_msg.nchars = strlen(buf);
num_of_msg.delta = 1;
num_of_msg.font = wmmail_font;
/* add the text to the shape mask */
XDrawText(disp, shape_mask, shape_mask_gc,
num_of_msg_x, num_of_msg_y, &num_of_msg, 1);
XDrawText(disp, shape_mask, shape_mask_gc,
num_of_msg_x, num_of_msg_y, &num_of_msg, 1);
}
/* apply the shape mask */
XShapeCombineMask(disp, XtWindow(wmmail_appicon), ShapeBounding, 0, 0,
shape_mask, ShapeSet);
if (!use_appicon_only)
XShapeCombineMask(XtDisplay(wmmail_widget), XtWindow(wmmail_widget), ShapeBounding, 0, 0,
shape_mask, ShapeSet);
/* draw XPM animation frame */
XCopyArea(disp, animations[wmmail_status]->pixmap, XtWindow(wmmail_appicon),
wmmail_gc, 0, 0, animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height, 0, 0);
if (!use_appicon_only)
XCopyArea(XtDisplay(wmmail_widget), animations[wmmail_status]->pixmap, XtWindow(wmmail_widget),
wmmail_gc, 0, 0, animations[wmmail_status]->attributes.width,
animations[wmmail_status]->attributes.height, 0, 0);
/* draw NumOfMsg */
if (num_of_msg_mode != SHOW_NONE)
{
XDrawText(disp, XtWindow(wmmail_appicon), wmmail_gc,
num_of_msg_x, num_of_msg_y, &num_of_msg, 1);
if (!use_appicon_only)
XDrawText(disp, XtWindow(wmmail_widget), wmmail_gc,
num_of_msg_x, num_of_msg_y, &num_of_msg, 1);
}
XFlush(disp);
}
void animate(XtPointer XtP, XtIntervalId *XtI)
{
animations[wmmail_status] = animations[wmmail_status]->next;
if (animations[wmmail_status]->text_cycle != -1) {
if (end_of_cycle) {
animations[wmmail_status]->text_cycle = 0;
end_of_cycle = False;
} else {
animations[wmmail_status]->text_cycle++;
}
}
redraw_appicon();
XtAppAddTimeOut(wmmail_context, anim_speed[wmmail_status], animate, NULL);
}
Pixel get_pixel_by_color(char *color_name)
{
XColor color;
XWindowAttributes attributes;
XGetWindowAttributes(disp, root, &attributes);
color.pixel = 0;
if (!XParseColor(disp, attributes.colormap, color_name, &color))
croak("cannot parse color '%s', using black", color_name);
else if (!XAllocColor(disp, attributes.colormap, &color))
croak("cannot allocate color '%s', using black", color_name);
return color.pixel;
}
void update_status(XtPointer XtP, XtIntervalId * XtI)
{
Mailbox *mailbox;
static int update_in_progress = False;
int i, ret;
int new_status = NO_MAIL;
int beep = False,
redraw = False,
run = False,
next_update = -1; /* time to next update in seconds */
if (!update_in_progress)
{
update_in_progress = True;
mailbox_count = list_length(mailbox_list);
for (i = 0; i < mailbox_count; i++)
{
mailbox = list_nth(i, mailbox_list);
if (mailbox->last_update + mailbox->update_interval > time(NULL))
{
/* don't check this mailbox if it isn't time yet */
ret = True;
}
else
{
#ifdef DEBUG
croak("checking mailbox %s", mailbox->name);
#endif
if (mailbox->execute_on_update)
exec_command(mailbox->execute_on_update);
#ifdef MBOX_SUPPORT
if (IS_MBOX(mailbox))
ret = MBOX_check(mailbox, &beep, &redraw, &run);
else
#endif
#ifdef MH_SUPPORT
if (IS_MH(mailbox))
ret = MH_check(mailbox, &beep, &redraw, &run);
else
#endif
#ifdef MAILDIR_SUPPORT
if (IS_MAILDIR(mailbox))
ret = MAILDIR_check(mailbox, &beep, &redraw, &run);
else
#endif
#ifdef POP3_SUPPORT
if (IS_POP3(mailbox))
ret = POP3_check(mailbox, &beep, &redraw, &run);
else
#endif
#ifdef IMAP_SUPPORT
if (IS_IMAP(mailbox))
ret = IMAP_check(mailbox, &beep, &redraw, &run);
else
#endif
/* ignore anything that we cannot handle; bug in properties.c? */
continue;
}
/* delete mailbox if it has become rotten */
if (!ret)
{
mailbox_list = list_remove_elem(mailbox_list, mailbox);
wfree(mailbox->execute_on_update);
wfree(mailbox->name);
wfree(mailbox);
mailbox_count--;
i--;
#ifdef DEBUG
croak("deleting mailbox %d", i + 1);
croak("mailbox count: %d", mailbox_count);
#endif
}
else
{
int tmp = mailbox->last_update + mailbox->update_interval;
if (mailbox->status > new_status)
new_status = mailbox->status;
if ( (next_update == -1) ||
(time(NULL) < tmp && time(NULL) + next_update > tmp) )
next_update = tmp - time(NULL);
}
}
if (mailbox_count == 0)
{
croak("no functional mailbox left to monitor");
exit(-1);
}
wmmail_status = new_status;
update_in_progress = False;
}
if (run && exec_on_new != NULL)
exec_command(exec_on_new);
if (beep && use_beep)
XBell(disp, 0);
if (redraw)
redraw_appicon();
#ifdef DEBUG
croak("next update: %d", next_update);
#endif
if (next_update < 0)
next_update = DEFAULT_INTERVAL;
XtAppAddTimeOut(wmmail_context, next_update * 1000, update_status, NULL);
}
void handle_expose(Widget w, XtPointer p, XEvent *e)
{
if (e->xexpose.count == 0)
redraw_appicon();
}
void handle_button(Widget w, XtPointer p, XEvent *e)
{
static Time last_left_mouse_click = -1;
static Time last_middle_mouse_click = -1;
if (e->xbutton.button == LEFT_BUTTON && exec_on_click != NULL)
{
if (last_left_mouse_click > 0 &&
e->xbutton.time - last_left_mouse_click <= double_click_time)
{
last_left_mouse_click = -1;
exec_command(exec_on_click);
}
last_left_mouse_click = e->xbutton.time;
}
else if (e->xbutton.button == MIDDLE_BUTTON)
{
if (last_middle_mouse_click > 0 &&
e->xbutton.time - last_middle_mouse_click <= double_click_time)
{
/* double-clicking with the middle button overrides mailbox status */
Mailbox *mailbox;
int i;
int new_status = NO_MAIL;
for (i = 0; i < list_length(mailbox_list); i++)
{
mailbox = list_nth(i, mailbox_list);
if (mailbox->status == NEW_MAIL)
mailbox->status = OLD_MAIL;
if (mailbox->status > new_status)
new_status = mailbox->status;
}
if (wmmail_status != new_status)
{
wmmail_status = new_status;
redraw_appicon();
}
else
wmmail_status = new_status;
}
last_middle_mouse_click = e->xbutton.time;
}
}
syntax highlighted by Code2HTML, v. 0.9.1