Pull to refresh

Пишем Addon к Mozilla Thunderbird

Reading time5 min
Views9.4K

Предисловие


Немного допилив exim (в т.ч. заставив его выводить в хэдеры результаты для SPF и DKIM тестов).
Я решил, что было бы хорошо выводить эту (и не только эту информацию в самому почтовом клиенте). И поскольку дополнительных модулей я не искал, то сразу приступил к написанию своего Аддона параллельно изучая, как по мне, то очень запутанную DOM\XUL\Javascript модель работы Thunderbird-a.

Постановка задачи:


Что хотелось видеть в результате работы аддона? Несколько измененный интерфейс где бы была видна информация по DKIM,SPF проверках (pass,none,fail,softfail......), а также Показатель «X-Spam-Score» который бы отображался в виде прогрес-бара и показывал «СПАМОВОСТЬ» конкретного писькаписьма, как ее определил наш серверный антиспам.

Структура


Детальнейшую информацию по начальному построению структуры можно получить здесь(англ.). Поэтому я только коротко остановлюсь на деталях организации:
  1. Создаем install.rdf — где записываем всю официальную информацию об аддоне: Автор, название, версия, тип (расширение, тема и т.д.), поддерживаемые версии Thunderbird-а и т.д.
  2. Создаем chrome.manifest. Тут описываем какие ресурсы будем использовать.
  3. Создаем вполне определенную структуру папок из которых нам понадобится только папка \chrome куда мы поставим файлы JavaScript с логикой и XUL файлы с описанием визуальных элементов. О которых и будет расказано в следующей главе

chrome.manifest в моем случае имеет следующий вид:
content signchk chrome/content/
overlay chrome://messenger/content/msgHdrViewOverlay.xul chrome://signchk/content/signchk.xul

здесь
1. Мы описываем путь к нашим файлам интерфейса и скрипта. которые внутри будут доступны по ссылкам chrome://sigchk/content/…
2. посредством ключевого слова overlay мы говорим что в msgHdrViewOverlay.xul будут добавлены наши визуальные элементы содержащиеся в файле signchk.xul.

Интерфейс работы


Для начала мы создадим XUL-файл со следующим содержанием:
<?xml version="1.0"?>
  <overlay id="signchk" 
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
      <vbox id="singlemessage">
        <hbox>
        <vbox id="SPFbox">
         <label id="spfbox_lbl" value="SPF" />
        </vbox>
        <vbox id="DKIMbox">
         <label id="dkimbox_lbl" value="DKIM" />
        </vbox>
        <box id="MsgProgressBox" pack="end">
        <stack pack="end">
	  <progressmeter mode="determined" value="0" id="auth_progress" max="70"/>
          <hbox align="center" pack="center">
	   <label value="" id="auth_res_lbl" />
	  </hbox>
        </stack>
        </box>
        </hbox>
      </vbox>
      <script type="application/x-javascript" src="chrome://signchk/content/signchk.js" />
</overlay>

