Mcabber 0.9.10 на Nokia N900


Некоторое время назад я постил этот материал на http://n8xx.com за неимением собственного блога и вот решил перепостить, дополнить, обновить.

Как известно, выбор xmpp-клиентов на n900 не особо велик. Встроенное приложение довольно ограниченное в плане функционала и работает не стабильно.

Просматривая репозитории n900 мне на глаза попался xmpp-клиент под названием mcabber. Это неприхотливый консольный и, как оказалось, самый полноценный клиент. В репозитории лежит версия 0.9.10. При желании можно прямо на таблетке собрать более новую версию, 0.10.1, или последнюю бета-версию 0.10.2-dev, но об этом в другой раз.

Сегодня я расскажу как настроить и повысить удобство этого клиента.

Что мы получим в итоге:

— Показ смены статуса в виде всплывающей подсказки по чёрному или белому списку с возможностью отключить показ перехода в оффлайн.
— При смене статуса отлавливаются j2j jid'ы, преобразуются к нормальному виду и в скобках указывается, что jid был подключён через j2j.
— Показ входящего сообщения в всплывающем окошке. Показываются сообщения, пришедшие на jid, в приваты конференций, а так-же из конференций в соответствии со списком хайлайтов.
— При входящем сообщении показывается jid, j2j, если сообщение пришло с j2j контакта, время сообщения.
— Настройка разных звуков на сообщения из ростера, конфы, статусы.
— Вывод девайса из стенбай режима при входящем сообщении или статусе. Настраивается раздельно на статусы и сообщения.
— Возможность отключить вывод из стенбая если девайс находится "в кармане". Работает через proximity sensor.
— Виджеты для hildon, которые показывают количество пропущенных событий, последний статус, последнее сообщение.
— Красивая иконка вместо стандартной "иконки терминала"

Так-же будут доступны горячие клавиши:

— Ctrl+Q - Перейти к следующему пропущенному событию.
— Ctrl+Z - Скрыть оффлайн контакты.
— Ctrl+J - Войти в конференцию, на которой стоит курсор.

Итак, ставим клиент:

sudo apt-get install mcabber

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

cd ~
mkdir .mcabber
cd .mcabber
mkdir event_files
mkdir histo
mkdir sounds
cd ~
wget http://files.dsy.name/mcabber/resources.tar.gz
cd /
sudo tar -xvfz ~/resources.tar.gz

Далее нам понадобятся два файла настроек. Настройки самого mcabber и настройки событий:

Переписываем под себя и сохраняем в ~/.mcabber/mcabberrc

# Sample ~/.mcabber/mcabberrc file
set username = ваш логин
set jid = ваш jid
set password = пароль
set server = сервер, на котором находится ваш jid
set port = 5222
set resource = mcabber
set disable_random_resource = 1
set priority = 10
set priority_away = 5
set ignore_self_presence = 1
set tls = 1
set ssl_ignore_checks = 1
set nickname = ваш ник
set lang = ru
set help_dirs = "/opt/maemo/usr/share/mcabber"
set help_to_current = 1
set cmdhistory_lines = 250
set roster_display_filter = foand_
set logging = 1
set load_logs = 1
set logging_dir = ~/.mcabber/histo/
set logging_ignore_status = 0
set log_muc_conf = 1
set load_muc_logs = 1
set statefile = ~/.mcabber/mcabber.state
set max_history_blocks = 8
set beep_on_message = 1
set event_log_files = 1
set event_log_dir = ~/.mcabber/event_files
set events_command = ~/.mcabber/event.py
set fifo_name = ~/.mcabber/mcabber.fifo
set tracelog_level = 1
set tracelog_file = ~/.mcabber/mcabber.log
set autoaway = 600
set delete_on_reject = 1
set muc_flag_joins = 2
set muc_auto_whois = 1
set muc_completion_suffix = ": "
set message = O_o
set message_avail = o_o
set message_free = O_O
set message_dnd = >_<
set message_notavail = x_x
set message_away = -_-
set message_autoaway = >_<
set color_background = white
set color_general = black
set color_info = black
set color_msgin = black
set color_msgout = blue
set color_msghl = red
set color_bgstatus = green
set color_status = black
set color_roster = black
set color_bgrostersel = black
set color_rostersel = white
set color_rosterselmsg = red
set color_rosternewmsg = red
set log_win_height = 3
set roster_width=32
set log_win_on_top = 1
set buddy_format = 2
set time_prefix = 1
set log_display_presence = 1
set show_status_in_buffer = 2
set url_regex = "(((https?|ftps?|nntp)://)|www[.][-a-z0-9.]+|(mailto:|news:))(%[0-9A-F]{2}|[-_.!~*';/?:@&=+$,#[:alnum:]])+"
alias me = say /me
alias online = status online o_o
alias away = status away x_x
alias dnd = status dnd >_<
alias notavail = status notavail
set use_mouse = 0
bind 17 = roster unread_next
bind 24 = roster alternate
bind 26 = roster toggle_offline
bind 22 = roster toggle
bind 521 = buffer up
bind 514 = buffer down
bind 18 = roster up
bind 6 = roster down
bind 10 = room join
alias idle = /request last
alias ping = /request ping
alias time = /request time
alias vcard = /request vcard
alias ver = /request version
alias kick = /room kick
alias ban = /room ban
alias unban = /room unban
alias aff = /room affil
alias pm = /room privmsg
alias nc = /room names --compact
alias leave = /room leave

