;;; -*- mode: Emacs-Lisp; coding: euc-japan -*- ;; Copyright (C) 2000 TSUCHIYA Masatoshi ;; Authors: TSUCHIYA Masatoshi , ;; Shun-ichi GOTO , ;; Satoru Takabayashi ;; Hideyuki SHIRAI ;; Keywords: w3m, WWW, hypermedia ;; w3m.el 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 of the License, or ;; (at your option) any later version. ;; w3m.el 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 w3m.el; if not, write to the Free Software Foundation, ;; Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; Commentary: ;; w3m.el is the interface program of w3m on Emacs. For more detail ;; about w3m, see: ;; ;; http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/ ;; ;;; How to install: ;; Please put this file to appropriate directory, and if you want ;; byte-compile it. And add following lisp expressions to your ;; ~/.emacs. ;; ;; (autoload 'w3m "w3m" "Interface for w3m on Emacs." t) ;;; Code: (or (and (boundp 'emacs-major-version) (>= emacs-major-version 20)) (progn (require 'poe) (require 'pcustom))) (defgroup w3m nil "w3m - the web browser of choice." :group 'hypermedia) (defgroup w3m-face nil "Faces for w3m." :group 'w3m :prefix "w3m-") (defcustom w3m-command "w3m" "*Name of the executable file of w3m." :group 'w3m :type 'string) (defcustom w3m-command-arguments '("-e" "-halfdump" "-cols" col url) "*Arguments of w3m." :group 'w3m :type '(repeat (restricted-sexp :match-alternatives (stringp 'col 'url)))) (defcustom w3m-viewer-command "xv" "*Name of the viewer." :group 'w3m :type 'string) (defcustom w3m-viewer-command-arguments '(file) "Arguments of viewer." :group 'w3m :type '(repeat (restricted-sexp :match-alternatives (stringp 'file)))) (defcustom w3m-browser-command "netscape" "*Command name or function name of the browser." :group 'w3m :type '(choice (string :tag "Name of command") (function :tag "Name of function"))) (defcustom w3m-browser-command-arguments '(url) "*Arguments of browser." :group 'w3m :type '(repeat (restricted-sexp :match-alternatives (stringp 'url)))) (defcustom w3m-mailto-url-function nil "*Mailto handling Function." :group 'w3m :type 'function) (defcustom w3m-use-cygdrive t "*If non-nil, use /cygdrive/ rule when expand-file-name." :group 'w3m :type 'boolean) (defcustom w3m-default-save-dir "~/.w3m" "*Default directory for save file." :group 'w3m :type 'directory) (defcustom w3m-coding-system (if (boundp 'MULE) '*euc-japan* 'euc-japan) "*Coding system for w3m." :group 'w3m :type 'symbol) (defcustom w3m-bookmark-file (expand-file-name "~/.w3m/bookmark.html") "*Bookmark file of w3m." :group 'w3m :type 'file) (defcustom w3m-arrived-list-file (expand-file-name "~/.w3m/.arrived") "*Arrived URL file of w3m." :group 'w3m :type 'file) (defcustom w3m-arrived-ct-file (expand-file-name "~/.w3m/.ctcheck") "*Arrived URL's context-type file of w3m." :group 'w3m :type 'file) (defcustom w3m-arrived-file-cs (if (boundp 'MULE) '*euc-japan*unix 'euc-japan-unix) "*Coding system for arrived file." :group 'w3m :type 'symbol) (defcustom w3m-arrived-list-keep 500 "*Arrived keep count of w3m." :group 'w3m :type 'integer) (defcustom w3m-keep-backlog 300 "*Back log size of w3m." :group 'w3m :type 'integer) (defcustom w3m-fill-column (- (frame-width) 4) "*Fill column of w3m." :group 'w3m :type 'integer) (defcustom w3m-always-html-url-regex nil "*If URL is matched this regex, it handle always Text/Html." :group 'w3m :type 'string) (defface w3m-anchor-face '((((class color) (background light)) (:foreground "red" :underline t)) (((class color) (background dark)) (:foreground "blue" :underline t)) (t (:underline t))) "*Face to fontify anchors." :group 'w3m-face) (defface w3m-arrived-anchor-face '((((class color) (background light)) (:foreground "navy" :underline t :bold t)) (((class color) (background dark)) (:foreground "blue" :underline t :bold t)) (t (:underline t))) "*Face to fontify anchors, if arrived." :group 'w3m-face) (defface w3m-image-face '((((class color) (background light)) (:foreground "ForestGreen")) (((class color) (background dark)) (:foreground "PaleGreen")) (t (:underline t))) "*Face to fontify image alternate strings." :group 'w3m-face) (defcustom w3m-hook nil "*Hook run before w3m called." :group 'w3m :type 'hook) (defcustom w3m-mode-hook nil "*Hook run before w3m-mode called." :group 'w3m :type 'hook) (defcustom w3m-fontify-before-hook nil "*Hook run before w3m-fontify called." :group 'w3m :type 'hook) (defcustom w3m-fontify-after-hook nil "*Hook run after w3m-fontify called." :group 'w3m :type 'hook) (defcustom w3m-process-type 'start-process "*Function type for w3m execution." :group 'w3m :type '(choice (symbol :tag "call-process" call-process) (symbol :tag "start-process" start-process))) (defcustom w3m-process-connection-type t "*Process connection type for w3m execution." :group 'w3m :type 'boolean) (defvar w3m-current-url nil "URL of this buffer.") (defvar w3m-current-title nil "Title of this buffer.") (defvar w3m-url-history nil "History of URL.") (defvar w3m-backlog-buffer nil) (defvar w3m-backlog-articles nil) (defvar w3m-backlog-hashtb nil) (defvar w3m-input-url-history nil) (defvar w3m-arrived-anchor-list nil) (defvar w3m-arrived-url-ct nil) (defvar w3m-arrived-user-list nil) (defvar w3m-process nil) (defvar w3m-process-string nil) (defvar w3m-process-url nil) (defvar w3m-process-user nil) (defvar w3m-process-passwd nil) (defvar w3m-process-user-counter 0) (make-variable-buffer-local 'w3m-process) (make-variable-buffer-local 'w3m-process-string) (make-variable-buffer-local 'w3m-process-url) (make-variable-buffer-local 'w3m-process-user) (make-variable-buffer-local 'w3m-process-passwd) (make-variable-buffer-local 'w3m-process-user-counter) (defun w3m-arrived-list-load () "Load arrived url list from 'w3m-arrived-list-file' and 'w3m-arrived-ct-file'." (when (file-readable-p w3m-arrived-ct-file) (with-temp-buffer (let ((file-coding-system-for-read w3m-arrived-file-cs) (coding-system-for-read w3m-arrived-file-cs)) (insert-file-contents w3m-arrived-ct-file) (setq w3m-arrived-url-ct (condition-case nil (read (current-buffer)) (error nil)))))) (when (file-readable-p w3m-arrived-list-file) (with-temp-buffer (let ((file-coding-system-for-read w3m-arrived-file-cs) (coding-system-for-read w3m-arrived-file-cs)) (insert-file-contents w3m-arrived-list-file) (setq w3m-arrived-anchor-list (condition-case nil (read (current-buffer)) (error nil))))))) (defun w3m-arrived-list-save () "Save arrived url list to 'w3m-arrived-list-file' and 'w3m-arrived-ct-file'." (when (> (length w3m-arrived-url-ct) w3m-arrived-list-keep) (setq w3m-arrived-url-ct (nreverse (nthcdr (- (length w3m-arrived-url-ct) w3m-arrived-list-keep) (nreverse w3m-arrived-url-ct))))) (when (and w3m-arrived-url-ct (file-writable-p w3m-arrived-ct-file)) (with-temp-buffer (let ((file-coding-system w3m-arrived-file-cs) (coding-system-for-write w3m-arrived-file-cs)) (prin1 w3m-arrived-url-ct (current-buffer)) (princ "\n" (current-buffer)) (write-region (point-min) (point-max) w3m-arrived-ct-file nil 'nomsg)))) (when (> (length w3m-arrived-anchor-list) w3m-arrived-list-keep) (setq w3m-arrived-anchor-list (nreverse (nthcdr (- (length w3m-arrived-anchor-list) w3m-arrived-list-keep) (nreverse w3m-arrived-anchor-list))))) (when (and w3m-arrived-anchor-list (file-writable-p w3m-arrived-list-file)) (with-temp-buffer (let ((file-coding-system w3m-arrived-file-cs) (coding-system-for-write w3m-arrived-file-cs)) (prin1 w3m-arrived-anchor-list (current-buffer)) (princ "\n" (current-buffer)) (write-region (point-min) (point-max) w3m-arrived-list-file nil 'nomsg) (setq w3m-arrived-anchor-list nil))))) (defun w3m-arrived-list-add (&optional url) "Cons url to 'w3m-arrived-anchor-list'. CAR is newest." (setq url (or url w3m-current-url)) (when (> (length url) 5) ;; ignore short (set-text-properties 0 (length url) nil url) (setq w3m-arrived-anchor-list (cons url (delete url w3m-arrived-anchor-list))))) (defun w3m-fontify () "Fontify this buffer." (let ((case-fold-search t)) (run-hooks 'w3m-fontify-before-hook) ;; Delete extra title tag. (let (start) (and (search-forward "" nil t) (setq start (match-beginning 0)) (search-forward "" nil t) (delete-region start (match-end 0)))) ;; Fontify bold characters. (goto-char (point-min)) (while (search-forward "" nil t) (let ((start (match-beginning 0))) (delete-region start (match-end 0)) (when (search-forward "" nil t) (delete-region (match-beginning 0) (match-end 0)) (put-text-property start (match-beginning 0) 'face 'bold)))) ;; Delete excessive `hseq' elements of anchor tags. (goto-char (point-min)) (while (re-search-forward "]+[ \t\n]href=\\(\"[^\"]*\"\\)" nil t) (setq href (buffer-substring (match-beginning 2) (match-end 2))) (delete-region (match-beginning 2) (match-end 2)) (goto-char (match-beginning 1)) (insert " href=" href))) ;; Fontify anchor tags. (goto-char (point-min)) (while (re-search-forward "]*>" nil t) (let ((url (match-string 2)) (tag (match-string 4)) (start (match-beginning 0)) (end)) (delete-region start (match-end 0)) (cond (url (when (search-forward "" nil t) (delete-region (setq end (match-beginning 0)) (match-end 0)) (if (member (w3m-expand-url url w3m-current-url) w3m-arrived-anchor-list) (put-text-property start end 'face 'w3m-arrived-anchor-face) (put-text-property start end 'face 'w3m-anchor-face)) (put-text-property start end 'w3m-href-anchor url)) (when tag (put-text-property start end 'w3m-name-anchor tag))) (tag (when (re-search-forward "<\\|\n" nil t) (setq end (match-beginning 0)) (put-text-property start end 'w3m-name-anchor tag)))))) ;; Fontify image alternate strings. (goto-char (point-min)) (while (re-search-forward "" nil t) (let ((src (match-string 1)) (start (match-beginning 0)) (end)) (delete-region start (match-end 0)) (when (search-forward "" nil t) (delete-region (setq end (match-beginning 0)) (match-end 0)) (put-text-property start end 'face 'w3m-image-face) (put-text-property start end 'w3m-image src)))) ;; Remove other markups. (goto-char (point-min)) (while (re-search-forward "]*>" nil t) (delete-region (match-beginning 0) (match-end 0))) ;; Decode escaped characters. (goto-char (point-min)) (let (prop) (while (re-search-forward "&\\(\\(nbsp\\)\\|\\(gt\\)\\|\\(lt\\)\\|\\(amp\\)\\|\\(quot\\)\\|\\(apos\\)\\);" nil t) (setq prop (text-properties-at (match-beginning 0))) (delete-region (match-beginning 0) (match-end 0)) (insert (if (match-beginning 2) " " (if (match-beginning 3) ">" (if (match-beginning 4) "<" (if (match-beginning 5) "&" (if (match-beginning 6) "\"" "'")))))) (if prop (add-text-properties (1- (point)) (point) prop)))) (run-hooks 'w3m-fontify-after-hook))) (defun w3m-refontify-anchor (&optional buff) "Change face 'w3m-anchor-face to 'w3m-arrived-anchor-face." (save-excursion (and buff (set-buffer buff)) (when (and (eq major-mode 'w3m-mode) (eq (get-text-property (point) 'face) 'w3m-anchor-face)) (let* (start (end (next-single-property-change (point) 'face)) (buffer-read-only nil)) (when(and end (setq start (previous-single-property-change end 'face))) (put-text-property start end 'face 'w3m-arrived-anchor-face)) (set-buffer-modified-p nil))))) (defun w3m-input-url (&optional prompt default) "Read a URL from the minibuffer, prompting with string PROMPT." (let (url candidates) (w3m-backlog-setup) (or w3m-input-url-history (setq w3m-input-url-history (or w3m-arrived-anchor-list (w3m-arrived-list-load)))) (mapatoms (lambda (x) (setq candidates (cons (cons (symbol-name x) x) candidates))) w3m-backlog-hashtb) (setq url (completing-read (or prompt "URL: ") candidates nil nil default 'w3m-input-url-history default)) ;; remove duplication (setq w3m-input-url-history (cons url (delete url w3m-input-url-history))) ;; return value url)) (defun w3m-backlog-setup () "Initialize backlog variables." (unless (and (bufferp w3m-backlog-buffer) (buffer-live-p w3m-backlog-buffer)) (save-excursion (set-buffer (get-buffer-create " *w3m backlog*")) (buffer-disable-undo) (setq buffer-read-only t w3m-backlog-buffer (current-buffer)))) (unless w3m-backlog-hashtb (setq w3m-backlog-hashtb (make-vector 1021 0)))) (defun w3m-backlog-shutdown () "Clear all backlog variables and buffers." (when (get-buffer w3m-backlog-buffer) (kill-buffer w3m-backlog-buffer)) (setq w3m-backlog-hashtb nil w3m-backlog-articles nil)) (defun w3m-backlog-enter (url buffer) (w3m-backlog-setup) (let ((ident (intern url w3m-backlog-hashtb))) (if (memq ident w3m-backlog-articles) () ; It's already kept. ;; Remove the oldest article, if necessary. (and (numberp w3m-keep-backlog) (>= (length w3m-backlog-articles) w3m-keep-backlog) (w3m-backlog-remove-oldest)) ;; Insert the new article. (save-excursion (set-buffer w3m-backlog-buffer) (let (buffer-read-only) (goto-char (point-max)) (unless (bolp) (insert "\n")) (let ((b (point))) (insert-buffer-substring buffer) ;; Tag the beginning of the article with the ident. (when (> (point-max) b) (put-text-property b (1+ b) 'w3m-backlog ident) (setq w3m-backlog-articles (cons ident w3m-backlog-articles))) )))))) (defun w3m-backlog-remove-oldest () (save-excursion (set-buffer w3m-backlog-buffer) (goto-char (point-min)) (if (zerop (buffer-size)) () ; The buffer is empty. (let ((ident (get-text-property (point) 'w3m-backlog)) buffer-read-only) ;; Remove the ident from the list of articles. (when ident (setq w3m-backlog-articles (delq ident w3m-backlog-articles))) ;; Delete the article itself. (delete-region (point) (next-single-property-change (1+ (point)) 'w3m-backlog nil (point-max))))))) (defun w3m-backlog-remove (url) "Remove data of URL from the backlog." (w3m-backlog-setup) (let ((ident (intern url w3m-backlog-hashtb)) beg end) (when (memq ident w3m-backlog-articles) ;; It was in the backlog. (save-excursion (set-buffer w3m-backlog-buffer) (let (buffer-read-only) (when (setq beg (text-property-any (point-min) (point-max) 'w3m-backlog ident)) ;; Find the end (i. e., the beginning of the next article). (setq end (next-single-property-change (1+ beg) 'w3m-backlog (current-buffer) (point-max))) (delete-region beg end))) (setq w3m-backlog-articles (delq ident w3m-backlog-articles)))))) (defun w3m-backlog-request (url &optional buffer) (w3m-backlog-setup) (let ((ident (intern url w3m-backlog-hashtb))) (when (memq ident w3m-backlog-articles) ;; It was in the backlog. (let (beg end) (save-excursion (set-buffer w3m-backlog-buffer) (if (not (setq beg (text-property-any (point-min) (point-max) 'w3m-backlog ident))) ;; It wasn't in the backlog after all. (setq w3m-backlog-articles (delq ident w3m-backlog-articles)) ;; Find the end (i. e., the beginning of the next article). (setq end (next-single-property-change (1+ beg) 'w3m-backlog (current-buffer) (point-max))))) (and beg end (save-excursion (and buffer (set-buffer buffer)) (let (buffer-read-only) (insert-buffer-substring w3m-backlog-buffer beg end)) t)))))) (defun w3m-exec (url &optional buffer ct) "Download URL with w3m to the BUFFER. If BUFFER is nil, all data is placed to the current buffer. CT denotes content-type." (let ((cbuf (current-buffer))) (when (let ((args (copy-sequence w3m-command-arguments))) (cond ;; backlog exist. ((w3m-backlog-request url) (w3m-exec-w3m url args buffer) nil) ;; ange|efs-ftp ((and (string-match "^ftp://" url) (not (string-match "\\.s?html?$" url))) (w3m-exec-ftp url) t) ;; text/html ((or (string-match "\\.s?html?$\\|/$" url) (and w3m-always-html-url-regex (string-match w3m-always-html-url-regex url)) (eq ct 'text/html)) (w3m-exec-w3m url args buffer) nil) ;; text/* ((or (string-match "\\.\\(txt\\|el\\)$" url) (eq ct 'text)) (setq args (cons "-dump" (delete "-halfdump" args))) (w3m-exec-w3m url args buffer) nil) ;; image/* ((eq ct 'image) (require 'w3) (w3-fetch url) t) ;; application/*, audio/*, etc... ((eq ct 'application) (require 'w3) (let ((mm-download-directory (file-name-as-directory w3m-default-save-dir))) (w3-download-url (w3m-expand-url url w3m-current-url))) t) ;; get context-type and w3-exec() call recursion . ((not ct) (w3m-exec url buffer (w3m-exec-w3m-ctcheck url))) ;; error (t (error "context-type check error.")))) ;; if not exec w3m, return (current-buffer) cbuf))) (defun w3m-exec-w3m-ctcheck (url) (or (cdr (assoc url w3m-arrived-url-ct)) (save-excursion (message "Dump header...") (set-buffer (get-buffer-create " *w3m ctcheck*")) (buffer-disable-undo) (delete-region (point-min) (point-max)) (let ((args (copy-sequence w3m-command-arguments)) (case-fold-search t) (ct 'error)) (setq args (cons "-dump_head" (delete "-halfdump" args))) (w3m-exec-process url args) (message "Dump header... done.") (goto-char (point-min)) (when (re-search-forward "^content-type: " nil t) (setq ct (if (looking-at "text/html") 'text/html (if (looking-at "text") 'text (if (looking-at "image") 'image 'application)))) (setq w3m-arrived-url-ct (cons (cons url ct) w3m-arrived-url-ct)) ct))))) (defun w3m-exec-w3m (url args buffer) (save-excursion (setq buffer-read-only nil) (if buffer (set-buffer buffer)) (delete-region (point-min) (point-max)) (unless (w3m-backlog-request url) (message "Loading page...") (w3m-exec-process url args) (message "Loading page... done.")) (w3m-backlog-enter url (current-buffer)) ;; Setting buffer local variables. (set (make-local-variable 'w3m-current-url) url) (goto-char (point-min)) (let (title) (mapcar (lambda (regexp) (goto-char 1) (when (re-search-forward regexp nil t) (setq title (match-string 1)) (delete-region (match-beginning 0) (match-end 0)))) '("" "\\([^<]\\)")) (if (and (null title) (< 0 (length (file-name-nondirectory url)))) (setq title (file-name-nondirectory url))) (set (make-local-variable 'w3m-current-title) (or title ""))) (set (make-local-variable 'w3m-url-history) (cons url w3m-url-history)) (setq-default w3m-url-history (cons url (default-value 'w3m-url-history))))) (defun w3m-exec-ftp (url) (let ((ftp (w3m-convert-ftp-to-emacsen url)) (file (file-name-nondirectory url))) (if (string-match "\\(\\.gz\\|\\.bz2\\|\\.zip\\|\\.lzh\\)$" file) (copy-file ftp (w3m-read-file-name nil nil file)) (dired-other-window ftp)))) (defun w3m-convert-ftp-to-emacsen (url) (or (and (string-match "^ftp://?\\([^/@]+@\\)?\\([^/]+\\)\\(/~/\\)?" url) (concat "/" (if (match-beginning 1) (substring url (match-beginning 1) (match-end 1)) "anonymous@") (substring url (match-beginning 2) (match-end 2)) ":" (substring url (match-end 2)))) (error "URL is strange."))) (defun w3m-exec-process (url args) (save-excursion (let ((coding-system-for-read w3m-coding-system) (coding-system-for-write w3m-coding-system) (default-process-coding-system (cons w3m-coding-system w3m-coding-system)) (process-connection-type w3m-process-connection-type)) (if (eq w3m-process-type 'start-process) ;; start-process (unwind-protect nil (let () ;; (pop-to-buffer (current-buffer)) (setq w3m-process-url url) (setq w3m-process-string nil) (setq w3m-process-user nil) (setq w3m-process-passwd nil) (setq w3m-process-user-counter 2) (setq buffer-read-only t) (setq w3m-process (apply 'start-process w3m-command (current-buffer) w3m-command (mapcar (lambda (arg) (if (eq arg 'col) (format "%d" w3m-fill-column) (eval arg))) args))) (set-process-coding-system w3m-process w3m-coding-system) (set-process-filter w3m-process 'w3m-exec-filter) (set-process-sentinel w3m-process 'w3m-exec-sentinel) (process-kill-without-query w3m-process) (while w3m-process (sit-for 0.5) (discard-input))) (setq w3m-process nil) (setq w3m-process-url url) (setq w3m-process-string nil) (setq w3m-process-user nil) (setq w3m-process-passwd nil) (setq w3m-process-user-counter 0) (setq buffer-read-only nil)) ;; call-process (apply 'call-process w3m-command nil t nil (mapcar (lambda (arg) (if (eq arg 'col) (format "%d" w3m-fill-column) (eval arg))) args)))))) (defun w3m-exec-filter (process string) (if (bufferp (process-buffer process)) (let ((obuf (buffer-name))) (unwind-protect (progn (set-buffer (process-buffer process)) (let ((buffer-read-only nil) (case-fold-search nil) file input prompt) (goto-char (point-max)) (setq w3m-process-string (concat w3m-process-string string)) (while (string-match "\n" w3m-process-string) (insert (concat (substring w3m-process-string 0 (match-beginning 0)) "\n")) (setq w3m-process-string (substring w3m-process-string (match-end 0)))) (cond ;; username ((string-match "^Username: " w3m-process-string) (setq prompt (match-string 0 w3m-process-string)) (setq w3m-process-string "") (setq w3m-process-user (or (nth 0 (w3m-exec-get-user w3m-process-url)) (read-from-minibuffer prompt))) (process-send-string process (concat w3m-process-user "\n"))) ;; passwd ((string-match "^Password: " w3m-process-string) (setq prompt (match-string 0 w3m-process-string)) (setq w3m-process-string "") (setq w3m-process-passwd (or (nth 1 (w3m-exec-get-user w3m-process-url)) (w3m-read-passwd prompt))) (process-send-string process (concat w3m-process-passwd "\n"))) ;; save file ((string-match "Save file to:" w3m-process-string) (setq w3m-process-string "") (setq input (w3m-read-file-name nil nil w3m-process-url)) (process-send-string process (concat input "\n")) (insert (format "Save to %s.\n" input))) ;; overwrite ((string-match "File exists. Overwrite? (y or n)" w3m-process-string) (setq w3m-process-string "") (condition-case nil (process-send-string process "y\n") (error nil))) ;; quit ((string-match " *Hit any key to quit w3m:" w3m-process-string) (condition-case nil (quit-process process) (error nil)))))) (if (get-buffer obuf) (set-buffer obuf)))))) (defun w3m-exec-get-user (url) (if (= w3m-process-user-counter 0) nil (let ((urllist w3m-arrived-user-list)) (catch 'get (while urllist (when (string-match (concat "^" (regexp-quote (car (car urllist)))) url) (setq w3m-process-user-counter (1- w3m-process-user-counter)) (throw 'get (cdr (car urllist)))) (setq urllist (cdr urllist))))))) (defun w3m-exec-sentinel (process event) (if (bufferp (process-buffer process)) (let ((obuf (buffer-name))) (unwind-protect (progn (set-buffer (process-buffer process)) (if (and w3m-process-url w3m-process-user) (setq w3m-arrived-user-list (cons (cons w3m-process-url (list w3m-process-user w3m-process-passwd)) (delete (assoc w3m-process-url w3m-arrived-user-list) w3m-arrived-user-list)))) (setq w3m-process-string nil) (setq w3m-process nil) (setq w3m-process-url nil) (setq w3m-process-user nil) (setq w3m-process-passwd nil)) (if (get-buffer obuf) (set-buffer obuf)))))) (defun w3m-read-file-name (&optional prompt dir default existing initial) (let* ((default (and default (file-name-nondirectory default))) (prompt (or prompt (if default (format "Save to (%s): " default) "Save to: "))) (initial (or initial default)) (dir (file-name-as-directory (or dir w3m-default-save-dir))) (default-directory dir) (file (read-file-name prompt dir default existing initial))) (if (not (file-directory-p file)) (setq w3m-default-save-dir (or (file-name-directory file) w3m-default-save-dir)) (setq w3m-default-save-dir file) (if default (setq file (expand-file-name default file)))) (expand-file-name file))) (defun w3m-read-passwd (prompt) (let ((inhibit-input-event-recording t)) (if (fboundp 'read-passwd) (condition-case nil (read-passwd prompt) (error "")) (let ((pass "") (c 0) (echo-keystrokes 0) (ociea cursor-in-echo-area)) (condition-case nil (progn (setq cursor-in-echo-area 1) (while (and (/= c ?\r) (/= c ?\n) (/= c ?\e) (/= c 7)) ;; ^G (message "%s%s" prompt (make-string (length pass) ?.)) (setq c (read-char-exclusive)) (cond ((char-equal c ?\C-u) (setq pass "")) ((or (char-equal c ?\b) (char-equal c ?\177)) ;; BS DELL ;; delete one character in the end (if (not (equal pass "")) (setq pass (substring pass 0 -1)))) ((< c 32) ()) ;; control, just ignore (t (setq pass (concat pass (char-to-string c)))))) (setq cursor-in-echo-area -1)) (quit (setq cursor-in-echo-area ociea) (signal 'quit nil)) (error ;; Probably not happen. Just align to the code above. (setq pass ""))) (setq cursor-in-echo-area ociea) (message "") (sit-for 0) pass)))) (defun w3m-search-name-anchor (name &optional quiet) (interactive "sName: ") (let ((pos (point-min))) (catch 'found (while (setq pos (next-single-property-change pos 'w3m-name-anchor)) (when (equal name (get-text-property pos 'w3m-name-anchor)) (goto-char pos) (throw 'found t)) (setq pos (next-single-property-change pos 'w3m-name-anchor))) (unless quiet (message "Not found such name anchor.")) nil))) (defun w3m-save-position (url) (if url (let ((ident (intern-soft url w3m-backlog-hashtb))) (when ident (set ident (cons (window-start) (point))))))) (defun w3m-restore-position (url) (let ((ident (intern-soft url w3m-backlog-hashtb))) (when (and ident (boundp ident)) (set-window-start nil (car (symbol-value ident))) (goto-char (cdr (symbol-value ident)))))) (defun w3m-view-previous-page (&optional arg) (interactive "p") (unless arg (setq arg 1)) (let ((url (nth arg w3m-url-history))) (when url (let (w3m-url-history) (w3m-goto-url url)) ;; restore last position (w3m-restore-position url) (setq w3m-url-history (nthcdr arg w3m-url-history))))) (defun w3m-view-previous-point () (interactive) (w3m-restore-position w3m-current-url)) (defun w3m-expand-url (url base) "Convert URL to absolute, and canonicalize it." (if (not base) (setq base "")) (if (string-match "^[^:]+://[^/]*$" base) (setq base (concat base "/"))) (cond ;; URL is relative on BASE. ((string-match "^#" url) (concat base url)) ;; URL has absolute spec. ((string-match "^[^:]+:" url) url) ((string-match "^/" url) (if (string-match "^\\([^:]+://[^/]*\\)/" base) (concat (match-string 1 base) url) url)) (t (let ((server "") path) (if (string-match "^\\([^:]+://[^/]*\\)/" base) (setq server (match-string 1 base) base (substring base (match-end 1)))) (setq path (expand-file-name url (file-name-directory base))) ;; remove drive (for Win32 platform) (if (string-match "^.:" path) (setq path (substring path (match-end 0)))) (concat server path))))) (defun w3m-view-this-url (arg) "*View the URL of the link under point." (interactive "P") (let ((url (get-text-property (point) 'w3m-href-anchor))) (if url (w3m-goto-url (w3m-expand-url url w3m-current-url) arg)))) (defun w3m-mouse-view-this-url (event) (interactive "e") (mouse-set-point event) (call-interactively (function w3m-view-this-url))) (defun w3m-view-image () "*View the image under point." (interactive) (let ((file (get-text-property (point) 'w3m-image))) (if (not file) (message "No file at point.") (require 'w3) (w3-fetch (w3m-expand-url file w3m-current-url))))) (defun w3m-save-image () "*Save the image under point to a file." (interactive) (let ((file (get-text-property (point) 'w3m-image))) (if (not file) (message "No file at point.") (require 'w3) (let ((mm-download-directory (file-name-as-directory w3m-default-save-dir))) (w3-download-url (w3m-expand-url file w3m-current-url)))))) (defun w3m-view-current-url-with-external-browser () "*View this URL." (interactive) (let ((buffer (get-buffer-create " *w3m-view*")) (url (get-text-property (point) 'w3m-href-anchor))) (if url (setq url (w3m-expand-url url w3m-current-url)) (if (y-or-n-p (format "Browse <%s> ? " w3m-current-url)) (setq url w3m-current-url))) (when url (message "Browse <%s>" url) (if (and (symbolp w3m-browser-command) (fboundp w3m-browser-command)) (funcall w3m-browser-command url) (apply 'start-process "w3m-external-browser" buffer w3m-browser-command (mapcar (function eval) w3m-browser-command-arguments)))))) (defun w3m-download-this-url () "*Download the URL of the link under point to a file." (interactive) (let ((url (get-text-property (point) 'w3m-href-anchor))) (if (not url) (message "No URL at point.") (require 'w3) (let ((mm-download-directory (file-name-as-directory w3m-default-save-dir))) (w3-download-url (w3m-expand-url url w3m-current-url))) (w3m-refontify-anchor (current-buffer))))) (defun w3m-print-current-url () "*Print the URL of current page and push it into kill-ring." (interactive) (kill-new w3m-current-url) (message "%s" w3m-current-url)) (defun w3m-print-this-url () "*Print the URL of the link under point." (interactive) (let ((url (get-text-property (point) 'w3m-href-anchor))) (if url (kill-new (setq url (w3m-expand-url url w3m-current-url)))) (message "%s" (or url "Not found.")))) (defun w3m-next-anchor (&optional arg) "*Move cursor to the next anchor." (interactive "p") (unless arg (setq arg 1)) (if (< arg 0) ;; If ARG is negative. (w3m-previous-anchor (- arg)) (when (get-text-property (point) 'w3m-href-anchor) (goto-char (next-single-property-change (point) 'w3m-href-anchor))) (while (and (> arg 0) (setq pos (next-single-property-change (point) 'w3m-href-anchor))) (goto-char pos) (unless (zerop (setq arg (1- arg))) (goto-char (next-single-property-change (point) 'w3m-href-anchor)))))) (defun w3m-previous-anchor (&optional arg) "Move cursor to the previous anchor." (interactive "p") (unless arg (setq arg 1)) (if (< arg 0) ;; If ARG is negative. (w3m-next-anchor (- arg)) (when (get-text-property (point) 'w3m-href-anchor) (goto-char (previous-single-property-change (1+ (point)) 'w3m-href-anchor))) (while (and (> arg 0) (setq pos (previous-single-property-change (point) 'w3m-href-anchor))) (goto-char (previous-single-property-change pos 'w3m-href-anchor)) (setq arg (1- arg))))) (defun w3m-expand-file-name (file) (setq file (expand-file-name file)) (if (string-match "^\\(.\\):\\(.*\\)" file) (if w3m-use-cygdrive (concat "/cygdrive/" (match-string 1 file) (match-string 2 file)) (concat "file://" (match-string 1 file) (match-string 2 file))) file)) (defun w3m-view-bookmark () (interactive) (if (file-readable-p w3m-bookmark-file) (w3m-goto-url (w3m-expand-file-name w3m-bookmark-file)))) (defun w3m-copy-buffer (buf &optional newname and-pop) "\ Create a twin copy of the current buffer. if NEWNAME is nil, it defaults to the current buffer's name. if AND-POP is non-nil, the new buffer is shown with `pop-to-buffer'." (interactive (list (current-buffer) (if current-prefix-arg (read-string "Name: ")) t)) (setq newname (or newname (buffer-name))) (if (string-match "<[0-9]+>\\'" newname) (setq newname (substring newname 0 (match-beginning 0)))) (with-current-buffer buf (let ((ptmin (point-min)) (ptmax (point-max)) (content (save-restriction (widen) (buffer-string))) (mode major-mode) (lvars (buffer-local-variables)) (new (generate-new-buffer (or newname (buffer-name))))) (with-current-buffer new ;;(erase-buffer) (insert content) (narrow-to-region ptmin ptmax) (funcall mode) ;still needed?? -sm (mapcar (lambda (v) (if (not (consp v)) (makunbound v) (condition-case () ;in case var is read-only (set (make-local-variable (car v)) (cdr v)) (error nil)))) lvars) (when and-pop (pop-to-buffer new)) new)))) (defvar w3m-mode-map nil) (unless w3m-mode-map (setq w3m-mode-map (make-keymap)) (define-key w3m-mode-map " " 'scroll-up) (define-key w3m-mode-map "b" 'scroll-down) (define-key w3m-mode-map [backspace] 'scroll-down) (define-key w3m-mode-map [delete] 'scroll-down) (define-key w3m-mode-map "h" 'backward-char) (define-key w3m-mode-map "j" 'next-line) (define-key w3m-mode-map "k" 'previous-line) (define-key w3m-mode-map "l" 'forward-char) (define-key w3m-mode-map "J" (lambda () (interactive) (scroll-up 1))) (define-key w3m-mode-map "K" (lambda () (interactive) (scroll-up -1))) (define-key w3m-mode-map "G" 'goto-line) (define-key w3m-mode-map "\C-?" 'scroll-down) (define-key w3m-mode-map "\t" 'w3m-next-anchor) (define-key w3m-mode-map [down] 'w3m-next-anchor) (define-key w3m-mode-map "\M-\t" 'w3m-previous-anchor) (define-key w3m-mode-map [up] 'w3m-previous-anchor) (define-key w3m-mode-map "\C-m" 'w3m-view-this-url) (define-key w3m-mode-map [right] 'w3m-view-this-url) (if (featurep 'xemacs) (define-key w3m-mode-map [(button2)] 'w3m-mouse-view-this-url) (define-key w3m-mode-map [mouse-2] 'w3m-mouse-view-this-url)) (define-key w3m-mode-map "\C-c\C-b" 'w3m-view-previous-point) (define-key w3m-mode-map [left] 'w3m-view-previous-page) (define-key w3m-mode-map "B" 'w3m-view-previous-page) (define-key w3m-mode-map "d" 'w3m-download-this-url) (define-key w3m-mode-map "u" 'w3m-print-this-url) (define-key w3m-mode-map "I" 'w3m-view-image) (define-key w3m-mode-map "\M-I" 'w3m-save-image) (define-key w3m-mode-map "c" 'w3m-print-current-url) (define-key w3m-mode-map "M" 'w3m-view-current-url-with-external-browser) (define-key w3m-mode-map "g" 'w3m) (define-key w3m-mode-map "U" 'w3m) (define-key w3m-mode-map "V" 'w3m) (define-key w3m-mode-map "v" 'w3m-view-bookmark) (define-key w3m-mode-map "q" 'w3m-quit) (define-key w3m-mode-map "Q" (lambda () (interactive) (w3m-quit t))) (define-key w3m-mode-map "\M-n" 'w3m-copy-buffer) (define-key w3m-mode-map "R" 'w3m-reload-this-page) (define-key w3m-mode-map "?" 'describe-mode) ) (defun w3m-quit (&optional force) (interactive "P") (when (or force (y-or-n-p "Do you want to exit w3m? ")) (kill-buffer (current-buffer)) (w3m-arrived-list-save) (or (save-excursion ;; Check existing w3m buffers. (delq nil (mapcar (lambda (b) (set-buffer b) (eq major-mode 'w3m-mode)) (buffer-list)))) ;; If no w3m buffer exists, then destruct all cache. (w3m-backlog-shutdown)))) (defun w3m-mode () "\\ Major mode to browsing w3m buffer. \\[w3m-view-this-url] View this url. \\[w3m-mouse-view-this-url] View this url. \\[w3m-reload-this-page] Reload this page. \\[w3m-next-anchor] Jump next anchor. \\[w3m-previous-anchor] Jump previous anchor. \\[w3m-view-previous-page] Back to previous page. \\[w3m-download-this-url] Download this url. \\[w3m-print-this-url] Print this url. \\[w3m-view-image] View image. \\[w3m-save-image] Save image. \\[w3m-print-current-url] Print current url. \\[w3m-view-current-url-with-external-browser] View current url with external browser. \\[scroll-up] Scroll up. \\[scroll-down] Scroll down. \\[next-line] Next line. \\[previous-line] Previous line. \\[forward-char] Forward char. \\[backward-char] Backward char. \\[goto-line] Jump to line. \\[w3m-view-previous-point] w3m-view-previous-point. \\[w3m] w3m. \\[w3m-view-bookmark] w3m-view-bookmark. \\[w3m-copy-buffer] w3m-copy-buffer. \\[w3m-quit] w3m-quit. \\[describe-mode] describe-mode. " (kill-all-local-variables) (buffer-disable-undo) (setq major-mode 'w3m-mode mode-name "w3m") (use-local-map w3m-mode-map) (run-hooks 'w3m-mode-hook)) (defun w3m-mailto-url (url) (if (and (symbolp w3m-mailto-url-function) (fboundp w3m-mailto-url-function)) (funcall w3m-mailto-url-function url) (let (comp) ;; Require `mail-user-agent' setting (if (not (and (boundp 'mail-user-agent) mail-user-agent (setq comp (intern-soft (concat (symbol-name mail-user-agent) "-compose"))) (fboundp comp))) (error "You must specify valid `mail-user-agent'.")) ;; Use rfc2368.el if exist. ;; rfc2368.el is written by Sen Nagata. ;; You can find it in "contrib" directory of Mew package ;; or in "utils" directory of Wanderlust package. (if (or (featurep 'rfc2368) (condition-case nil (require 'rfc2368) (error nil))) (let ((info (rfc2368-parse-mailto-url url))) (apply comp (mapcar (lambda (x) (cdr (assoc x info))) '("To" "Subject")))) ;; without rfc2368.el. (funcall comp (match-string 1 url)))))) (defun w3m-goto-url (url &optional reload) "Retrieve URL and display it in this buffer." (let (name buff) (if reload (w3m-backlog-remove url)) (cond ;; process mailto: protocol ((string-match "^mailto:\\(.*\\)" url) (w3m-mailto-url url)) (t (when (string-match "#\\([^#]+\\)$" url) (setq name (match-string 1 url) url (substring url 0 (match-beginning 0)))) (w3m-save-position w3m-current-url) (or w3m-arrived-anchor-list (w3m-arrived-list-load)) (w3m-arrived-list-add url) (if (setq buff (w3m-exec url)) ;; no w3m exec and return *w3m* buffer. (w3m-refontify-anchor buff) ;; w3m exec. (w3m-fontify) (setq buffer-read-only t) (set-buffer-modified-p nil) (or (and name (w3m-search-name-anchor name)) (goto-char (point-min)))))))) (defun w3m-reload-this-page () "Reload current page without cache." (interactive) (setq w3m-url-history (cdr w3m-url-history)) (w3m-goto-url w3m-current-url 'reload)) (defun w3m (url &optional args) "Interface for w3m on Emacs." (interactive (list (w3m-input-url))) (set-buffer (get-buffer-create "*w3m*")) (or (eq major-mode 'w3m-mode) (w3m-mode)) (setq mode-line-buffer-identification (list "%12b" " / " 'w3m-current-title)) (if (string= url "") (w3m-view-bookmark) (w3m-goto-url url)) (switch-to-buffer (current-buffer)) (run-hooks 'w3m-hook)) (defun w3m-browse-url (url &optional new-window) "w3m interface function for browse-url.el." (interactive (progn (require 'browse-url) (browse-url-interactive-arg "w3m URL: "))) (if new-window (split-window)) (w3m url)) (defun w3m-find-file (file) "w3m Interface function for local file." (interactive "fFilename: ") (w3m (w3m-expand-file-name file))) (provide 'w3m) ;;; w3m.el ends here.