;;; gnus-loose-threads-by-date.el --- gather loose threads by subject AND date.

;; Author: Mark Triggs <mst@dishevelled.net>
;; Heavily based on code by Lars Magne Ingebrigtsen <larsi@gnus.org>

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; I seem to have a lot of people (even non-spammers) writing to me with the
;; subject "Hi".  These people almost always seem to have broken mail software
;; that doesn't add a "References" header.  Coincidence?

;; Eventually I got sick of five years' worth of "Hi" messages building up in
;; one enormous thread, so I wrote this.  As well as grouping loose threads by
;; subject, it compares their dates.  To be included in a thread, a message
;; must have been sent within `gnus-summary-thread-max-period' days of some
;; other message in the thread.

;; After requiring this file, just add:

;;   (setq gnus-summary-thread-gathering-function
;;         'gnus-gather-threads-by-subject-and-date)

;; to your init file.

;;; Code:

(defvar gnus-summary-thread-max-period 7)

(defun gnus-gather-threads-by-subject-and-date (threads)
  "Gather threads by looking at Subject headers and the message date.
If a message was received more than `gnus-summary-thread-max-period' days than
any other message in a thread, it will not be grouped in that thread."
  (if (not gnus-summary-make-false-root)
      threads
    (let ((hashtb (gnus-make-hashtable 1024))
          (prev threads)
          (result threads)
          subject hthread whole-subject)
      (while threads
        (setq subject (gnus-general-simplify-subject
                       (setq whole-subject (mail-header-subject
                                            (caar threads)))))
        (when subject
          (if (and (setq hthread (gnus-gethash subject hashtb))
                   (let ((time (time-to-days
                                (gnus-date-get-time
                                 (mail-header-date (caar threads))))))
                     (some (lambda (m)
                             (let ((mtime (time-to-days
                                           (gnus-date-get-time
                                            (mail-header-date (car m))))))
                               (< (abs (- time mtime))
                                  gnus-summary-thread-max-period)))
                           (cdr (car hthread)))))
              (progn
                ;; We enter a dummy root into the thread, if we
                ;; haven't done that already.
                (unless (stringp (caar hthread))
                  (setcar hthread (list whole-subject (car hthread))))

                ;; We add this new gathered thread to this gathered
                ;; thread.
                (setcdr (car hthread)
                        (nconc (cdar hthread)
                               (list (car threads))))
                ;; Remove it from the list of threads.
                (setcdr prev (cdr threads))
                (setq threads prev))
            ;; Enter this thread into the hash table.
            (gnus-sethash subject
                          (if gnus-summary-make-false-root-always
                              (progn
                                ;; If you want a dummy root above all
                                ;; threads...
                                (setcar threads (list whole-subject
                                                      (car threads)))
                                threads)
                            threads)
                          hashtb)))
        (setq prev threads)
        (setq threads (cdr threads)))
      result)))

(provide 'gnus-loose-threads-by-date)
;;; gnus-loose-threads-by-date.el ends here
