Thunderbird 52でnsPreferenceが死んだ話


普段からthunderbirdを利用しているのですが、4/6頃に降ってきたver52に
アップデートしたところ常用していた[confirm-address](https://addons.mozilla.org/ja/thunderbird/addon/confirm-address-5582/)が動かなくなりました。

コンソールでエラーをみていると以下のエラー

```
An error occurred executing the cmd_sendButton command: 
[Exception... "[JavaScript Error: "nsPreferences is not defined" 
{file: "chrome://confirm-mail/content/confirm-mail.js" line: 788}]'
[JavaScript Error: "nsPreferences is not defined"
 {file: "chrome://confirm-mail/content/confirm-mail.js" line: 788}]' 
when calling method: [nsIController::doCommand]"  
nsresult: "0x80570021 (NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS)"  
location: "JS frame :: chrome://global/content/globalOverlay.js :: goDoCommand :: line 100"  data: yes]  g
```

どうやら、アドオンがthunderbirdの設定を読み書きするための`nsPreferences `が未定義になっている模様。これはFirefox52も同じみたいです。

> [XPCOM とモジュール:toolkit/obsolete ディレクトリが削除されました。](https://dev.mozilla.jp/2016/12/firefox-52-addon-compatibility/)
>toolkit/obsolete ディレクトリが削除されました。これには、nsUserSettings.js 内の nsPreferences、strres.js 内の文字列バンドル関数など、古いアドオンで使われているユーティリティーオブジェクトがいくつか含まれます。

FirefoxはAddon-sdkとかXPCOM後発の情報が多いんですが雷鳥はそれが少ないので影響が顕著だったのかと思います。

とりあえず、以下の用に[preferences-service](https://developer.mozilla.org/ja/docs/Code_snippets/Preferences)を使えば設定の読み書きは
できます。

```js
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
                   .getService(Components.interfaces.nsIPrefService)
```

しかし、挙動とかメソッドが`nsPreferences`とちょっと違って単純に置き換えてもだめでした。

* nsPreferencesにあったcopyUnicharPrefがない
* 存在しないキーを指定した際に例外が出る(?)
* Unicodeを保存するインターフェースがちがう(?)

とりあえず、confirm-addressで使われていたnsPreferencesのメソッドだけしか実装してませんが、近い動きができるように以下のようなラッパーをつくってお茶を濁してます。

```js
/**
 * copyやgetは存在しないキーを指定しても例外ではなくデフォルト値や
 * 空文字を戻すのがnsPreferencesの動作のようなのでそれを踏襲
 * できるように例外をハンドリングする
 * 
 */
var customPrefs = {
    orgPrefs: Components.classes["@mozilla.org/preferences-service;1"]
                   .getService(Components.interfaces.nsIPrefService)
                   .getBranch(""),
    copyUnicharPref:function(key, defaultVal){ // 文字列の取得
        
        if(defaultVal === undefined){
            defaultVal = "";
        }
        var val = undefined;
        try{
            val = this.orgPrefs.getComplexValue(key, Components.interfaces.nsISupportsString).data;
        }catch(e){  
            console.log(e);
        }
        if(val !== undefined && val !== ""){
            return val;
        }else{
            return defaultVal;
        }
    },
    setUnicharPref: function(key,val){ // 文字列の保存
        var str = Components.classes["@mozilla.org/supports-string;1"]
                    .createInstance(Components.interfaces.nsISupportsString);
        str.data = val;
        this.orgPrefs.setComplexValue(key, Components.interfaces.nsISupportsString, str);
    },
    getBoolPref: function(key, defaultVal){ // booleanの取得
        try{
            var tmpVal = this.orgPrefs.getBoolPref(key);
            if(tmpVal || tmpVal === "true"){
                return true;
            }else{
                return false;
            }
        }catch(e){
            return defaultVal;
        }
    },
    setBoolPref: function(key,val){ // booleanの保存
        if(val || val === "true"){
            this.orgPrefs.setBoolPref(key, true);
        }else{
            this.orgPrefs.setBoolPref(key, false);
        }
    },
    getIntPref: function(key, defaultVal){ // 数値の取得
        try{
            return this.orgPrefs.getIntPref(key);
        }catch(e){
            return defaultVal;
        }
    },
    setIntPref: function(key, val){ // 数値の保存
        this.orgPrefs.setIntPref(key, val);
    },
};
```

一応これで

```js

var settingStr = customPrefs.copyUnicharPref("hoge.foo.bar", "defalt val");
```

みたいな感じでnsPreferencesの置き換えはできています。あくまでとりあえず動く。という程度のものですが、雷鳥周りの日本語情報って少ないのでどなたかの参考になれば幸いです。