1;;; url-methods.el --- Load URL schemes as needed
2
3;; Copyright (C) 1996, 1997, 1998, 1999, 2004,
4;;   2005, 2006, 2007 Free Software Foundation, Inc.
5
6;; Keywords: comm, data, processes, hypermedia
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14;;
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18;; GNU General Public License for more details.
19;;
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING.  If not, write to the
22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23;; Boston, MA 02110-1301, USA.
24
25;;; Commentary:
26
27;;; Code:
28
29(eval-when-compile
30  (require 'cl))
31
32;; This loads up some of the small, silly URLs that I really don't
33;; want to bother putting in their own separate files.
34(require 'url-parse)
35
36(defvar url-scheme-registry (make-hash-table :size 7 :test 'equal))
37
38(defconst url-scheme-methods
39  '((default-port      . variable)
40    (asynchronous-p    . variable)
41    (expand-file-name  . function)
42    (file-exists-p     . function)
43    (file-attributes   . function)
44    (parse-url         . function)
45    (file-symlink-p    . function)
46    (file-writable-p   . function)
47    (file-directory-p  . function)
48    (file-executable-p . function)
49    (directory-files   . function)
50    (file-truename     . function))
51  "Assoc-list of methods that each URL loader can provide.")
52
53(defconst url-scheme-default-properties
54  (list 'name "unknown"
55	'loader 'url-scheme-default-loader
56	'default-port 0
57	'expand-file-name 'url-identity-expander
58	'parse-url 'url-generic-parse-url
59	'asynchronous-p nil
60	'file-directory-p 'ignore
61	'file-truename (lambda (&rest args)
62			 (url-recreate-url (car args)))
63	'file-exists-p 'ignore
64	'file-attributes 'ignore))
65
66(defun url-scheme-default-loader (url &optional callback cbargs)
67  "Signal an error for an unknown URL scheme."
68  (error "Unkown URL scheme: %s" (url-type url)))
69
70(defun url-scheme-register-proxy (scheme)
71  "Automatically find a proxy for SCHEME and put it in `url-proxy-services'."
72  (let* ((env-var (concat scheme "_proxy"))
73	 (env-proxy (or (getenv (upcase env-var))
74			(getenv (downcase env-var))))
75	 (cur-proxy (assoc scheme url-proxy-services))
76	 (urlobj nil))
77
78    ;; If env-proxy is an empty string, treat it as if it were nil
79    (when (and (stringp env-proxy)
80	       (string= env-proxy ""))
81      (setq env-proxy nil))
82
83    ;; Store any proxying information - this will not overwrite an old
84    ;; entry, so that people can still set this information in their
85    ;; .emacs file
86    (cond
87     (cur-proxy nil)			; Keep their old settings
88     ((null env-proxy) nil)		; No proxy setup
89     ;; First check if its something like hostname:port
90     ((string-match "^\\([^:]+\\):\\([0-9]+\\)$" env-proxy)
91      (setq urlobj (url-generic-parse-url nil)) ; Get a blank object
92      (url-set-type urlobj "http")
93      (url-set-host urlobj (match-string 1 env-proxy))
94      (url-set-port urlobj (string-to-number (match-string 2 env-proxy))))
95     ;; Then check if its a fully specified URL
96     ((string-match url-nonrelative-link env-proxy)
97      (setq urlobj (url-generic-parse-url env-proxy))
98      (url-set-type urlobj "http")
99      (url-set-target urlobj nil))
100     ;; Finally, fall back on the assumption that its just a hostname
101     (t
102      (setq urlobj (url-generic-parse-url nil)) ; Get a blank object
103      (url-set-type urlobj "http")
104      (url-set-host urlobj env-proxy)))
105
106     (if (and (not cur-proxy) urlobj)
107	 (progn
108	   (setq url-proxy-services
109		 (cons (cons scheme (format "%s:%d" (url-host urlobj)
110					    (url-port urlobj)))
111		       url-proxy-services))
112	   (message "Using a proxy for %s..." scheme)))))
113
114(defun url-scheme-get-property (scheme property)
115  "Get property of a URL SCHEME.
116Will automatically try to load a backend from url-SCHEME.el if
117it has not already been loaded."
118  (setq scheme (downcase scheme))
119  (let ((desc (gethash scheme url-scheme-registry)))
120    (if (not desc)
121	(let* ((stub (concat "url-" scheme))
122	       (loader (intern stub)))
123	  (condition-case ()
124	      (require loader)
125	    (error nil))
126	  (if (fboundp loader)
127	      (progn
128		;; Found the module to handle <scheme> URLs
129		(url-scheme-register-proxy scheme)
130		(setq desc (list 'name scheme
131				 'loader loader))
132		(dolist (cell url-scheme-methods)
133		  (let ((symbol (intern-soft (format "%s-%s" stub (car cell))))
134			(type (cdr cell)))
135		    (if symbol
136			(case type
137			  (function
138			   ;; Store the symbol name of a function
139			   (if (fboundp symbol)
140			       (setq desc (plist-put desc (car cell) symbol))))
141			  (variable
142			   ;; Store the VALUE of a variable
143			   (if (boundp symbol)
144			       (setq desc (plist-put desc (car cell)
145						     (symbol-value symbol)))))
146			  (otherwise
147			   (error "Malformed url-scheme-methods entry: %S"
148				  cell))))))
149		(puthash scheme desc url-scheme-registry)))))
150    (or (plist-get desc property)
151	(plist-get url-scheme-default-properties property))))
152
153(provide 'url-methods)
154
155;; arch-tag: 336863f8-5a07-4906-9be5-b3c6bcebbe67
156;;; url-methods.el ends here
157