+2003-01-10 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-cite.el (gnus-cite-delete-overlays): Protect against
+ errors when deleting overlays.
+
+ * gnus-score.el (gnus-score-followup): Allow tracing.
+
+ * gnus-art.el (gnus-treat-display-face): New variable.
+ (article-display-face): New command.
+
+ * gnus-fun.el (gnus-face-from-file): New function.
+ (gnus-convert-face-to-png): Ditto.
+
+ * gnus-art.el (gnus-ignored-headers): Added Face.
+
2003-01-10 Simon Josefsson <jas@extundo.com>
* nndraft.el (nndraft-request-group): Avoid crash in
db parameter only if it's set
(spam-ifile-register-with-ifile): ditto
+2003-01-09 Alex Schroeder <alex@emacswiki.org>
+
+ * spam-stat.el (spam-stat-save): Set spam-stat-ngood and
+ spam-stat-nbad before creating the hash table.
+ (spam-stat-reset): Set spam-stat-ngood and spam-stat-nbad to 0.
+ Changed copyright statement to FSF.
+
2002-01-09 Kevin Greiner <kgreiner@xpediantsolutions.com>
* gnus-agent.el (gnus-agent-catchup): Do not mark cached nor
"^X-Request-PGP:" "^X-Fingerprint:" "^X-WRIEnvto:" "^X-WRIEnvfrom:"
"^X-Virus-Scanned:" "^X-Delivery-Agent:" "^Posted-Date:" "^X-Gateway:"
"^X-Local-Origin:" "^X-Local-Destination:" "^X-UserInfo1:"
- "^X-Received-Date:" "^X-Hashcash:")
+ "^X-Received-Date:" "^X-Hashcash:" "^Face:")
"*All headers that start with this regexp will be hidden.
This variable can also be a list of regexps of headers to be ignored.
If `gnus-visible-headers' is non-nil, this variable will be ignored."
"Internal variable used to say whether `smiley-mule' is loaded (whether
smiley functions are not overridden by `smiley').")
+(defcustom gnus-treat-display-face
+ (and (not noninteractive)
+ (or (and (fboundp 'image-type-available-p)
+ (image-type-available-p 'png))
+ (and (featurep 'xemacs)
+ (featurep 'png)))
+ 'head)
+ "Display Face headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)X-Face' for details."
+ :group 'gnus-article-treat
+ :version "21.1"
+ :link '(custom-manual "(gnus)Customizing Articles")
+ :link '(custom-manual "(gnus)X-Face")
+ :type gnus-article-treat-head-custom)
+(put 'gnus-treat-display-xface 'highlight t)
+
(defcustom gnus-treat-display-grey-xface
(and (not noninteractive)
(or (featurep 'xemacs)
(gnus-treat-date-original gnus-article-date-original)
(gnus-treat-date-user-defined gnus-article-date-user)
(gnus-treat-date-iso8601 gnus-article-date-iso8601)
+ (gnus-treat-display-face gnus-article-display-face)
(gnus-treat-hide-headers gnus-article-maybe-hide-headers)
(gnus-treat-hide-boring-headers gnus-article-hide-boring-headers)
(gnus-treat-hide-signature gnus-article-hide-signature)
(forward-line 1)
(point))))))
+(defun article-display-face ()
+ "Display any Face headers in the header."
+ (interactive)
+ (gnus-with-article-headers
+ (let ((face nil))
+ (save-excursion
+ (when (gnus-buffer-live-p gnus-original-article-buffer)
+ (set-buffer gnus-original-article-buffer)
+ (setq face (message-fetch-field "face"))))
+ (when face
+ (let ((png (gnus-convert-face-to-png face))
+ image)
+ (when png
+ (setq image (gnus-create-image png 'png t))
+ (gnus-article-goto-header "from")
+ (when (bobp)
+ (insert "From: [no `from' set]\n")
+ (forward-char -17))
+ (gnus-add-wash-type 'face)
+ (gnus-add-image 'face image)
+ (gnus-put-image image)))))))
+
(defun article-display-x-face (&optional force)
"Look for an X-Face header and display it if present."
(interactive (list 'force))
article-remove-cr
article-remove-leading-whitespace
article-display-x-face
+ article-display-face
article-de-quoted-unreadable
article-de-base64-unreadable
article-decode-HZ
(and (>= (gnus-overlay-end overlay) (point-min))
(<= (gnus-overlay-end overlay) (point-max))))
(setq gnus-cite-overlay-list (delete overlay gnus-cite-overlay-list))
- (gnus-delete-overlay overlay))))
+ (ignore-errors
+ (gnus-delete-overlay overlay)))))
(defun gnus-cite-parse-wrapper ()
;; Wrap chopped gnus-cite-parse.
:group 'gnus-fun
:type 'string)
+(defcustom gnus-convert-image-to-face-command "djpeg %s | ppmnorm | pnmscale -width 48 -height 48 | ppmquant %d | pnmtopng"
+ "Command for converting a GIF to an X-Face."
+ :group 'gnus-fun
+ :type 'string)
+
(defun gnus-shell-command-to-string (command)
"Like `shell-command-to-string' except not mingling ERROR."
(with-output-to-string
(format gnus-convert-image-to-x-face-command
(shell-quote-argument file)))))
+(defun gnus-face-from-file (file)
+ "Return an Face header based on an image file."
+ (interactive "fImage file name:" )
+ (when (file-exists-p file)
+ (let ((done nil)
+ (attempt "")
+ (quant 16))
+ (while (and (not done)
+ (> quant 1))
+ (setq attempt
+ (gnus-shell-command-to-string
+ (format gnus-convert-image-to-face-command
+ (shell-quote-argument file)
+ quant)))
+ (if (> (length attempt) 740)
+ (progn
+ (setq quant (- quant 2))
+ (message "Length %d; trying quant %d"
+ (length attempt) quant))
+ (setq done t)))
+ (if done
+ (mm-with-unibyte-buffer
+ (insert attempt)
+ (base64-encode-region (point-min) (point-max))
+ (goto-char (point-min))
+ (forward-line 1)
+ (while (not (eobp))
+ (insert " ")
+ (forward-line 1))
+ (buffer-string))
+ nil))))
+
+;;;###autoload
+(defun gnus-convert-face-to-png (face)
+ (mm-with-unibyte-buffer
+ (insert face)
+ (base64-decode-region (point-min) (point-max))
+ (buffer-string)))
+
(defun gnus-convert-image-to-gray-x-face (file depth)
(let* ((mapfile (mm-make-temp-file (expand-file-name "gnus."
mm-tmp-directory)))
;; Found a match, update scores.
(while (setq art (pop arts))
(setcdr art (+ score (cdr art)))
+ (when trace
+ (push (cons
+ (car-safe (rassq alist gnus-score-cache))
+ kill)
+ gnus-score-trace))
(when (setq new (gnus-score-add-followups
(car art) score all-scores thread))
(push new news)))))
("gnus-demon" :interactive t
gnus-demon-init gnus-demon-cancel)
("gnus-fun" gnus-convert-gray-x-face-to-xpm gnus-display-x-face-in-from
- gnus-convert-image-to-gray-x-face)
+ gnus-convert-image-to-gray-x-face gnus-convert-face-to-png
+ gnus-face-from-file)
("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
gnus-tree-open gnus-tree-close gnus-carpal-setup-buffer)
("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
+2003-01-10 Alex Schroeder <alex@emacswiki.org>
+
+ * gnus.texi (Creating a spam-stat dictionary): Explain how using
+ the Gnus Agent with nnimap might work to do this.
+ (Splitting mail using spam-stat): Use nnimap-split-fancy if you
+ use the nnimap back end.
+
2003-01-10 Katsumi Yamaoka <yamaoka@jpl.org>
* gnus.texi (Filtering Spam Using spam.el): Trivial fix.
\e$B>o\e(B @samp{nnml:mail.misc} \e$B%0%k!<%W$KBP1~\e(B) \e$B$KBP$7\e(B
\e$B$F\e(B @code{spam-stat-process-non-spam-directory} \e$B$r8F$V$G$7$g$&!#\e(B
+\e$B$"$J$?$,\e(B IMAP \e$B$r;H$C$F$$$k$J$i%a!<%k$r%m!<%+%k$K$O;}$C$F$$$J$$$N$G!"$=$l\e(B
+\e$B$OF0$+$J$$$G$7$g$&!#0l$D$N2r7h:v$O!"\e(Bgnus \e$B%(!<%8%'%s%H$G5-;v$r%-%c%C%7%e\e(B
+\e$B$9$k$3$H$G$9!#$=$&$9$l$P\e(B @code{spam-stat-process-spam-directory} \e$B$H$7\e(B
+\e$B$F\e(B @file{"~/News/agent/nnimap/mail.yourisp.com/personal_spam"} \e$B$N$h$&$J\e(B
+\e$B$b$N$,;H$($^$9!#\e(B@xref{Agent as Cache}\e$B!#\e(B
+
@defvar spam-stat
\e$B$3$NJQ?t$O$9$Y$F$NE}7W$N%O%C%7%e%F!<%V%k\e(B -- \e$B2f!9$,<-=q$H8@$C$F$$$k$b\e(B
\e$B$N\e(B -- \e$B$r;}$A$^$9!#$3$N%O%C%7%e%F!<%V%k$O!"APJ}$N%3%l%/%7%g%s$N$9$Y$F$NC1\e(B
\e$B$3$l$OI,MW$J\e(B gnus \e$B$N%3!<%I$H$"$J$?$,:n$C$?<-=q$r\e(B load \e$B$7$^$9!#\e(B
\e$B<!$K!"FC5iJ,3d$N5,B'$rE,9g$5$;$kI,MW$,$"$j$^$9\e(B: \e$B$I$&$d$C\e(B
-\e$B$F\e(B @code{spam-stat} \e$B$r;H$&$+$r7h$a$F2<$5$$!#$G\e(B
-\e$B$O\e(B @samp{mail.misc} \e$B$H\e(B @samp{mail.spam} \e$B$NFs$D$N%0%k!<%W$@$1$,$"$k:G$bC1\e(B
-\e$B=c$J;vNc$G$O$I$&$J$k$+!#0J2<$N<0$O%a!<%k$,\e(B spam \e$B$G$"$k$+!"$^$?$O$=$l\e(B
+\e$B$F\e(B @code{spam-stat} \e$B$r;H$&$+$r7h$a$F2<$5$$!#0J2<$NNc$O\e(B nnml \e$B%P%C%/%(%s%I\e(B
+\e$BMQ$G$9!#\e(Bnnimap \e$B%P%C%/%(%s%I$G$b$^$C$?$/F1MM$KF0:n$7$^$9!#C1\e(B
+\e$B$K\e(B @code{nnmail-split-fancy} \e$B$NBe$o$j$K\e(B @code{nnimap-split-fancy} \e$B$r;H$C\e(B
+\e$B$F2<$5$$!#\e(B
+
+\e$B$G$O\e(B @samp{mail.misc} \e$B$H\e(B @samp{mail.spam} \e$B$NFs$D$N%0%k!<%W$@$1$,$"$k:G$b\e(B
+\e$BC1=c$J;vNc$G$O$I$&$J$k$+!#0J2<$N<0$O%a!<%k$,\e(B spam \e$B$G$"$k$+!"$^$?$O$=$l\e(B
\e$B$,\e(B @samp{mail.misc} \e$B$K9T$/$Y$-$@$H8@$C$F$$$^$9!#$b$7\e(B spam \e$B$@$C$?\e(B
\e$B$i\e(B @code{spam-stat-split-fancy} \e$B$O\e(B @samp{mail.spam} \e$B$rJV$7$^$9!#\e(B
@file{~/Mail/mail/misc} (this usually corresponds the the group
@samp{nnml:mail.misc}).
+When you are using IMAP, you won't have the mails available locally,
+so that will not work. One solution is to use the Gnus Agent to cache
+the articles. Then you can use directories such as
+@file{"~/News/agent/nnimap/mail.yourisp.com/personal_spam"} for
+@code{spam-stat-process-spam-directory}. @xref{Agent as Cache}.
+
@defvar spam-stat
This variable holds the hash-table with all the statistics -- the
dictionary we have been talking about. For every word in either
created.
Next, you need to adapt your fancy splitting rules: You need to
-determine how to use @code{spam-stat}. In the simplest case, you only have
-two groups, @samp{mail.misc} and @samp{mail.spam}. The following expression says
-that mail is either spam or it should go into @samp{mail.misc}. If it is
-spam, then @code{spam-stat-split-fancy} will return @samp{mail.spam}.
+determine how to use @code{spam-stat}. The following examples are for
+the nnml back end. Using the nnimap back end works just as well. Just
+use @code{nnimap-split-fancy} instead of @code{nnmail-split-fancy}.
+
+In the simplest case, you only have two groups, @samp{mail.misc} and
+@samp{mail.spam}. The following expression says that mail is either
+spam or it should go into @samp{mail.misc}. If it is spam, then
+@code{spam-stat-split-fancy} will return @samp{mail.spam}.
@example
(setq nnmail-split-fancy