1 ;;; nnoo.el --- OO Gnus Backends
3 ;; Copyright (C) 1996-2013 Free Software Foundation, Inc.
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
8 ;; This file is part of GNU Emacs.
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 3 of the License, or
13 ;; (at your option) any later version.
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.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
28 (eval-when-compile (require 'cl
))
30 (defvar nnoo-definition-alist nil
)
31 (defvar nnoo-state-alist nil
)
32 (defvar nnoo-parent-backend nil
)
34 (defmacro defvoo
(var init
&optional doc
&rest map
)
35 "The same as `defvar', only takes list of variables to MAP to."
38 `(defvar ,var
,init
,(concat doc
"\n\nThis is a Gnus server variable. See Info node `(gnus)Select Methods'."))
40 (nnoo-define ',var
',map
)))
41 (put 'defvoo
'lisp-indent-function
2)
42 (put 'defvoo
'edebug-form-spec
'(var init
&optional doc
&rest map
))
44 (defmacro deffoo
(func args
&rest forms
)
45 "The same as `defun', only register FUNC."
47 (defun ,func
,args
,@forms
)
48 (nnoo-register-function ',func
)))
49 (put 'deffoo
'lisp-indent-function
2)
50 (put 'deffoo
'edebug-form-spec
'(&define name lambda-list def-body
))
52 (defun nnoo-register-function (func)
53 (let ((funcs (nthcdr 3 (assoc (nnoo-backend func
)
54 nnoo-definition-alist
))))
56 (error "%s belongs to a backend that hasn't been declared" func
))
57 (setcar funcs
(cons func
(car funcs
)))))
59 (defmacro nnoo-declare
(backend &rest parents
)
61 (if (assq ',backend nnoo-definition-alist
)
62 (setcar (cdr (assq ',backend nnoo-definition-alist
))
63 (mapcar 'list
',parents
))
65 (mapcar 'list
',parents
)
67 nnoo-definition-alist
))
68 (unless (assq ',backend nnoo-state-alist
)
69 (push (list ',backend
"*internal-non-initialized-backend*")
71 (put 'nnoo-declare
'lisp-indent-function
1)
73 (defun nnoo-parents (backend)
74 (nth 1 (assoc backend nnoo-definition-alist
)))
76 (defun nnoo-variables (backend)
77 (nth 2 (assoc backend nnoo-definition-alist
)))
79 (defun nnoo-functions (backend)
80 (nth 3 (assoc backend nnoo-definition-alist
)))
82 (defmacro nnoo-import
(backend &rest imports
)
83 `(nnoo-import-1 ',backend
',imports
))
84 (put 'nnoo-import
'lisp-indent-function
1)
86 (defun nnoo-import-1 (backend imports
)
88 (if (symbolp (car imports
)) (pop imports
) 'nnoo-parent-function
))
89 imp functions function
)
90 (while (setq imp
(pop imports
))
93 (nnoo-functions (car imp
))))
98 (nnoo-rest-symbol (car functions
)))))
99 (eval `(deffoo ,function
(&rest args
)
100 (,call-function
',backend
',(car functions
) args
))))
103 (defun nnoo-parent-function (backend function args
)
104 (let ((pbackend (nnoo-backend function
))
105 (nnoo-parent-backend backend
))
106 (nnoo-change-server pbackend
107 (nnoo-current-server backend
)
108 (cdr (assq pbackend
(nnoo-parents backend
))))
110 (apply function args
)
111 ;; Copy the changed variables back into the child.
112 (let ((vars (cdr (assq pbackend
(nnoo-parents backend
)))))
114 (set (cadar vars
) (symbol-value (caar vars
)))
115 (setq vars
(cdr vars
)))))))
117 (defun nnoo-execute (backend function
&rest args
)
118 "Execute FUNCTION on behalf of BACKEND."
119 (let ((pbackend (nnoo-backend function
))
120 (nnoo-parent-backend backend
))
121 (nnoo-change-server pbackend
122 (nnoo-current-server backend
)
123 (cdr (assq pbackend
(nnoo-parents backend
))))
125 (apply function args
)
126 ;; Copy the changed variables back into the child.
127 (let ((vars (cdr (assq pbackend
(nnoo-parents backend
)))))
129 (set (cadar vars
) (symbol-value (caar vars
)))
130 (setq vars
(cdr vars
)))))))
132 (defmacro nnoo-map-functions
(backend &rest maps
)
133 `(nnoo-map-functions-1 ',backend
',maps
))
134 (put 'nnoo-map-functions
'lisp-indent-function
1)
136 (defun nnoo-map-functions-1 (backend maps
)
138 (while (setq m
(pop maps
))
141 (while (< i
(length (cdr m
)))
142 (if (numberp (nth i
(cdr m
)))
143 (push `(nth ,i args
) margs
)
144 (push (nth i
(cdr m
)) margs
))
146 (eval `(deffoo ,(nnoo-symbol backend
(nnoo-rest-symbol (car m
)))
148 (nnoo-parent-function ',backend
',(car m
)
149 ,(cons 'list
(nreverse margs
))))))))
151 (defun nnoo-backend (symbol)
152 (string-match "^[^-]+-" (symbol-name symbol
))
153 (intern (substring (symbol-name symbol
) 0 (1- (match-end 0)))))
155 (defun nnoo-rest-symbol (symbol)
156 (string-match "^[^-]+-" (symbol-name symbol
))
157 (intern (substring (symbol-name symbol
) (match-end 0))))
159 (defun nnoo-symbol (backend symbol
)
160 (intern (format "%s-%s" backend symbol
)))
162 (defun nnoo-define (var map
)
163 (let* ((backend (nnoo-backend var
))
164 (def (assq backend nnoo-definition-alist
))
165 (parents (nth 1 def
)))
167 (error "%s belongs to a backend that hasn't been declared" var
))
168 (setcar (nthcdr 2 def
)
169 (delq (assq var
(nth 2 def
)) (nth 2 def
)))
170 (setcar (nthcdr 2 def
)
171 (cons (cons var
(symbol-value var
))
174 (nconc (assq (nnoo-backend (car map
)) parents
)
175 (list (list (pop map
) var
))))))
177 (defun nnoo-change-server (backend server defs
)
178 (let* ((bstate (cdr (assq backend nnoo-state-alist
)))
179 (current (car bstate
))
180 (parents (nnoo-parents backend
))
181 (server (if nnoo-parent-backend
182 (format "%s+%s" nnoo-parent-backend server
)
184 (bvariables (nnoo-variables backend
))
186 ;; If we don't have a current state, we push an empty state
189 (push (setq bstate
(list backend nil
))
192 (if (equal server current
)
194 (nnoo-push-server backend current
)
195 (setq state
(or (cdr (assoc server
(cddr bstate
)))
196 (nnoo-variables backend
)))
198 (set (caar state
) (cdar state
))
200 (setcar bstate server
)
201 (unless (cdr (assoc server
(cddr bstate
)))
202 (while (setq def
(pop defs
))
203 (unless (assq (car def
) bvariables
)
205 (list (cons (car def
) (and (boundp (car def
))
206 (symbol-value (car def
)))))))
207 (if (equal server
"*internal-non-initialized-backend*")
208 (set (car def
) (symbol-value (cadr def
)))
209 (set (car def
) (cadr def
)))))
212 (caar parents
) (format "%s+%s" backend server
)
213 (mapcar (lambda (def) (list (car def
) (symbol-value (cadr def
))))
218 (defun nnoo-push-server (backend current
)
219 (let ((bstate (assq backend nnoo-state-alist
))
220 (defs (nnoo-variables backend
)))
221 ;; Remove the old definition.
222 (setcdr (cdr bstate
) (delq (assoc current
(cddr bstate
)) (cddr bstate
)))
223 ;; If this is the first time we push the server (i. e., this is
224 ;; the nil server), then we update the default values of
225 ;; all the variables to reflect the current values.
226 (when (equal current
"*internal-non-initialized-backend*")
227 (let ((defaults (nnoo-variables backend
))
229 (while (setq def
(pop defaults
))
230 (setcdr def
(symbol-value (car def
))))))
233 (push (cons (caar defs
) (symbol-value (caar defs
)))
236 (nconc bstate
(list (cons current state
))))))
238 (defsubst nnoo-current-server-p
(backend server
)
239 (equal (nnoo-current-server backend
)
240 (if nnoo-parent-backend
241 (format "%s+%s" nnoo-parent-backend server
)
244 (defun nnoo-current-server (backend)
245 (nth 1 (assq backend nnoo-state-alist
)))
247 (defun nnoo-close-server (backend &optional server
)
249 (setq server
(nnoo-current-server backend
)))
251 (let* ((bstate (cdr (assq backend nnoo-state-alist
)))
252 (defs (assoc server
(cdr bstate
))))
255 (setcdr bstate
(delq defs
(cdr bstate
)))
258 (set (car (pop defs
)) nil
)))))
261 (defun nnoo-close (backend)
262 (setq nnoo-state-alist
263 (delq (assq backend nnoo-state-alist
)
267 (defun nnoo-status-message (backend server
)
268 (nnheader-get-report backend
))
270 (defun nnoo-server-opened (backend server
)
271 (and (nnoo-current-server-p backend server
)
273 (buffer-name nntp-server-buffer
)))
275 (defmacro nnoo-define-basics
(backend)
276 "Define `close-server', `server-opened' and `status-message'."
278 (nnoo-define-basics-1 ',backend
)))
280 (defun nnoo-define-basics-1 (backend)
281 (let ((functions '(close-server server-opened status-message
)))
283 (eval `(deffoo ,(nnoo-symbol backend
(car functions
))
285 (,(nnoo-symbol 'nnoo
(pop functions
)) ',backend server
)))))
286 (eval `(deffoo ,(nnoo-symbol backend
'open-server
)
287 (server &optional defs
)
288 (nnoo-change-server ',backend server defs
))))
290 (defmacro nnoo-define-skeleton
(backend)
291 "Define all required backend functions for BACKEND.
292 All functions will return nil and report an error."
294 (nnoo-define-skeleton-1 ',backend
)))
296 (defun nnoo-define-skeleton-1 (backend)
297 (let ((functions '(retrieve-headers
298 request-close request-article
299 request-group close-group
300 request-list request-post request-list-newsgroups
))
302 (while (setq function
(pop functions
))
303 (when (not (fboundp (setq fun
(nnoo-symbol backend function
))))
306 (nnheader-report ',backend
,(format "%s-%s not implemented"
307 backend function
))))))))
309 (defun nnoo-set (server &rest args
)
310 (let ((parents (nnoo-parents (car server
)))
311 (nnoo-parent-backend (car server
)))
313 (nnoo-change-server (caar parents
)
317 (nnoo-change-server (car server
)
318 (cadr server
) (cddr server
))
320 (set (pop args
) (pop args
))))
324 ;;; nnoo.el ends here