Mercurial > hg > xemacs-beta
comparison lisp/w3/url-cache.el @ 26:441bb1e64a06 r19-15b96
Import from CVS: tag r19-15b96
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:51:32 +0200 |
parents | |
children | ec9a17fef872 |
comparison
equal
deleted
inserted
replaced
25:383a494979f8 | 26:441bb1e64a06 |
---|---|
1 ;;; url-cache.el --- Uniform Resource Locator retrieval tool | |
2 ;; Author: wmperry | |
3 ;; Created: 1997/02/20 15:33:47 | |
4 ;; Version: 1.3 | |
5 ;; Keywords: comm, data, processes, hypermedia | |
6 | |
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
8 ;;; Copyright (c) 1993-1996 by William M. Perry (wmperry@cs.indiana.edu) | |
9 ;;; Copyright (c) 1996, 1997 Free Software Foundation, Inc. | |
10 ;;; | |
11 ;;; This file is not part of GNU Emacs, but the same permissions apply. | |
12 ;;; | |
13 ;;; GNU Emacs is free software; you can redistribute it and/or modify | |
14 ;;; it under the terms of the GNU General Public License as published by | |
15 ;;; the Free Software Foundation; either version 2, or (at your option) | |
16 ;;; any later version. | |
17 ;;; | |
18 ;;; GNU Emacs is distributed in the hope that it will be useful, | |
19 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 ;;; GNU General Public License for more details. | |
22 ;;; | |
23 ;;; You should have received a copy of the GNU General Public License | |
24 ;;; along with GNU Emacs; see the file COPYING. If not, write to the | |
25 ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
26 ;;; Boston, MA 02111-1307, USA. | |
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
28 (require 'md5) | |
29 | |
30 ;; Cache manager | |
31 (defun url-cache-file-writable-p (file) | |
32 "Follows the documentation of file-writable-p, unlike file-writable-p." | |
33 (and (file-writable-p file) | |
34 (if (file-exists-p file) | |
35 (not (file-directory-p file)) | |
36 (file-directory-p (file-name-directory file))))) | |
37 | |
38 (defun url-prepare-cache-for-file (file) | |
39 "Makes it possible to cache data in FILE. | |
40 Creates any necessary parent directories, deleting any non-directory files | |
41 that would stop this. Returns nil if parent directories can not be | |
42 created. If FILE already exists as a non-directory, it changes | |
43 permissions of FILE or deletes FILE to make it possible to write a new | |
44 version of FILE. Returns nil if this can not be done. Returns nil if | |
45 FILE already exists as a directory. Otherwise, returns t, indicating that | |
46 FILE can be created or overwritten." | |
47 | |
48 ;; COMMENT: We don't delete directories because that requires | |
49 ;; recursively deleting the directories's contents, which might | |
50 ;; eliminate a substantial portion of the cache. | |
51 | |
52 (cond | |
53 ((url-cache-file-writable-p file) | |
54 t) | |
55 ((file-directory-p file) | |
56 nil) | |
57 (t | |
58 (catch 'upcff-tag | |
59 (let ((dir (file-name-directory file)) | |
60 dir-parent dir-last-component) | |
61 (if (string-equal dir file) | |
62 ;; *** Should I have a warning here? | |
63 ;; FILE must match a pattern like /foo/bar/, indicating it is a | |
64 ;; name only suitable for a directory. So presume we won't be | |
65 ;; able to overwrite FILE and return nil. | |
66 (throw 'upcff-tag nil)) | |
67 | |
68 ;; Make sure the containing directory exists, or throw a failure | |
69 ;; if we can't create it. | |
70 (if (file-directory-p dir) | |
71 nil | |
72 (or (fboundp 'make-directory) | |
73 (throw 'upcff-tag nil)) | |
74 (make-directory dir t) | |
75 ;; make-directory silently fails if there is an obstacle, so | |
76 ;; we must verify its results. | |
77 (if (file-directory-p dir) | |
78 nil | |
79 ;; Look at prefixes of the path to find the obstacle that is | |
80 ;; stopping us from making the directory. Unfortunately, there | |
81 ;; is no portable function in Emacs to find the parent directory | |
82 ;; of a *directory*. So this code may not work on VMS. | |
83 (while (progn | |
84 (if (eq ?/ (aref dir (1- (length dir)))) | |
85 (setq dir (substring dir 0 -1)) | |
86 ;; Maybe we're on VMS where the syntax is different. | |
87 (throw 'upcff-tag nil)) | |
88 (setq dir-parent (file-name-directory dir)) | |
89 (not (file-directory-p dir-parent))) | |
90 (setq dir dir-parent)) | |
91 ;; We have found the longest path prefix that exists as a | |
92 ;; directory. Deal with any obstacles in this directory. | |
93 (if (file-exists-p dir) | |
94 (condition-case nil | |
95 (delete-file dir) | |
96 (error (throw 'upcff-tag nil)))) | |
97 (if (file-exists-p dir) | |
98 (throw 'upcff-tag nil)) | |
99 ;; Try making the directory again. | |
100 (setq dir (file-name-directory file)) | |
101 (make-directory dir t) | |
102 (or (file-directory-p dir) | |
103 (throw 'upcff-tag nil)))) | |
104 | |
105 ;; The containing directory exists. Let's see if there is | |
106 ;; something in the way in this directory. | |
107 (if (url-cache-file-writable-p file) | |
108 (throw 'upcff-tag t) | |
109 (condition-case nil | |
110 (delete-file file) | |
111 (error (throw 'upcff-tag nil)))) | |
112 | |
113 ;; The return value, if we get this far. | |
114 (url-cache-file-writable-p file)))))) | |
115 | |
116 (defvar url-cache-ignored-protocols | |
117 '("www" "about" "https" "mailto") | |
118 "*A list of protocols that we should never cache.") | |
119 | |
120 (defun url-cache-cachable-p (obj) | |
121 ;; return t iff the current buffer is cachable | |
122 (cond | |
123 ((null obj) ; Something horribly confused | |
124 nil) | |
125 ((member (url-type obj) url-cache-ignored-protocols) | |
126 ;; We have been told to ignore this type of object | |
127 nil) | |
128 ((and (member (url-type obj) '("file" "ftp")) (not (url-host obj))) | |
129 ;; We never want to cache local files... what's the point? | |
130 nil) | |
131 ((member (url-type obj) '("http" "https")) | |
132 (let* ((status (cdr-safe (assoc "status" url-current-mime-headers))) | |
133 (class (if status (/ status 100) 0))) | |
134 (case class | |
135 (2 ; Various 'OK' statuses | |
136 (memq status '(200))) | |
137 (otherwise nil)))) | |
138 (t | |
139 nil))) | |
140 | |
141 ;;;###autoload | |
142 (defun url-store-in-cache (&optional buff) | |
143 "Store buffer BUFF in the cache" | |
144 (if (and buff (get-buffer buff)) | |
145 nil | |
146 (save-excursion | |
147 (and buff (set-buffer buff)) | |
148 (if (not (url-cache-cachable-p url-current-object)) | |
149 nil | |
150 (let* ((fname (url-create-cached-filename (url-view-url t))) | |
151 (fname-hdr (concat fname ".hdr")) | |
152 (info (mapcar (function (lambda (var) | |
153 (cons (symbol-name var) | |
154 (symbol-value var)))) | |
155 '( url-current-content-length | |
156 url-current-object | |
157 url-current-isindex | |
158 url-current-mime-encoding | |
159 url-current-mime-headers | |
160 url-current-mime-type | |
161 )))) | |
162 (cond ((and (url-prepare-cache-for-file fname) | |
163 (url-prepare-cache-for-file fname-hdr)) | |
164 (write-region (point-min) (point-max) fname nil 5) | |
165 (set-buffer (get-buffer-create " *cache-tmp*")) | |
166 (erase-buffer) | |
167 (insert "(setq ") | |
168 (mapcar | |
169 (function | |
170 (lambda (x) | |
171 (insert (car x) " " | |
172 (cond ((null (setq x (cdr x))) "nil") | |
173 ((stringp x) (prin1-to-string x)) | |
174 ((listp x) (concat "'" (prin1-to-string x))) | |
175 ((vectorp x) (prin1-to-string x)) | |
176 ((numberp x) (int-to-string x)) | |
177 (t "'???")) "\n"))) | |
178 info) | |
179 (insert ")\n") | |
180 (write-region (point-min) (point-max) fname-hdr nil 5)))))))) | |
181 | |
182 | |
183 ;;;###autoload | |
184 (defun url-is-cached (url) | |
185 "Return non-nil if the URL is cached." | |
186 (let* ((fname (url-create-cached-filename url)) | |
187 (attribs (file-attributes fname))) | |
188 (and fname ; got a filename | |
189 (file-exists-p fname) ; file exists | |
190 (not (eq (nth 0 attribs) t)) ; Its not a directory | |
191 (nth 5 attribs)))) ; Can get last mod-time | |
192 | |
193 (defun url-create-cached-filename-using-md5 (url) | |
194 (if url | |
195 (expand-file-name (md5 url) | |
196 (concat url-temporary-directory "/" | |
197 (user-real-login-name))))) | |
198 | |
199 ;;;###autoload | |
200 (defun url-create-cached-filename (url) | |
201 "Return a filename in the local cache for URL" | |
202 (if url | |
203 (let* ((url url) | |
204 (urlobj (if (vectorp url) | |
205 url | |
206 (url-generic-parse-url url))) | |
207 (protocol (url-type urlobj)) | |
208 (hostname (url-host urlobj)) | |
209 (host-components | |
210 (cons | |
211 (user-real-login-name) | |
212 (cons (or protocol "file") | |
213 (nreverse | |
214 (delq nil | |
215 (mm-string-to-tokens | |
216 (or hostname "localhost") ?.)))))) | |
217 (fname (url-filename urlobj))) | |
218 (if (and fname (/= (length fname) 0) (= (aref fname 0) ?/)) | |
219 (setq fname (substring fname 1 nil))) | |
220 (if fname | |
221 (let ((slash nil)) | |
222 (setq fname | |
223 (mapconcat | |
224 (function | |
225 (lambda (x) | |
226 (cond | |
227 ((and (= ?/ x) slash) | |
228 (setq slash nil) | |
229 "%2F") | |
230 ((= ?/ x) | |
231 (setq slash t) | |
232 "/") | |
233 (t | |
234 (setq slash nil) | |
235 (char-to-string x))))) fname "")))) | |
236 | |
237 (if (and fname (memq system-type '(ms-windows ms-dos windows-nt)) | |
238 (string-match "\\([A-Za-z]\\):[/\\]" fname)) | |
239 (setq fname (concat (url-match fname 1) "/" | |
240 (substring fname (match-end 0))))) | |
241 | |
242 (setq fname (and fname | |
243 (mapconcat | |
244 (function (lambda (x) | |
245 (if (= x ?~) "" (char-to-string x)))) | |
246 fname "")) | |
247 fname (cond | |
248 ((null fname) nil) | |
249 ((or (string= "" fname) (string= "/" fname)) | |
250 url-directory-index-file) | |
251 ((= (string-to-char fname) ?/) | |
252 (if (string= (substring fname -1 nil) "/") | |
253 (concat fname url-directory-index-file) | |
254 (substring fname 1 nil))) | |
255 (t | |
256 (if (string= (substring fname -1 nil) "/") | |
257 (concat fname url-directory-index-file) | |
258 fname)))) | |
259 | |
260 ;; Honor hideous 8.3 filename limitations on dos and windows | |
261 ;; we don't have to worry about this in Windows NT/95 (or OS/2?) | |
262 (if (and fname (memq system-type '(ms-windows ms-dos))) | |
263 (let ((base (url-file-extension fname t)) | |
264 (ext (url-file-extension fname nil))) | |
265 (setq fname (concat (substring base 0 (min 8 (length base))) | |
266 (substring ext 0 (min 4 (length ext))))) | |
267 (setq host-components | |
268 (mapcar | |
269 (function | |
270 (lambda (x) | |
271 (if (> (length x) 8) | |
272 (concat | |
273 (substring x 0 8) "." | |
274 (substring x 8 (min (length x) 11))) | |
275 x))) | |
276 host-components)))) | |
277 | |
278 (and fname | |
279 (expand-file-name fname | |
280 (expand-file-name | |
281 (mapconcat 'identity host-components "/") | |
282 url-temporary-directory)))))) | |
283 | |
284 ;;;###autoload | |
285 (defun url-extract-from-cache (fnam) | |
286 "Extract FNAM from the local disk cache" | |
287 (set-buffer (get-buffer-create url-working-buffer)) | |
288 (erase-buffer) | |
289 (setq url-current-mime-viewer nil) | |
290 (insert-file-contents-literally fnam) | |
291 (load (concat (if (memq system-type '(ms-windows ms-dos os2)) | |
292 (url-file-extension fnam t) | |
293 fnam) ".hdr") t t)) | |
294 | |
295 ;;;###autoload | |
296 (defun url-cache-expired (url mod) | |
297 "Return t iff a cached file has expired." | |
298 (if (not (string-match url-nonrelative-link url)) | |
299 t | |
300 (let* ((urlobj (url-generic-parse-url url)) | |
301 (type (url-type urlobj))) | |
302 (cond | |
303 (url-standalone-mode | |
304 (not (file-exists-p (url-create-cached-filename urlobj)))) | |
305 ((string= type "http") | |
306 (if (not url-standalone-mode) t | |
307 (not (file-exists-p (url-create-cached-filename urlobj))))) | |
308 ((not (fboundp 'current-time)) | |
309 t) | |
310 ((member type '("file" "ftp")) | |
311 (if (or (equal mod '(0 0)) (not mod)) | |
312 (return t) | |
313 (or (> (nth 0 mod) (nth 0 (current-time))) | |
314 (> (nth 1 mod) (nth 1 (current-time)))))) | |
315 (t nil))))) | |
316 | |
317 (provide 'url-cache) |