Задача: научиться моргать светодиодом клавиатуры в случае, если есть новые непрочитанные сообщения в нашем почтовом ящике.
Доп. условия: ОС — linux, язык — perl (проверка почты) и bash (собственно моргание).
Собственно как и советовали в изначальном топике разобьем задачу на составляющие:
- Научиться моргать курсером
- Научиться проверять почту на наличие новых сообщений
- Подружить оба пункта между собой
Учимся моргать курсером
Существует демон 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; sleep 1; `xset -led named "Scroll Lock"` } } }
ссылка на оригинал статьи http://habrahabr.ru/post/199270/
Добавить комментарий