Здесь самым главным элементов является корневой vbox id=«singlemessage» так как именно он задает положение где будут размещаться наши дополнительные элементы. Сам id этого элемента можно найти через Инспектор DOM (дополнительный компонент которые позволяет пройтись по дереву элементов интерфейса Thunderbird-а).
После того как мы нашли этот элемент, дальше мы просто добавляем необходимые нам элементы интерфейса и даем из осознанные id-шники чтоб потом можно было легко их найти и управлять.
В последней строке мы делаем ссылку на javascript-файл содержащий логику работы.
(Отступление: Если кто задался вопросом для чего там стоитxmlns=«www.mozilla.org/keymaster/gatekeeper/there.is.only.xul» — просто потому что оно должно там быть. Если там будет стоять что-то другое к примеру как chrome.manifest: chrome://messenger/content/msgHdrViewOverlay.xul, то может произойти переписывание полезного контента и вы получите просто пустой экран. Если же кто-то найдет переведет это определение более правильно, и напишет здесь то я буду только рад)

Логика работы


Для начала мы подготовим почву для работы:
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;

var auth_res_lbl;
var auth_progress;
var spfbox_lbl;
var dkimbox_lbl;

window.addEventListener('load', function(e) { startup(); },false);

function startup() {
 document.getElementById('threadTree').addEventListener("select",selChange,false);
 auth_res_lbl = document.getElementById('auth_res_lbl');
 auth_progress = document.getElementById('auth_progress');
 spfbox_lbl = document.getElementById('spfbox_lbl');
 dkimbox_lbl = document.getElementById('dkimbox_lbl');
}

Здесь мы делаем синонимы на определенные компоненты, объявляем переменные которые будут соответствовать визуальным элементам созданным на предыдущем шаге, делаем их инициализацию и ставим на прослушивание событие event элемента threadTree, который соответствует списку сообщений thunderbird-a.
Далее нам необходимо получить текущее сообщение, прочитать его, выделить заголовки и пропарсить их.
Собственно это и делает следующий код:
function selChange(event) {
 var msgHdr = window.gFolderDisplay.selectedMessage;
 var messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
 var stream = Cc["@mozilla.org/network/sync-stream-listener;1"].createInstance(Ci.nsISyncStreamListener);
 var sis = Cc['@mozilla.org/scriptableinputstream;1'].createInstance(Ci.nsIScriptableInputStream);
 var uri = msgHdr.folder.getUriForMsg(msgHdr);
 sis.init(stream);
 messenger.messageServiceFromURI(uri).streamMessage(uri, stream, null, null, false, null);
 var _message = sis.read(sis.available()); 
 var headers = _message.split(/\r\n\r\n|\r\r|\n\n/, 1)[0];
 var mimeHeaders = Cc["@mozilla.org/messenger/mimeheaders;1"].createInstance(Ci.nsIMimeHeaders);
 mimeHeaders.initialize(headers, headers.length);

После этого мы уже можем выделить любой заголовок и делать с ним все что захотим:
 //spam score
 var res = mimeHeaders.extractHeader("X-Spam-Score", false);
 if(res) { 
	 auth_res_lbl.setAttribute('value',res.split(" ",1)[0]);
	 auth_progress.setAttribute('value',res.split(" ",1)[0]);
 } else {
	 auth_res_lbl.setAttribute('value',"");
	 auth_progress.setAttribute('value',0);
 }
 //spf status
 res = mimeHeaders.extractHeader("Recieved-SPF", false);
 if(res) { 
	 spfbox_lbl.setAttribute('value',"SPF: "+res.split(" ",1)[0]);
 } else {
	 spfbox_lbl.setAttribute('value',"SPF: undefined");
 }
 //dkim status (Authentication-Result)
 res = mimeHeaders.extractHeader("Authentication-Results", false);
 if(res) { 
         var tmp = res.split(", ",1)[0].split("=")[1];
	 dkimbox_lbl.setAttribute('value','DKIM: '+tmp);
 } else {
	 dkimbox_lbl.setAttribute('value',"DKIM: undefined");
 }


В результате у нас получилось вот что:


P.S. После того как работа была закончена то нашелся и обходной путь получения заголовков — правда не такой «спортивный» и зависящий от настроек самого thunderbird-a. Использовать window.currentHeaderData — массив содержащий заголовки текущего сообщения. НО содержимое этой переменной зависит от пункта меню Вид->Заголовки. Так, если в этом пункте выбрано отображение всех заголовков тогда currentHeaderData будет содержать ВСЕ заголовки письма. НО по умолчанию этот режим отключен и не стоит надеяться что у пользователя он будет включен так как это повлияет на отображение заголовков в окне предпросмотра сообщения.

P.P.S.
Большинство информации было почерпнуто из:
https://developer.mozilla.org/en/Building_a_Thunderbird_extension
https://developer.mozilla.org/en/Extensions/Thunderbird/HowTos
http://old.nabble.com/Mozilla---Thunderbird-f6673.html, а конкретно здесь
Tags:
Hubs:
Total votes 31: ↑30 and ↓1+29
Comments12

Articles