-;;;
-;;; Gnus MIME viewing functions
-;;;
-
-(defvar gnus-mime-button-line-format "%{%([%p. %t%d%n]%)%}%e\n"
- "The following specs can be used:
-%t The MIME type
-%n The `name' parameter
-%d The description, if any
-%l The length of the encoded part
-%p The part identifier
-%e Dots if the part isn't displayed")
-
-(defvar gnus-mime-button-line-format-alist
- '((?t gnus-tmp-type ?s)
- (?n gnus-tmp-name ?s)
- (?d gnus-tmp-description ?s)
- (?p gnus-tmp-id ?s)
- (?l gnus-tmp-length ?d)
- (?e gnus-tmp-dots ?s)))
-
-(defvar gnus-mime-button-commands
- '((gnus-article-press-button "\r" "Toggle Display")
- ;(gnus-mime-view-part "\M-\r" "View Interactively...")
- (gnus-mime-view-part "v" "View Interactively...")
- (gnus-mime-save-part "o" "Save...")
- (gnus-mime-copy-part "c" "View In Buffer")
- (gnus-mime-inline-part "i" "View Inline")
- (gnus-mime-pipe-part "|" "Pipe To Command...")))
-
-(defvar gnus-mime-button-map nil)
-(unless gnus-mime-button-map
- (setq gnus-mime-button-map (make-sparse-keymap))
- (set-keymap-parent gnus-mime-button-map gnus-article-mode-map)
- (define-key gnus-mime-button-map gnus-mouse-2 'gnus-article-push-button)
- (define-key gnus-mime-button-map gnus-mouse-3 'gnus-mime-button-menu)
- (mapcar (lambda (c)
- (define-key gnus-mime-button-map (cadr c) (car c)))
- gnus-mime-button-commands))
-
-(defun gnus-mime-button-menu (event)
- "Construct a context-sensitive menu of MIME commands."
- (interactive "e")
- (let ((response (x-popup-menu
- t `("MIME Part"
- ("" ,@(mapcar (lambda (c)
- (cons (caddr c) (car c)))
- gnus-mime-button-commands)))))
- (pos (event-start event)))
- (when response
- (set-buffer (window-buffer (posn-window pos)))
- (goto-char (posn-point pos))
- (funcall response))))
-
-(defun gnus-mime-view-all-parts ()
- "View all the MIME parts."
- (interactive)
- (let ((handles gnus-article-mime-handles))
- (while handles
- (mm-display-part (pop handles)))))
-
-(defun gnus-mime-save-part ()
- "Save the MIME part under point."
- (interactive)
- (let ((data (get-text-property (point) 'gnus-data)))
- (mm-save-part data)))
-
-(defun gnus-mime-pipe-part ()
- "Pipe the MIME part under point to a process."
- (interactive)
- (let ((data (get-text-property (point) 'gnus-data)))
- (mm-pipe-part data)))
-
-(defun gnus-mime-view-part ()
- "Interactively choose a view method for the MIME part under point."
- (interactive)
- (let ((data (get-text-property (point) 'gnus-data))
- (url-standalone-mode (not gnus-plugged)))
- (mm-interactively-view-part data)))
-
-(defun gnus-mime-copy-part ()
- "Put the the MIME part under point into a new buffer."
- (interactive)
- (let* ((handle (get-text-property (point) 'gnus-data))
- (contents (mm-get-part handle))
- (buffer (generate-new-buffer
- (file-name-nondirectory
- (or
- (mail-content-type-get (mm-handle-type handle) 'name)
- (mail-content-type-get (mm-handle-type handle)
- 'filename)
- "*decoded*")))))
- (switch-to-buffer buffer)
- (insert contents)
- (normal-mode)
- (goto-char (point-min))))
-
-(defun gnus-mime-inline-part ()
- "Insert the MIME part under point into the current buffer."
- (interactive)
- (let* ((data (get-text-property (point) 'gnus-data))
- (contents (mm-get-part data))
- (url-standalone-mode (not gnus-plugged))
- (b (point))
- buffer-read-only)
- (if (mm-handle-undisplayer data)
- (mm-remove-part data)
- (forward-line 2)
- (mm-insert-inline data contents)
- (goto-char b))))
-
-(defun gnus-article-view-part (n)
- "View MIME part N, which is the numerical prefix."
- (interactive "p")
- (save-current-buffer
- (set-buffer gnus-article-buffer)
- (when (> n (length gnus-article-mime-handle-alist))
- (error "No such part"))
- (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
- (gnus-article-goto-part n)
- (if (equal (car handle) "multipart/alternative")
- (gnus-article-press-button)
- (when (eq (gnus-mm-display-part handle) 'internal)
- (gnus-set-window-start))))))
-
-(defun gnus-mm-display-part (handle)
- "Display HANDLE and fix MIME button."
- (let ((id (get-text-property (point) 'gnus-part))
- (point (point))
- buffer-read-only)
- (delete-region (gnus-point-at-bol) (progn (forward-line 1) (point)))
- (gnus-insert-mime-button
- handle id (list (not (mm-handle-displayed-p handle))))
- (prog1
- (mm-display-part handle)
- (goto-char point))))
-
-(defun gnus-article-goto-part (n)
- "Go to MIME part N."
- (goto-char (text-property-any (point-min) (point-max) 'gnus-part n)))
-
-(defun gnus-insert-mime-button (handle gnus-tmp-id &optional displayed)
- (let ((gnus-tmp-name (mail-content-type-get (mm-handle-type handle) 'name))
- (gnus-tmp-type (car (mm-handle-type handle)))
- (gnus-tmp-description (mm-handle-description handle))
- (gnus-tmp-dots
- (if (if displayed (car displayed)
- (mm-handle-displayed-p handle))
- "" "..."))
- (gnus-tmp-length (save-excursion
- (set-buffer (mm-handle-buffer handle))
- (buffer-size)))
- b e)
- (setq gnus-tmp-name
- (if gnus-tmp-name
- (concat " (" gnus-tmp-name ")")
- ""))
- (setq gnus-tmp-description
- (if gnus-tmp-description
- (concat " (" gnus-tmp-description ")")
- ""))
- (setq b (point))
- (gnus-eval-format
- gnus-mime-button-line-format gnus-mime-button-line-format-alist
- `(local-map ,gnus-mime-button-map
- keymap ,gnus-mime-button-map
- gnus-callback gnus-mm-display-part
- gnus-part ,gnus-tmp-id
- article-type annotation
- gnus-data ,handle))
- (setq e (point))
- (widget-convert-button 'link b e :action 'gnus-widget-press-button
- :button-keymap gnus-mime-button-map)))
-
-(defun gnus-widget-press-button (elems el)
- (goto-char (widget-get elems :from))
- (let ((url-standalone-mode (not gnus-plugged)))
- (gnus-article-press-button)))
-
-(defun gnus-display-mime (&optional ihandles)
- "Insert MIME buttons in the buffer."
- (let* ((handles (or ihandles (mm-dissect-buffer) (mm-uu-dissect)))
- handle name type b e display)
- (when handles
- (unless ihandles
- ;; Top-level call; we clean up.
- (mm-destroy-parts gnus-article-mime-handles)
- (setq gnus-article-mime-handles handles
- gnus-article-mime-handle-alist nil)
- (goto-char (point-min))
- (search-forward "\n\n" nil t)
- (delete-region (point) (point-max)))
- (if (stringp (car handles))
- (if (equal (car handles) "multipart/alternative")
- (gnus-mime-display-alternative (cdr handles))
- (gnus-mime-display-mixed (cdr handles)))
- (gnus-mime-display-single handles)))))
-
-(defun gnus-mime-display-mixed (handles)
- (let (handle)
- (while (setq handle (pop handles))
- (if (stringp (car handle))
- (if (equal (car handle) "multipart/alternative")
- (let ((id (1+ (length gnus-article-mime-handle-alist))))
- (push (cons id handle) gnus-article-mime-handle-alist)
- (gnus-mime-display-alternative (cdr handle) nil nil id))
- (gnus-mime-display-mixed (cdr handle)))
- (gnus-mime-display-single handle)))))
-
-(defun gnus-mime-display-single (handle)
- (let ((type (car (mm-handle-type handle)))
- (ignored gnus-ignored-mime-types)
- display text)
- (catch 'ignored
- (progn
- (while ignored
- (when (string-match (pop ignored) type)
- (throw 'ignored nil)))
- (if (and (mm-automatic-display-p type)
- (mm-inlinable-part-p type)
- (or (not (mm-handle-disposition handle))
- (equal (car (mm-handle-disposition handle))
- "inline")))
- (setq display t)
- (when (equal (car (split-string type "/"))
- "text")
- (setq text t)))
- (let ((id (1+ (length gnus-article-mime-handle-alist))))
- (push (cons id handle) gnus-article-mime-handle-alist)
- (gnus-insert-mime-button handle id (list (or display text))))
- (insert "\n\n")
- (cond
- (display
- (forward-line -2)
- (mm-display-part handle t)
- (goto-char (point-max)))
- (text
- (forward-line -2)
- (insert "\n")
- (mm-insert-inline handle (mm-get-part handle))
- (goto-char (point-max))))))))
-
-(defun gnus-mime-display-alternative (handles &optional preferred ibegend id)
- (let* ((preferred (mm-preferred-alternative handles preferred))
- (ihandles handles)
- (point (point))
- handle buffer-read-only from props begend not-pref)
- (save-restriction
- (when ibegend
- (narrow-to-region (car ibegend) (cdr ibegend))
- (delete-region (point-min) (point-max))
- (mm-remove-parts handles))
- (setq begend (list (point-marker)))
- ;; Do the toggle.
- (unless (setq not-pref (cadr (member preferred ihandles)))
- (setq not-pref (car ihandles)))
- (gnus-add-text-properties
- (setq from (point))
- (progn
- (insert (format "%d. " id))
- (point))
- `(gnus-callback
- (lambda (handles)
- (gnus-mime-display-alternative
- ',ihandles ,(if (stringp (car not-pref))
- (car not-pref)
- (car (mm-handle-type not-pref)))
- ',begend ,id))
- local-map ,gnus-mime-button-map
- ,gnus-mouse-face-prop ,gnus-article-mouse-face
- face ,gnus-article-button-face
- keymap ,gnus-mime-button-map
- gnus-part ,id
- gnus-data ,handle))
- (widget-convert-button 'link from (point)
- :action 'gnus-widget-press-button
- :button-keymap gnus-widget-button-keymap)
- ;; Do the handles
- (while (setq handle (pop handles))
- (gnus-add-text-properties
- (setq from (point))
- (progn
- (insert (format "[%c] %-18s"
- (if (equal handle preferred) ?* ? )
- (if (stringp (car handle))
- (car handle)
- (car (mm-handle-type handle)))))
- (point))
- `(gnus-callback
- (lambda (handles)
- (gnus-mime-display-alternative
- ',ihandles ,(if (stringp (car handle))
- (car handle)
- (car (mm-handle-type handle)))
- ',begend ,id))
- local-map ,gnus-mime-button-map
- ,gnus-mouse-face-prop ,gnus-article-mouse-face
- face ,gnus-article-button-face
- keymap ,gnus-mime-button-map
- gnus-part ,id
- gnus-data ,handle))
- (widget-convert-button 'link from (point)
- :action 'gnus-widget-press-button
- :button-keymap gnus-widget-button-keymap)
- (insert " "))
- (insert "\n\n")
- (when preferred
- (if (stringp (car preferred))
- (gnus-display-mime preferred)
- (mm-display-part preferred)
- (goto-char (point-max))
- (setcdr begend (point-marker)))))
- (when ibegend
- (goto-char point))))
-