Данный конфиг является упрощённым и оптимизированным вариантом оригинального файла настроек, который можно взять тут: http://mcabber.com/files/mcabberrc.example

Далее создаём файл-обработчик событий, который необходимо поместить в ~/.mcabber/event.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
# -------------------------------------
# Event controller for mcabber on N900!
# (c) Disabler Production Lab.
# -------------------------------------
import sys,os,re,time
# ----------------------- Settings ----------------------
# Заголовок, который будет показываться перед каждым сообщением
mtitle = 'mcabber: '
# Заголовок, который будет показываться перед каждым статусом
ptitle = 'mcabber: '
# Размер сообщения, свыше которого будет обрезаться
size_limit = 1024
# Список слов, сообщения с которыми надо показывать. Например можно вписать ваш ник.
highlight = ['diSabler',u'Disаbler',u'Disablеr',u'дисаблер',u'дизаблер']
# Список слов, сообщения с которыми не надо показывать. Желательно вписать ваш ник, что-бы сообщения от вас вам же не показывались
self_nick = ['diSabler','diSabler.mc']
# Путь к настройкам. Желательно не менять.
set_path = '/home/user/.mcabber/%s'
# Путь, по которому будет хранится количество пропущенных событий. Нужен для показа в desktop execution widget.
# для показа в него надо прописать команду cat /home/user/.mcabber/unread_messages
unreads = set_path % 'unread_messages'
# Путь, по которому будет хранится последний статус и сообщение. Нужно для показа в desktop execution widget.
# для показа в него надо прописать команду cat /home/user/.mcabber/last_message
# либо cat /home/user/.mcabber/last_status
last_message = set_path % 'last_message'
last_status = set_path % 'last_status'
# Чёрный список jid'ов, смена статусов которых не должна показываться.
status_black = ['disabler_@twitter.tweet.im','rss@isida-bot.com',
'en-ru@isida-bot.com','ru-en@isida-bot.com',
'de-ru@isida-bot.com','ru-de@isida-bot.com',
'isida@isida-bot.com']
# Белый список jid'ов. Смена статусов будет показана только для них.
status_white = ['dissy@jabber.ru', 'dissy@isida-bot.com']
# Выбор активного списка показа статусов 'white' или 'black'
status_type = 'white'
# Информировать о переходе jid'а в офлайн - False или True
show_offline = False
# Включение отладочных логов событий - False или True
logs = False
events = set_path % 'events.log'
# Проигрывать звуки при сообщениях и смене статусов
play_sound = True
# Вибра при сообщениях и смене статусов
use_vibra = True
# Мигать светодиодом при пропущенном событии
flash_led = True
# Снимать с блокировки при входящем сообщении
wakeup_on_presence = True
# Снимать с блокировки при смене статуса
wakeup_on_message = True
# Снимать с блокировки только если n900 не находится в кармане и не лежит экраном вниз
wakeup_on_air = True
# Настройки звуков
play = {'MUC':'chat_their_message', # сообщение из конференции
#'2':'connected',
#'3':'groupchat_server_message',
#'1':'groupchat_their_message',
'IN':'groupchat_their_message_to_me', # сообщение в ростер
'AV':'presence_available', # подключение jid'а
'UNAV':'presence_unavailable'} # отключение jid'а
# ----------------------- The end of settings ----------------------
tmp_file = set_path % 'temporary.tmp'
def message(text):
if wakeup_on_message and air_status(): os.system(unlock_script)
os.system(message_script % text)
writefile(last_message,'%s\n' % text)
def presence(text):
if air_status() and (not lock_status() or wakeup_on_presence):
os.system(unlock_script)
os.system(presence_script % text)
writefile(last_status,'%s\n' % text)
def readfile(filename):
fp = file(filename)
data = fp.read()
fp.close()
return data
def appendfile(filename, data):
fp = file(filename, 'a')
fp.write(data)
fp.close()
def writefile(filename, data):
fp = file(filename, 'w')
fp.write(data)
fp.close()
def player(sound):
if play_sound: os.system(sound_cmd % play[sound])
if use_vibra: os.system(vibra_script)
def lock_status():
try: os.system('rm -rf %s' % tmp_file)
except: pass
os.system(get_status_script)
try: st = readfile(tmp_file).split('"')[1]
except: st = 'locked'
return st == 'locked'
def air_status():
if not wakeup_on_air: return False
try: os.system('rm -rf %s' % tmp_file)
except: pass
os.system(air_status_script)
try: st = readfile(tmp_file).split()[0]
except: st = 'closed'
return st == 'open'
presence_script = 'run-standalone.sh dbus-send --type=method_call --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteInfoprint string:"'+ptitle+'%s"'
message_script = 'run-standalone.sh dbus-send --print-reply --type=method_call --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog string:"'+mtitle+'%s" uint32:0 string:'' 2> /dev/null 1> /dev/null'
vibra_script = 'dbus-send --print-reply --system --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_vibrator_pattern_activate string:"PatternChatAndEmail" &'
led_flash_on = 'dbus-send --system --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_led_pattern_activate string:PatternCommunicationIM'
led_flash_off = 'dbus-send --system --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_led_pattern_deactivate string:PatternCommunicationIM'
get_status_script = 'dbus-send --system --print-reply --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.get_tklock_mode | grep string | awk \'{print $2}\' >> %s' % tmp_file
unlock_script = 'dbus-send --system --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_tklock_mode_change string:"unlocked"'
lock_script = 'dbus-send --system --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_tklock_mode_change string:"locked"'
air_status_script = 'cat /sys/devices/platform/gpio-switch/proximity/state >> %s' % tmp_file
sound_path = set_path % 'sounds/%s.wav'
sound_cmd = 'play-sound %s &' % sound_path
if logs: appendfile(events,'|'.join(sys.argv)+'\n')
type,subtype,j2j = sys.argv[1],sys.argv[2],0
if type == 'MSG':
jid,fname = sys.argv[3],sys.argv[4]
if jid.count('%') and (jid.count('@j2j.') or jid.count('@j3j.') or jid.count('@xmpp.')): jid,j2j = jid.split('@',1)[0].replace('%','@'),1
if subtype in ['IN','MUC']:
try: text = readfile(fname)
except: sys.exit()
hl = None
if subtype == 'MUC':
if text[:2] == '~ ' or text[:5] == 'PRIV#': hl = True
else:
snick = re.findall(r'^<(.*?)> ',text,re.I+re.S+re.U)
if snick[0] in self_nick: txt = text.lower().split('> ')[1]
else: txt = text.lower()
for t in highlight:
if t.lower() in txt:
hl = True
break
if (subtype == 'MUC' and hl) or subtype == 'IN':
player(subtype)
text = text[:text.find(' ',size_limit)].replace('$','\$')#.replace('&','&amp;').replace('"','&quot;').replace('<','&lt;').replace('>','&gt;')
me_nick = re.findall(r'^<(.*?)> /me ',text,re.S+re.I+re.U)
if me_nick: text = re.sub(r'(^<.*?> /me)','*%s' % me_nick[0],text,re.I+re.S+re.U)
message('%s%s\n%s\n%s' % (jid,['',' [j2j]'][j2j],time.ctime(),text))
os.system('rm -rf %s' % fname)
elif type == 'UNREAD':
try: unr = int(subtype.split(' ',1)[0])
except: unr = 0
if flash_led:
if unr: os.system(led_flash_on)
else: os.system(led_flash_off)
writefile(unreads,'%s event(s)\n' % unr)
elif type == 'STATUS':
status = {'A':'Away','D':'Dnd','N':'Xa','O':'Online','_':'Offline','F':'Chat'}
jid = sys.argv[3]
if jid.count('%') and (jid.count('@j2j.') or jid.count('@j3j.') or jid.count('@xmpp.')): jid,j2j = jid.split('@',1)[0].replace('%','@'),True
if status_type == 'black' and jid in status_black: sys.exit()
elif status_type == 'white' and not jid in status_white: sys.exit()
try: stat = status[sys.argv[2]]
except: stat = 'Online'
if not show_offline and stat == 'Offline': sys.exit()
player(['AV','UNAV'][stat == 'Offline'])
presence('%s%s - %s' % (jid,['',' [j2j]'][j2j],stat))
# That's all!

Назначаем ему права на исполнение:

sudo chmod +x ~/.mcabber/event.py

Файл доступен по ссылке: http://files.dsy.name/mcabber/event.py
Перед использованием файл надо открыть любым текстовым редактором и поправить настройки под себя.

После всех манипуляций желательно перезапустить таблетку для того, что-бы обновилась иконка клиента и ярлык.

В итоге мы получим нечто похожее на это: