...

понедельник, 28 октября 2013 г.

[Из песочницы] Мигаем Scroll lock'ом при входящем email сообщении (perl + bash)

По мотивам этого вопроса.

Задача: научиться моргать светодиодом клавиатуры в случае, если есть новые непрочитанные сообщения в нашем почтовом ящике.


Доп. условия: ОС — linux, язык — perl (проверка почты) и bash (собственно моргание).


Собственно как и советовали в изначальном топике разобьем задачу на составляющие:



  1. Научиться моргать курсером

  2. Научиться проверять почту на наличие новых сообщений

  3. Подружить оба пункта между собой


Учимся моргать курсером



Существует демон Ledcontrol, однако в моих репозитариях его не оказалось, поэтому я буду мигать курсором используя команду xset

#!/bin/bash
trap "xset -led named "Scroll Lock"; exit " SIGINT

while(true); do
xset led named "Scroll Lock" ;
sleep 0.05 ;
xset -led named "Scroll Lock";
sleep 0.05;
done




этот код был сохранен в файл beepScroll, файл положен в один из каталогов перечисленных в $PATH и даны права на выполнение. Обратите внимание что при получении SIGINT мы выключаем светодиод и выключаемся через trap.

Учимся проверять почту на наличие новых сообщений


sub mymail(){
use Mail::IMAPClient;
use IO::Socket::SSL;
while (42){
my $user = 'login';
my $server = 'server.ltd';
my $pass = 'P@ssw0rd';

my $socket = IO::Socket::SSL->new(
PeerAddr => $server,
PeerPort => 993,
) or die "socket(): $@";
my $imap = Mail::IMAPClient->new(
Socket => $socket,
Server => $server,
User => $user,
Password => $pass,
Debug => 0) or die "Cannot connect to $server as $user: $@";
my $not_read;
foreach my $f ($imap->folders) {
my $i = $imap->unseen_count($f)||0 ;
$not_read += $i;
}
$imap->logout();
print $not_read;
}
}





Здесь мы подключаем нужные модули (Mail::IMAPClient не входит в стандартную поставку, его потребуется доставить отдельно) и запускаем бесконечный цикл который 1) подключается по imap к серверу, получает количество непрочитанных сообщений в директории INBOX и ее поддиректориях и возвращает их число, ждет минуту и начинает с начала.
Дружим все вместе



Тут бы хотелось остановиться подробнее. Мы будем запускать 2 потока. Первый будет проверять почту и посылать количество непрочитанных сообщений второму. Второй будет получать сообщения от первого запускать\останавливать скрипт моргания курсором.

Итак:

#!/usr/bin/perl
# Нужные модули
use strict;
use threads; #Модуль потоков
use Thread::Queue; #Модуль для организации общей очереди между потоками

my $mypipe = Thread::Queue->new; #Инициализируем очередь

# Стартуем оба потока
threads->create(\&mymail); # Проверка почты
threads->create(\&myleds)->join; #Разбор сообщений от первого потока




join во втором потоке значит что нам перед продолжением действия требуется дождаться окончания работы этого потока.

Сам код функции myleds:

sub myleds(){
my $beep = 0; #1 если сейчас есть новые сообщения.
my $mypid; # pid процесса, который мограет

while($_ = $mypipe->dequeue){ # Принимаем сообщения из очереди
if ($_ > 1){
if ($beep == 0){
$mypid = `nohup beepScroll > /dev/null 2>&1 &echo \$!`; #Такая хитрая конструкция для получения pid'а запущенного процесса
$beep = 1;
}
} else {
`kill $mypid` if $mypid; # Если новых писем нет, то выключаем моргание и обнуляем переменные.
$mypid = 0 if $mypid;
$beep = 0;
}
}
}


, а в функции mymail() следует заменить

prinr $not_read

на

$mypipe->enqueue($not_read+1)

"$not_read+1" потому что если while получит 0, то посчитает что условия ложное.
Конечная версия скрипта


#!/usr/bin/perl

use strict;
use threads;
use Thread::Queue;

my $mypipe = Thread::Queue->new;
threads->create(\&mymail);
threads->create(\&myleds)->join;

sub mymail(){
use Mail::IMAPClient;
use IO::Socket::SSL;
while (42){
my $user = 'login';
my $server = 'server.ltd';
my $pass = 'P@ssw0rd';

my $socket = IO::Socket::SSL->new(
PeerAddr => $server,
PeerPort => 993,
) or die "socket(): $@";
my $imap = Mail::IMAPClient->new(
Socket => $socket,
Server => $server,
User => $user,
Password => $pass,
Debug => 0) or die "Cannot connect to $server as $user: $@";
my $not_read;
foreach my $f ($imap->folders) {
my $i = $imap->unseen_count($f)||0 ;
$not_read += $i;
}
$imap->logout();
$mypipe->enqueue($not_read+1);
sleep 60;
}
# Это никогда не выполниться ... но на всякий случай :)
$mypipe->enqueue(undef);
exit 1;
}
sub myleds(){
my $beep = 0;
my $mypid;

while($_ = $mypipe->dequeue){
if ($_ > 1){
if ($beep == 0){
$mypid = `nohup beepScroll > /dev/null 2>&1 &echo \$!`;
$beep = 1;
}
} else {
$beep = 0;
`kill $mypid` if $mypid;
$mypid = 0 if $mypid;
}
}
}



This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий