From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Ivan Kanis Newsgroups: gmane.emacs.devel Subject: patches and one bug Date: Mon, 24 Jun 2013 11:58:34 +0200 Message-ID: <87bo6v25kl.fsf@kanis.fr> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1372068318 23454 80.91.229.3 (24 Jun 2013 10:05:18 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 24 Jun 2013 10:05:18 +0000 (UTC) Cc: Emacs Development List To: Lars Ingebrigtsen Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jun 24 12:05:19 2013 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Ur3eA-0007Tq-R0 for ged-emacs-devel@m.gmane.org; Mon, 24 Jun 2013 12:05:19 +0200 Original-Received: from localhost ([::1]:38972 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur3eA-0008AJ-B4 for ged-emacs-devel@m.gmane.org; Mon, 24 Jun 2013 06:05:18 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:33431) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur3e3-00080x-6s for emacs-devel@gnu.org; Mon, 24 Jun 2013 06:05:14 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ur3e0-0000ar-0e for emacs-devel@gnu.org; Mon, 24 Jun 2013 06:05:11 -0400 Original-Received: from kanis.fr ([46.19.35.252]:41579 helo=srv2.kanis.fr) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur3Xr-0006tT-P4 for emacs-devel@gnu.org; Mon, 24 Jun 2013 05:58:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=kanis.fr; s=alpha; h=Content-Type:MIME-Version:Message-ID:Date:cc:Subject:To:From; bh=bVF+WAYgeTe7HU8U6pPxzZQT2pdYrbXTKBJW5PtNnio=; b=oMGn3bDQcH2Nm9pzNzJ+opbSC7RveTk7di2VH7Iz5Iu7xFPsK8wI3UaHPLcb1AlS6RMegz6pqP76AxfCs1DF0Z8hu6MBshSTXVng8gjpEUsdhGl6oIglZR7HaYsUUqqX; Original-Received: from smtp.comencini.fr ([164.138.25.8]) by smtp.comencini.fr with esmtpsa (TLS1.1:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.80.1) (envelope-from ) id 1Ur3Xj-00089Z-5m; Mon, 24 Jun 2013 11:58:46 +0200 Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAAXNSR0IArs4c6QAAAB5QTFRF IBkXUxMTOCwoTC4qcUY8iFxQmmper31txpaJ/v/8aKZ1oAAAAcVJREFUOMt100tu2zAQAFDCXnUZ oAcIqG68LZULVLQBbwuSiffm6AIRRyeotAySJoVu2+FPpJWWC3/4NKOZocSW/yxWfnJ2+Bdwzhj7 8gleWVy7DXC2rkMNr2V/zRbghXIwthf3VbIA9Ffc71vZCSFyCEsBggtNS8ludwvfmhYA0Vn9o4DP zMWxR7+cPWzAYFzwM0ModtdmcDbDS6i/hT7L+RZof5yCXGrYe5jn2YO6BYMjgY+51tCIAqHgBLwR pwLnGuRjAKyBJkuN4yd4U92uCY1vUr2D/c5b8DuxyQwfOHUeaLqDJhnkkuGXbB56h2C1IVBdgncc bBi6feroa9B6jUDojnQPQKupbyXyeeCE1oT7Oqrt+SnfY3mkiyGA/3AmD3H5g32CcBx6hY8pRkwJ 9PpcjRGobUfprFnhAa1vepwcgMOhwG+pdSgKHFU9HAvoAH6XUl7lDUCCq5Qb6GMbVm3Aj++qDYCt wdBc/YHgOFCmS3mjDMRcSE2qY4E3Q3PVIQRQmeodNH4QEbRUFZzW+VotzwX4yTcRTySOML1qjcE5 hTirVqDHkMAP0PjAywp3d18JZtqzvr9zDYD+GaSKtE6Zlr/DLPNFmOcvBAAAAABJRU5ErkJggg== User-Agent: Gnus/5.130008 (Ma Gnus v0.8) Emacs/24.3 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 46.19.35.252 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:160927 Archived-At: --=-=-= Content-Type: text/plain Lars, I have attached more patches. There is a bug that I don't think I'll fix: it is the function eww-open-file. It doesn't work with a file that doesn't have HTTP headers. emacs-wget fetches a file with wget asynchronously. It pops a small window with the progress of the download. I have attached my wget.el. I sent the author an e-mail to see if he would sign the FSF paper work to include it in Emacs. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-fix-opening-file-URL.patch >From 017c749f5590e0e564d9dab2de7dabd60766318e Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 08:06:08 +0200 Subject: [PATCH 1/7] fix opening file:/// URL --- emacs/gnus/eww.el | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/emacs/gnus/eww.el b/emacs/gnus/eww.el index 959fc4d..53fa882 100644 --- a/emacs/gnus/eww.el +++ b/emacs/gnus/eww.el @@ -106,8 +106,9 @@ It will be used when emacs runs on neither Windows or Mac." (> (length (split-string url "\\.")) 1)) (unless (string-match-p "\\`[a-zA-Z][-a-zA-Z0-9+.]*://" url) (setq url (concat "http://" url))) - (setq url (concat eww-search-prefix - (replace-regexp-in-string " " "+" url)))) + (unless (string-match-p "^file:" url) + (setq url (concat eww-search-prefix + (replace-regexp-in-string " " "+" url))))) (url-retrieve url 'eww-render (list url))) ;;;###autoload -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0002-handle-quoted-charset-header.patch >From 22526c5f7dabdf2d48ee58e93cb78c2d1f2ec9ed Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 08:39:26 +0200 Subject: [PATCH 2/7] handle quoted charset header (https://wincent.com/products/command-t to reproduce bug) --- emacs/gnus/eww.el | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/emacs/gnus/eww.el b/emacs/gnus/eww.el index 53fa882..aa39585 100644 --- a/emacs/gnus/eww.el +++ b/emacs/gnus/eww.el @@ -180,7 +180,7 @@ It will be used when emacs runs on neither Windows or Mac." (pt (point))) (or (and html-p (re-search-forward - "]*charset=\"?\\([^\t\n\r \"/>]+\\)" nil t) + "]*charset=\"?\\([^\t\n\r \"/>]+\\)[\\\"'.*]" nil t) (goto-char pt) (match-string 1)) (and (looking-at -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0003-key-y-puts-page-url-in-kill-ring.patch >From f5ccea29a6f31f3d3e742d5d224ec6140a7316e3 Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 08:44:58 +0200 Subject: [PATCH 3/7] key 'y' puts page url in kill ring --- emacs/gnus/eww.el | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/emacs/gnus/eww.el b/emacs/gnus/eww.el index aa39585..50737d5 100644 --- a/emacs/gnus/eww.el +++ b/emacs/gnus/eww.el @@ -321,6 +321,7 @@ It will be used when emacs runs on neither Windows or Mac." (define-key map "u" 'eww-up-url) (define-key map "t" 'eww-top-url) (define-key map "w" 'eww-browse-with-external-browser) + (define-key map "y" 'eww-yank-page-url) map)) (define-derived-mode eww-mode nil "eww" @@ -845,6 +846,10 @@ It support Windows and Mac then calls the function specified in (t (funcall eww-external-browser url))))) +(defun eww-yank-page-url () + (interactive) + (message eww-current-url) + (kill-new eww-current-url)) (provide 'eww) ;;; eww.el ends here -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0004-tack-at-the-end-of-naked-url.patch >From b183f74911508df20c2aee843490da05f4535a59 Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 10:14:21 +0200 Subject: [PATCH 4/7] tack / at the end of naked url ie: http://google.com -> http://google.com/ --- emacs/gnus/eww.el | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/emacs/gnus/eww.el b/emacs/gnus/eww.el index 50737d5..d34b84a 100644 --- a/emacs/gnus/eww.el +++ b/emacs/gnus/eww.el @@ -109,6 +109,16 @@ It will be used when emacs runs on neither Windows or Mac." (unless (string-match-p "^file:" url) (setq url (concat eww-search-prefix (replace-regexp-in-string " " "+" url))))) + + (and (string-match "https*://\\(.*\\)" url) + ;; true when url part is just a hostname + (not (string-match "/" (substring url (match-beginning 1) + (match-end 1)))) + ;; Last character is not / + (not (string= (substring url (1- (length url)) (length url)) "/")) + ;; tack / at the end of naked url + ;; ie: http://google.com -> http://google.com/ + (setq url ( concat url "/"))) (url-retrieve url 'eww-render (list url))) ;;;###autoload -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0005-add-optional-argument-needed-for-browse-url.patch >From b879b382de4ee3f14dbe652ebc996645cf52807a Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 11:17:51 +0200 Subject: [PATCH 5/7] add optional argument needed for browse url --- emacs/gnus/eww.el | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/emacs/gnus/eww.el b/emacs/gnus/eww.el index d34b84a..f5c2eb9 100644 --- a/emacs/gnus/eww.el +++ b/emacs/gnus/eww.el @@ -99,8 +99,9 @@ It will be used when emacs runs on neither Windows or Mac." (defvar eww-contents-url nil) ;;;###autoload -(defun eww (url) - "Fetch URL and render the page." +(defun eww (url &optional new-session interactive-p) + "Fetch URL and render the page. +NEW-SESSION and INTERCATIVE-P are not used" (interactive "sEnter URL or keywords: ") (if (and (= (length (split-string url)) 1) (> (length (split-string url "\\.")) 1)) -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0006-add-emacs-wget.patch >From 8816a9029f33ca98437ad88323ab9068f5b964fe Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 11:41:58 +0200 Subject: [PATCH 6/7] add emacs-wget --- emacs/gnus/shr.el | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/emacs/gnus/shr.el b/emacs/gnus/shr.el index 868956d..5f74f27 100644 --- a/emacs/gnus/shr.el +++ b/emacs/gnus/shr.el @@ -141,6 +141,7 @@ cid: URL as the argument.") (define-key map "u" 'shr-copy-url) (define-key map "v" 'shr-browse-url) (define-key map "o" 'shr-save-contents) + (define-key map "d" 'shr-wget) (define-key map "\r" 'shr-browse-url) map)) @@ -1634,6 +1635,17 @@ ones, in case fg and bg are nil." (list oldval face) (list face oldval)))))))))) +(defun shr-wget () + "Download URL under point." + (interactive) + (when (not (fboundp 'wget-api)) + (error "You need to install emacs-wget.")) + + (let ((url (get-text-property (point) 'shr-url))) + (if (not url) + (message "No URL under point") + (wget-api url nil)))) + (provide 'shr) ;; Local Variables: -- 1.7.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0007-C-u-RET-opens-link-in-external-browser.patch >From 5ab007318cab14c2cb354a8d2c956321d4fe09f3 Mon Sep 17 00:00:00 2001 From: Ivan Kanis Date: Mon, 24 Jun 2013 11:50:25 +0200 Subject: [PATCH 7/7] C-u RET opens link in external browser --- emacs/gnus/shr.el | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/emacs/gnus/shr.el b/emacs/gnus/shr.el index 5f74f27..117c7f6 100644 --- a/emacs/gnus/shr.el +++ b/emacs/gnus/shr.el @@ -640,9 +640,9 @@ size, and full-buffer size." (forward-line 1) (goto-char end)))))) -(defun shr-browse-url () +(defun shr-browse-url (arg) "Browse the URL under point." - (interactive) + (interactive "P") (let ((url (get-text-property (point) 'shr-url))) (cond ((not url) @@ -650,7 +650,9 @@ size, and full-buffer size." ((string-match "^mailto:" url) (browse-url-mail url)) (t - (browse-url url))))) + (if arg + (eww-browse-with-external-browser) + (browse-url url)))))) (defun shr-save-contents (directory) "Save the contents from URL in a file." -- 1.7.1 --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=wget.el Content-Transfer-Encoding: quoted-printable ;;; wget.el --- Interface program of wget on Emacs ;; Copyright (C) 2001, 2002, 2003, 2004 Masayuki Ataka ;; $Id: wget.el,v 1.94 2004/10/16 06:43:43 ataka Exp $ ;; Author: Masayuki Ataka ;; Keywords: hypermedia, WWW ;; This file is the main part of emacs-wget. ;; 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 this program; if not, you can either send email to this ;; program's maintainer or write to: The Free Software Foundation, ;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. ;;; Commentary: ;; emacs-wget is an interface program of GNU wget on Emacs. For more ;; details about emacs-wget, see: ;; ;; http://pop-club.hp.infoseek.co.jp/emacs/emacs-wget/ ;;; How to install: ;; See README. ;;; Usage: ;; See USAGE. ;;; Code: (require 'wget-sysdep) (require 'thingatpt) (defgroup wget nil "wget program interface." :group 'hypermedia :prefix "wget-") ;;;; User Options (defcustom wget-command "wget" "*Program name of `wget'." :group 'wget :type 'string) (defvar wget-basic-options '("-v" ;--verbose: Be verbose. "--progress=3Ddot") ;--progress=3Ddot: progress bar (= wget =3D> 1.8). "*List of default emacs/wget system options.") (defcustom wget-default-options nil ;; '("-nc" "-c") ; <- example. "*List of default options of wget." :group 'wget :type '(repeat (restricted-sexp :tag "Option"))) (defcustom wget-web-page-options `(,@wget-default-options "-r" ;--recursive: Turn on recursive ret= rieving. "-np") ;--no-parent: Do not ever ascend to= the parent directory. "*List of options to download all Web pages." :group 'wget :type '(repeat (restricted-sexp :tag "Web page Option"))) (defcustom wget-ftp-default-options nil "*List of default options when download from ftp. If nil, use `wget-default-options' instead." :group 'wget :type '(repeat (restricted-sexp :tag "FTP Option"))) ;; Download dir (defcustom wget-download-directory "~/download" "*Default directory name that retrieved files go. If nil, always ask download directory." :group 'wget :type '(choice directory (sexp :tag "Lisp object"))) (defcustom wget-download-directory-filter nil "*Function that defines the filtering of download directory." :group 'wget :type '(radio (const :tag "No filter" nil) (const :tag "Filter by regexp" wget-download-dir-filter-regexp) (const :tag "Aliases" wget-download-dir-filter-alias) (const :tag "Filter by regexp and alias" wget-download-dir-filter-regexp-and-alias) (const :tag "Check current dir" wget-download-dir-filter-current-dir) (function :tag "Other Function"))) ;; Download Log (defcustom wget-download-log-file nil "*Default file name for download log. If emacs-wget find this file in the download directory, append download log in format `wget-download-log-format'. If log file is not found, create or ask creating. See the variable `wget-create-download-log'." :group 'wget :type 'file) (defcustom wget-create-download-log 'always "*If non-nil, create or ask creating the log file when the log file is not found in the download directory. 'always Always create log file 'ask Ask creating log file nil Do not create log file. The log file name is defined by variable `wget-download-log-file'." :group 'wget :type '(choice (const always) (const ask) (const nil))) (defcustom wget-download-log-format "%T\t%U\n" "*Format string for `wget-download-log-file'. %T Time format string replaced by `wget-download-log-time-format' %t Title %U URI" :group 'wget :type 'string) (defcustom wget-download-log-time-format "%Y-%m-%d %H:%M:%S" "*Time format string for `wget-download-log-file'. See the function `format-time-string' for format-string." :group 'wget :type 'string) (defcustom wget-add-download-log-eof t "*If non-nil, download log is added at the end of file, else it is added at the beginning of file. Download log is added to the file `wget-download-log-file' in the format `wget-download-log-format'." :group 'wget :type 'boolean) ;; misc (defcustom wget-executable-file-extension-list nil ; '("exe" "sh" "csh" "pl" "rb") ; <- example "*List of file extension that change file permission executable after dow= nloading." :group 'wget :type '(repeat (restricted-sexp :tag "File extension"))) (defcustom wget-truncate-partial-width-windows t "*Non-nil means truncate lines in *wget* buffer less than full frame wide= ." :group 'wget :type 'boolean) (defcustom wget-max-window-height (/ (frame-height) 2) "*Max height of *wget* buffer." :group 'wget :type 'integer) ;; Hooks (defcustom wget-hook nil "*Hook run after calling `wget-uri'." :group 'wget :type 'hook) (defcustom wget-after-hook nil "*Hook run after finishing downloading file." :group 'wget :type 'hook) (defcustom wget-load-hook nil "*Hook run after loading Emacs-wget." :group 'wget :type 'hook) ;; debug etc... (defcustom wget-debug nil "*Non nil means save wget log message in buffer `wget-debug-buffer'." :group 'wget :type 'boolean) (defvar wget-process-buffer "*wget*" "*Name of wget process buffer. If nil, do not show the wget buffer.") ;;; System Variables (defvar wget-debug-buffer " *wget-log*" "Name of wget log buffer.") (defconst wget-long-option-alist (eval-when-compile (let ((options '(;; Download Options "bind-address=3DADDRESS" "tries=3DNUMBER" "no-clobber" "contin= ue" "timestamping" "timeout=3DSECONDS" "limit-rate=3DAMOUNT" "wait= =3DSECONDS" "waitretry=3DSECONDS" "random-wait" "proxy=3Don/off" "quota=3D= QUOTA" ; (NEW in 1.9) "dns-timeout=3DSECONDS" "connect-timeout=3DSECONDS" "read-time= out=3DSECONDS" "dns-cache=3Doff" "restrict-file-names=3DMODE" ;; Directory Options "no-directories" "force-directories" "no-host-directories" "cut-dirs=3DNUMBER" "directory-prefix=3DPREFIX" ;; HTTP Options "html-extension" "http-user=3DUSER" "http-passwd=3DPASSWORD" "cache=3Don/off" "cookies=3Don/off" "load-cookies FILE" "save-= cookies FILE" "ignore-length" "header=3DADDITIONAL-HEADER" "proxy-user=3DUSE= R" "proxy-passwd=3DPASSWORD" "referer=3DURL" "save-headers" "user= -agent=3DAGENT-STRING" ; (NEW in 1.9) "post-data=3DSTRING" "post-file=3DFILE" ;; FTP Options "dont-remove-listing" "glob=3Don/off" "passive-ftp" "retr-syml= inks" ;; Recursive Retrieval Options "recursive" "level=3DDEPTH" "delete-after" "convert-links" "backup-converted" "mirror" "page-requisites" ; (New in 1.9) "strict-comments" ;; Recursive Accept/Reject Options "accept ACCLIST" "reject REJLIST" "domains=3DDOMAIN-LIST" "exclude-domains DOMAIN-LIST" "follow-ftp" "follow-tags=3DLIST" "ignore-tags=3DLIST" "span-hosts" "relative" "include-director= ies=3DLIST" "exclude-directories=3DLIST" "no-parent"))) (sort (mapcar (lambda (wrd) (let* ((eql (or (string-match "=3D" wrd) (string-match " " wrd))) (opt (concat "--" (substring wrd 0 (and eql (1+ eql)))))) (cons wrd opt))) options) (lambda (x y) (string< (car x) (car y)))))) "Alist of wget long options") (defvar wget-process-percent-alist nil "Alist of (PROC . PERCENT) of each wget process. PROC is process of wget and PERCENT is number of download percentage. See also `wget-process-byte-alist', `wget-process-length-alist', `wget-process-saved-alist', `wget-process-dir-alist', and `wget-process-messg-alist'.") (defvar wget-process-byte-alist nil "Alist of (PROC . BYTE) of each wget process. PROC is process of wget and BYTE is number of download byte. See `wget-process-percent-alist' for more information.") (defvar wget-process-length-alist nil "Alist of (PROC . LENGTH) of each wget process. PROC is process of wget and BYTE is number of download byte. See `wget-process-percent-alist' for more information.") (defvar wget-process-mime-alist nil "Alist of (PROC . MIME) of each wget process. PROC is process of wget and MIME is stirng of MIME code. See `wget-process-percent-alist' for more information.") (defvar wget-process-saved-alist nil "Alist of (PROC . SAVED) of each wget process. PROC is process of wget and SAVED is string of saved file name. See `wget-process-percent-alist' for more information.") (defvar wget-process-dir-alist nil "Alist of (PROC . DIR) of each wget process. PROC is process of wget and DIR is string of directory name where to downlo= ad. See `wget-process-percent-alist' for more information.") (defvar wget-process-messg-alist nil "Alist of (PROC . MESSG) of each wget process. PROC is process of wget and MESSG is message string. See `wget-process-percent-alist' for more information.") (defvar wget-ftp-regexp "^ftp://" "Regexp for FTP.") (defvar wget-current-title nil) (defconst wget-download-line-format (format " %s%11s" "[100%]" " ")) ;;;; User Interface ;;;###autoload (defun wget (uri &optional arg) "Wget interface to download URI asynchronously. If argument ARG is non-nil, ask some options. Called with prefix argument, turn argument ARG t. If you are in dired mode which is seeing ftp directory, `wget' regard current line file name as URI." (interactive (list (if (string=3D major-mode "dired-mode") (dired-wget) (read-string "URI: " (thing-at-point-url-at-point))) (when current-prefix-arg t))) (let ((options (if (and wget-ftp-default-options (string-match wget-ftp-regexp uri)) wget-ftp-default-options wget-default-options)) (dir (wget-cd-download-dir arg uri))) (when dir (setq options (append wget-basic-options (if arg (wget-read-options "Wget options: " options wget-long-option-alist) options))) (if (string=3D uri "") (error "There is no uri") (wget-uri uri dir options))))) ;;;###autoload (defun wget-web-page (uri &optional arg) "Wget interface to download whole Web page. If argument ARG is non-nil, ask options. Called with prefix argument, turn argument ARG t. Second argument URI is string. wget-web-page downlod whole Web page from it following relative link." (interactive (list (read-string "Web Page URI: " (thing-at-point-url-at-point)) (if current-prefix-arg t))) (let ((options wget-web-page-options) (dir (wget-cd-download-dir arg uri))) (when dir (setq options (append wget-basic-options (if arg (wget-read-options "Wget options: " options wget-long-option-alist) options))) (if (string=3D uri "") (error "There is no uri") (wget-uri uri dir options))))) ;;; Internal Code (Not including process) (defun dired-wget () "Wget interface for dired-mode in ftp directory. Return string of URI at current line." (save-excursion (let ((max (progn (end-of-line 1) (point))) uri base) (forward-line 0) (unless (re-search-forward " \\([^ ]+\\)$" max t) (error "No file at point")) (setq uri (match-string 1)) (goto-char (point-min)) (re-search-forward "@\\(.+\\):" nil t) (setq base (match-string 1)) (read-string "URI: " (concat base "/" uri))))) ;;;###autoload (defun wget-api (uri current-uri &optional arg) "Application Program Interface for wget" (if uri (progn (when arg (setq uri (read-string "URI: " uri))) (wget uri arg)) ;;No URI at point. (let ((char (read-char "Download: [c]urrent page; [w]eb pages; [q]ui= t"))) (cond ;; Current Page. ((equal ?c char) (if arg (setq uri (read-string "URI: " current-uri)) (setq uri current-uri)) (wget uri arg)) ;; Web Pages. ((equal ?w char) (if arg (setq uri (read-string "Web Page URI: " current-uri)) (setq uri current-uri)) (wget-web-page uri arg)) ;; Quit. ((equal ?q char) nil) (t (wget-api uri current-uri arg)))))) (defun wget-cd-download-dir (arg uri) "Change directory to wget download dir. If ARG is non-nil, download dir is `wget-download-directory'. Otherwise, Ask download dir. When download dir is not directory or unwritable, get error" (let ((dir wget-download-directory)) (cond ((functionp wget-download-directory-filter) (setq dir (funcall wget-download-directory-filter arg uri dir))) (arg (setq dir (wget-read-download-dir dir)))) (unless dir (setq dir (wget-read-download-dir))) ;; Check directory exist and writable (catch 'directory (while t (cond ((file-exists-p dir) (throw 'directory t)) ((y-or-n-p (format "%s does not exist. Create it? " dir)) (make-directory dir t) (throw 'directory t)) (t (if (functionp wget-download-directory-filter) (setq dir (funcall wget-download-directory-filter arg uri d= ir)) (setq dir (wget-read-download-dir dir))))))) (unless (file-directory-p dir) (error "%s is not directory" dir)) (unless (file-writable-p dir) (error "Can't open download directory: %s" dir)) ;; Change Directory (setq dir (expand-file-name dir)) (save-excursion (set-buffer (get-buffer-create (or wget-process-buffer " *wget*"))) (cd dir)))) ;; filter functions (defun wget-download-dir-filter-current-dir (arg uri dir) "Ask download dir if current dir is not under DIR'. If current dir is under DIR, then use current dir for download dir. If first argument ARG is non-nil, always ask download dir. Third argument DIR should be a string, not a list." (if (stringp dir) (if (and (not arg) (string-match (concat "^" (expand-file-name dir)) default-di= rectory)) default-directory (wget-read-download-dir dir)) dir)) (defun wget-download-dir-filter-regexp (arg uri dir) "Change download directory by regexp. `wget-download-directory' should be an alist of (REGEXP . DIR). FILE that matches REGEXP goes to DIR. Example of `wget-download-directory': ((\"\\\\.\\\\(jpe?g\\\\|png\\\\)$\" . \"~/pictures\") (\"\\\\.el$\" . \"~/site-lisp\") (\".\" . \"~/download\"))" (if (consp dir) (assoc-default uri dir #'string-match) dir)) (defun wget-download-dir-filter-alias (arg uri dir) "Ask alias of download directory. `wget-download-directory' should be an alist of (ALIAS . DIR). The alias \"default\" is special. If it is found in `wget-download-directory', use it by default. When prefix argument C-u is specified, ask aliases. Example of `wget-download-directory': ((\"pics\" . \"~/pictures\") (\"elisp\" . \"~/site-lisp\") (\"default\" . \"~/download\"))" (when (consp dir) (let ((default (cdr (assoc "default" dir)))) (if arg ; C-u wget (setq dir (wget-read-download-dir (cdr (assoc (completing-read "Directory alias: " dir) = dir)))) ;; Without C-u (if default (setq dir default) (setq dir (cdr (assoc (completing-read "Directory alias: " dir) d= ir))))))) dir) (defun wget-download-dir-filter-regexp-and-alias (arg uri dir) "Change download directory by regexp and alias. First call function `wget-download-dir-filter-regexp', and then call function `wget-download-dir-filter-alias'. So, `wget-download-directory' should be an alist and its value should be one of them: (REGEXP . DIR) or (REGEXP . ((ALIAS . DIR)...)). Example of `wget-download-directory': ((\"\\\\.\\\\(jpe?g\\\\|png\\\\)$\" . ((\"dog\" . \"~/dogs/picture\") (\"cat\" . \"~/cats/picture\") (\"default\" . \"~/pictures\"))) (\"\\\\.el$\" . \"~/site-lisp\") (\".\" . \"~/download\"))" (setq dir (wget-download-dir-filter-regexp arg uri dir)) (wget-download-dir-filter-alias arg uri dir)) ;; misc (defun wget-read-download-dir (&optional dir) "Ask download dir. The optional rgument DIR is default directory name." (wget-read-directory-name "Download directory: " (and dir (file-name-as-directory dir)))) ;;; Completion (defvar wget-read-options-map (copy-keymap minibuffer-local-completion-map) "Local keymap for minibuffer to read wget long options.") (define-key wget-read-options-map " " 'self-insert-command) (define-key wget-read-options-map "\C-i" 'wget-option-completion) (defun wget-read-options (prompt init-list table) "Read a string of wget option with completion." (let ((minibuffer-completion-table table) (init (mapconcat (lambda (x) x) init-list " "))) (split-string (read-from-minibuffer prompt init wget-read-options-map)))) (defun wget-option-completion () "Complete wget long options, stop to space." (interactive) (goto-char (point-max)) (let* ((pos (point)) (start (progn (skip-chars-backward "^ \n\t") (point))) (word (prog1 (buffer-substring (if (looking-at "--") (+ 2 start) st= art) pos) (goto-char pos))) (result (try-completion word minibuffer-completion-table)) (tmpmesg '(lambda (x) (save-excursion (goto-char (point-max)) (save-excursion (insert " " x)) (sit-for 1) (delete-region (point) (point-max)))))) (cond ((eq result t) (funcall tmpmesg "[Sole Completion]")) ((eq result nil) (ding) (funcall tmpmesg "[No Match!]")) ((string=3D result word) (with-output-to-temp-buffer "*Completions*" (display-completion-list (all-completions word minibuffer-completion-table)))) ((=3D (preceding-char) ?=3D) (with-output-to-temp-buffer "*Completions*" (display-completion-list (all-completions word minibuffer-completion-table))) (funcall tmpmesg "[Sole Completion]")) (t (delete-region start pos) (insert (cdr (or (assoc result minibuffer-completion-table) (cons result (concat "--" result))))) (unless (eq t (try-completion result minibuffer-completion-table)) (funcall tmpmesg "[Complete, but not unique]")))))) ;;;; Wget Process (defmacro wget-delete-property (proc alist) "Delete a member whose car is PROC from ALIST." `(when (assoc ,proc ,alist) (setq ,alist (delete (assoc ,proc ,alist) ,alist)))) (defmacro wget-change-property (proc value alist) "Change a property of process PROC in ALIST with cons-cell of (PROC . VAL= UE)." `(progn (wget-delete-property ,proc ,alist) (setq ,alist (cons (cons ,proc ,value) ,alist)))) (defun wget-uri (uri dir &optional options) "Wget URI asynchronously. Optional argument OPTIONS is a list of options to pass wget process." (let* ((args `(,@options ,uri)) (buf wget-process-buffer) (lang (concat "LANG=3D" (getenv "LANG"))) (process-environment (cons "LANG=3DC" (delete lang (copy-sequence process-env= ironment)))) (proc (save-excursion (set-buffer (or buf " *wget*")) (wget-write-download-log uri) (apply 'start-process "wget" buf wget-command args))) (win (selected-window))) ;; Initialize property. (wget-change-property proc nil wget-process-percent-alist) (wget-change-property proc nil wget-process-byte-alist) (wget-change-property proc nil wget-process-length-alist) (wget-change-property proc nil wget-process-saved-alist) (wget-change-property proc dir wget-process-dir-alist) (wget-change-property proc nil wget-process-messg-alist) ;; Set process functions. (when buf (set-process-filter proc 'wget-process-filter)) (set-process-sentinel proc 'wget-process-sentinel) (message "Downloading %s..." (wget-process-file-name proc)) (wget-state-of-progress proc) (run-hooks 'wget-hook))) ;;; Debug Code ;; ;; (apply 'start-process "WGET" "*Wget*" "wget" ;wget-command ;; '("http://pop-club.hp.infoseek.co.jp/emacs/fcopy.el")) ;; (defun wget-process-filter (proc string) "Process filter function for wget. Argument PROC is process of wget and argument STRING is an output string fr= om wget." (when wget-debug (save-excursion (set-buffer (get-buffer-create wget-debug-buffer)) (insert string "=1F"))) (when (string-match "[0-9a-Z]" string) ; Ignore wget output that contains= only `.' (let ((proc-cell (wget-get-wget-process proc)) length mime percent byte saved messg) ;; Connecting (when (string-match "Connecting to" string) (wget-progress-update proc-cell "connecting")) ;; Connected (when (string-match "connected[!.]" string) (wget-progress-update proc-cell "connected")) ;; Reusing connection (when (string-match "Reusing connection to" string) (wget-change-property proc 0 wget-process-percent-alist) (wget-progress-update proc-cell 0)) ;; Length (when (string-match "Length: \\([0-9,]+\\)" string) (setq length (match-string 1 string)) (wget-change-property proc length wget-process-length-alist)) (when (string-match "Length: \\([0-9,]+\\) \\(\\[.+\\]\\|(.+)\\)" string) (setq mime (match-string 2 string)) (wget-change-property proc mime wget-process-mime-alist)) ;; Saving (when (string-match "=3D> `\\(.+\\)'" string) (wget-change-property proc (match-string 1 string) wget-process-saved-alist)) ;; Retrieved (when (string-match "The file is already fully retrieved; nothing to = do\\." string) (wget-change-property proc "retrieved" wget-process-messg-alist)) (when (string-match "no newer than local file" string) (wget-change-property proc "retrieved" wget-process-messg-alist)) ;; Percent (when (string-match "\\([ 1][ 0-9][0-9]\\)%" string) (setq percent (string-to-number (match-string 1 string))) (wget-change-property proc percent wget-process-percent-alist) (wget-progress-update proc-cell percent)) ;; Byte (when (string-match "\\([0-9]+\\)K" string) (setq byte (string-to-number (match-string 1 string))) (wget-change-property proc byte wget-process-byte-alist)) ;; Saved (when (string-match "`\\(.+\\)' saved" string) (setq saved (match-string 1 string)) (wget-change-property proc saved wget-process-saved-alist)) )) (if (and (> (point) (length " --- Wget Process ---")) (string=3D (buffer-name (current-buffer)) wget-process-buffer)) (move-to-column (length wget-download-line-format)))) (defun wget-reset-property (proc) "Reset property of process PROC in `wget-process-*-alist'. See also `wget-change-property'." (wget-delete-property proc wget-process-percent-alist) (wget-delete-property proc wget-process-byte-alist) (wget-delete-property proc wget-process-length-alist) (wget-delete-property proc wget-process-saved-alist) (wget-delete-property proc wget-process-dir-alist) (wget-delete-property proc wget-process-messg-alist)) (defun wget-process-sentinel (proc state) "Process setinel function for wget. Argument PROC is process of wget and STATE is state." (let ((ps (process-status proc)) (status (process-exit-status proc)) (win (when (process-buffer proc) (get-buffer-window (process-buffer proc))))) (cond ((eq ps 'exit) (unwind-protect (if (and (eq status 0) (wget-get-wget-process proc)) (progn (ding) (message "Downloading %s...done" (or (cdr (assoc proc wget-process-saved-alist)) (wget-process-file-name proc))) (if (string=3D (cdr (assoc proc wget-process-messg-alist)) "retrieved") (wget-progress-update (wget-get-wget-process proc) "ret= rieved") (wget-progress-update (wget-get-wget-process proc) "downl= oaded")) (wget-close-wget-output-window win) (when wget-executable-file-extension-list (wget-set-file-executable proc)) (run-hooks 'wget-after-hook)) (ding) (message "Downloading %s...failed" (wget-process-file-name proc)) (wget-revert-buffer) (wget-close-wget-output-window win)) (wget-reset-property proc))) ((eq ps 'signal) (unwind-protect (if (eq status 9) (progn (wget-revert-buffer) (wget-close-wget-output-window win)) (error "Downloading %s...failed and exit" (wget-process-file-name proc))) (wget-reset-property proc))) (t nil)))) (defun wget-quit () "Kill wget process." (interactive) (let (proc (proc-alist (wget-get-process-alist))) (cond ;; No wget process. ((null proc-alist) (error "No wget process")) ;; Only one wget process. ((null (cdr proc-alist)) (setq proc (cdr (car proc-alist)))) ;; Called in *wget* buffer. ((equal wget-process-buffer (buffer-name)) (setq proc (let ((file (progn (forward-line 0) (buffer-substring-no-properties (progn (move-to-column (length wget-download-lin= e-format)) (point)) (progn (end-of-line 1) (point)))))) (or (cdr (assoc file proc-alist)) (car (rassoc file wget-process-saved-alist))))) (unless proc (error "No wget process"))) ;; Many wget processes. (t (setq proc (cdr (assoc (completing-read "Kill: " proc-alist nil t) proc-alist))))) (if (rassoc proc proc-alist) (if (wget-kill-process proc t t) (message "Killed process and removed %s" (wget-process-file-name proc)) (message "Killed process")) (message "Wget process is finised")))) (defun wget-quit-and-exit () "Kill all wget processes." (interactive) (while (wget-get-process-alist) (wget-kill-process (cdr (car (wget-get-process-alist))) t nil) (sit-for 1) ;;Quitting Process too fast lead to Emacs panic?? )) (defun wget-kill-process (proc del &optional query) "Kill wget process PROC. If argument DEL is non-nil, remove downloaded file. However, if process download recursively, do not remove files and directory. If optional argument QUERY is non-nil, ask remove or not." (wget-reset-property proc) (kill-process proc) (let ((file (expand-file-name (wget-process-file-name proc) (cdr (assoc proc wget-process-dir-alist))))) (if (and del (not (wget-recursive-p proc)) (file-exists-p file) (or (not query) (y-or-n-p "Remove downloaded file? "))) (delete-file file)))) (defun wget-get-process-alist () "Return alist of (URI . PROCESS). If no process for wget, just return nil." (let ((proc-alist (mapcar 'wget-get-wget-process (process-list)))) (delete nil proc-alist))) (defun wget-get-wget-process (proc) "Return cons cell of (URI . PROCESS) if PROC is `wget-command' process. If not, return nil." (let ((command (process-command proc))) (when (string=3D wget-command (car command)) (cons (nth (1- (length command)) command) proc)))) (defun wget-process-file-name (proc) "Return file or directory name of URI under wget process PROC." (let ((uri (car (wget-get-wget-process proc)))) (wget-replace-regexp-in-string ".+/" "" uri))) (defun wget-close-wget-output-window (win) "Close *wget* window. Argument WIN is window." (when (and (windowp win) (not (wget-get-process-alist))) (delete-window win))) (defun wget-recursive-p (proc) "Return t if wget option contains \"-r\" or \"--recursive\"." (let ((proc-com (process-command proc))) (or (member "-r" proc-com) (member "--recursive" proc-com)))) ;;;; Wget mode (defvar wget-mode-map nil) (if wget-mode-map nil (let ((map (make-keymap))) (suppress-keymap map) (define-key map "q" 'quit-window) (define-key map "Q" 'wget-quit-and-exit) (define-key map "d" 'wget-quit) (define-key map "g" 'wget-revert-buffer) (define-key map "i" 'wget-info) (define-key map "n" 'wget-next-line) (define-key map "p" 'wget-previous-line) (setq wget-mode-map map))) (defun wget-mode () "Major mode for operating wget process. State of wget downloading rogress is described as follows: [STATE]: [PROGRESS] [URI] STATE show percent of downloading. PROGRESS show bar graph of download. Keybindings: \\{wget-mode-map}" (kill-all-local-variables) (setq truncate-lines wget-truncate-partial-width-windows) (use-local-map wget-mode-map) (setq major-mode 'wget-mode mode-name "wget" buffer-read-only t)) (defun wget-state-of-progress (proc) "Show state of wget downloading progress." (interactive (list (cdr (cdr (wget-get-process-alist))))) (let ((win (selected-window)) (buf wget-process-buffer) (window-min-height 3)) (when buf (if (get-buffer-window buf) (progn (select-window (get-buffer-window buf)) (if (< (window-height) wget-max-window-height) (enlarge-window 1))) (select-window (split-window-vertically (- (if (< (+ 3 (length (wget-get-process-alist))) wget-max-window-height) (+ 3 (length (wget-get-process-alist))) wget-max-window-height)))) (switch-to-buffer buf)) (wget-revert-buffer) (wget-mode) (select-window win)))) (defun wget-revert-buffer () "Revert wget buffer." (interactive) (when wget-process-buffer (save-excursion (set-buffer wget-process-buffer) (let ((proc-alist (wget-get-process-alist)) (buffer-read-only nil) (height (wget-window-height))) (erase-buffer) (goto-char (point-min)) (insert " --- Wget Process ---") (if proc-alist (progn (mapcar 'wget-progress-update proc-alist) (when (and (not (one-window-p)) (> height (+ 2 (length proc-alist)))) (shrink-window (- height (+ 2 (length proc-alist)))))) ;; if no processes. (insert "\n ** No Wget Process **")) (set-buffer-modified-p nil))))) (defun wget-progress-update (proc-cell &optional progress) "Update wget progress and return uri. Argument PROC-CELL is cons cell of (URI . PROCESS)." (when (process-buffer (cdr proc-cell)) (save-excursion (let* ((status "[ 0%]") (bar (format "%11c" ? )) (uri (wget-replace-regexp-in-string "~" "%7E" (car proc-cell)= )) (proc (cdr proc-cell)) (buffer-read-only (prog1 nil (set-buffer (process-buffer proc))))) (if progress (let ((file (cdr (assoc proc wget-process-saved-alist)))) (goto-char (point-min)) (when uri (if (not (and file (wget-recursive-p proc))) (search-forward uri nil t) (if file (unless (search-forward file nil t) (goto-char (point-max)) (search-forward uri nil t)))) (delete-region (progn (forward-line 0) (point)) (progn (end-of-line 1) (point))) (forward-line 0)) (if (numberp progress) (setq status (format "[%3d%%]" progress) bar (format "%-11s" (make-string (/ progress 10) ?*))) ;; if PROGRESS is not a number but a string. (setq bar "") (cond ((string=3D progress "connecting") (setq status "*Connecting... ")) ((string=3D progress "connected") (setq status "=3D*=3DConnected=3D*=3D ")) ((string=3D progress "retrieved") (setq status "=3D*=3DUp-To-Date=3D*=3D " uri (wget-process-file-name proc))) ((string=3D progress "downloaded") (setq status "=3D*=3DDOWNLOADED=3D*=3D " uri (concat (file-name-as-directory (cdr (assoc proc wget-process-dir-alis= t))) file))))) (when (and file (wget-recursive-p proc)) (setq uri file))) ;; If no progress (if (cdr (assoc proc wget-process-percent-alist)) (setq progress (cdr (assoc proc wget-process-percent-alist)) status (format "[%3d%%]" progress) bar (format "%-11s" (make-string (/ progress 10) ?*)))) (end-of-line 1) (insert "\n")) (when uri (insert " " status bar uri) (set-buffer-modified-p nil)))))) (defun wget-info () "Show information about the retrieving file." (interactive) (let* ((file (save-excursion (buffer-substring (progn (forward-line 0) (move-to-column (length wget-download-line-format)) (point)) (progn (end-of-line) (point))))) (proc (cdr (assoc file (wget-get-process-alist))))) (when proc (let ((byte (cdr (assoc proc wget-process-byte-alist))) (length (cdr (assoc proc wget-process-length-alist))) (percent (cdr (assoc proc wget-process-percent-alist))) (mime (cdr (assoc proc wget-process-mime-alist))) (dir (cdr (assoc proc wget-process-dir-alist)))) (princ (concat (if byte (number-to-string byte)) (if length (format " / %s byte " length)) (if percent (format "(%d%%) " percent) " ") mime " =3D> " dir)))))) (defun wget-next-line (arg) "Move cursor vertically down ARG lines at beginning of URI." (interactive "p") (forward-line arg) (move-to-column (length wget-download-line-format)) (wget-info)) (defun wget-previous-line (arg) "Move cursor vertically up ARG lines at beginning of URI." (interactive "p") (forward-line (- arg)) (unless (bobp) (move-to-column (length wget-download-line-format)) (wget-info))) ;;;; misc (defun wget-write-download-log (uri) "Write download log into `wget-download-log-file'." (let ((log wget-download-log-file) (case-fold-search nil) str) (when log (setq log (expand-file-name log)) (when (or (file-exists-p log) (eq wget-create-download-log 'always) (and (eq wget-create-download-log 'ask) (y-or-n-p "Create download log file? "))) ;; format log str (setq str (wget-replace-regexp-in-string "%T" (format-time-string wget-download-log-time-format) wget-download-log-format t)) (when (string-match "%t" str) (setq str (wget-replace-regexp-in-string "%t" (read-string "Title: " wget-current-title) str t))) (setq str (wget-replace-regexp-in-string "%U" uri str t)) (save-excursion (set-buffer (or (get-file-buffer log) (find-file-noselect log))) (if wget-add-download-log-eof (goto-char (point-max)) (goto-char (point-min))) (unless (bolp) (insert "\n")) (insert str) (basic-save-buffer)))))) (defun wget-set-file-executable (proc) "Change file permission executable if file extension matches `wget-execut= able-file-extension-list'." (let ((dir (cdr (assoc proc wget-process-dir-alist))) (file (or (cdr (assoc proc wget-process-saved-alist)) (wget-process-file-name proc))) (ext (concat "\\." (regexp-opt wget-executable-file-extension-list= ) "\\'")) modes) (when (string-match ext file) (setq file (expand-file-name file dir)) (if (eq system-type 'windows-nt) (call-process "chmod" nil nil nil "+x" file) (setq modes (logior (file-modes file) ?\111)) (set-file-modes file modes))))) (provide 'wget) (unless noninteractive (run-hooks 'wget-load-hook)) ;;; wget.el ends here --=-=-=--