remove sigio blocking
[bpt/emacs.git] / lisp / url / url-util.el
CommitLineData
8c8b8430 1;;; url-util.el --- Miscellaneous helper routines for URL library
a2fd1462 2
93a583ee 3;; Copyright (C) 1996-1999, 2001, 2004-2014 Free Software Foundation, Inc.
a2fd1462 4
8c8b8430 5;; Author: Bill Perry <wmperry@gnu.org>
93a583ee 6;; Maintainer: emacs-devel@gnu.org
8c8b8430
SM
7;; Keywords: comm, data, processes
8
a2fd1462
SM
9;; This file is part of GNU Emacs.
10;;
4936186e 11;; GNU Emacs is free software: you can redistribute it and/or modify
a2fd1462 12;; it under the terms of the GNU General Public License as published by
4936186e
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
15
a2fd1462
SM
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
4936186e 20
a2fd1462 21;; You should have received a copy of the GNU General Public License
4936186e 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
a2fd1462
SM
23
24;;; Commentary:
25
26;;; Code:
8c8b8430
SM
27
28(require 'url-parse)
e17d428f 29(require 'url-vars)
8c8b8430
SM
30(autoload 'timezone-parse-date "timezone")
31(autoload 'timezone-make-date-arpa-standard "timezone")
c6bfe6e7 32(autoload 'mail-header-extract "mailheader")
8c8b8430
SM
33
34(defvar url-parse-args-syntax-table
35 (copy-syntax-table emacs-lisp-mode-syntax-table)
36 "A syntax table for parsing sgml attributes.")
37
38(modify-syntax-entry ?' "\"" url-parse-args-syntax-table)
39(modify-syntax-entry ?` "\"" url-parse-args-syntax-table)
40(modify-syntax-entry ?{ "(" url-parse-args-syntax-table)
41(modify-syntax-entry ?} ")" url-parse-args-syntax-table)
42
43;;;###autoload
44(defcustom url-debug nil
a5cda60e 45 "What types of debug messages from the URL library to show.
8c8b8430
SM
46Debug messages are logged to the *URL-DEBUG* buffer.
47
48If t, all messages will be logged.
49If a number, all messages will be logged, as well shown via `message'.
50If a list, it is a list of the types of messages to be logged."
51 :type '(choice (const :tag "none" nil)
52 (const :tag "all" t)
53 (checklist :tag "custom"
54 (const :tag "HTTP" :value http)
55 (const :tag "DAV" :value dav)
56 (const :tag "General" :value retrieval)
57 (const :tag "Filename handlers" :value handlers)
58 (symbol :tag "Other")))
59 :group 'url-hairy)
60
61;;;###autoload
62(defun url-debug (tag &rest args)
63 (if quit-flag
64 (error "Interrupted!"))
65 (if (or (eq url-debug t)
66 (numberp url-debug)
67 (and (listp url-debug) (memq tag url-debug)))
a2fd1462 68 (with-current-buffer (get-buffer-create "*URL-DEBUG*")
8c8b8430
SM
69 (goto-char (point-max))
70 (insert (symbol-name tag) " -> " (apply 'format args) "\n")
71 (if (numberp url-debug)
72 (apply 'message args)))))
73
74;;;###autoload
75(defun url-parse-args (str &optional nodowncase)
76 ;; Return an assoc list of attribute/value pairs from an RFC822-type string
77 (let (
78 name ; From name=
79 value ; its value
80 results ; Assoc list of results
81 name-pos ; Start of XXXX= position
82 val-pos ; Start of value position
83 st
84 nd
85 )
86 (save-excursion
87 (save-restriction
88 (set-buffer (get-buffer-create " *urlparse-temp*"))
89 (set-syntax-table url-parse-args-syntax-table)
90 (erase-buffer)
91 (insert str)
92 (setq st (point-min)
93 nd (point-max))
94 (set-syntax-table url-parse-args-syntax-table)
95 (narrow-to-region st nd)
96 (goto-char (point-min))
97 (while (not (eobp))
98 (skip-chars-forward "; \n\t")
99 (setq name-pos (point))
100 (skip-chars-forward "^ \n\t=;")
101 (if (not nodowncase)
102 (downcase-region name-pos (point)))
103 (setq name (buffer-substring name-pos (point)))
104 (skip-chars-forward " \t\n")
105 (if (/= (or (char-after (point)) 0) ?=) ; There is no value
106 (setq value nil)
107 (skip-chars-forward " \t\n=")
108 (setq val-pos (point)
109 value
110 (cond
111 ((or (= (or (char-after val-pos) 0) ?\")
112 (= (or (char-after val-pos) 0) ?'))
113 (buffer-substring (1+ val-pos)
114 (condition-case ()
115 (prog2
116 (forward-sexp 1)
117 (1- (point))
118 (skip-chars-forward "\""))
119 (error
120 (skip-chars-forward "^ \t\n")
121 (point)))))
122 (t
123 (buffer-substring val-pos
124 (progn
125 (skip-chars-forward "^;")
126 (skip-chars-backward " \t")
127 (point)))))))
128 (setq results (cons (cons name value) results))
129 (skip-chars-forward "; \n\t"))
130 results))))
131
132;;;###autoload
133(defun url-insert-entities-in-string (string)
134 "Convert HTML markup-start characters to entity references in STRING.
135Also replaces the \" character, so that the result may be safely used as
04558d31
BG
136an attribute value in a tag. Returns a new string with the result of the
137conversion. Replaces these characters as follows:
8c8b8430
SM
138 & ==> &amp;
139 < ==> &lt;
140 > ==> &gt;
141 \" ==> &quot;"
142 (if (string-match "[&<>\"]" string)
937e6a56 143 (with-current-buffer (get-buffer-create " *entity*")
8c8b8430
SM
144 (erase-buffer)
145 (buffer-disable-undo (current-buffer))
146 (insert string)
147 (goto-char (point-min))
148 (while (progn
149 (skip-chars-forward "^&<>\"")
150 (not (eobp)))
151 (insert (cdr (assq (char-after (point))
152 '((?\" . "&quot;")
153 (?& . "&amp;")
154 (?< . "&lt;")
155 (?> . "&gt;")))))
156 (delete-char 1))
157 (buffer-string))
158 string))
159
160;;;###autoload
161(defun url-normalize-url (url)
162 "Return a 'normalized' version of URL.
163Strips out default port numbers, etc."
07e9b3f0 164 (let (type data retval)
8c8b8430
SM
165 (setq data (url-generic-parse-url url)
166 type (url-type data))
167 (if (member type '("www" "about" "mailto" "info"))
168 (setq retval url)
4968291f
GM
169 ;; FIXME all this does, and all this function seems to do in
170 ;; most cases, is remove any trailing "#anchor" part of a url.
d18ec89f 171 (setf (url-target data) nil)
8c8b8430
SM
172 (setq retval (url-recreate-url data)))
173 retval))
174
175;;;###autoload
176(defun url-lazy-message (&rest args)
177 "Just like `message', but is a no-op if called more than once a second.
a2fd1462 178Will not do anything if `url-show-status' is nil."
08b8ba9f
LMI
179 (if (or (and url-current-object
180 (url-silent url-current-object))
181 (null url-show-status)
8c8b8430
SM
182 (active-minibuffer-window)
183 (= url-lazy-message-time
184 (setq url-lazy-message-time (nth 1 (current-time)))))
185 nil
186 (apply 'message args)))
187
188;;;###autoload
189(defun url-get-normalized-date (&optional specified-time)
d626f888
TZ
190 "Return a 'real' date string that most HTTP servers can understand."
191 (let ((system-time-locale "C"))
192 (format-time-string "%a, %d %b %Y %T GMT"
193 (or specified-time (current-time)) t)))
8c8b8430
SM
194
195;;;###autoload
196(defun url-eat-trailing-space (x)
197 "Remove spaces/tabs at the end of a string."
198 (let ((y (1- (length x)))
199 (skip-chars (list ? ?\t ?\n)))
200 (while (and (>= y 0) (memq (aref x y) skip-chars))
201 (setq y (1- y)))
202 (substring x 0 (1+ y))))
203
204;;;###autoload
205(defun url-strip-leading-spaces (x)
206 "Remove spaces at the front of a string."
207 (let ((y (1- (length x)))
208 (z 0)
209 (skip-chars (list ? ?\t ?\n)))
210 (while (and (<= z y) (memq (aref x z) skip-chars))
211 (setq z (1+ z)))
212 (substring x z nil)))
213
0bf29ba6
LL
214
215(define-obsolete-function-alias 'url-pretty-length
216 'file-size-human-readable "24.4")
8c8b8430
SM
217
218;;;###autoload
219(defun url-display-percentage (fmt perc &rest args)
08b8ba9f
LMI
220 (when (and url-show-status
221 (or (null url-current-object)
222 (not (url-silent url-current-object))))
48d2bac4
MH
223 (if (null fmt)
224 (if (fboundp 'clear-progress-display)
225 (clear-progress-display))
226 (if (and (fboundp 'progress-display) perc)
227 (apply 'progress-display fmt perc args)
228 (apply 'message fmt args)))))
8c8b8430
SM
229
230;;;###autoload
231(defun url-percentage (x y)
232 (if (fboundp 'float)
233 (round (* 100 (/ x (float y))))
234 (/ (* x 100) y)))
235
08299ea7
CY
236;;;###autoload
237(defalias 'url-basepath 'url-file-directory)
238
8c8b8430 239;;;###autoload
76fb5862
RS
240(defun url-file-directory (file)
241 "Return the directory part of FILE, for a URL."
8c8b8430
SM
242 (cond
243 ((null file) "")
5589b70e 244 ((string-match "\\?" file)
577d5eea
DE
245 (url-file-directory (substring file 0 (match-beginning 0))))
246 ((string-match "\\(.*\\(/\\|%2[fF]\\)\\)" file)
247 (match-string 1 file))))
8c8b8430 248
76fb5862
RS
249;;;###autoload
250(defun url-file-nondirectory (file)
251 "Return the nondirectory part of FILE, for a URL."
252 (cond
253 ((null file) "")
5589b70e 254 ((string-match "\\?" file)
577d5eea
DE
255 (url-file-nondirectory (substring file 0 (match-beginning 0))))
256 ((string-match ".*\\(?:/\\|%2[fF]\\)\\(.*\\)" file)
257 (match-string 1 file))
258 (t file)))
76fb5862 259
8c8b8430 260;;;###autoload
6fd388f3 261(defun url-parse-query-string (query &optional downcase allow-newlines)
8c8b8430 262 (let (retval pairs cur key val)
530e968e 263 (setq pairs (split-string query "[;&]"))
8c8b8430
SM
264 (while pairs
265 (setq cur (car pairs)
266 pairs (cdr pairs))
530e968e
TZ
267 (unless (string-match "=" cur)
268 (setq cur (concat cur "=")))
269
270 (when (string-match "=" cur)
271 (setq key (url-unhex-string (substring cur 0 (match-beginning 0))
272 allow-newlines))
273 (setq val (url-unhex-string (substring cur (match-end 0) nil)
274 allow-newlines))
275 (if downcase
276 (setq key (downcase key)))
277 (setq cur (assoc key retval))
278 (if cur
279 (setcdr cur (cons val (cdr cur)))
280 (setq retval (cons (list key val) retval)))))
8c8b8430
SM
281 retval))
282
530e968e
TZ
283;;;###autoload
284(defun url-build-query-string (query &optional semicolons keep-empty)
285 "Build a query-string.
286
287Given a QUERY in the form:
288'((key1 val1)
289 (key2 val2)
290 (key3 val1 val2)
291 (key4)
04558d31 292 (key5 \"\"))
530e968e
TZ
293
294\(This is the same format as produced by `url-parse-query-string')
295
296This will return a string
297\"key1=val1&key2=val2&key3=val1&key3=val2&key4&key5\". Keys may
298be strings or symbols; if they are symbols, the symbol name will
299be used.
300
301When SEMICOLONS is given, the separator will be \";\".
302
303When KEEP-EMPTY is given, empty values will show as \"key=\"
304instead of just \"key\" as in the example above."
305 (mapconcat
306 (lambda (key-vals)
307 (let ((escaped
308 (mapcar (lambda (sym)
309 (url-hexify-string (format "%s" sym))) key-vals)))
310 (mapconcat (lambda (val)
311 (let ((vprint (format "%s" val))
312 (eprint (format "%s" (car escaped))))
313 (concat eprint
314 (if (or keep-empty
315 (and val (not (zerop (length vprint)))))
316 "="
317 "")
318 vprint)))
319 (or (cdr escaped) '("")) (if semicolons ";" "&"))))
320 query (if semicolons ";" "&")))
321
8c8b8430
SM
322(defun url-unhex (x)
323 (if (> x ?9)
324 (if (>= x ?a)
325 (+ 10 (- x ?a))
326 (+ 10 (- x ?A)))
327 (- x ?0)))
328
c6bfe6e7
SM
329;; Fixme: Is this definition better, and does it ever matter?
330
331;; (defun url-unhex-string (str &optional allow-newlines)
332;; "Remove %XX, embedded spaces, etc in a url.
333;; If optional second argument ALLOW-NEWLINES is non-nil, then allow the
334;; decoding of carriage returns and line feeds in the string, which is normally
335;; forbidden in URL encoding."
336;; (setq str (or str ""))
337;; (setq str (replace-regexp-in-string "%[[:xdigit:]]\\{2\\}"
338;; (lambda (match)
339;; (string (string-to-number
340;; (substring match 1) 16)))
341;; str t t))
342;; (if allow-newlines
343;; (replace-regexp-in-string "[\n\r]" (lambda (match)
344;; (format "%%%.2X" (aref match 0)))
345;; str t t)
346;; str))
347
8c8b8430 348;;;###autoload
8d8d31f9 349(defun url-unhex-string (str &optional allow-newlines)
d1ce47b0 350 "Remove %XX embedded spaces, etc in a URL.
8c8b8430
SM
351If optional second argument ALLOW-NEWLINES is non-nil, then allow the
352decoding of carriage returns and line feeds in the string, which is normally
8d8d31f9 353forbidden in URL encoding."
8c8b8430
SM
354 (setq str (or str ""))
355 (let ((tmp "")
356 (case-fold-search t))
357 (while (string-match "%[0-9a-f][0-9a-f]" str)
358 (let* ((start (match-beginning 0))
359 (ch1 (url-unhex (elt str (+ start 1))))
360 (code (+ (* 16 ch1)
361 (url-unhex (elt str (+ start 2))))))
362 (setq tmp (concat
363 tmp (substring str 0 start)
364 (cond
365 (allow-newlines
c3bb441d 366 (byte-to-string code))
8c8b8430
SM
367 ((or (= code ?\n) (= code ?\r))
368 " ")
c3bb441d 369 (t (byte-to-string code))))
8c8b8430 370 str (substring str (match-end 0)))))
d3f7611b 371 (concat tmp str)))
8c8b8430
SM
372
373(defconst url-unreserved-chars
ce7b18ec 374 '(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
8c8b8430
SM
375 ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
376 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
ce7b18ec
CY
377 ?- ?_ ?. ?~)
378 "List of characters that are unreserved in the URL spec.
379This is taken from RFC 3986 (section 2.3).")
380
381(defconst url-encoding-table
382 (let ((vec (make-vector 256 nil)))
383 (dotimes (byte 256)
bdac2d37
CY
384 ;; RFC 3986 (Section 2.1): For consistency, URI producers and
385 ;; normalizers should use uppercase hexadecimal digits for all
386 ;; percent-encodings.
387 (aset vec byte (format "%%%02X" byte)))
ce7b18ec
CY
388 vec)
389 "Vector translating bytes to URI-encoded %-sequences.")
390
391(defun url--allowed-chars (char-list)
392 "Return an \"allowed character\" mask (a 256-slot vector).
393The Nth element is non-nil if character N is in CHAR-LIST. The
394result can be passed as the second arg to `url-hexify-string'."
395 (let ((vec (make-vector 256 nil)))
396 (dolist (byte char-list)
397 (ignore-errors (aset vec byte t)))
398 vec))
8c8b8430
SM
399
400;;;###autoload
ce7b18ec
CY
401(defun url-hexify-string (string &optional allowed-chars)
402 "URI-encode STRING and return the result.
403If STRING is multibyte, it is first converted to a utf-8 byte
404string. Each byte corresponding to an allowed character is left
405as-is, while all other bytes are converted to a three-character
bdac2d37 406string: \"%\" followed by two upper-case hex digits.
ce7b18ec
CY
407
408The allowed characters are specified by ALLOWED-CHARS. If this
409argument is nil, the list `url-unreserved-chars' determines the
410allowed characters. Otherwise, ALLOWED-CHARS should be a vector
411whose Nth element is non-nil if character N is allowed."
412 (unless allowed-chars
413 (setq allowed-chars (url--allowed-chars url-unreserved-chars)))
07e9b3f0 414 (mapconcat (lambda (byte)
ce7b18ec
CY
415 (if (aref allowed-chars byte)
416 (char-to-string byte)
417 (aref url-encoding-table byte)))
418 (if (multibyte-string-p string)
419 (encode-coding-string string 'utf-8)
420 string)
421 ""))
422
423(defconst url-host-allowed-chars
424 ;; Allow % to avoid re-encoding %-encoded sequences.
425 (url--allowed-chars (append '(?% ?! ?$ ?& ?' ?\( ?\) ?* ?+ ?, ?\; ?=)
426 url-unreserved-chars))
427 "Allowed-character byte mask for the host segment of a URI.
428These characters are specified in RFC 3986, Appendix A.")
429
430(defconst url-path-allowed-chars
431 (let ((vec (copy-sequence url-host-allowed-chars)))
432 (aset vec ?/ t)
433 (aset vec ?: t)
434 (aset vec ?@ t)
435 vec)
436 "Allowed-character byte mask for the path segment of a URI.
437These characters are specified in RFC 3986, Appendix A.")
438
439(defconst url-query-allowed-chars
440 (let ((vec (copy-sequence url-path-allowed-chars)))
441 (aset vec ?? t)
442 vec)
443 "Allowed-character byte mask for the query segment of a URI.
444These characters are specified in RFC 3986, Appendix A.")
445
446;;;###autoload
447(defun url-encode-url (url)
448 "Return a properly URI-encoded version of URL.
449This function also performs URI normalization, e.g. converting
450the scheme to lowercase if it is uppercase. Apart from
451normalization, if URL is already URI-encoded, this function
452should return it unchanged."
453 (if (multibyte-string-p url)
454 (setq url (encode-coding-string url 'utf-8)))
455 (let* ((obj (url-generic-parse-url url))
456 (user (url-user obj))
457 (pass (url-password obj))
458 (host (url-host obj))
9f9aa044
CY
459 (path-and-query (url-path-and-query obj))
460 (path (car path-and-query))
461 (query (cdr path-and-query))
462 (frag (url-target obj)))
ce7b18ec
CY
463 (if user
464 (setf (url-user obj) (url-hexify-string user)))
465 (if pass
466 (setf (url-password obj) (url-hexify-string pass)))
9f9aa044
CY
467 ;; No special encoding for IPv6 literals.
468 (and host
469 (not (string-match "\\`\\[.*\\]\\'" host))
470 (setf (url-host obj)
471 (url-hexify-string host url-host-allowed-chars)))
472
473 (if path
474 (setq path (url-hexify-string path url-path-allowed-chars)))
475 (if query
476 (setq query (url-hexify-string query url-query-allowed-chars)))
477 (setf (url-filename obj) (if query (concat path "?" query) path))
478
ce7b18ec
CY
479 (if frag
480 (setf (url-target obj)
481 (url-hexify-string frag url-query-allowed-chars)))
482 (url-recreate-url obj)))
8c8b8430
SM
483
484;;;###autoload
485(defun url-file-extension (fname &optional x)
486 "Return the filename extension of FNAME.
d1ce47b0
JB
487If optional argument X is t, then return the basename
488of the file with the extension stripped off."
8c8b8430 489 (if (and fname
76fb5862 490 (setq fname (url-file-nondirectory fname))
8c8b8430
SM
491 (string-match "\\.[^./]+$" fname))
492 (if x (substring fname 0 (match-beginning 0))
493 (substring fname (match-beginning 0) nil))
494 ;;
495 ;; If fname has no extension, and x then return fname itself instead of
496 ;; nothing. When caching it allows the correct .hdr file to be produced
497 ;; for filenames without extension.
498 ;;
499 (if x
500 fname
501 "")))
502
503;;;###autoload
504(defun url-truncate-url-for-viewing (url &optional width)
d9e52e92 505 "Return a shortened version of URL that is WIDTH characters wide or less.
8c8b8430
SM
506WIDTH defaults to the current frame width."
507 (let* ((fr-width (or width (frame-width)))
508 (str-width (length url))
8c8b8430
SM
509 (fname nil)
510 (modified 0)
511 (urlobj nil))
512 ;; The first thing that can go are the search strings
513 (if (and (>= str-width fr-width)
514 (string-match "?" url))
515 (setq url (concat (substring url 0 (match-beginning 0)) "?...")
07e9b3f0 516 str-width (length url)))
8c8b8430
SM
517 (if (< str-width fr-width)
518 nil ; Hey, we are done!
519 (setq urlobj (url-generic-parse-url url)
520 fname (url-filename urlobj)
521 fr-width (- fr-width 4))
522 (while (and (>= str-width fr-width)
523 (string-match "/" fname))
524 (setq fname (substring fname (match-end 0) nil)
525 modified (1+ modified))
d18ec89f 526 (setf (url-filename urlobj) fname)
8c8b8430
SM
527 (setq url (url-recreate-url urlobj)
528 str-width (length url)))
529 (if (> modified 1)
530 (setq fname (concat "/.../" fname))
531 (setq fname (concat "/" fname)))
d18ec89f 532 (setf (url-filename urlobj) fname)
8c8b8430
SM
533 (setq url (url-recreate-url urlobj)))
534 url))
535
536;;;###autoload
537(defun url-view-url (&optional no-show)
538 "View the current document's URL.
539Optional argument NO-SHOW means just return the URL, don't show it in
540the minibuffer.
541
542This uses `url-current-object', set locally to the buffer."
543 (interactive)
544 (if (not url-current-object)
545 nil
546 (if no-show
547 (url-recreate-url url-current-object)
548 (message "%s" (url-recreate-url url-current-object)))))
549
5589b70e
GM
550(defvar url-get-url-filename-chars "-%.?@a-zA-Z0-9()_/:~=&"
551 "Valid characters in a URL.")
8c8b8430
SM
552
553(defun url-get-url-at-point (&optional pt)
554 "Get the URL closest to point, but don't change position.
555Has a preference for looking backward when not directly on a symbol."
556 ;; Not at all perfect - point must be right in the name.
557 (save-excursion
558 (if pt (goto-char pt))
559 (let (start url)
560 (save-excursion
561 ;; first see if you're just past a filename
562 (if (not (eobp))
563 (if (looking-at "[] \t\n[{}()]") ; whitespace or some parens
564 (progn
565 (skip-chars-backward " \n\t\r({[]})")
566 (if (not (bobp))
567 (backward-char 1)))))
568 (if (and (char-after (point))
5589b70e 569 (string-match (concat "[" url-get-url-filename-chars "]")
8c8b8430
SM
570 (char-to-string (char-after (point)))))
571 (progn
572 (skip-chars-backward url-get-url-filename-chars)
573 (setq start (point))
574 (skip-chars-forward url-get-url-filename-chars))
575 (setq start (point)))
576 (setq url (buffer-substring-no-properties start (point))))
577 (if (and url (string-match "^(.*)\\.?$" url))
578 (setq url (match-string 1 url)))
579 (if (and url (string-match "^URL:" url))
580 (setq url (substring url 4 nil)))
581 (if (and url (string-match "\\.$" url))
582 (setq url (substring url 0 -1)))
583 (if (and url (string-match "^www\\." url))
584 (setq url (concat "http://" url)))
585 (if (and url (not (string-match url-nonrelative-link url)))
586 (setq url nil))
587 url)))
588
589(defun url-generate-unique-filename (&optional fmt)
590 "Generate a unique filename in `url-temporary-directory'."
59f7af81 591 (declare (obsolete make-temp-file "23.1"))
f0cfa8f0
GM
592 ;; This variable is obsolete, but so is this function.
593 (let ((tempdir (with-no-warnings url-temporary-directory)))
594 (if (not fmt)
595 (let ((base (format "url-tmp.%d" (user-real-uid)))
596 (fname "")
597 (x 0))
598 (setq fname (format "%s%d" base x))
599 (while (file-exists-p
600 (expand-file-name fname tempdir))
601 (setq x (1+ x)
602 fname (concat base (int-to-string x))))
603 (expand-file-name fname tempdir))
604 (let ((base (concat "url" (int-to-string (user-real-uid))))
8c8b8430
SM
605 (fname "")
606 (x 0))
f0cfa8f0 607 (setq fname (format fmt (concat base (int-to-string x))))
8c8b8430 608 (while (file-exists-p
f0cfa8f0 609 (expand-file-name fname tempdir))
8c8b8430 610 (setq x (1+ x)
f0cfa8f0
GM
611 fname (format fmt (concat base (int-to-string x)))))
612 (expand-file-name fname tempdir)))))
8c8b8430
SM
613
614(defun url-extract-mime-headers ()
615 "Set `url-current-mime-headers' in current buffer."
616 (save-excursion
617 (goto-char (point-min))
618 (unless url-current-mime-headers
619 (set (make-local-variable 'url-current-mime-headers)
620 (mail-header-extract)))))
621
8703ea53
GM
622(defun url-make-private-file (file)
623 "Make FILE only readable and writable by the current user.
624Creates FILE and its parent directories if they do not exist."
625 (let ((dir (file-name-directory file)))
626 (when dir
627 ;; For historical reasons.
628 (make-directory dir t)))
629 ;; Based on doc-view-make-safe-dir.
630 (condition-case nil
d63d883a
GM
631 (with-file-modes #o0600
632 (with-temp-buffer
633 (write-region (point-min) (point-max) file nil 'silent nil 'excl)))
8703ea53
GM
634 (file-already-exists
635 (if (file-symlink-p file)
636 (error "Danger: `%s' is a symbolic link" file))
637 (set-file-modes file #o0600))))
638
8c8b8430 639(provide 'url-util)
e5566bd5 640
a2fd1462 641;;; url-util.el ends here