最近、Pythonにはまっている。
PHPとかに比べてフォーマットがインデントベースになっていて見通しが良い。 Rubyも同じだけど、Linux系だとほぼ標準で入っているからお名前.com VPSとかでもデフォルト状態ですぐ走らせられるし、Windows EXE化も簡単だったりしてポータビリティも良い。
で、今回、Office365のメールのフルバックアップを取るスクリプトを書いてみた。
POP3でアクセスする場合、Office365では受信トレイしか取れない仕様らしい。
普段OutlookアプリやスマホのExchangeアクセスでフォルダ分けしたりしているから、POP3だとフルバックアップにはならないので、対応策としてIMAP4でアクセスする事になった。
IMAP4のSSL使用アクセスは何の問題も無く簡単に実装できたが、ディレクトリ名がデコードできない。 軽く検索するとIMAPCLIENTと言うパッケージを使うとか言う解決策が示されている程度だった。
で、Pythonの気に入っているポイントはポータビリティの良さなので、実行環境にパッケージを入れずに済ませたいので、仕様を調べて軽く実装してみた。
IMAP4のディレクトリ名は、修正UTF-7形式。
UTF-7のコーデックはPython2.7系に標準で入ってるけど、修正UTF-7は無い。
修正UTF-7ではUTF-7とエンコード対象文字が一部異なる(ディレクトリに使われやすい記号がASCIIのまま。 B64エンコードの開始終了記号が&ではじまり-で終了する等)
B64エンコードの中身は/が,になっている以外は同じみたいなので、元文字列からエンコードされている部分を切り出して、,を/に置換してUTF-7コーデックでデコードして、B64されていない部分と結合していくと言う実装をしてみた。
Decoding the modified UTF-7(i18n IMAP4 directory) to Unicode on the Python2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
def decode_mod_utf7(str): ret = u"" while len(str)>0: if str[0]=='&': if str[1]=='-': ret = ret + '&' str = str[2:] continue str = str[1:] strb64 = "" for j in range(len(str)): if str[j]=='-': str = str[j+1:] break else: strb64 = strb64+str[j] strb64 = strb64.replace(',','/') strb64 = '+'+strb64+'-' ret = ret+ strb64.decode('utf_7') else: ret = ret+str[0] str = str[1:] return ret |
入力文字列を1文字ずつチェックしていくんでfor文かなと思うんだけど、Pythonでfor文中でカウンタを進める方法がわからなかったのでwhile文にした。 処理済みの文字列を随時消していくという処理で、入力文字列長が1未満になるまで回す。
修正UTF-7のルールで、Printableな文字はそのまま通す、非Printableな文字は&で始めるから、先頭文字が&かチェック、ただしソースに&自体がある場合は&-になっているので次の文字が-かチェックしている。
&-じゃなければとりあえず1文字進める(&自体を消す)
-が来るまでB64部分保存用バッファに保存していくループ。 -が来たら1文字進めてループ終了。
修正B64ルールの,と/置換を逆置換してB64ルールにして、バッファ全体をB64として示すために+と-で挟む。
これでUTF-7のB64部分だけになっているはずなので、UTF-7コーデックでデコードしてリターン変数に突っ込む。
あとは、ディレクトリ名を引数にこいつをコールしてやれば、Unicodeなディレクトリ名が戻る。
とりあえず、自分が使ってるExchangeでは問題なくデコードできたけど、斜め読みした仕様をベースに作ってるんでほんとに正しいかは保証しないよ。
(1158)