1
/* $Id: mailcheck.c 4263 2004-12-29 03:50:20Z kelnos $
3
* Copyright (C) 2002-2004 Jasper Huijsmans (jasper@xfce.org)
5
* - 2004 Add Maildir support Julien NOEL (dev@no-l.org)
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU Library General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
#ifdef HAVE_SYS_STAT_H
29
#ifdef HAVE_SYS_WAIT_H
33
#ifdef HAVE_NETINET_IN_H
34
#include <netinet/in.h>
42
#include <sys/socket.h>
44
#include <libxfce4util/libxfce4util.h>
45
#include <libxfcegui4/xfce_iconbutton.h>
47
#include <panel/xfce.h>
48
#include <panel/settings.h>
49
#include <panel/plugins.h>
50
#include <panel/item_dialog.h>
54
#define MAILCHECK_ROOT "Mailcheck"
58
static GtkTooltips *tooltips = NULL;
64
char *newmail_command;
70
char pop3_username[256];
71
char pop3_password[256];
72
char pop3_hostname[256];
79
GdkPixbuf *newmail_pb;
80
GdkPixbuf *oldmail_pb;
96
static char *mailcheck_icon_names[] = {
104
get_mail_pixbuf (void)
108
pb = themed_pixbuf_from_name_list (mailcheck_icon_names,
109
icon_size[settings.size]);
111
if (G_UNLIKELY (!pb))
113
g_critical ("Mail icon could not be found");
114
pb = get_pixbuf_by_id (UNKNOWN_ICON);
121
_dimm_icon (GdkPixbuf * pixbuf)
123
int x, y, pixel_stride, row_stride;
124
guchar *row, *pixels;
130
if (!gdk_pixbuf_get_has_alpha (pixbuf))
132
gdk_pixbuf_saturate_and_pixelate (pixbuf, pixbuf, 0, TRUE);
136
w = gdk_pixbuf_get_width (pixbuf);
137
h = gdk_pixbuf_get_height (pixbuf);
141
row = gdk_pixbuf_get_pixels (pixbuf);
142
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
144
for (y = 0; y < h; y++)
148
for (x = 0; x < w; x++)
152
pixels += pixel_stride;
158
gdk_pixbuf_saturate_and_pixelate (pixbuf, pixbuf, 0, TRUE);
162
reset_mailcheck_icons (t_mailcheck * mc)
165
g_object_unref (mc->newmail_pb);
168
g_object_unref (mc->nomail_pb);
171
g_object_unref (mc->oldmail_pb);
173
mc->newmail_pb = get_mail_pixbuf ();
175
g_return_if_fail (mc->newmail_pb != NULL);
177
mc->nomail_pb = gdk_pixbuf_copy (mc->newmail_pb);
178
_dimm_icon (mc->nomail_pb);
180
mc->oldmail_pb = mc->nomail_pb;
181
g_object_ref (mc->oldmail_pb);
188
mailcheck_set_tip (t_mailcheck * mc)
193
tooltips = gtk_tooltips_new ();
195
if (mc->command && strlen (mc->command))
197
tip = g_strdup (mc->command);
199
tip[0] = g_ascii_toupper (tip[0]);
201
gtk_tooltips_set_tip (tooltips, mc->button, tip, NULL);
208
set_mail_icon (t_mailcheck * mc)
210
if (mc->status == NO_MAIL)
212
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mc->button),
215
else if (mc->status == OLD_MAIL)
217
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mc->button),
222
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mc->button),
232
pop3_read_response (int fd, char *buff, int size)
237
while (bytes_read < size && state != 2)
239
bytes_read += read (fd, &buff[bytes_read], sizeof (char));
244
if (buff[bytes_read - 1] == '\r')
248
if (buff[bytes_read - 1] == '\n')
257
buff[bytes_read - 2 * sizeof (char)] = '\0';
259
if (strncmp (buff, "+OK", 3 * sizeof (char)) == 0)
266
pop3_send_command (int fd, char *buff)
268
return write (fd, buff, strlen (buff));
272
pop3_check_mail (char *username, char *password, char *hostname, int port)
274
struct sockaddr_in sa;
282
/* Lookup hostname */
283
hp = gethostbyname (hostname);
287
sa.sin_port = htons (port);
288
sa.sin_family = hp->h_addrtype;
290
/* Create the socket */
291
sd = socket (AF_INET, SOCK_STREAM, 0);
295
/* Try each address until we get one that works */
298
if (hp->h_addr_list[i] == NULL)
304
memcpy ((char *) &sa.sin_addr, hp->h_addr_list[i], hp->h_length);
306
if (connect (sd, (struct sockaddr *) &sa, sizeof (sa)) == 0)
310
if (!pop3_read_response (sd, buff, 1024))
316
g_snprintf (command, 256, "USER %s\r\n", username);
317
pop3_send_command (sd, command);
318
if (!pop3_read_response (sd, buff, 1024))
320
pop3_send_command (sd, "QUIT\r\n");
325
g_snprintf (command, 256, "PASS %s\r\n", password);
326
pop3_send_command (sd, command);
327
if (!pop3_read_response (sd, buff, 1024))
329
pop3_send_command (sd, "QUIT\r\n");
334
pop3_send_command (sd, "STAT\r\n");
335
if (!pop3_read_response (sd, buff, 1024))
337
pop3_send_command (sd, "QUIT\r\n");
342
sscanf (buff, "+OK %d", &msg_count);
344
pop3_send_command (sd, "QUIT\r\n");
355
exec_newmail_cmd (const char *cmd)
357
exec_cmd (cmd, FALSE, FALSE);
363
check_mail (t_mailcheck * mailcheck)
368
DBG ("Checking mail ... ");
370
if (mailcheck->pop3 == TRUE)
372
mail = pop3_check_mail (mailcheck->pop3_username,
373
mailcheck->pop3_password,
374
mailcheck->pop3_hostname,
375
mailcheck->pop3_port);
379
if (stat (mailcheck->mbox, &s) < 0)
383
else if (S_ISREG (s.st_mode))
389
else if (s.st_mtime <= s.st_atime)
395
else if (S_ISDIR (s.st_mode))
399
char *c_list[] = { "tmp", "cur", "new" };
403
/* mailbox is a maildir */
404
DBG ("maildir format");
408
/* Verify the Maildir integrity */
409
for (i_tmp = 0; i_tmp < 3; i_tmp++)
412
g_build_filename (mailcheck->mbox, c_list[i_tmp], NULL);
414
if (stat (c_tmp, &s) >= 0 && S_ISDIR (s.st_mode))
416
dr = opendir (c_tmp);
420
while ((de = readdir (dr)))
422
if (strlen (de->d_name) >= 1 &&
423
de->d_name[0] != '.')
447
if (mail != mailcheck->status)
449
if (mail == NEW_MAIL && mailcheck->status != NEW_MAIL &&
450
mailcheck->newmail_command &&
451
strlen (mailcheck->newmail_command) != 0)
453
g_idle_add ((GSourceFunc) exec_newmail_cmd,
454
mailcheck->newmail_command);
457
mailcheck->status = mail;
458
g_idle_add ((GSourceFunc) set_mail_icon, mailcheck);
463
/* keep the g_timeout running */
469
run_mailcheck (t_mailcheck * mc)
471
if (mc->timeout_id > 0)
474
if (mc->interval > 0)
476
mc->timeout_id = g_timeout_add (mc->interval * 1000,
477
(GSourceFunc) check_mail, mc);
481
/* set mailbox type */
483
set_mbox_type(t_mailcheck *mc)
485
if (strncmp (mc->mbox, "pop3://", 7 * sizeof (char)) == 0)
489
sscanf (mc->mbox, "pop3://%[^:]:%[^@]@%[^:]:%d",
491
mc->pop3_password, mc->pop3_hostname, &mc->pop3_port);
496
mailcheck_read_config (Control * control, xmlNodePtr node)
501
t_mailcheck *mc = (t_mailcheck *) control->data;
503
if (!node || !node->children)
506
node = node->children;
508
if (!xmlStrEqual (node->name, (const xmlChar *) MAILCHECK_ROOT))
511
value = xmlGetProp (node, (const xmlChar *) "interval");
523
for (node = node->children; node; node = node->next)
525
if (xmlStrEqual (node->name, (const xmlChar *) "Mbox"))
531
mc->mbox = (char *) value;
537
(node->name, (const xmlChar *) "newmail-command"))
543
g_free (mc->newmail_command);
544
mc->newmail_command = (char *) value;
547
else if (xmlStrEqual (node->name, (const xmlChar *) "Command"))
553
g_free (mc->command);
554
mc->command = (char *) value;
557
value = xmlGetProp (node, "term");
561
int n = atoi (value);
571
value = xmlGetProp (node, "sn");
575
int n = atoi (value);
589
mailcheck_set_tip (mc);
593
mailcheck_write_config (Control * control, xmlNodePtr parent)
595
xmlNodePtr root, node;
596
char value[MAXSTRLEN + 1];
598
t_mailcheck *mc = (t_mailcheck *) control->data;
600
root = xmlNewTextChild (parent, NULL, MAILCHECK_ROOT, NULL);
602
g_snprintf (value, 4, "%d", mc->interval);
603
xmlSetProp (root, "interval", value);
605
xmlNewTextChild (root, NULL, "Mbox", mc->mbox);
607
node = xmlNewTextChild (root, NULL, "Command", mc->command);
609
g_snprintf (value, 2, "%d", mc->term);
610
xmlSetProp (node, "term", value);
612
g_snprintf (value, 2, "%d", mc->use_sn);
613
xmlSetProp (node, "sn", value);
615
xmlNewTextChild (root, NULL, "newmail-command", mc->newmail_command);
619
mailcheck_attach_callback (Control * control, const char *signal,
620
GCallback callback, gpointer data)
622
t_mailcheck *mc = control->data;
624
g_signal_connect (mc->button, signal, callback, data);
628
run_mail_command (t_mailcheck * mc)
630
exec_cmd (mc->command, mc->term, mc->use_sn);
636
t_mailcheck *mailcheck;
639
mailcheck = g_new0 (t_mailcheck, 1);
641
mailcheck->status = NO_MAIL;
642
mailcheck->interval = 30;
643
mailcheck->timeout_id = 0;
645
reset_mailcheck_icons (mailcheck);
647
mailcheck->newmail_command = g_strdup ("");
649
mail = g_getenv ("MAIL");
653
mailcheck->mbox = g_strdup (mail);
657
const char *logname = g_getenv ("LOGNAME");
659
mailcheck->mbox = g_strconcat ("/var/spool/mail/", logname, NULL);
663
xfce_iconbutton_new_from_pixbuf (mailcheck->nomail_pb);
664
gtk_widget_show (mailcheck->button);
665
gtk_button_set_relief (GTK_BUTTON (mailcheck->button), GTK_RELIEF_NONE);
667
g_signal_connect_swapped (mailcheck->button,
668
"clicked", G_CALLBACK (run_mail_command),
671
mailcheck_set_tip (mailcheck);
677
mailcheck_free (Control * control)
679
t_mailcheck *mailcheck = (t_mailcheck *) control->data;
681
if (mailcheck->timeout_id > 0)
682
g_source_remove (mailcheck->timeout_id);
684
g_free (mailcheck->mbox);
685
g_free (mailcheck->command);
686
g_free (mailcheck->newmail_command);
688
g_object_unref (mailcheck->nomail_pb);
689
g_object_unref (mailcheck->oldmail_pb);
690
g_object_unref (mailcheck->newmail_pb);
696
mailcheck_set_theme (Control * control, const char *theme)
698
t_mailcheck *mailcheck = (t_mailcheck *) control->data;
700
reset_mailcheck_icons (mailcheck);
702
if (mailcheck->status == NO_MAIL)
704
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mailcheck->button),
705
mailcheck->nomail_pb);
707
else if (mailcheck->status == OLD_MAIL)
709
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mailcheck->button),
710
mailcheck->oldmail_pb);
714
xfce_iconbutton_set_pixbuf (XFCE_ICONBUTTON (mailcheck->button),
715
mailcheck->newmail_pb);
730
GtkWidget *mbox_entry;
731
GtkWidget *interval_spin;
732
GtkWidget *newmail_cmd_entry;
733
CommandOptions *cmd_opts;
738
free_maildialog (MailDialog * md)
745
mailcheck_apply_options (MailDialog * md)
748
t_mailcheck *mc = md->mc;
750
g_free (mc->command);
752
command_options_get_command (md->cmd_opts, &(mc->command), &(mc->term),
755
tmp = gtk_entry_get_text (GTK_ENTRY (md->mbox_entry));
760
mc->mbox = g_strdup (tmp);
764
tmp = gtk_entry_get_text (GTK_ENTRY (md->newmail_cmd_entry));
768
g_free (mc->newmail_command);
769
mc->newmail_command = g_strdup (tmp);
773
gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
774
(md->interval_spin));
776
mailcheck_set_tip (mc);
783
mbox_browse_cb (GtkWidget * b, MailDialog * md)
788
text = gtk_entry_get_text (GTK_ENTRY (md->mbox_entry));
790
file = select_file_name (NULL, text, md->dialog);
794
gtk_entry_set_text (GTK_ENTRY (md->mbox_entry), file);
796
mailcheck_apply_options (md);
800
/* newmail command */
802
newmail_cmd_brows_cb (GtkWidget * b, MailDialog * md)
807
text = gtk_entry_get_text (GTK_ENTRY (md->newmail_cmd_entry));
809
file = select_file_name (NULL, text, md->dialog);
813
gtk_entry_set_text (GTK_ENTRY (md->newmail_cmd_entry), file);
815
mailcheck_apply_options (md);
820
entry_lost_focus (MailDialog * md)
822
mailcheck_apply_options (md);
824
/* needed to let entry handle focus-out as well */
829
add_mbox_box (GtkWidget * vbox, GtkSizeGroup * sg, MailDialog * md)
831
GtkWidget *hbox, *label, *button, *image;
832
t_mailcheck *mc = md->mc;
834
hbox = gtk_hbox_new (FALSE, BORDER);
835
gtk_widget_show (hbox);
836
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
838
label = gtk_label_new (_("Mail box:"));
839
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
840
gtk_size_group_add_widget (sg, label);
841
gtk_widget_show (label);
842
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
844
md->mbox_entry = gtk_entry_new ();
846
gtk_entry_set_text (GTK_ENTRY (md->mbox_entry), mc->mbox);
847
gtk_widget_show (md->mbox_entry);
848
gtk_box_pack_start (GTK_BOX (hbox), md->mbox_entry, TRUE, TRUE, 0);
850
button = gtk_button_new ();
851
gtk_widget_show (button);
852
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
854
image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
855
gtk_widget_show (image);
856
gtk_container_add (GTK_CONTAINER (button), image);
858
g_signal_connect (button, "clicked", G_CALLBACK (mbox_browse_cb), md);
860
/* only set label on focus out */
861
g_signal_connect_swapped (md->mbox_entry, "focus-out-event",
862
G_CALLBACK (entry_lost_focus), md);
866
add_newmail_cmd_box (GtkWidget * vbox, GtkSizeGroup * sg, MailDialog * md)
868
GtkWidget *hbox, *label, *button, *image;
869
t_mailcheck *mc = md->mc;
871
hbox = gtk_hbox_new (FALSE, BORDER);
872
gtk_widget_show (hbox);
873
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
875
label = gtk_label_new (_("New mail command:"));
876
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
877
gtk_size_group_add_widget (sg, label);
878
gtk_widget_show (label);
879
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
881
md->newmail_cmd_entry = gtk_entry_new ();
882
if (mc->newmail_command)
883
gtk_entry_set_text (GTK_ENTRY (md->newmail_cmd_entry),
884
mc->newmail_command);
885
gtk_widget_show (md->newmail_cmd_entry);
886
gtk_box_pack_start (GTK_BOX (hbox), md->newmail_cmd_entry, TRUE, TRUE, 0);
888
gtk_tooltips_set_tip (tooltips, md->newmail_cmd_entry,
889
_("Command to run when new mail arrives"), NULL);
891
button = gtk_button_new ();
892
gtk_widget_show (button);
893
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
895
image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
896
gtk_widget_show (image);
897
gtk_container_add (GTK_CONTAINER (button), image);
899
g_signal_connect (button, "clicked", G_CALLBACK (newmail_cmd_brows_cb),
902
/* only set label on focus out */
903
g_signal_connect_swapped (md->mbox_entry, "focus-out-event",
904
G_CALLBACK (entry_lost_focus), md);
909
add_command_box (GtkWidget * vbox, GtkSizeGroup * sg, MailDialog * md)
911
md->cmd_opts = create_command_options (sg);
913
command_options_set_command (md->cmd_opts, md->mc->command,
914
md->mc->term, md->mc->use_sn);
916
gtk_box_pack_start (GTK_BOX (vbox), md->cmd_opts->base, FALSE, TRUE, 0);
918
gtk_tooltips_set_tip (tooltips, md->cmd_opts->command_entry,
919
_("Command to run when the button "
920
"on the panel is clicked"), NULL);
925
interval_changed (GtkSpinButton * spin, MailDialog * md)
927
md->mc->interval = gtk_spin_button_get_value_as_int (spin);
931
add_interval_box (GtkWidget * vbox, GtkSizeGroup * sg, MailDialog * md)
933
GtkWidget *hbox, *label;
934
t_mailcheck *mc = md->mc;
936
hbox = gtk_hbox_new (FALSE, BORDER);
937
gtk_widget_show (hbox);
938
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
940
label = gtk_label_new (_("Interval (sec):"));
941
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
942
gtk_size_group_add_widget (sg, label);
943
gtk_widget_show (label);
944
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
946
md->interval_spin = gtk_spin_button_new_with_range (1, 600, 1);
947
gtk_spin_button_set_value (GTK_SPIN_BUTTON (md->interval_spin),
949
gtk_widget_show (md->interval_spin);
950
gtk_box_pack_start (GTK_BOX (hbox), md->interval_spin, FALSE, FALSE, 0);
952
g_signal_connect (md->interval_spin, "value-changed",
953
G_CALLBACK (interval_changed), md);
958
mailcheck_create_options (Control * control, GtkContainer * container,
962
GtkSizeGroup *sg = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
965
xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
967
md = g_new0 (MailDialog, 1);
969
md->mc = (t_mailcheck *) control->data;
971
md->dialog = gtk_widget_get_toplevel (done);
973
vbox = gtk_vbox_new (FALSE, BORDER);
974
gtk_widget_show (vbox);
976
add_mbox_box (vbox, sg, md);
978
add_interval_box (vbox, sg, md);
980
add_newmail_cmd_box (vbox, sg, md);
982
add_command_box (vbox, sg, md);
985
g_signal_connect_swapped (done, "clicked",
986
G_CALLBACK (mailcheck_apply_options), md);
988
g_signal_connect_swapped (md->dialog, "destroy-event",
989
G_CALLBACK (free_maildialog), md);
991
gtk_container_add (container, vbox);
994
/* create panel control */
996
create_mailcheck_control (Control * control)
998
t_mailcheck *mailcheck = mailcheck_new ();
999
GtkWidget *b = mailcheck->button;
1001
gtk_container_add (GTK_CONTAINER (control->base), b);
1003
control->data = (gpointer) mailcheck;
1004
control->with_popup = FALSE;
1010
G_MODULE_EXPORT void
1011
xfce_control_class_init (ControlClass * cc)
1013
xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
1015
cc->name = "mailcheck";
1016
cc->caption = _("Mail checker");
1018
cc->create_control = (CreateControlFunc) create_mailcheck_control;
1020
cc->free = mailcheck_free;
1021
cc->read_config = mailcheck_read_config;
1022
cc->write_config = mailcheck_write_config;
1023
cc->attach_callback = mailcheck_attach_callback;
1025
cc->create_options = (gpointer) mailcheck_create_options;
1027
cc->set_theme = mailcheck_set_theme;
1031
XFCE_PLUGIN_CHECK_INIT