html/mail.pl
1 $VERSION = "2.92";
2 %IRSSI = (
3 authors => "Timo Sirainen, Matti Hiljanen, Joost Vunderink, Bart Matthaei",
4 contact => "tss\@iki.fi, matti\@hiljanen.com, joost\@carnique.nl, bart\@dreamflow.nl",
5 name => "mail",
6 description => "Fully customizable mail counter statusbar item with multiple mailbox and multiple Maildir support",
7 license => "Public Domain",
8 url => "http://irssi.org, http://scripts.irssi.de",
9 );
10
11 # Mail counter statusbar item
12 # for irssi 0.8.1 by Timo Sirainen
13 #
14 # Maildir support added by Matti Hiljanen
15 # Multiple Maildir/mbox and customization support added by Joost Vunderink
16 # OLD mailtreatment switch added by Bart Matthaei.
17 # Improved some regexps in maildirmode by Bart Matthaei.
18 # Maildirmode regexps (hopefully) fixed for good by Matti Hiljanen.
19 #
20 # You can add any number of mailboxes or Maildirs to watch for new mail in.
21 # Give them any name and <name>:<count> will appear in your mail
22 # statusbar item, where <count> is the number of unread messages.
23 # If only 1 mailbox/Maildir is defined, the statusbar item will have the
24 # familiar form [Mail: <count>].
25 # If you set mail_show_message to ON, irssi will print a message in the
26 # active window whenever new mail arrives.
27 #
28 # Check /mailbox help for help.
29
30 use Irssi::TextUI;
31
32 my $maildirmode = 0; # maildir=1, file(spools)=0
33 my $old_is_not_new = 0;
34 my $extprog;
35 my ($last_refresh_time, $refresh_tag);
36
37 # for mbox caching
38 my $last_size, $last_mtime, $last_mailcount, $last_mode;
39
40 # list of mailboxes
41 my %mailboxes = ();
42 my %new_mails_in_box = ();
43 my $nummailboxes = 0;
44
45 # the string to be stored in Irssi's mail_mailboxes setting
46 my $mailboxsetting = "";
47
48 sub cmd_print_help {
49 Irssi::print(
50 "MAILBOX ADD <num> <file|dir>\n".
51 "MAILBOX DEL <num>\n".
52 "MAILBOX SHOW\n\n".
53 "Statusbar item to keep track of how many (new) emails there are in ".
54 "each of your mailboxes/Maildirs.\n\n".
55 "/MAILBOX ADD <name> <file|dir>\n".
56 " - Adds a mailbox or a Maildir to the list.\n".
57 "/MAILBOX DEL <name>\n".
58 " - Removes mailbox or Maildir named <name> from the list.\n".
59 "/MAILBOX SHOW\n".
60 " - Shows a list of the defined mailboxes.\n\n".
61 "Use the following commands to change the behaviour:\n\n".
62 "/SET MAILDIRMODE on|off\n".
63 " - If maildirmode is on, the mailboxes in the list are assumed to be ".
64 "directories. Otherwise they are assumed to be spool files.\n".
65 " Default: off.\n".
66 "/SET MAIL_OLDNOTNEW on|off\n".
67 " - If switched on, mail marked als \"OLD\" will not be treated as new.\n".
68 " Default: off.\n".
69 "/SET MAIL_EXT_PROGRAM <prog>\n".
70 " - <prog> will be used to check for mail.\n".
71 "/SET MAIL_REFRESH_TIME <num>\n".
72 " - Sets the time between checks to <num> seconds.\n Default: 60.\n".
73 "/SET MAIL_SHOW_MESSAGE on|off\n".
74 " - If this is on, a message will be printed in the active window ".
75 "whenever new email is received.\n Default: off.\n".
76 "/SET MAIL_SHOW_ONLY_UNREAD on|off\n".
77 " - If you don't want to see a mailbox if it does not contain any new ".
78 "mail, set this to on.\n Default: on.\n" .
79 "/SET MAIL_SEPARATOR <char>\n".
80 " - Sets the character to be printed between each mailbox.\n".
81 " The default is a comma.\n".
82 "/SET MAIL_FORMAT <format>\n".
83 " - Sets the format of each mailbox.\n".
84 " Allowed variables:\n".
85 " %%n = mailbox name\n".
86 " %%u = number of unread mail\n".
87 " %%r = number of read mail\n".
88 " %%t = total amount of mail\n".
89 " The default format is %%n:%%u/%%t.\n".
90 "\nSee also: STATUSBAR"
91 ,MSGLEVEL_CRAP);
92 }
93
94 sub mbox_count {
95 my $mailfile = shift;
96 my $unread = 0;
97 my $read = 0;
98 my $maildirmode=Irssi::settings_get_bool('maildir_mode');
99 my $old_is_not_new=Irssi::settings_get_bool('mail_oldnotnew');
100
101 if ($extprog ne "") {
102 $total = `$extprog`;
103 chomp $unread;
104 } else {
105 if (!$maildirmode) {
106 if (-f $mailfile) {
107 my @stat = stat($mailfile);
108 my $size = $stat[7];
109 my $mtime = $stat[9];
110
111 # if the file hasn't changed, get the count from cache
112 return $last_mailcount if ($last_size == $size && $last_mtime == $mtime);
113 $last_size = $size;
114 $last_mtime = $mtime;
115
116 my $f = gensym;
117 return 0 if (!open($f, $mailfile));
118
119 # count new mails only
120 my $internal_removed = 0;
121 while (<$f>) {
122 $unread++ if (/^From /);
123
124 if(!$old_is_not_new) {
125 $unread-- if (/^Status: R/);
126 } else {
127 $unread-- if (/^Status: [OR]/);
128 }
129
130 $read++ if (/^From /);
131
132 # Remove folder internal data, but only once
133 if (/^Subject: .*FOLDER INTERNAL DATA/) {
134 if ($internal_removed == 0) {
135 $internal_removed = 1;
136 $read--;
137 $unread--;
138 }
139 }
140 }
141 close($f);
142 }
143 } else {
144 opendir(DIR, "$mailfile/cur") or return 0;
145 while (defined(my $file = readdir(DIR))) {
146 next if $file =~ /^(.|..)$/;
147 # Maildir flags: http://cr.yp.to/proto/maildir.html
148 # My old regexps were useless if the MUA added any
149 # non-default flags -qvr
150 #
151 # deleted mail
152 next if $file =~ /\:.*?T.*?$/;
153 if($old_is_not_new) {
154 # when mail gets moved from new to cur it's name _always_
155 # changes from uniq to uniq:info, even when it's still not
156 # read. I assume "old mail" means mail which hasn't been read
157 # yet but it has been "acknowledged" by the user. (it's been
158 # moved to cur) -qvr
159 if ($file =~ /\:.*?$/) {
160 $read++;
161 next;
162 }
163 } else {
164 if ($file =~ /\:.*?S.*?$/) {
165 $read++;
166 next;
167 }
168 }
169 $unread++;
170 }
171 closedir(DIR);
172
173 opendir(DIR, "$mailfile/new") or return 0;
174 while (defined(my $file = readdir(DIR))) {
175 next if $file =~ /^(.|..)$/;
176 $unread++;
177 }
178 closedir(DIR);
179 }
180 }
181
182 if ($unread eq "" || $unread < 0) {
183 $unread = 0;
184 }
185 if ($read eq "" || $read < 0) {
186 $read = 0;
187 }
188
189 $last_mailcount = $unread;
190
191 return ($unread, $read);
192 }
193
194 # Checks for mail and sets the statusbar item to the right string.
195 # Also shows a message in the active window if that setting is set.
196 sub mail {
197 my ($item, $get_size_only) = @_;
198
199 my $result;
200 my $format = Irssi::settings_get_str('mail_format');
201 my $unread = 0;
202 my $read = 0;
203 my $total = 0;
204
205 # check all mailboxes for new email
206 foreach $name (keys(%mailboxes)) {
207 my $box = $mailboxes{$name};
208 # replace "~/" at the beginning by the user's home dir
209 $box =~ s/^~\//$ENV{'HOME'}\//;
210
211 ($unread, $read) = mbox_count($box);
212 $unread = "0" if ($unread eq "");
213 $read = "0" if ($read eq "");
214 $total = $unread + $read;
215 $total = "0" if ($total eq "");
216
217 next if (Irssi::settings_get_bool('mail_show_only_unread') && $unread == 0);
218
219 if ($total eq "") { $total = 0; }
220 if (length($result) > 0) {
221 $result .= Irssi::settings_get_str('mail_separator');
222 }
223 my $string = $format;
224 $string =~ s/%n/$name/;
225 $string =~ s/%u/$unread/;
226 $string =~ s/%r/$read/;
227 $string =~ s/%t/$total/;
228 $result .= $string;
229
230 # Show -!- You have <num> new messages in <name>.
231 # Show this only if there are any new, unread messages.
232 if (Irssi::settings_get_bool('mail_show_message') &&
233 $unread > $new_mails_in_box{$name}) {
234 $new_mails = $unread - $new_mails_in_box{$name};
235 if ($nummailboxes == 1) {
236 Irssi::print("You have $new_mails new message" . ($new_mails != 1 ? "s." : "."), MSGLEVEL_CRAP);
237 } else {
238 Irssi::print("You have $new_mails new message" . ($new_mails != 1 ? "s " : " ") . "in $name.", MSGLEVEL_CRAP);
239 }
240 }
241
242 $new_mails_in_box{$name} = $unread;
243 }
244
245 if (length($result) == 0) {
246 # no mail - don't print the [Mail: ] at all
247 if ($get_size_only) {
248 $item->{min_size} = $item->{max_size} = 0;
249 }
250 } else {
251 $item->default_handler($get_size_only, undef, $result, 1);
252 }
253 }
254
255 sub refresh_mail {
256 Irssi::statusbar_items_redraw('mail');
257 }
258
259 # Adds the mailboxes from a string. Only to be used during startup.
260 sub add_mailboxes {
261 my $boxstring = $_[0];
262 my @boxes = split(/,/, $boxstring);
263
264 foreach $dbox(@boxes) {
265 my $name = $dbox;
266 $name = substr($dbox, 0, index($dbox, '='));
267 my $box = $dbox;
268 $box = substr($dbox, index($dbox, '=') + 1, length($dbox));
269 addmailbox($name, $box);
270 }
271 }
272
273 sub addmailbox {
274 my ($name, $box) = @_;
275
276 if (exists($mailboxes{$name})) {
277 if ($box eq $mailboxes{$name}) {
278 Irssi::print("Mailbox $name already set to $box", MSGLEVEL_CRAP);
279 } else {
280 Irssi::print("Mailbox $name changed to $box", MSGLEVEL_CRAP);
281 $new_mails_in_box{$name} = 0;
282 }
283 } else {
284 Irssi::print("Mailbox $name added: " . $box, MSGLEVEL_CRAP);
285 $new_mails_in_box{$name} = 0;
286 $nummailboxes++;
287 }
288 $mailboxes{$name} = $box;
289 }
290
291 sub delmailbox {
292 my $name = $_[0];
293
294 if (exists($mailboxes{$name})) {
295 Irssi::print("Mailbox $name removed", MSGLEVEL_CRAP);
296 delete($mailboxes{$name});
297 delete($new_mails_in_box{$name});
298 $nummailboxes--;
299 } else {
300 Irssi::print("No such mailbox $name. Use /mailbox show to see a list.", MSGLEVEL_CRAP);
301 }
302 }
303
304 sub update_settings_string {
305 my $setting;
306
307 foreach $name (keys(%mailboxes)) {
308 $setting .= $name . "=" . $mailboxes{$name} . ",";
309 }
310
311 Irssi::settings_set_str("mail_mailboxes", $setting);
312 }
313
314 sub cmd_addmailbox {
315 my ($name, $box) = split(/ +/, $_[0]);
316
317 if ($name eq "" || $box eq "") {
318 Irssi::print("Use /mailbox add <name> <mailbox> to add a mailbox.", MSGLEVEL_CRAP);
319 return;
320 }
321
322 addmailbox($name, $box);
323 update_settings_string();
324 refresh_mail();
325 }
326
327 sub cmd_delmailbox {
328 my $name = $_[0];
329
330 if ($name eq "") {
331 Irssi::print("Use /mailbox del <name> to delete a mailbox.", MSGLEVEL_CRAP);
332 return;
333 }
334
335 delmailbox($name);
336 update_settings_string();
337 refresh_mail();
338 }
339
340 sub cmd_showmailboxes {
341 if ($nummailboxes == 0) {
342 Irssi::print("No mailboxes defined.", MSGLEVEL_CRAP);
343 return;
344 }
345 Irssi::print("Mailboxes:", MSGLEVEL_CRAP);
346 foreach $box (keys(%mailboxes)) {
347 Irssi::print("$box: " . $mailboxes{$box}, MSGLEVEL_CRAP);
348 }
349 }
350
351 sub cmd_mailboxes {
352 my ($data, $server, $item) = @_;
353 if ($data =~ m/^[(show)|(add)|(del)]/i ) {
354 Irssi::command_runsub ('mailbox', $data, $server, $item);
355 }
356 else {
357 Irssi::print("Use /mailbox (show|add|del).")
358 }
359 }
360
361 sub init_mailboxes {
362 # Add the mailboxes at startup of the script
363 my $boxes = Irssi::settings_get_str('mail_mailboxes');
364 if (length($boxes) > 0) {
365 add_mailboxes($boxes);
366 }
367 }
368
369 sub read_settings {
370 $extprog = Irssi::settings_get_str('mail_ext_program');
371 my $time = Irssi::settings_get_int('mail_refresh_time');
372 my $mode = Irssi::settings_get_bool('maildir_mode');
373 unless ($time == $last_refresh_time) {
374 $last_refresh_time = $time;
375 Irssi::timeout_remove($refresh_tag) if ($refresh_tag);
376 $refresh_tag = Irssi::timeout_add($time*1000, 'refresh_mail', undef);
377 }
378 return if ($mode == $last_mode);
379 $last_mode = $mode;
380 refresh_mail;
381 }
382
383
384 if (!$maildirmode) {
385 my $default = "1=" . $ENV{'MAIL'} . ",";
386 Irssi::settings_add_str('misc', 'mail_mailboxes', $default);
387 } else {
388 my $default = "1=~/Maildir/,";
389 Irssi::settings_add_str('misc', 'mail_mailboxes', $default);
390 }
391
392 Irssi::command_bind('mailbox show', 'cmd_showmailboxes');
393 Irssi::command_bind('mailbox add', 'cmd_addmailbox');
394 Irssi::command_bind('mailbox del', 'cmd_delmailbox');
395 Irssi::command_bind('mailbox help', 'cmd_print_help');
396 Irssi::command_bind('mailbox', 'cmd_mailboxes');
397
398 Irssi::settings_add_str('misc', 'mail_ext_program', '');
399 Irssi::settings_add_int('misc', 'mail_refresh_time', 60);
400 Irssi::settings_add_bool('misc', 'maildir_mode', "$maildirmode");
401 Irssi::settings_add_bool('misc', 'mail_oldnotnew', "$old_is_not_new");
402 Irssi::settings_add_str('misc', 'mail_separator', ",");
403 Irssi::settings_add_bool('misc', 'mail_show_message', "0");
404 Irssi::settings_add_str('misc', 'mail_format', '%n:%u/%t');
405 Irssi::settings_add_bool('misc', 'mail_show_only_unread', "1");
406
407 Irssi::statusbar_item_register('mail', '{sb Mail: $0-}', 'mail');
408
409 read_settings();
410 init_mailboxes();
411 Irssi::signal_add('setup changed', 'read_settings');
412 refresh_mail();
413
414 # EOF