X-Git-Url: http://cgit.sxemacs.org/?p=gnus;a=blobdiff_plain;f=lisp%2Fmm-url.el;h=0da136e1efcfff2e465c3cb1a5166cb031b66f5b;hp=561f89aea80b3b92dd35e09e99eeebc04fcac0cd;hb=123adcf9b783e574789164bc5e3df6a1a4528c31;hpb=28fbd9104a37c092b00d271f18d088f48c17069d diff --git a/lisp/mm-url.el b/lisp/mm-url.el index 561f89aea..0da136e1e 100644 --- a/lisp/mm-url.el +++ b/lisp/mm-url.el @@ -1,24 +1,24 @@ ;;; mm-url.el --- a wrapper of url functions/commands for Gnus -;; Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +;; Free Software Foundation, Inc. ;; Author: Shenghuo Zhu ;; This file is part of GNU Emacs. -;; GNU Emacs 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. +;; GNU Emacs 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 3 of the License, or +;; (at your option) any later version. -;; GNU Emacs 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. +;; GNU Emacs 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. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -34,8 +34,9 @@ (require 'mm-util) (require 'gnus) -(eval-and-compile - (autoload 'executable-find "executable")) +(defvar url-current-object) +(defvar url-package-name) +(defvar url-package-version) (defgroup mm-url nil "A wrapper of url package and external url command for Gnus." @@ -45,15 +46,16 @@ (condition-case nil (require 'url) (error nil))) - "*If not-nil, use external grab program `mm-url-program'." + "*If non-nil, use external grab program `mm-url-program'." + :version "22.1" :type 'boolean :group 'mm-url) (defvar mm-url-predefined-programs - '((wget "wget" "-q" "-O" "-") + '((wget "wget" "--user-agent=mm-url" "-q" "-O" "-") (w3m "w3m" "-dump_source") (lynx "lynx" "-source") - (curl "curl"))) + (curl "curl" "--silent" "--user-agent" "mm-url" "--location"))) (defcustom mm-url-program (cond @@ -62,7 +64,9 @@ ((executable-find "lynx") 'lynx) ((executable-find "curl") 'curl) (t "GET")) - "The url grab program." + "The url grab program. +Likely values are `wget', `w3m', `lynx' and `curl'." + :version "22.1" :type '(choice (symbol :tag "wget" wget) (symbol :tag "w3m" w3m) @@ -73,6 +77,7 @@ (defcustom mm-url-arguments nil "The arguments for `mm-url-program'." + :version "22.1" :type '(repeat string) :group 'mm-url) @@ -262,32 +267,58 @@ This is taken from RFC 2396.") (defun mm-url-load-url () "Load `url-insert-file-contents'." (unless (condition-case () - (require 'url-handlers) + (progn + (require 'url-handlers) + (require 'url-parse) + (require 'url-vars)) (error nil)) ;; w3-4.0pre0.46 or earlier version. (require 'w3-vars) (require 'url))) +;;;###autoload (defun mm-url-insert-file-contents (url) + "Insert file contents of URL. +If `mm-url-use-external' is non-nil, use `mm-url-program'." (if mm-url-use-external - (if (string-match "^file:/+" url) - (insert-file-contents (substring url (1- (match-end 0)))) - (mm-url-insert-file-contents-external url)) + (progn + (if (string-match "^file:/+" url) + (insert-file-contents (substring url (1- (match-end 0)))) + (mm-url-insert-file-contents-external url)) + (goto-char (point-min)) + (if (fboundp 'url-generic-parse-url) + (setq url-current-object + (url-generic-parse-url url))) + (list url (buffer-size))) (mm-url-load-url) (let ((name buffer-file-name) + (url-request-extra-headers + ;; ISTM setting a Connection header was a workaround for + ;; older versions of url included with w3, but it does more + ;; harm than good with the one shipped with Emacs. --ansel + (if (not (and (boundp 'url-version) + (equal url-version "Emacs"))) + (list (cons "Connection" "Close")))) (url-package-name (or mm-url-package-name url-package-name)) (url-package-version (or mm-url-package-version - url-package-version))) - (prog1 - (url-insert-file-contents url) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "\r 1000\r ?" nil t) - (replace-match ""))) - (setq buffer-file-name name))))) - + url-package-version)) + result) + (setq result (url-insert-file-contents url)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "\r 1000\r ?" nil t) + (replace-match ""))) + (setq buffer-file-name name) + (if (and (fboundp 'url-generic-parse-url) + (listp result)) + (setq url-current-object (url-generic-parse-url + (car result)))) + result))) + +;;;###autoload (defun mm-url-insert-file-contents-external (url) + "Insert file contents of URL using `mm-url-program'." (let (program args) (if (symbolp mm-url-program) (let ((item (cdr (assq mm-url-program mm-url-predefined-programs)))) @@ -295,35 +326,59 @@ This is taken from RFC 2396.") args (append (cdr item) (list url)))) (setq program mm-url-program args (append mm-url-arguments (list url)))) - (apply 'call-process program nil t nil args))) + (unless (eq 0 (apply 'call-process program nil t nil args)) + (error "Couldn't fetch %s" url)))) + +(defvar mm-url-timeout 30 + "The number of seconds before timing out an URL fetch.") + +(defvar mm-url-retries 10 + "The number of retries after timing out when fetching an URL.") (defun mm-url-insert (url &optional follow-refresh) "Insert the contents from an URL in the current buffer. If FOLLOW-REFRESH is non-nil, redirect refresh url in META." - (if follow-refresh - (save-restriction - (narrow-to-region (point) (point)) - (mm-url-insert-file-contents url) - (goto-char (point-min)) - (when (re-search-forward - "]*URL=\\([^\"]+\\)\"" nil t) - (let ((url (match-string 1))) - (delete-region (point-min) (point-max)) - (mm-url-insert url t)))) - (mm-url-insert-file-contents url))) + (let ((times mm-url-retries) + (done nil) + (first t) + result) + (while (and (not (zerop (decf times))) + (not done)) + (with-timeout (mm-url-timeout) + (unless first + (message "Trying again (%s)..." (- mm-url-retries times))) + (setq first nil) + (if follow-refresh + (save-restriction + (narrow-to-region (point) (point)) + (mm-url-insert-file-contents url) + (goto-char (point-min)) + (when (re-search-forward + "]*URL=\\([^\"]+\\)\"" nil t) + (let ((url (match-string 1))) + (delete-region (point-min) (point-max)) + (setq result (mm-url-insert url t))))) + (setq result (mm-url-insert-file-contents url))) + (setq done t))) + result)) (defun mm-url-decode-entities () "Decode all HTML entities." (goto-char (point-min)) - (while (re-search-forward "&\\(#[0-9]+\\|[a-z]+\\);" nil t) - (let ((elem (if (eq (aref (match-string 1) 0) ?\#) - (let ((c - (string-to-number (substring - (match-string 1) 1)))) - (if (mm-char-or-char-int-p c) c 32)) - (or (cdr (assq (intern (match-string 1)) - mm-url-html-entities)) - ?#)))) + (while (re-search-forward "&\\(#[0-9]+\\|#x[0-9a-f]+\\|[a-z]+[0-9]*\\);" nil t) + (let* ((entity (match-string 1)) + (elem (if (eq (aref entity 0) ?\#) + (let ((c (mm-ucs-to-char + ;; Hex number: ㈒ + (if (eq (aref entity 1) ?x) + (string-to-number (substring entity 2) + 16) + ;; Decimal number:  + (string-to-number (substring entity 1)))))) + (if (mm-char-or-char-int-p c) c ?#)) + (or (cdr (assq (intern entity) + mm-url-html-entities)) + ?#)))) (unless (stringp elem) (setq elem (char-to-string elem))) (replace-match elem t t)))) @@ -337,7 +392,7 @@ If FOLLOW-REFRESH is non-nil, redirect refresh url in META." (with-temp-buffer (insert string) (mm-url-decode-entities) - (buffer-substring (point-min) (point-max)))) + (buffer-string))) (defun mm-url-form-encode-xwfu (chunk) "Escape characters in a string for application/x-www-form-urlencoded. @@ -354,14 +409,10 @@ spaces. Die Die Die." ((= char ? ) "+") ((memq char mm-url-unreserved-chars) (char-to-string char)) (t (upcase (format "%%%02x" char))))) - ;; Fixme: Should this actually be accepting multibyte? Is there a - ;; better way in XEmacs? - (if (featurep 'mule) - (encode-coding-string chunk - (if (fboundp 'find-coding-systems-string) - (car (find-coding-systems-string chunk)) - buffer-file-coding-system)) - chunk) + (mm-encode-coding-string chunk + (if (fboundp 'find-coding-systems-string) + (car (find-coding-systems-string chunk)) + buffer-file-coding-system)) "")) (defun mm-url-encode-www-form-urlencoded (pairs) @@ -372,6 +423,50 @@ spaces. Die Die Die." (mm-url-form-encode-xwfu (cdr data)))) pairs "&")) +(autoload 'mml-compute-boundary "mml") + +(defun mm-url-encode-multipart-form-data (pairs &optional boundary) + "Return PAIRS encoded in multipart/form-data." + ;; RFC1867 + + ;; Get a good boundary + (unless boundary + (setq boundary (mml-compute-boundary '()))) + + (concat + + ;; Start with the boundary + "--" boundary "\r\n" + + ;; Create name value pairs + (mapconcat + 'identity + ;; Delete any returned items that are empty + (delq nil + (mapcar (lambda (data) + (when (car data) + ;; For each pair + (concat + + ;; Encode the name + "Content-Disposition: form-data; name=\"" + (car data) "\"\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n" + + (cond ((stringp (cdr data)) + (cdr data)) + ((integerp (cdr data)) + (int-to-string (cdr data)))) + + "\r\n"))) + pairs)) + ;; use the boundary as a separator + (concat "--" boundary "\r\n")) + + ;; put a boundary at the end. + "--" boundary "--\r\n")) + (defun mm-url-fetch-form (url pairs) "Fetch a form from URL with PAIRS as the data using the POST method." (mm-url-load-url)