diff --git a/web/imprint.org b/web/imprint.org index 830583f..d41a244 100644 --- a/web/imprint.org +++ b/web/imprint.org @@ -1,26 +1,28 @@ #+TITLE: GnuPG - Imprint #+STARTUP: showall #+SETUPFILE: "share/setup.inc" * Imprint GnuPG is an international community project run by volunteers and not a legal entity. g10^code GmbH is the privately owned legal - entity behind the GnuPG. They employ all paid developers and - re-invest all profits into the development of GnuPG and related free - software. See also this [[https://www.gnupg.org/blog/20141214-gnupg-and-g10.html][article]]. + entity behind the GnuPG project. They employ all paid developers + and re-invest all profits into the development of GnuPG and related + free software. See also this [[https://www.gnupg.org/blog/20141214-gnupg-and-g10.html][article]]. g10 Code GmbH\\ Hüttenstr. 61\\ D-40699 Erkrath\\ Germany g10 Code GmbH is registered at Amtsgericht Wuppertal under HRB 14459.\\ Geschäftsführung: Werner Koch.\\ VAT-Id: DE215605608.\\ Phone: +49-2104-173855 Note that we provide the phone number only for legal reasons. Please do not call g10^code to ask for free support. For paid support see their [[https://g10code.com/contact.html][contact page]]. + + Please see [[file:privacy-policy.org][here]] for the privacy policy. diff --git a/web/privacy-policy.org b/web/privacy-policy.org index c3f4168..2864e50 100644 --- a/web/privacy-policy.org +++ b/web/privacy-policy.org @@ -1,31 +1,188 @@ #+TITLE: GnuPG - Privacy Policy -#+STARTUP: showall indent +#+STARTUP: showall #+SETUPFILE: "share/setup.inc" * Privacy Policy #+index: privacy policy #+index: analytics #+index: log files -** Log files +The GnuPG project runs several web sites on different technical +platforms. + +We do not track the use of these sites or store data of users except +to fulfill the user requested actions, to aid in fixing technical +problems and due to financial accounting requirements. + +No data is ever shared with external parties unless explicitly +requested by the user. We use cookies only for session management +without any personal data and at https://dev.gnupg.org to store the +name of a registered user. + +Find below details for all provided services; the responsible person +for data privacy can be found at the end of this page. + +** Website www.gnupg.org This website uses log files to identify problems with the site and to monitor traffic. The raw log files are kept for a week and are then -deleted. For web analytics the data from the log files is anonymized +deleted. For web analytic the data from the log files is anonymized by truncating the IP addresses to 40 bit for IPv6 and 20 bits for IPv4 -and send to another machine. Neither the raw log files nor the -anonymized data from the log file is shared with anyone; however -system administrators have access to the log files to solve technical -problems. Reports on the use of this site will always be fully -anonymized and may eventually be published at this site. +and send to another machine. Reports on the use of this site will +always be fully anonymized and may be published at [[http://ambler.gnupg.org][one of our servers]]. + +Neither the raw log files nor the anonymized data from the log files +are shared with anyone; however within the first week system +administrators have access to the log files to solve technical +problems. In exceptional cases stripped down copies of the log files +may be stored for longer to analyze problems spanning more than a +week. These copies are deleted as soon as the problem has been +solved. + +** Donation system at www.gnupg.org + +For the donation system we use several external payment processing +services and submit data entered by the user pertaining to the +donation. For bookkeeping and administrative needs we store and +process this data: + + - The name of the user if given by the user. This is not shared with + the payment processing service. + - A contact mail address if given by the user. This is not be shared + with the payment processing service. + - A message text if given by the user. This is not be shared + with the payment processing service. + - The mail address or user name as returned by the payment processing + service. + - The amount of data. + - Transaction IDs. + +The data is stored in a local data base and in donation log files. +Log files which are older than a week are encrypted in a way +that only the back office is able to decrypt them. Access to this data +is only granted to system administrators and staff responsible for the +donations. We do not share this information with anyone else. Data +will be deleted according to general bookkeeping rules. If the user +has opted for publication, we put the entered name on our donation +thanks page. + +Our payment service providers are: + + - PayPal for PayPal based donations. Click here for their [[https://www.paypal.com/webapps/mpp/ua/privacy-prev][privacy policy]]. + - Stripe for credit card based donations. Click here for their + [[https://stripe.com/de/privacy][privacy policy]]. + - SEPA. This is not a real payment service; instead we send only + a random number to the user which allows us to match the stored + information with a receipt of payment. + +** Mailing lists + +The mailing list as listed at +https://lists.gnupg.org/mailman/listinfo/ are used for discussions +between users. Reading the archives of the mailing lists keeps no +personal data other then IP address as described above under +/Website/. Anyone may subscribe to a mailing list using a valid mail +address. This can be done using the web interface or by sending +special mail to the system. Unsubscribing is also a self-service +using the same web interface; a link to the web interface if shown in +the footer of all for warded mails. + +We store the subscription mail address and a user given password and +optionally a name. The mail address is used to deliver mails to the +user and for no other purpose. The password is required for +unsubscribing or temporary disabling message delivering. The password +does not protect any personal information but protects against +malicious unsubscribing requests. + +Users who want to post to the list send a mail through our mail system +(see below) which is then forwarded to all users and stored in a +public mail archive. All information send by the user is forwarded to +all users; this includes all information which are send in a standard +mail. The content of the mail is considered to be in the /public +domain/ with the exception of code snippets and patches which are +subject to their respective license. As a public visible service we +have no control whatsoever where these mails and the mail archives are +copied to. Thus it is not possible to retract a one posted message. +In exceptional cases and for illegal posted content we are able and +will redact a message stored in our mail archive. Please contact as +at the mail address five at the end of the page. + + +** Mailing system + +All mails to gnupg.org and related sites are passing through our mail +servers. We keep log files for 10 days to analyze technical problems +and for spam prevention. The IP addresses and sender addresses of +incoming mails are compared to addresses we have on local black- and +whitelists. We also compare them using DNS based list of known +spamming addresses. All mail is conveyed using TLS encryption if +supported by the peer. + +** FTP Server + +The FTP server ftp.gnupg.org is similar to the Web server and can be +used to download files and other material. The logs are kept for 7 +days and carry the IP address of the requested, the requested file and +an error code. For access analytic the same system and properties as +used by the web server are in place. All files on the FTP server are +also available via the more secure HTTPS protocol using the address +https://gnupg.org/ftp/ which is served by our web server. + +** Git repository + +This is a public service which carries all published code along with +the names and mail addresses of their authors. This is required for +technical and legal (copyright) reasons. + +** Bug tracker dev.gnupg.org + +The system https://dev.gnupg.org is a general purpose bug track er +which is in general visible to everyone. No registration is required +to view the public data, similar to the web server. To file a bug +report a user must be registered; this is only done to avoid misuse of +the server by spammer. A user who registered must provide a valid +mail address and an arbitrary name for his account. A user may +disable his own account but can't delete any data he entered into the +system. This is required for proper documentation and the overall +security of the software developed by the GnuPG project. + +Only available to the administrators of the system are the IP +addresses and login times of the users. We need to keep them to help +preventing abuse of this public service. No such data is ever shared +with any 3rd party or used for other purposes. + +All user entered content is considered to be in the /public domain/ +with the exception of code snippets and patches which are subject to +their respective license. + +# Fixme: We need to figure out properties of the log files etc. + +** Responsible person for data protection + +If you have any questions about our privacy policy or need to get +information on the data strored about you, write to + +Werner Koch, =data-privacy at gnupg dot org= ([[file:share/data-privacy-key.asc][OpenPGP key]])\\ +g10 Code GmbH\\ +Hüttenstr. 61\\ +40699 Erkrath\\ +Germany + +You can expect a response within a week. If exceptionally you don't +get a timely response please send a reminder or call us at the phone +number given in the [[file:imprint.org][imprint]]. -We have not been forced by any court order or other means not to obey -to the above rules. ** History -- 2013-11-07 :: Installed Piwik web analytics software and wrote a - privacy policy. +- 2018-05-18 :: Revamped the page. No actual policy changes. - 2014-03-12 :: Removed the Piwik web analytics software and changed the policy to allow for log file based analytics. + +- 2013-11-07 :: Installed Piwik web analytics software and wrote a + privacy policy. + + +We have not been forced by any court order or other means not to obey +to the above rules. diff --git a/web/share/data-privacy-key.asc b/web/share/data-privacy-key.asc new file mode 100644 index 0000000..f75eeb0 --- /dev/null +++ b/web/share/data-privacy-key.asc @@ -0,0 +1,38 @@ + +pub rsa2048 2018-05-16 [SC] [expires: 2020-05-15] + DC3629A4DBD434211589A0E1EB6CA96502867BDA +uid data-privacy@gnupg.org +sub rsa2048 2018-05-16 [E] + AB9897AC6DAAB01680F6C8FFC36EBD049AEA1BAA + + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFr72M0BCADzDmCPrvQWm/aObH6mGkPZdAtaiTTpHh0/okXcCSYdofjqXJe/ +myBHj1eMZ5MO29+lahmDiwsb2v+JAxYzKc76DhBVv1Ee5/GmNH27bmERC2sS3KO6 +pae43aXf1xsdOjXw0BthS1CZZ4MNukUzpUVeeo2GkThFy3v1HHzgTPUcGSzN7LUl +8X0+PyX+N0Y0S4sWsVOadyj0PokP/L8+zHnBQP3UkjBwahAEM9YQ2EDiUak1UK5S +4t50+q43vPikfohEDm/Tk0A6lU7Q3KUyIlS/rjwzPn/ZA1o02Xehyl3odp6aUFVB +D5xW98SF3PgYvgAxAMXx21PPnQ0Ai8W2oTgXABEBAAG0FmRhdGEtcHJpdmFjeUBn +bnVwZy5vcmeJAVQEEwECAD4WIQTcNimk29Q0IRWJoOHrbKllAoZ72gUCWvvYzQIb +AwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRDrbKllAoZ72vKZCACD +X/4YuYxCliWF7Fla01K7fAcivl8XUiDHWDbvWL55bbN5wAcl+EmyGfVcQjprrR/N +8fXySBOZuBhm3d898APhKzqMrsKSnqnys2qfPtyA9Ft4FTQ81Py3Dq3n/ULIRdnd +Rd/5Q46b98o1KXE9Y291TqW5tKBGbC7QIVZ0avma44dlp43u/fjwoLccBN7AY0eW +KAKvcIh5qMpa3nXEvKzlUg3JBG4RfPxHWxeJYfX5H4ibipSIYbjsxFIs4L2wER/U +o46BdPC5rw2FuGSD8yKCdKRIsupqNP3Fkj5VUe4XwdU8OZZGnrSclsAX7xROoEkS +ZrjV0mZkfYW9PUv1P+SjuQENBFr72M0BCADCTuMKyGLoj5nmCmYHO9hOnGt3qVEF +9g4UvOIu/REl/gLNRFOcGqqmDyJjeo77syHqQVI98yc4JOr74tdPvr2rS22Hmuv3 +CCcFhSDT32kV6l8eTgB5SB6Ap+q63OuFBwAEVnJqf5TzvYdGsGQSrFgoEinp1upa +E5tSknF0EEPrC+htDh845+YtAXPcDcIvZZHb6irG629Jl6BgnNJaL2xHxxtcLm6H +g92PACiOVmdThTk15PKDAznYtHmxu5jRUF5+KWT/E6N8FFr6aYRvPK7KctRRDJMm +fqijnsXvELZav5MBnW27cnGL5nTjYXEdzFOLghAT2qotyJjmjOVIvqF5ABEBAAGJ +ATYEGAECACAWIQTcNimk29Q0IRWJoOHrbKllAoZ72gUCWvvYzQIbDAAKCRDrbKll +AoZ72rwpB/9bHDd3h3M7+2IEnl4WnbMUUTN6TiGc+vBulNPnTjeOp2+6p+j79HYD +LPrOZo4nYz0GBwbWe91W8p9li5VYAs2WLXnJ1nLfll/mrA6OxWLwW7VotSeFLInz +vxPGlLbI6mEJ3L6PyLNCd6buGEIyVoJNkUAVSOjuVby1BZJftItWH3q5drTLkQzg +mJ8h+ctQxDkn0UD4LWzEmE55ieLH0ySnVzY7nOzGtcE/IjzgtuRllkoNZmc22VOk +EvTeR84kdIntwk6nb2St8qMnN9ea81/iDNSCt9xkz/HMN5WAjLTYqr7LSQrUTae1 +/r7eE98xbr4BrOpjQOefGkVreSPcJHT9 +=Fr5h +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web/share/gpgweb.el b/web/share/gpgweb.el index 9f14d1c..8c968c9 100644 --- a/web/share/gpgweb.el +++ b/web/share/gpgweb.el @@ -1,543 +1,543 @@ ;;; gpgweb.el --- elisp helper code for the GnuPG web pages (if (< (string-to-number emacs-version) 24) (require 'org-exp)) ;; makeindex disabled because the generated file is created in the ;; source directory. (defun gpgweb-setup-project () "Set up an org-publish project for the gnupg.org website." (progn (require 'ox-gpgweb (concat gpgweb-root-dir "share/ox-gpgweb.el")) (aput 'org-publish-project-alist "gpgweb-org" `(:base-directory ,gpgweb-root-dir :base-extension "org" :language "en" :html-extension "html" :recursive t :publishing-directory ,gpgweb-stage-dir :publishing-function gpgweb-org-to-html :body-only t :section-numbers nil :tags nil :with-toc nil :makeindex nil :auto-sitemap nil :sitemap-title "GnuPG - Sitemap" :sitemap-sort-folders "last" :sitemap-file-entry-format "%t @@html:@@(%d)@@html:@@" :style-include-default nil :timestamp-file nil :html-head "" :html-head-include-scripts nil)) (aput 'org-publish-project-alist "gpgweb-other" `(:base-directory ,gpgweb-root-dir - :base-extension "jpg\\|png\\|css\\|txt\\|rss\\|lst\\|sig\\|js\\|map\\|eot\\|ttf\\|woff\\|woff2\\|svg" + :base-extension "jpg\\|png\\|css\\|txt\\|rss\\|lst\\|sig\\|js\\|map\\|eot\\|ttf\\|woff\\|woff2\\|svg\\|asc" :recursive t :publishing-directory ,gpgweb-stage-dir :publishing-function org-publish-attachment :completion-function gpgweb-upload)) (aput 'org-publish-project-alist "gpgweb" '(:components ("gpgweb-org" "gpgweb-other"))) (add-hook 'org-export-before-processing-hook 'gpgweb-preprocess))) (defun gpgweb-preprocess (backend) "Insert certain stuff before processing." (let () (goto-char (point-min)) (when (re-search-forward "^#\\+GPGWEB-NEED-SWDB\\b" 2048 t) (beginning-of-line) (kill-line 1) (insert (org-file-contents (concat gpgweb-root-dir "swdb.mac") 'noerror))))) (defun gpgweb-insert-header (title committed-at custom) "Insert the header. COMMITTED-AT is the commit date string of the source file or nil if not available. If CUSTOM is true only a minimal header is set." (goto-char (point-min)) (insert " " title " ") (when (and committed-at (>= (length committed-at) 10)) (insert "\n")) (insert " ") (unless custom (insert " "))) (defconst gpgweb-gnupg-menu-alist '(("/index.html" "Home" (("/index.html" "Home") ("/news.html" "News") ("/people/index.html" "People") ("/verein/index.html" "Verein") ("/documentation/sites.html" "Sites"))) ("/donate/index.html" "Donate" (("/donate/index.html" "Donate") ("/donate/kudos.html" "List of Donors"))) ("/software/index.html" "Software" (("/software/index.html" "GnuPG") ("/software/frontends.html" "Frontends") ("/software/tools.html" "Tools") ("/software/libraries.html" "Libraries") ("/software/swlist.html" "All"))) ("/download/index.html" "Download" (("/download/index.html" "Download") ("/download/integrity_check.html" "Integrity Check") ("/download/supported_systems.html" "Supported Systems") ("/download/release_notes.html" "Release Notes") ("/download/mirrors.html" "Mirrors") ("/download/git.html" "GIT"))) ("/documentation/index.html" "Documentation" (("/documentation/howtos.html" "HOWTOs") ("/documentation/manuals.html" "Manuals") ("/documentation/guides.html" "Guides") ("/documentation/faqs.html" "FAQs") ("/documentation/mailing-lists.html" "Mailing Lists") ("/service.html" "3rd Party Support") ("/documentation/bts.html" "Bug Tracker") ("/documentation/security.html" "Security"))) ("/blog/index.html" "Blog")) "The definition of the gnupg.org menu structure.") (defconst gpgweb-gnupg-bottom-menu-alist '(("/privacy-policy.html" "Privacy Policy" ()) ("/imprint.html" "Imprint" ()) ("/misc/index.html" "Archive" ()) ("/sitemap.html" "Sitemap" ()) ("/blog/index.html" "Blog" ()) ("/ftp/index.html" "Files" ())) "The definition of the gnupg.org bottom menu structure.") (defun gpgweb--any-selected-menu-p (menu selected-file) "Return t if any item in MENU has been selected." (let ((item (car menu)) res) (when menu (when item (when (string= (car item) selected-file) (setq res t)) (when (caddr item) (when (gpgweb--any-selected-menu-p (caddr item) selected-file) (setq res t)))) (when (gpgweb--any-selected-menu-p (cdr menu) selected-file) (setq res t))) res)) (defun gpgweb--selected-top-menu (menu selected-file) "Return the selected top menu or nil." (when menu (let ((item (car menu))) (if (and item (or (string= (car item) selected-file) (gpgweb--any-selected-menu-p (caddr item) selected-file))) menu (gpgweb--selected-top-menu (cdr menu) selected-file))))) (defun gpgweb--insert-menu (menu lvl selected-file) "Helper function to insert the menu." (when menu (let ((item (car menu))) (when item (dotimes (i (1+ lvl)) (insert " ")) (insert "
  • " (cadr item) "\n") (when (caddr item) (dotimes (i (1+ lvl)) (insert " ")) (insert " \n")) (dotimes (i (1+ lvl)) (insert " ")) (insert "
  • \n"))) (gpgweb--insert-menu (cdr menu) lvl selected-file))) (defun gpgweb--insert-submenu (menu selected-file) "Helper function to insert the sub-menu." (when menu (let ((item (car menu))) (when item (insert "
  • " (cadr item) "
  • \n"))) (gpgweb--insert-submenu (cdr menu) selected-file))) (defun gpgweb-insert-menu (selected-file) "Insert the menu structure into the HTML file." (goto-char (point-min)) (when (re-search-forward "^\n" nil t) (insert "
     
    ") (let ((m (caddr (car (gpgweb--selected-top-menu gpgweb-gnupg-menu-alist selected-file))))) (when m (insert "\n"))) (insert "
    "))) (defun gpgweb-blog-index (orgfile filelist) "Return the index of ORGFILE in FILELIST or nil if not found." (let (found (i 0)) (while (and filelist (not found)) (if (string= orgfile (car filelist)) (setq found i)) (setq i (1+ i)) (setq filelist (cdr filelist))) found)) (defun gpgweb-blog-prev (fileidx filelist) "Return the chronological previous file at FILEIDX from FILELIST with the suffixed replaced by \"html\"." (if (> fileidx 1) (concat (file-name-sans-extension (nth (1- fileidx) filelist)) ".html"))) (defun gpgweb-blog-next (orgfile filelist) "Return the chronological next file at FILEIDX from FILELIST with the suffixed replaced by \"html\"." (if (< fileidx (1- (length filelist))) (concat (file-name-sans-extension (nth (1+ fileidx) filelist)) ".html"))) (defun gpgweb-fixup-blog (info orgfile filelist) "Insert the blog specific content. INFO is the usual plist. ORGFILE is the name of the current source file without the directory part. If FILELIST is a list it has an ordered list of org filenames." (let ((authorstr (car (plist-get info :author))) (datestr (car (plist-get info :date)))) (goto-char (point-min)) (if (re-search-forward "^
    " nil t) (let* ((indexp (string= orgfile "index.org")) (fileidx (if (listp filelist) (if indexp (1- (length filelist)) (gpgweb-blog-index orgfile filelist)))) (prevfile (if fileidx (gpgweb-blog-prev fileidx filelist))) (nextfile (if (and fileidx (not indexp)) (gpgweb-blog-next fileidx filelist)))) (move-beginning-of-line nil) (insert "\n"))) (if (and datestr authorstr) (if (re-search-forward "^

    Posted " datestr " by " authorstr "

    \n"))))) (defun gpgweb-insert-footer (htmlfile committed-at blogmode) "Insert the footer. HTMLFILE is HTML file name and COMMITTED-AT is the commit date string of the source file or nil if not available." (let ((srcfile (concat "https://git.gnupg.org/cgi-bin/gitweb.cgi?" "p=gnupg-doc.git;a=blob;f=" (if blogmode "misc/blog.gnupg.org" "web/") ;; The replace below is a hack to cope with ;; blogmode where HTMLFILE is like "./foo.html". (replace-regexp-in-string "^\\./" "/" (file-name-sans-extension htmlfile) t) ".org")) (changed (if (and committed-at (>= (length committed-at) 10)) (substring committed-at 0 10) "[unknown]"))) (goto-char (point-max)) (insert "

      ") (gpgweb--insert-menu gpgweb-gnupg-bottom-menu-alist 0 nil) (insert "
    ") (insert "
    \"Traueranzeige:

    ") (goto-char (point-min)) (unless (search-forward "" nil t) (goto-char (point-max)) (if (string-prefix-p "verein/" htmlfile) (insert "
    \"CC  This web page is Copyright 2018 GnuPG e.V. and licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. See copying for details. Page source last changed on " changed ".
    \n") (insert "
    \"CC  These web pages are Copyright 1998--2018 The GnuPG Project and licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. See copying for details. Page source last changed on " changed ".
    \n"))) (goto-char (point-max)) (insert "
    "))) (defun gpgweb-publish-find-title (file &optional reset) "Find the title of FILE in project. This is a copy of org-publish-find-title which switches the buffer into read-write mode so that it works with read-only files." (or (and (not reset) (org-publish-cache-get-file-property file :title nil t)) (let* ((org-inhibit-startup t) (visiting (find-buffer-visiting file)) (buffer (or visiting (find-file-noselect file)))) (with-current-buffer buffer (toggle-read-only 0) (let ((title (let ((property (plist-get ;; protect local variables in open buffers (if visiting (org-export-with-buffer-copy (org-export-get-environment)) (org-export-get-environment)) :title))) (if property (org-no-properties (org-element-interpret-data property)) (file-name-nondirectory (file-name-sans-extension file)))))) (unless visiting (kill-buffer buffer)) (org-publish-cache-set-file-property file :title title) title))))) (defun gpgweb-want-custom-page-p () "Return true if the current buffer indicated that it wants to be a custom page." (let ((savepoint (point)) (result)) (goto-char (point-min)) (setq result (not (not (search-forward "" nil t)))) (goto-char savepoint) result)) (defun gpgweb-postprocess-html (plist orgfile htmlfile blogmode) "Post-process the generated HTML file - Insert header and footer - Insert \"class=selected\" into the active menu entry - Fixup sitemap. If blogmode is not nil the output is rendered as a blog. BLOGMODE may then contain an ordered list of org file names which are used to create the previous and Next links for an entry." (let* ((visitingp (find-buffer-visiting htmlfile)) (work-buffer (or visitingp (find-file-noselect htmlfile))) (committed-at (shell-command-to-string (concat "git" (if blogmode (concat " -C " gpgweb-blog-dir)) " log -1 --format='%ci' -- " orgfile)))) (prog1 (with-current-buffer work-buffer (let ((fname (file-name-nondirectory htmlfile)) (fname-2 (replace-regexp-in-string ".*/gnupg-doc-stage/web/\\(.*\\)$" "\\1" htmlfile t)) (title (gpgweb-publish-find-title orgfile)) (custom (gpgweb-want-custom-page-p))) ;; Insert header, menu, and footer. (gpgweb-insert-header title committed-at custom) (unless custom (goto-char (point-min)) (unless (search-forward "" nil t) (gpgweb-insert-menu fname-2)) (if blogmode (gpgweb-fixup-blog plist (file-name-nondirectory orgfile) blogmode)) (gpgweb-insert-footer fname-2 committed-at blogmode)) ; Fixup the sitemap (when (string-equal fname "sitemap.html") (goto-char (point-min)) (while (re-search-forward "^.*
  • .*>\\(GnuPG - \\).* and ; attributes. (goto-char (point-min)) (when (search-forward "" nil t) (goto-char (point-min)) (while (re-search-forward "^