[mew-dist 29226] 受け取った暗号化 Zip の内容を Mew のメッセージバッファに表示する

Kiyoto Hamano kiyoto at example.com
2010年 5月 13日 (木) 19:11:20 JST


濱野と申します。

暗号化 Zip ファイルでメール本文をやり取りする事があり、その内容を
Mew のメッセージバッファで見たいと考え、添付の elisp を作成して使っ
ています。今回、Zip の暗号化機能が搭載されたとあり、問題点は数多く
残ってはおりますが、思い切って投稿してみます。

主な機能は、以下の通りです。

 メールに添付された暗号化 Zip ファイルを裏で zip コマンドを使用し
 て解凍し、解凍したファイルの内容をメッセージバッファに表示する。
 解凍後のファイルが複数あれば、その中からどのファイルをメッセージ
 バッファに表示するかを選択し、選択したファイルを表示する。

利点は、端末に戻ってパスワードを入力して Zip ファイルを解凍、そして閲覧、
という動作を Emacs 内で完結できる点です。

現状はらんでいる主な問題点は、以下の通りです。

 * Mew 6.3 と Mew 4.2 でのみしか動かない。
 * パスワードを間違えた事を検知できない。
 * パスワードを間違って記憶させると、クリアするコマンドが無い。
 * このディレクトリでは、このパスワードのような組み合わせができない。
 * などなど

よろしければ、どうぞ。

-- 
HAMANO Kiyoto
kiyoto at example.com


-------------- next part --------------
;; -*- Coding:iso-2022-jp; Mode:Emacs-lisp -*-

;; version: 0.4
;; created by HAMANO Kiyoto <kiyoto at example.com>

