PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lisp/gnus/gnus-sync.el

https://github.com/T-force/emacs
Emacs Lisp | 242 lines | 158 code | 33 blank | 51 comment | 4 complexity | 14994455387c92c6433fbdda8fd617a7 MD5 | raw file
  1. ;;; gnus-sync.el --- synchronization facility for Gnus
  2. ;; Copyright (C) 2010-2011 Free Software Foundation, Inc.
  3. ;; Author: Ted Zlatanov <tzz@lifelogs.com>
  4. ;; Keywords: news synchronization nntp nnrss
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This is the gnus-sync.el package.
  18. ;; It's due for a rewrite using gnus-after-set-mark-hook and
  19. ;; gnus-before-update-mark-hook, and my plan is to do this once No
  20. ;; Gnus development is done. Until then please consider it
  21. ;; experimental.
  22. ;; Put this in your startup file (~/.gnus.el for instance)
  23. ;; possibilities for gnus-sync-backend:
  24. ;; Tramp over SSH: /ssh:user@host:/path/to/filename
  25. ;; Tramp over IMAP: /imaps:user@yourhosthere.com:/INBOX.test/filename
  26. ;; ...or any other file Tramp and Emacs can handle...
  27. ;; (setq gnus-sync-backend "/remote:/path.gpg" ; will use Tramp+EPA if loaded
  28. ;; gnus-sync-global-vars `(gnus-newsrc-last-checked-date)
  29. ;; gnus-sync-newsrc-groups `("nntp" "nnrss")
  30. ;; gnus-sync-newsrc-offsets `(2 3))
  31. ;; TODO:
  32. ;; - after gnus-sync-read, the message counts are wrong. So it's not
  33. ;; run automatically, you have to call it with M-x gnus-sync-read
  34. ;; - use gnus-after-set-mark-hook and gnus-before-update-mark-hook to
  35. ;; catch the mark updates
  36. ;;; Code:
  37. (eval-when-compile (require 'cl))
  38. (require 'gnus)
  39. (require 'gnus-start)
  40. (require 'gnus-util)
  41. (defgroup gnus-sync nil
  42. "The Gnus synchronization facility."
  43. :version "24.1"
  44. :group 'gnus)
  45. (defcustom gnus-sync-newsrc-groups `("nntp" "nnrss")
  46. "List of groups to be synchronized in the gnus-newsrc-alist.
  47. The group names are matched, they don't have to be fully
  48. qualified. Typically you would choose all of these. That's the
  49. default because there is no active sync backend by default, so
  50. this setting is harmless until the user chooses a sync backend."
  51. :group 'gnus-sync
  52. :type '(repeat regexp))
  53. (defcustom gnus-sync-newsrc-offsets '(2 3)
  54. "List of per-group data to be synchronized."
  55. :group 'gnus-sync
  56. :type '(set (const :tag "Read ranges" 2)
  57. (const :tag "Marks" 3)))
  58. (defcustom gnus-sync-global-vars nil
  59. "List of global variables to be synchronized.
  60. You may want to sync `gnus-newsrc-last-checked-date' but pretty
  61. much any symbol is fair game. You could additionally sync
  62. `gnus-newsrc-alist', `gnus-server-alist', `gnus-topic-topology',
  63. and `gnus-topic-alist' to cover all the variables in
  64. newsrc.eld (except for `gnus-format-specs' which should not be
  65. synchronized, I believe). Also see `gnus-variable-list'."
  66. :group 'gnus-sync
  67. :type '(repeat (choice (variable :tag "A known variable")
  68. (symbol :tag "Any symbol"))))
  69. (defcustom gnus-sync-backend nil
  70. "The synchronization backend."
  71. :group 'gnus-sync
  72. :type '(radio (const :format "None" nil)
  73. (string :tag "Sync to a file")))
  74. (defvar gnus-sync-newsrc-loader nil
  75. "Carrier for newsrc data")
  76. (defun gnus-sync-save ()
  77. "Save the Gnus sync data to the backend."
  78. (interactive)
  79. (cond
  80. ((stringp gnus-sync-backend)
  81. (gnus-message 7 "gnus-sync: saving to backend %s" gnus-sync-backend)
  82. ;; populate gnus-sync-newsrc-loader from all but the first dummy
  83. ;; entry in gnus-newsrc-alist whose group matches any of the
  84. ;; gnus-sync-newsrc-groups
  85. ;; TODO: keep the old contents for groups we don't have!
  86. (let ((gnus-sync-newsrc-loader
  87. (loop for entry in (cdr gnus-newsrc-alist)
  88. when (gnus-grep-in-list
  89. (car entry) ;the group name
  90. gnus-sync-newsrc-groups)
  91. collect (cons (car entry)
  92. (mapcar (lambda (offset)
  93. (cons offset (nth offset entry)))
  94. gnus-sync-newsrc-offsets)))))
  95. (with-temp-file gnus-sync-backend
  96. (progn
  97. (let ((coding-system-for-write gnus-ding-file-coding-system)
  98. (standard-output (current-buffer)))
  99. (princ (format ";; -*- mode:emacs-lisp; coding: %s; -*-\n"
  100. gnus-ding-file-coding-system))
  101. (princ ";; Gnus sync data v. 0.0.1\n")
  102. (let* ((print-quoted t)
  103. (print-readably t)
  104. (print-escape-multibyte nil)
  105. (print-escape-nonascii t)
  106. (print-length nil)
  107. (print-level nil)
  108. (print-circle nil)
  109. (print-escape-newlines t)
  110. (variables (cons 'gnus-sync-newsrc-loader
  111. gnus-sync-global-vars))
  112. variable)
  113. (while variables
  114. (if (and (boundp (setq variable (pop variables)))
  115. (symbol-value variable))
  116. (progn
  117. (princ "\n(setq ")
  118. (princ (symbol-name variable))
  119. (princ " '")
  120. (prin1 (symbol-value variable))
  121. (princ ")\n"))
  122. (princ "\n;;; skipping empty variable ")
  123. (princ (symbol-name variable)))))
  124. (gnus-message
  125. 7
  126. "gnus-sync: stored variables %s and %d groups in %s"
  127. gnus-sync-global-vars
  128. (length gnus-sync-newsrc-loader)
  129. gnus-sync-backend)
  130. ;; Idea from Dan Christensen <jdc@chow.mat.jhu.edu>
  131. ;; Save the .eld file with extra line breaks.
  132. (gnus-message 8 "gnus-sync: adding whitespace to %s"
  133. gnus-sync-backend)
  134. (save-excursion
  135. (goto-char (point-min))
  136. (while (re-search-forward "^(\\|(\\\"" nil t)
  137. (replace-match "\n\\&" t))
  138. (goto-char (point-min))
  139. (while (re-search-forward " $" nil t)
  140. (replace-match "" t t))))))))
  141. ;; the pass-through case: gnus-sync-backend is not a known choice
  142. (nil)))
  143. (defun gnus-sync-read ()
  144. "Load the Gnus sync data from the backend."
  145. (interactive)
  146. (when gnus-sync-backend
  147. (gnus-message 7 "gnus-sync: loading from backend %s" gnus-sync-backend)
  148. (cond ((stringp gnus-sync-backend)
  149. ;; read data here...
  150. (if (or debug-on-error debug-on-quit)
  151. (load gnus-sync-backend nil t)
  152. (condition-case var
  153. (load gnus-sync-backend nil t)
  154. (error
  155. (error "Error in %s: %s" gnus-sync-backend (cadr var)))))
  156. (let ((valid-count 0)
  157. invalid-groups)
  158. (dolist (node gnus-sync-newsrc-loader)
  159. (if (gnus-gethash (car node) gnus-newsrc-hashtb)
  160. (progn
  161. (incf valid-count)
  162. (loop for store in (cdr node)
  163. do (setf (nth (car store)
  164. (assoc (car node) gnus-newsrc-alist))
  165. (cdr store))))
  166. (push (car node) invalid-groups)))
  167. (gnus-message
  168. 7
  169. "gnus-sync: loaded %d groups (out of %d) from %s"
  170. valid-count (length gnus-sync-newsrc-loader)
  171. gnus-sync-backend)
  172. (when invalid-groups
  173. (gnus-message
  174. 7
  175. "gnus-sync: skipped %d groups (out of %d) from %s"
  176. (length invalid-groups)
  177. (length gnus-sync-newsrc-loader)
  178. gnus-sync-backend)
  179. (gnus-message 9 "gnus-sync: skipped groups: %s"
  180. (mapconcat 'identity invalid-groups ", ")))))
  181. (nil))
  182. ;; make the hashtable again because the newsrc-alist may have been modified
  183. (when gnus-sync-newsrc-offsets
  184. (gnus-message 9 "gnus-sync: remaking the newsrc hashtable")
  185. (gnus-make-hashtable-from-newsrc-alist))))
  186. ;;;###autoload
  187. (defun gnus-sync-initialize ()
  188. "Initialize the Gnus sync facility."
  189. (interactive)
  190. (gnus-message 5 "Initializing the sync facility")
  191. (gnus-sync-install-hooks))
  192. ;;;###autoload
  193. (defun gnus-sync-install-hooks ()
  194. "Install the sync hooks."
  195. (interactive)
  196. ;; (add-hook 'gnus-get-new-news-hook 'gnus-sync-read)
  197. ;; (add-hook 'gnus-read-newsrc-el-hook 'gnus-sync-read)
  198. (add-hook 'gnus-save-newsrc-hook 'gnus-sync-save))
  199. (defun gnus-sync-unload-hook ()
  200. "Uninstall the sync hooks."
  201. (interactive)
  202. (remove-hook 'gnus-get-new-news-hook 'gnus-sync-read)
  203. (remove-hook 'gnus-save-newsrc-hook 'gnus-sync-save)
  204. (remove-hook 'gnus-read-newsrc-el-hook 'gnus-sync-read))
  205. (add-hook 'gnus-sync-unload-hook 'gnus-sync-unload-hook)
  206. ;; this is harmless by default, until the gnus-sync-backend is set
  207. (gnus-sync-initialize)
  208. (provide 'gnus-sync)
  209. ;;; gnus-sync.el ends here