Мигаем 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; 			sleep 1; 			`xset -led named "Scroll Lock"` 		} 	} } 

ссылка на оригинал статьи http://habrahabr.ru/post/199270/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *