comparison lisp/gnus/nneething.el @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents 1a767b41a199
children 0d2f883870bc
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
1 ;;; nneething.el --- random file access for Gnus 1 ;;; nneething.el --- random file access for Gnus
2 ;; Copyright (C) 1995,96,97 Free Software Foundation, Inc. 2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc.
3 3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> 4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> 5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
6 ;; Keywords: news, mail 6 ;; Keywords: news, mail
7 7
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA. 23 ;; Boston, MA 02111-1307, USA.
24 24
25 ;;; Commentary: 25 ;;; Commentary:
26 26
27 ;; Based on nnspool.el by Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>.
28 ;; For an overview of what the interface functions do, please see the
29 ;; Gnus sources.
30
27 ;;; Code: 31 ;;; Code:
28 32
29 (require 'nnheader) 33 (require 'nnheader)
30 (require 'nnmail) 34 (require 'nnmail)
31 (require 'nnoo) 35 (require 'nnoo)
32 (require 'gnus-util) 36 (eval-when-compile (require 'cl))
33 (require 'cl)
34 37
35 (nnoo-declare nneething) 38 (nnoo-declare nneething)
36 39
37 (defvoo nneething-map-file-directory "~/.nneething/" 40 (defvoo nneething-map-file-directory "~/.nneething/"
38 "Where nneething stores the map files.") 41 "*Where nneething stores the map files.")
39 42
40 (defvoo nneething-map-file ".nneething" 43 (defvoo nneething-map-file ".nneething"
41 "Name of the map files.") 44 "*Name of the map files.")
42 45
43 (defvoo nneething-exclude-files nil 46 (defvoo nneething-exclude-files nil
44 "Regexp saying what files to exclude from the group. 47 "*Regexp saying what files to exclude from the group.
45 If this variable is nil, no files will be excluded.") 48 If this variable is nil, no files will be excluded.")
46 49
47 50
48 51
49 ;;; Internal variables. 52 ;;; Internal variables.
50 53
51 (defconst nneething-version "nneething 1.0" 54 (defconst nneething-version "nneething 1.0"
52 "nneething version.") 55 "nneething version.")
53 56
54 (defvoo nneething-current-directory nil 57 (defvoo nneething-current-directory nil
55 "Current news group directory.") 58 "Current news group directory.")
56 59
57 (defvoo nneething-status-string "") 60 (defvoo nneething-status-string "")
61 (defvoo nneething-group-alist nil)
58 62
59 (defvoo nneething-message-id-number 0) 63 (defvoo nneething-message-id-number 0)
60 (defvoo nneething-work-buffer " *nneething work*") 64 (defvoo nneething-work-buffer " *nneething work*")
61 65
66 (defvoo nneething-directory nil)
62 (defvoo nneething-group nil) 67 (defvoo nneething-group nil)
63 (defvoo nneething-map nil) 68 (defvoo nneething-map nil)
64 (defvoo nneething-read-only nil) 69 (defvoo nneething-read-only nil)
65 (defvoo nneething-active nil) 70 (defvoo nneething-active nil)
66 71
108 (nnheader-fold-continuation-lines) 113 (nnheader-fold-continuation-lines)
109 'headers)))) 114 'headers))))
110 115
111 (deffoo nneething-request-article (id &optional group server buffer) 116 (deffoo nneething-request-article (id &optional group server buffer)
112 (nneething-possibly-change-directory group) 117 (nneething-possibly-change-directory group)
113 (let ((file (unless (stringp id) 118 (let ((file (unless (stringp id) (nneething-file-name id)))
114 (nneething-file-name id)))
115 (nntp-server-buffer (or buffer nntp-server-buffer))) 119 (nntp-server-buffer (or buffer nntp-server-buffer)))
116 (and (stringp file) ; We did not request by Message-ID. 120 (and (stringp file) ; We did not request by Message-ID.
117 (file-exists-p file) ; The file exists. 121 (file-exists-p file) ; The file exists.
118 (not (file-directory-p file)) ; It's not a dir. 122 (not (file-directory-p file)) ; It's not a dir.
119 (save-excursion 123 (save-excursion
120 (nnmail-find-file file) ; Insert the file in the nntp buf. 124 (nnmail-find-file file) ; Insert the file in the nntp buf.
121 (unless (nnheader-article-p) ; Either it's a real article... 125 (or (nnheader-article-p) ; Either it's a real article...
122 (goto-char (point-min)) 126 (progn
123 (nneething-make-head file (current-buffer)) ; ... or we fake some headers. 127 (goto-char (point-min))
124 (insert "\n")) 128 (nneething-make-head file (current-buffer)) ; ... or we fake some headers.
129 (insert "\n")))
125 t)))) 130 t))))
126 131
127 (deffoo nneething-request-group (group &optional server dont-check) 132 (deffoo nneething-request-group (group &optional dir dont-check)
128 (nneething-possibly-change-directory group server) 133 (nneething-possibly-change-directory group dir)
129 (unless dont-check 134 (unless dont-check
130 (nneething-create-mapping) 135 (nneething-create-mapping)
131 (if (> (car nneething-active) (cdr nneething-active)) 136 (if (> (car nneething-active) (cdr nneething-active))
132 (nnheader-insert "211 0 1 0 %s\n" group) 137 (nnheader-insert "211 0 1 0 %s\n" group)
133 (nnheader-insert 138 (nnheader-insert
134 "211 %d %d %d %s\n" 139 "211 %d %d %d %s\n"
135 (- (1+ (cdr nneething-active)) (car nneething-active)) 140 (- (1+ (cdr nneething-active)) (car nneething-active))
136 (car nneething-active) (cdr nneething-active) 141 (car nneething-active) (cdr nneething-active)
137 group))) 142 group)))
138 t) 143 t)
139 144
148 153
149 (deffoo nneething-close-group (group &optional server) 154 (deffoo nneething-close-group (group &optional server)
150 (setq nneething-current-directory nil) 155 (setq nneething-current-directory nil)
151 t) 156 t)
152 157
153 (deffoo nneething-open-server (server &optional defs)
154 (nnheader-init-server-buffer)
155 (if (nneething-server-opened server)
156 t
157 (unless (assq 'nneething-directory defs)
158 (setq defs (append defs (list (list 'nneething-directory server)))))
159 (nnoo-change-server 'nneething server defs)))
160
161 158
162 ;;; Internal functions. 159 ;;; Internal functions.
163 160
164 (defun nneething-possibly-change-directory (group &optional server) 161 (defun nneething-possibly-change-directory (group &optional dir)
165 (when (and server 162 (when group
166 (not (nneething-server-opened server))) 163 (if (and nneething-group
167 (nneething-open-server server)) 164 (string= group nneething-group))
168 (when (and group 165 t
169 (not (equal nneething-group group))) 166 (let (entry)
170 (setq nneething-group group) 167 (if (setq entry (assoc group nneething-group-alist))
171 (setq nneething-map nil) 168 (progn
172 (setq nneething-active (cons 1 0)) 169 (setq nneething-group group)
173 (nneething-create-mapping))) 170 (setq nneething-directory (nth 1 entry))
171 (setq nneething-map (nth 2 entry))
172 (setq nneething-active (nth 3 entry)))
173 (setq nneething-group group)
174 (setq nneething-directory dir)
175 (setq nneething-map nil)
176 (setq nneething-active (cons 1 0))
177 (nneething-create-mapping)
178 (push (list group dir nneething-map nneething-active)
179 nneething-group-alist))))))
174 180
175 (defun nneething-map-file () 181 (defun nneething-map-file ()
176 ;; We make sure that the .nneething directory exists. 182 ;; We make sure that the .nneething directory exists.
177 (gnus-make-directory nneething-map-file-directory) 183 (unless (file-exists-p nneething-map-file-directory)
184 (make-directory nneething-map-file-directory 'parents))
178 ;; We store it in a special directory under the user's home dir. 185 ;; We store it in a special directory under the user's home dir.
179 (concat (file-name-as-directory nneething-map-file-directory) 186 (concat (file-name-as-directory nneething-map-file-directory)
180 nneething-group nneething-map-file)) 187 nneething-group nneething-map-file))
181 188
182 (defun nneething-create-mapping () 189 (defun nneething-create-mapping ()
183 ;; Read nneething-active and nneething-map. 190 ;; Read nneething-active and nneething-map.
184 (when (file-exists-p nneething-directory) 191 (let ((map-file (nneething-map-file))
185 (let ((map-file (nneething-map-file)) 192 (files (directory-files nneething-directory))
186 (files (directory-files nneething-directory)) 193 touched map-files)
187 touched map-files) 194 (if (file-exists-p map-file)
188 (when (file-exists-p map-file) 195 (condition-case nil
189 (ignore-errors 196 (load map-file nil t t)
190 (load map-file nil t t))) 197 (error nil)))
191 (unless nneething-active 198 (or nneething-active (setq nneething-active (cons 1 0)))
192 (setq nneething-active (cons 1 0))) 199 ;; Old nneething had a different map format.
193 ;; Old nneething had a different map format. 200 (when (and (cdar nneething-map)
194 (when (and (cdar nneething-map) 201 (atom (cdar nneething-map)))
195 (atom (cdar nneething-map))) 202 (setq nneething-map
196 (setq nneething-map 203 (mapcar (lambda (n)
197 (mapcar (lambda (n) 204 (list (cdr n) (car n)
198 (list (cdr n) (car n) 205 (nth 5 (file-attributes
199 (nth 5 (file-attributes 206 (nneething-file-name (car n))))))
200 (nneething-file-name (car n)))))) 207 nneething-map)))
201 nneething-map))) 208 ;; Remove files matching the exclusion regexp.
202 ;; Remove files matching the exclusion regexp. 209 (when nneething-exclude-files
203 (when nneething-exclude-files 210 (let ((f files)
204 (let ((f files)
205 prev)
206 (while f
207 (if (string-match nneething-exclude-files (car f))
208 (if prev (setcdr prev (cdr f))
209 (setq files (cdr files)))
210 (setq prev f))
211 (setq f (cdr f)))))
212 ;; Remove deleted files from the map.
213 (let ((map nneething-map)
214 prev) 211 prev)
215 (while map 212 (while f
216 (if (and (member (cadar map) files) 213 (if (string-match nneething-exclude-files (car f))
217 ;; We also remove files that have changed mod times. 214 (if prev (setcdr prev (cdr f))
218 (equal (nth 5 (file-attributes 215 (setq files (cdr files)))
219 (nneething-file-name (cadar map)))) 216 (setq prev f))
220 (caddar map))) 217 (setq f (cdr f)))))
221 (progn 218 ;; Remove deleted files from the map.
222 (push (cadar map) map-files) 219 (let ((map nneething-map)
223 (setq prev map)) 220 prev)
224 (setq touched t) 221 (while map
225 (if prev 222 (if (and (member (cadar map) files)
226 (setcdr prev (cdr map)) 223 ;; We also remove files that have changed mod times.
227 (setq nneething-map (cdr nneething-map)))) 224 (equal (nth 5 (file-attributes
228 (setq map (cdr map)))) 225 (nneething-file-name (cadar map))))
229 ;; Find all new files and enter them into the map. 226 (caddar map)))
230 (while files 227 (progn
231 (unless (member (car files) map-files) 228 (push (cadar map) map-files)
232 ;; This file is not in the map, so we enter it. 229 (setq prev map))
233 (setq touched t) 230 (setq touched t)
234 (setcdr nneething-active (1+ (cdr nneething-active))) 231 (if prev
235 (push (list (cdr nneething-active) (car files) 232 (setcdr prev (cdr map))
236 (nth 5 (file-attributes 233 (setq nneething-map (cdr nneething-map))))
237 (nneething-file-name (car files))))) 234 (setq map (cdr map))))
238 nneething-map)) 235 ;; Find all new files and enter them into the map.
239 (setq files (cdr files))) 236 (while files
240 (when (and touched 237 (unless (member (car files) map-files)
241 (not nneething-read-only)) 238 ;; This file is not in the map, so we enter it.
242 (nnheader-temp-write map-file 239 (setq touched t)
243 (insert "(setq nneething-map '") 240 (setcdr nneething-active (1+ (cdr nneething-active)))
244 (gnus-prin1 nneething-map) 241 (push (list (cdr nneething-active) (car files)
245 (insert ")\n(setq nneething-active '") 242 (nth 5 (file-attributes
246 (gnus-prin1 nneething-active) 243 (nneething-file-name (car files)))))
247 (insert ")\n")))))) 244 nneething-map))
245 (setq files (cdr files)))
246 (when (and touched
247 (not nneething-read-only))
248 (save-excursion
249 (nnheader-set-temp-buffer " *nneething map*")
250 (insert "(setq nneething-map '" (prin1-to-string nneething-map) ")\n"
251 "(setq nneething-active '" (prin1-to-string nneething-active)
252 ")\n")
253 (write-region (point-min) (point-max) map-file nil 'nomesg)
254 (kill-buffer (current-buffer))))))
248 255
249 (defun nneething-insert-head (file) 256 (defun nneething-insert-head (file)
250 "Insert the head of FILE." 257 "Insert the head of FILE."
251 (when (nneething-get-head file) 258 (when (nneething-get-head file)
252 (insert-buffer-substring nneething-work-buffer) 259 (insert-buffer-substring nneething-work-buffer)
253 (goto-char (point-max)))) 260 (goto-char (point-max))))
254 261
255 (defun nneething-make-head (file &optional buffer) 262 (defun nneething-make-head (file &optional buffer)
256 "Create a head by looking at the file attributes of FILE." 263 "Create a head by looking at the file attributes of FILE."
257 (let ((atts (file-attributes file))) 264 (let ((atts (file-attributes file)))
258 (insert 265 (insert
259 "Subject: " (file-name-nondirectory file) "\n" 266 "Subject: " (file-name-nondirectory file) "\n"
260 "Message-ID: <nneething-" 267 "Message-ID: <nneething-"
261 (int-to-string (incf nneething-message-id-number)) 268 (int-to-string (incf nneething-message-id-number))
262 "@" (system-name) ">\n" 269 "@" (system-name) ">\n"
263 (if (equal '(0 0) (nth 5 atts)) "" 270 (if (equal '(0 0) (nth 5 atts)) ""
264 (concat "Date: " (current-time-string (nth 5 atts)) "\n")) 271 (concat "Date: " (current-time-string (nth 5 atts)) "\n"))
265 (or (when buffer 272 (or (if buffer
266 (save-excursion 273 (save-excursion
267 (set-buffer buffer) 274 (set-buffer buffer)
268 (when (re-search-forward "<[a-zA-Z0-9_]@[-a-zA-Z0-9_]>" 1000 t) 275 (if (re-search-forward "<[a-zA-Z0-9_]@[-a-zA-Z0-9_]>" 1000 t)
269 (concat "From: " (match-string 0) "\n")))) 276 (concat "From: " (match-string 0) "\n"))))
270 (nneething-from-line (nth 2 atts) file)) 277 (nneething-from-line (nth 2 atts) file))
271 (if (> (string-to-int (int-to-string (nth 7 atts))) 0) 278 (if (> (string-to-int (int-to-string (nth 7 atts))) 0)
272 (concat "Chars: " (int-to-string (nth 7 atts)) "\n") 279 (concat "Chars: " (int-to-string (nth 7 atts)) "\n")
273 "") 280 "")
274 (if buffer 281 (if buffer
275 (save-excursion 282 (save-excursion
276 (set-buffer buffer) 283 (set-buffer buffer)
277 (concat "Lines: " (int-to-string 284 (concat "Lines: " (int-to-string
278 (count-lines (point-min) (point-max))) 285 (count-lines (point-min) (point-max))) "\n"))
279 "\n"))
280 "") 286 "")
281 ))) 287 )))
282 288
283 (defun nneething-from-line (uid &optional file) 289 (defun nneething-from-line (uid &optional file)
284 "Return a From header based of UID." 290 "Return a From header based of UID."
285 (let* ((login (condition-case nil 291 (let* ((login (condition-case nil
286 (user-login-name uid) 292 (user-login-name uid)
287 (error 293 (error
288 (cond ((= uid (user-uid)) (user-login-name)) 294 (cond ((= uid (user-uid)) (user-login-name))
289 ((zerop uid) "root") 295 ((zerop uid) "root")
290 (t (int-to-string uid)))))) 296 (t (int-to-string uid))))))
291 (name (condition-case nil 297 (name (condition-case nil
292 (user-full-name uid) 298 (user-full-name uid)
293 (error 299 (error
294 (cond ((= uid (user-uid)) (user-full-name)) 300 (cond ((= uid (user-uid)) (user-full-name))
295 ((zerop uid) "Ms. Root"))))) 301 ((zerop uid) "Ms. Root")))))
296 (host (if (string-match "\\`/[^/@]*@\\([^:/]+\\):" file) 302 (host (if (string-match "\\`/[^/@]*@\\([^:/]+\\):" file)
297 (prog1 303 (prog1
298 (substring file 304 (substring file
299 (match-beginning 1) 305 (match-beginning 1)
300 (match-end 1)) 306 (match-end 1))
301 (when (string-match "/\\(users\\|home\\)/\\([^/]+\\)/" file) 307 (if (string-match "/\\(users\\|home\\)/\\([^/]+\\)/" file)
302 (setq login (substring file 308 (setq login (substring file
303 (match-beginning 2) 309 (match-beginning 2)
304 (match-end 2)) 310 (match-end 2))
305 name nil))) 311 name nil)))
306 (system-name)))) 312 (system-name))))
307 (concat "From: " login "@" host 313 (concat "From: " login "@" host
308 (if name (concat " (" name ")") "") "\n"))) 314 (if name (concat " (" name ")") "") "\n")))
309 315
310 (defun nneething-get-head (file) 316 (defun nneething-get-head (file)
311 "Either find the head in FILE or make a head for FILE." 317 "Either find the head in FILE or make a head for FILE."
312 (save-excursion 318 (save-excursion
313 (set-buffer (get-buffer-create nneething-work-buffer)) 319 (set-buffer (get-buffer-create nneething-work-buffer))
314 (setq case-fold-search nil) 320 (setq case-fold-search nil)
315 (buffer-disable-undo (current-buffer)) 321 (buffer-disable-undo (current-buffer))
316 (erase-buffer) 322 (erase-buffer)
317 (cond 323 (cond
318 ((not (file-exists-p file)) 324 ((not (file-exists-p file))
319 ;; The file do not exist. 325 ;; The file do not exist.
320 nil) 326 nil)
321 ((or (file-directory-p file) 327 ((or (file-directory-p file)
322 (file-symlink-p file)) 328 (file-symlink-p file))
323 ;; It's a dir, so we fudge a head. 329 ;; It's a dir, so we fudge a head.
324 (nneething-make-head file) t) 330 (nneething-make-head file) t)
325 (t 331 (t
326 ;; We examine the file. 332 ;; We examine the file.
327 (nnheader-insert-head file) 333 (nnheader-insert-head file)
328 (if (nnheader-article-p) 334 (if (nnheader-article-p)
329 (delete-region 335 (delete-region
330 (progn 336 (progn
331 (goto-char (point-min)) 337 (goto-char (point-min))
332 (or (and (search-forward "\n\n" nil t) 338 (or (and (search-forward "\n\n" nil t)
333 (1- (point))) 339 (1- (point)))
334 (point-max))) 340 (point-max)))