;; 概要:
;;
;; パスワードつき Zip で圧縮されたメッセージを Mew の *Mew message* バッ
;; ファに表示する。
;;
;; (*) まだバグが多々あると思われます。
;;
;;
;; 使用法:
;;
;; load-path の通ったディレクトリにこのファイルを置き、.emacs に以下の
;; 設定を足す。
;;
;; (require 'mew-dispzip)
;; ;; summary-mode で C-cy でを押す事でzipファイルを解凍し、表示する
;; (add-hook
;;  'mew-summary-mode-hook
;;  (lambda ()
;;    (define-key mew-summary-mode-map "\C-cy"
;;      'mew-dispzip-summary-execute-command)))
;;
;; C-cy を押すのは、# で作られた文字で大きく Binary と書かれているバッ
;; ファ(*Mew summary*)が表示されている状態で行う。解凍したファイルが 1 
;; つのみならば、ただちにそのファイルを表示し、複数ファイルの場合は、
;; どのファイルを表示するかを選択する。
;;
;;
;; 設定:
;;
;; * パスワードの保存
;; パスワードを入力したくない場合は、mew-dispzip-unzip-password にパス
;; ワードを設定する。
;;
;; (setq mew-dispzip-unzip-password "hogehoge")
;;
;; * 一度パスワードを入力したら、キャッシュする
;; パスワードを一度入力したら、上記 mew-dispzip-unzip-password に保存
;; したい場合、mew-dispzip-unzip-password-caching を t にする。
;; (.emacs にパスワードを書きたくない場合)
;;
;; (setq mew-dispzip-unzip-password-caching t)
;;
;; * 展開した zip ファイルの内容を保存するディレクトリを変更する
;; 解凍した zip ファイルの内容を置くディレクトリを変更する場合、
;; mew-dispzip-save-dir の値を変更する。
;; (注) このディレクトリを作成する際、パーミッションの設定は特に行うよ
;;      うにしていない。
;;
;; ;; mew-dispzip-directory-clear 関数でクリアするとこのディレクトリ以
;; ;; 下の内容がまるごと削除される可能性があるので、他にファイルのある
;; ;; ディレクトリを指定してはいけない。
;; (setq mew-dispzip-save-dir "/home/foo/.archive")
;;
;; * 展開した zip ファイルの内容を保存しない
;; 毎回 zip ファイルを解凍し、解凍し終わったら、作成したディレクトリ・
;; ファイルを削除するようにする。
;;
;; (setq mew-dispzip-unzip-caching nil)
;;
;;
;; 必要物:
;;
;; * unzip コマンド
;; * mew
;;
;;
;; TODO:
;;
;; * *Mew message* バッファに表示するファイルが txt であるかどうかを確
;;   認する(現在は確認せず insert している)。
;; * Mail のあるディレクトリ毎に使用するパスワードを変える仕組み(不要?)
;; * 入力した password があっていたかどうかの確認処理
;;   * 難しいならば、password のキャッシュを削除する処理
;; * 別のディレクトリへzipファイルを見たメールを移動した場合の考慮
;;   * 毎回 unzip するオプションを追加した
;;     * その場合、mew-dispzip-save-dir に指定されたディレクトリを毎度
;;     削除する。
;; * コメントの追加
;; * 関数名・変数名の修正
;;   * だいたい行った
;;
;; ChangeLog:
;;
;; 0.4: Emacs 23.1 + Mew 6.3 暫定対応
;;
;; テスト環境:
;;
;; * emacs 23.1 + mew 6.3
;;

(require 'mew)

;; Variables:

(defvar mew-dispzip-unzip-command "unzip")
(defvar mew-dispzip-unzip-options '("-o"
                                    (concat "-P" mew-dispzip-unzip-password)
                                    (concat "-d" mew-dispzip-save-dir)))
(defvar mew-dispzip-unzip-password nil)
(defvar mew-dispzip-unzip-password-caching nil)
(defvar mew-dispzip-save-dir (concat (getenv "HOME")
                                     "/"
                                     ".mew-dispzip-archive")
  "*Zip ファイルを解凍した内容が収められるディレクトリ。
`mew-dispzip-unzip-caching' が nil のとき、このディレクトリは、解
凍の都度削除されるので、解凍した Zip ファイル以外に内容があるディ
レクトリを指定してはいけない。")
(defvar mew-dispzip-unzip-caching t)

;; Functions:

(defun mew-dispzip-directory-clear (&optional dir no-confirm)
  (interactive)
  (let* ((d (if dir
                dir
              mew-dispzip-save-dir))
         (files (mew-dispzip-directory-files d t)))
    (when (or no-confirm
              (yes-or-no-p (format "Delete the dir %s (yes/no):"
                                   d)))
      (message "Delete files...")
      (dolist (i files)
        (setq i (format "%s/%s" d i))
        (cond
         ((file-directory-p i)
          (delete-directory i))
         (t
          (delete-file i))))
      (delete-directory d)
      (message "Delete files...done"))))

(defun mew-dispzip-directory-files (dir &optional include-directory)
  (let ((mew-dispzip-directory-files-internal
         '(lambda (din &optional subdir)
            (let ((d din))
              (if subdir
                  (progn
                    (setq d (concat d "/" subdir))
                    (if include-directory
                        (setq files (cons (format "%s/" subdir)
                                          files)))))
              (dolist (i (directory-files d))
                (cond
                 ((file-directory-p (concat d "/" i))
                  (unless (or (member i '("." "..")))
                    (funcall mew-dispzip-directory-files-internal
                             din
                             (concat subdir "/" i))))
                 (t
                  (cond
                   (subdir
                    (setq files (cons (format "%s/%s" subdir i)
                                      files)))
                   (t
                    (setq files (cons (format "%s" i)
                                      files))))))))))
        files)
    (funcall mew-dispzip-directory-files-internal dir)
    files))

(defun mew-dispzip-summary-concat-options ()
  (let ((password (if mew-dispzip-unzip-password
                      mew-dispzip-unzip-password
                    (read-passwd "Password: "))))
    (when (and mew-dispzip-unzip-password-caching
               (null mew-dispzip-unzip-password))
      ;; set password to global
      (setq mew-dispzip-unzip-password password))
    (let ((optstring "")
          ;; set password to local
          (mew-dispzip-unzip-password password))
      (dolist (i mew-dispzip-unzip-options)
        (cond
         ((and (listp i)
               (symbolp (car i)))
          (setq optstring (concat optstring " " (eval i))))
         (t
          (setq optstring (concat optstring " " i)))))
      optstring)))

;; for mew 6.3
(defun my-mew-dispzip-summary-execute-external (program options)
  (mew-summary-msg-or-part
   (let* ((fld    (mew-summary-folder-name))
	  (msg    (mew-summary-message-number2))
	  (nums   (mew-syntax-nums))
	  (cache  (mew-cache-hit fld msg 'must-hit))
	  (syntax (mew-cache-decode-syntax cache))
	  (stx    (mew-syntax-get-entry syntax nums))
	  (ctl    (mew-syntax-get-ct stx))
	  (ct     (mew-syntax-get-value ctl 'cap))
	  (win    (selected-window))
	  (begin  (mew-syntax-get-begin stx))
          (end    (mew-syntax-get-end stx))
          (params (mew-syntax-get-params ctl))
          (cdpl   (mew-syntax-get-cdp stx))
          (fname  (mew-syntax-get-filename cdpl ctl)))
     (mew-summary-toggle-disp-msg 'on)
     (mew-window-configure 'message)
     ;; message buffer
     (unwind-protect
	 (mew-elet
          ;; nil or t
          (mew-summary-execute-program
           program ct ctl cache begin end params fname options t)
	  (mew-summary-display-postscript 'no-hook))
       (select-window win)))))

(defun mew-dispzip-summary-execute-command (&optional arg)
  "zip ファイルを解凍し、*Mew message* バッファに表示する。一度解凍し
たファイルは、mew-dispzip-save-dir にキャッシュされ、以後、そのファイルが使
われる。unzip し直したい場合は、前置引数(C-u など)をつけてこの関数を実
行する。"
  (interactive "P")
  (let* ((num (mew-summary-message-number2))
         (dir (substring (mew-summary-folder-name) 1))
         (mew-dispzip-save-dir
          (concat mew-dispzip-save-dir
                  (unless (equal "/"
                                 (substring mew-dispzip-save-dir
                                            (1- (length mew-dispzip-save-dir))))
                    "/")
                  dir
                  "/"
                  num))
         filenum
         selected)
    ;; clear unzip cache
    (when (and (null mew-dispzip-unzip-caching)
               (file-exists-p mew-dispzip-save-dir))
      (mew-dispzip-directory-clear mew-dispzip-save-dir t)
      (message ""))                     ; clear minibuffer
    ;; directory don't exist.
    (unless (file-exists-p mew-dispzip-save-dir)
      (make-directory mew-dispzip-save-dir t)
      (unless (file-exists-p mew-dispzip-save-dir)
        (error "make-directory")))
    ;; do unzip
    (when (or arg
              (= 2 (length (directory-files mew-dispzip-save-dir))))
      (when (and num dir mew-dispzip-save-dir)
        (mew-summary-msg-or-part
         (cond
          ((string= mew-version-number "4.2")
           (mew-summary-execute-base
            nil
            mew-dispzip-unzip-command
            (delete "" (mew-split-quoted (mew-dispzip-summary-concat-options)
                                         mew-sp
                                         ?\"
                                         ?\"))))
         ((string= mew-version-number "6.3")
          (my-mew-dispzip-summary-execute-external
           mew-dispzip-unzip-command
           (delete "" (mew-split-quoted (mew-dispzip-summary-concat-options)
                                        mew-sp
                                        ?\"
                                        ?\"))))))
        (sit-for 0.1)))                 ; force sync...
    ;; select file
    (setq filenum (length (mew-dispzip-directory-files mew-dispzip-save-dir)))
    (when (> filenum 0)
      (setq selected
            (cond
             ((= filenum 1)
              (car (nthcdr 2 (directory-files mew-dispzip-save-dir))))
             (t
              (completing-read
               "Select File: "
               (mapcar 'list
                       (mew-dispzip-directory-files mew-dispzip-save-dir))
               nil
               t))))
      ;; display selected file to *Mew message* buffer.
      (let ((cwin (get-buffer-window (current-buffer)))
            (mwin (get-buffer-window (mew-buffer-message))))
        (when mwin
          (select-window mwin)
          (unwind-protect
              (progn
                (setq buffer-read-only nil)
                (erase-buffer)
                (mew-message-clear-end-of)
                (insert (with-current-buffer (find-file-noselect
                                              (concat mew-dispzip-save-dir
                                                      "/"
                                                      selected))
                          (buffer-string)))
                (mew-message-set-end-of)
                (goto-char (point-min)))
            (progn (setq buffer-read-only t)
                   (select-window cwin)))))
      ;; clear unzip cache
      (when (and (null mew-dispzip-unzip-caching)
                 (file-exists-p mew-dispzip-save-dir))
        (mew-dispzip-directory-clear mew-dispzip-save-dir t)
        (message "")))))                ; clear minibuffer

(provide 'mew-dispzip)
;; mew-dispzip.el ends here


Mew-dist メーリングリストの案内