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