;;; mmimap.el --- MIME entity module for IMAP4rev1 (RFC2060). ;; **** This is EXPERIMENTAL ***** ;; Copyright (C) 2000 Yuuichi Teranishi ;; Author: Yuuichi Teranishi ;; Keywords: IMAP, MIME, multimedia, mail, news ;; This file is part of FLIM (Faithful Library about Internet Message). ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2, or (at ;; your option) any later version. ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; ;;; Code: (require 'mmgeneric) (require 'mime) (require 'pces) (require 'static) (require 'mime-parse) (eval-and-compile (luna-define-class mime-imap-entity (mime-entity) (size header-string body-string new requested)) (luna-define-internal-accessors 'mime-imap-entity)) ;;; @ MIME IMAP location ;; It should contain server, mailbox and uid (sequence number). (eval-and-compile (luna-define-class mime-imap-location () ())) (luna-define-generic mime-imap-location-section-body (location section) "Return a body string from LOCATION which corresponds to SECTION. SECTION is a section string which is defined in RFC2060.") (luna-define-generic mime-imap-location-bodystructure (location) "Return a parsed bodystructure of LOCATION. `NIL' should be converted to nil, `astring' should be converted to a string.") (luna-define-generic mime-imap-location-fetch-entity-p (location entity) "Return non-nil when LOCATION may fetch the ENTITY.") ;;; @ Subroutines ;; (defun mmimap-entity-section (node-id) "Return a section string from NODE-ID" (cond ((numberp node-id) (number-to-string (1+ node-id))) ((listp node-id) (mapconcat 'mmimap-entity-section (reverse node-id) ".")))) (eval-and-compile (defun-maybe mime-decode-parameters (attrlist) (let (ret-val) (while attrlist (setq ret-val (append ret-val (list (cons (downcase (car attrlist)) (car (cdr attrlist)))))) (setq attrlist (cdr (cdr attrlist)))) ret-val))) (defun mmimap-make-mime-entity (bodystructure class location node-id number parent) "Analyze parsed IMAP4 BODYSTRUCTURE response and make MIME entity. CLASS, LOCATION, NODE-ID, PARENT are set to the returned entity." (cond ((listp (car bodystructure)) ; multipart (let ((num 0) curp children content-type entity) (setq entity (luna-make-entity class :new t :parent parent :location location :node-id (if (eq number 0) node-id (nconc (list number) node-id)))) (while (and (setq curp (car bodystructure)) (listp curp)) (setq children (nconc children (list (mmimap-make-mime-entity curp class location (if (eq number 0) node-id (nconc (list number) node-id)) num entity)))) (setq num (+ num 1)) (setq bodystructure (cdr bodystructure))) (mime-entity-set-children-internal entity children) (mime-entity-set-content-type-internal entity (make-mime-content-type 'multipart (if (car bodystructure) (intern (downcase (car bodystructure)))) (mime-decode-parameters (nth 1 bodystructure)))) entity)) (t ; singlepart (let (content-type entity) (setq node-id (nconc (list number) node-id)) (setq entity (luna-make-entity class :new t :size (nth 6 bodystructure) :content-type content-type :location location :parent parent :node-id node-id)) (mime-entity-set-content-type-internal entity (make-mime-content-type (intern (downcase (car bodystructure))) (if (nth 1 bodystructure) (intern (downcase (nth 1 bodystructure)))) (mime-decode-parameters (nth 2 bodystructure)))) (mime-entity-set-encoding-internal entity (and (nth 5 bodystructure) (downcase (nth 5 bodystructure)))) (if (and (nth 7 bodystructure) (nth 8 bodystructure)) ; children. (mime-entity-set-children-internal entity (list (mmimap-make-mime-entity (nth 8 bodystructure) class location node-id 0 entity)))) entity)))) (luna-define-method initialize-instance :after ((entity mime-imap-entity) &rest init-args) ;; To prevent infinite loop... (if (mime-imap-entity-new-internal entity) entity (mmimap-make-mime-entity (mime-imap-location-bodystructure (mime-entity-location-internal entity)) (luna-class-name entity) (mime-entity-location-internal entity) nil 0 nil))) ;;; @ entity ;; (luna-define-method mime-insert-entity ((entity mime-imap-entity)) (if (mime-root-entity-p entity) (progn (insert (mime-imap-entity-header-string entity)) (mime-insert-entity-body entity)) ;; Insert body if it is not a multipart. (unless (eq (mime-content-type-primary-type (mime-entity-content-type entity)) 'multipart) (mime-insert-entity-body entity)))) (luna-define-method mime-write-entity ((entity mime-imap-entity) filename) (with-temp-buffer (mime-insert-entity entity) (write-region-as-raw-text-CRLF (point-min) (point-max) filename))) ;;; @ entity body ;; (luna-define-method mime-entity-body ((entity mime-imap-entity)) (or (mime-imap-entity-body-string-internal entity) (if (or (mime-imap-entity-requested-internal entity) ; second time. (mime-imap-location-fetch-entity-p (mime-entity-location-internal entity) entity)) (mime-imap-entity-set-body-string-internal entity (mime-imap-location-section-body (mime-entity-location-internal entity) (mmimap-entity-section (mime-entity-node-id-internal entity)))) (mime-imap-entity-set-requested-internal entity t) ""))) (luna-define-method mime-insert-entity-body ((entity mime-imap-entity)) (insert (mime-entity-body entity))) (luna-define-method mime-write-entity-body ((entity mime-imap-entity) filename) (with-temp-buffer (mime-insert-entity-body entity) (write-region-as-binary (point-min) (point-max) filename))) ;;; @ entity content ;; (luna-define-method mime-entity-content ((entity mime-imap-entity)) (let ((ret (mime-entity-body entity))) (if ret (mime-decode-string ret (mime-entity-encoding entity)) (message "Cannot decode content.") nil))) (luna-define-method mime-insert-entity-content ((entity mime-imap-entity)) (insert (mime-entity-content entity))) (luna-define-method mime-write-entity-content ((entity mime-imap-entity) filename) (with-temp-buffer (mime-insert-entity-body entity) (mime-write-decoded-region (point-min) (point-max) filename (or (mime-entity-encoding entity) "7bit")))) ;;; @ header field ;; (defun mime-imap-entity-header-string (entity) (or (mime-imap-entity-header-string-internal entity) (mime-imap-entity-set-header-string-internal entity (mime-imap-location-section-body (mime-entity-location-internal entity) (if (if (eq (car (mime-entity-node-id-internal entity)) 0) (cdr (mime-entity-node-id-internal entity)) (mime-entity-node-id-internal entity)) (concat (mmimap-entity-section (if (eq (car (mime-entity-node-id-internal entity)) 0) (cdr (mime-entity-node-id-internal entity)) (mime-entity-node-id-internal entity))) ".HEADER") "HEADER"))))) (luna-define-method mime-entity-fetch-field :around ((entity mime-imap-entity) field-name) (if (mime-root-entity-p entity) (or (luna-call-next-method) (with-temp-buffer (insert (mime-imap-entity-header-string entity)) (let ((ret (std11-fetch-field field-name))) (when ret (or (symbolp field-name) (setq field-name (intern (capitalize (capitalize field-name))))) (mime-entity-set-original-header-internal entity (put-alist field-name ret (mime-entity-original-header-internal entity))) ret)))))) (luna-define-method mime-insert-header ((entity mime-imap-entity) &optional invisible-fields visible-fields) (let ((the-buf (current-buffer)) buf p-min p-max) (with-temp-buffer (insert (mime-imap-entity-header-string entity)) (setq buf (current-buffer) p-min (point-min) p-max (point-max)) (set-buffer the-buf) (mime-insert-header-from-buffer buf p-min p-max invisible-fields visible-fields)))) ;;; @ end ;; (provide 'mmimap) ;;; mmimap.el ends here