Miranda + Python (MirPy)
Как-то так случилось, что Miranda потеряла в своей базе список контактов (дважды). Восстановить-то она его восстановила - список хранится на сервере, но вся история сообщений потерялась, так как в базе данных все события привязаны к внутренним айдишникам контактов. Я уже думал писать программу, которая будет разбирать вручную кривую мирандовскую базу данных, но тут я наткнулся на замечательный плагин - MirPy (miranda forums), который предоставляет питоновскую консоль.
Я использовал последнюю на данный момент версию - 0.1.3.1 (static), которая скомпилирована с поддержкой
Python 2.5. Подключаем плагин к миранде, запускаем - MirPy показывает формочку, с полем для ввода и
полем для вывода, куда перенаправляется весь обычный вывод. В нашем распоряжении - весь питон со всеми
установленными расширениями, плюс модули MirPy, clist, contact,
database, messaging, mirandamisc, popups,
status. Какой-либо внешней документации я не нашёл, только три примера от автора плагина
на miranda forum‘ах. Впрочем, я
документацию особо и не искал, а воспользовался таким кусочком кода:
import MirPy
import database
from pprint import pprint
MirPy.ConsoleClear()
pprint(database.__dict__)
for k, v in database.__dict__.items():
if v.__doc__:
print k, '::\n', v.__doc__, '\n\n'
Он вывел всю информацию, которая мне впоследствии понадобилась для поставленной задачи.
Если доставать список контактов обычным способом (первый->следующий), то достаются только те контакты, которые и так видны, а затеряные в пучинах так и остаются неведомы. Поэтому я воспользовался брут-форсом и просто перебрал все возможные идентификаторы:
import MirPy
import database
MirPy.ConsoleClear()
# first -> next
contacts = []
contact = database.ContactFindFirst()
while contact:
contacts.append(contact)
contact = database.ContactFindNext(contacts)
print contacts
# brute-force
# needs several tens of seconds to execute
contacts = []
min_cont, max_cont = 0, 25000000
for contact in xrange(min_cont, max_cont):
if database.ContactIs(contact):
contacts_all.append(contact)
print contacts
Первым способом достало 141 контакт, вторым - 467. Дальше, собственно, можно получить всю историю,
а значит, нужно разобраться с форматом событий. У события есть такие параметры: timestamp,
flags, blob, module, eventType. Лезть в исходники
Миранды было лень, и потому я просто поглядел на дамп сырых данных. Результаты:
timestamp- ясное дело, проблем не вызвал; это время события от Эпохиblob- тело сообщенияmodule- строка, которая идентифицирует модуль (протокол). В моём случае - ‘ICQ’, ‘JABBER’.eventType- тип события. 0 - сообщение, 1001 - запрос на авторизацию, 1002 - файл. Других не нашёлflags- разные битовые флаги. Первый бит говорит о том, что это первое сообщение в истории, второй бит - исходящее сообщение, третий бит - исходящее, пятый - юникодное.
import database
from datetime import datetime
DIRECTORY = 'd:\\history\\'
DIRECTORY_PROCESSED = 'd:\\history\\processed\\'
FORMAT_TIME = '%Y-%m-%d %H:%M:%S'
contacts = [9301095]
for contact in contacts:
event = database.EventFindFirst(contact)
if not event:
continue
f = open('%s%d.txt' % (DIRECTORY, contact), 'w')
f_p = open('%s%d.txt' % (DIRECTORY_PROCESSED, contact), 'w')
event_obj = database.EventGet(event)
f_p.write('Module: %s\n\n' % event_obj.module)
while event:
event_obj = database.EventGet(event)
f.write(str(event_obj.__dict__))
f.write('\n')
event_time = datetime.fromtimestamp(event_obj.timestamp).strftime(FORMAT_TIME)
is_utf8 = event_obj.flags & 16
direction = 'IN' if event_obj.flags & 4 else 'OUT'
# first_message = event_obj.flags & 1
try:
event_body = event_obj.blob.decode('utf8' if is_utf8 else 'cp1251')
processed = u'%s %s\n%s\n\n' % (direction, event_time, event_body)
f_p.write(processed.encode('utf8'))
except:
f_p.write('%s %s\n### ERROR ###\n%s\n\n' % (direction, event_time, event_obj.blob))
event = database.EventFindNext(event)
f.close()
f_p.close()
Список контактов надо положить в contacts.
P.S.На всю мою историю нашлось три вхождения ### ERROR ###. Не знаю в чём причина, может
вуглускр покоцал три сообщения :)
P.P.S.Версия миранды - 0.7.1.