From: anund@idt.unit.no (Anund Lie)
Subject: Problem with timezones in Unix message delimiters
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 13 Apr 1992 19:15:38 GMT

The problem concerns GNU emacs 18.58 and several older versions,
probably on all platforms.

The system's "date" command may output strange timezone names which
the code handling Unix mail message delimiters in sendmail.el and
rmail.el are not prepared to handle.  In our case, the symptom was
that rmail-convert-to-babyl-format was not able to recognize the
message delimiters in a file containing several FCC'ed messages.

To fix the problem at this site, I've made two changes:

1)	Make rmail.el somewhat more robust when recognizing Unix
	From-lines.  In the date, timezone names of the form "xxT DST"
	are now recognized.  (In searching for the next message
	boundary, it might be even better to search for just "^From "
	instead of the long regexp.)

	Also, in rmail-nuke-pinhead-header, if timezone is missing in
	the Unix From-line, the local timezone is inserted, instead of 
	arbitrarily EST.  This is the only dependency between these two
	changes, since this code calls mail-get-timezone from
	sendmail.el.

2)	Make sendmail.el (mail-do-fcc) generate RFC822 conforming
	timezones in the From-line.  Instead of attempting to pick the
	timezone name out of the output of "date", the difference
	between the time output by "date" and "date -u" is computed,
	and the timezone is specified numerically.

	Also, the order of the timezone and year is swapped.  The old
	mail-do-fcc did output dates on the form ... <YEAR> <TIMEZONE>, 
	which rmail-convert-to-babyl-format did not recognize even
	with a correct <TIMEZONE>.

	Caveat:  I've been unable to find any documentation describing the
	valid formats of the Unix From line.  Thus, I've somewhat
	arbitrarily made this change here, instead of the opposite
	change in rmail.el.  I've tested SunOS 4.1 /bin/mail and HP-UX
	8.0 /bin/mail.  The first one does not output any timezone,
	while the second one puts timezone before year.

The diffs are enclosed.

Sincerely,
Anund Lie
Division of Computer Systems and Telematics 
Norwegian Inst. of Technology, N-7034 Trondheim, Norway
Email: anund@idt.unit.no       (Internet)

*** /local/emacs/lisp/rmail.el	Tue Jul 23 20:21:22 1991
--- rmail.el	Mon Apr 13 16:36:49 1992
***************
*** 83,88 ****
--- 83,104 ----
  (defvar rmail-last-multi-labels nil)
  (defvar rmail-last-file nil)
  (defvar rmail-last-rmail-file nil)
+ 
+ (defvar rmail-unix-mail-delimiter
+   "From \\([^ \n]*\\(\\|\".*\"[^ \n]*\\)\\)  ?\\([^ \n]*\\) \\([^ ]*\\) *\\([0-9]*\\) \\([0-9:]*\\)\\( ?[A-Z]?[A-Z][A-Z]T\\( DST\\)?\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) 19\\([0-9]*\\) *\\(remote from [^\n]*\\)?\n"
+    "Regexp matching the delimiter of messages in UNIX mail format (UNIX From lines), minus the
+ initial ^.  ")
+ 
+ ;;; indexes of \\( \\)-pairs bracketing parts of the UNIX From line 
+ 
+ (defvar rmail-unix-mail-from 1)
+ (defvar rmail-unix-mail-dayofweek 3)
+ (defvar rmail-unix-mail-month 4)
+ (defvar rmail-unix-mail-day 5)
+ (defvar rmail-unix-mail-hour 6) 
+ (defvar rmail-unix-mail-timezone 7)
+ (defvar rmail-unix-mail-year 9)
+ 
  
  ;;;; *** Rmail Mode ***
  
***************
*** 601,609 ****
  			 
  	       (if (re-search-forward
  		    (concat "^[\^_]?\\("
! 			    "From [^ \n]*\\(\\|\".*\"[^ \n]*\\)  ?[^ \n]* [^ \n]* *"
! 			    "[0-9]* [0-9:]*\\( ?[A-Z]?[A-Z][A-Z]T\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) " ; EDT, -0500
! 			    "19[0-9]* *\\(remote from .*\\)?$\\|"
  			    mmdf-delim1 "\\|"
  			    "^BABYL OPTIONS:\\|"
  			    "\^L\n[01],\\)") nil t)
--- 617,624 ----
  			 
  	       (if (re-search-forward
  		    (concat "^[\^_]?\\("
! 			    rmail-unix-mail-delimiter
! 			    "\\|"
  			    mmdf-delim1 "\\|"
  			    "^BABYL OPTIONS:\\|"
  			    "\^L\n[01],\\)") nil t)
***************
*** 625,630 ****
--- 640,647 ----
  	      (t (delete-char 1)))))
      count))
  
+ (autoload 'mail-get-timezone "sendmail")
+ 
  (defun rmail-nuke-pinhead-header ()
    (save-excursion
      (save-restriction
***************
*** 645,652 ****
  	  (setq has-date (and (search-forward "\nDate:" nil t) (point)))
  	  (goto-char start))
  	(let ((case-fold-search nil))
! 	  (if (re-search-forward
! 	       "^From \\([^ ]*\\(\\|\".*\"[^ ]*\\)\\)  ?\\([^ ]*\\) \\([^ ]*\\) *\\([0-9]*\\) \\([0-9:]*\\)\\( ?[A-Z]?[A-Z][A-Z]T\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) 19\\([0-9]*\\) *\\(remote from [^\n]*\\)?\n" nil t)
  	      (replace-match
  		(concat
  		  ;; Keep and reformat the date if we don't
--- 662,668 ----
  	  (setq has-date (and (search-forward "\nDate:" nil t) (point)))
  	  (goto-char start))
  	(let ((case-fold-search nil))
! 	  (if (re-search-forward (concat "^" rmail-unix-mail-delimiter) nil t)
  	      (replace-match
  		(concat
  		  ;; Keep and reformat the date if we don't
***************
*** 653,662 ****
  		  ;;  have a Date: field.
  		  (if has-date
  		      ""
! 		    ;; If no time zone specified, assume est.
! 		    (if (= (match-beginning 7) (match-end 7))
! 			"Date: \\3, \\5 \\4 \\8 \\6 EST\n"
! 			"Date: \\3, \\5 \\4 \\8 \\6\\7\n"))
  		  ;; Keep and reformat the sender if we don't
  		  ;; have a From: field.
  		  (if has-from
--- 669,685 ----
  		  ;;  have a Date: field.
  		  (if has-date
  		      ""
! 		    (format "Date: \\%d, \\%d \\%d \\%d \\%d%s\n"
! 			     rmail-unix-mail-dayofweek
! 			     rmail-unix-mail-day
! 			     rmail-unix-mail-month
! 			     rmail-unix-mail-year
! 			     rmail-unix-mail-hour
! 			     ;; If no time zone specified, assume local timezone
! 			     (if (= (match-beginning rmail-unix-mail-timezone)
! 				    (match-end rmail-unix-mail-timezone))
! 				 (concat " " (mail-get-timezone))
! 			       (format "\\%d" rmail-unix-mail-timezone))))
  		  ;; Keep and reformat the sender if we don't
  		  ;; have a From: field.
  		  (if has-from
*** /local/emacs/lisp/sendmail.el	Tue Jan 28 22:22:56 1992
--- sendmail.el	Mon Apr 13 17:08:18 1992
***************
*** 256,265 ****
        (if (bufferp errbuf)
  	  (kill-buffer errbuf)))))
  
  (defun mail-do-fcc (header-end)
    (let (fcc-list
  	(rmailbuf (current-buffer))
- 	timezone
  	(tembuf (generate-new-buffer " rmail output"))
  	(case-fold-search t))
      (save-excursion
--- 256,313 ----
        (if (bufferp errbuf)
  	  (kill-buffer errbuf)))))
  
+ 
+ (defvar mail-timezone nil)
+ 
+ (defun mail-get-integer (index)
+   (string-to-int (buffer-substring (match-beginning index) (match-end index))))
+ 
+ (defun mail-get-time (cmd &rest args)
+   (save-excursion
+     (let ((time-in-minutes nil)
+ 	  (scratch-buffer (generate-new-buffer " date output")))
+       (set-buffer scratch-buffer)
+       (erase-buffer)
+       (apply 'call-process cmd nil t nil args)
+       (beginning-of-buffer)
+       (if (re-search-forward "\\([0-9][0-9]\\):\\([0-9][0-9]\\):[0-9][0-9]")
+ 	  (setq time-in-minutes (+ (* (mail-get-integer 1) 60) (mail-get-integer 2)))
+ 	(error (format "Can't parse output of %s to get hour and minutes." cmd))
+ 	)
+       (kill-buffer scratch-buffer)
+       time-in-minutes)))
+ 
+ (defun mail-two-digits (int)
+   (if (< int 10)
+       (format "0%1d" int)
+      (format "%2d" int)))
+ 
+ (defun mail-get-timezone ()
+   (or mail-timezone
+       (let (gmt-offset sign gmt-time local-time)
+ 	(while (progn
+ 		 (setq local-time (mail-get-time "date"))
+ 		 (setq gmt-time (mail-get-time  "date" "-u"))
+ 		 (setq gmt-offset (- local-time gmt-time))
+ 		 (not (= local-time (mail-get-time "date"))))	; minute did not change
+ 	  nil)
+ 	(cond
+ 	 ((< gmt-offset (* -12 60))
+ 	  (setq gmt-offset (+ gmt-offset (* 24 60))))
+ 	 ((> gmt-offset (* 12 60))
+ 	  (setq gmt-offset (- gmt-offset (* 24 60)))))
+ 	(setq sign (< gmt-offset 0))
+ 	(if sign (setq gmt-offset (- gmt-offset)))
+ 	(setq mail-timezone 
+ 	      (concat
+ 		      (if sign "-" "+")
+ 		      (mail-two-digits (/ gmt-offset 60))
+ 		      (mail-two-digits (mod gmt-offset 60))))
+ )))
+ 
  (defun mail-do-fcc (header-end)
    (let (fcc-list
  	(rmailbuf (current-buffer))
  	(tembuf (generate-new-buffer " rmail output"))
  	(case-fold-search t))
      (save-excursion
***************
*** 275,289 ****
  		       (progn (forward-line 1) (point))))
        (set-buffer tembuf)
        (erase-buffer)
-       (call-process "date" nil t nil)
-       (end-of-line)
-       (forward-word -1)
-       (delete-region (1- (point)) (point-max))
-       (forward-word -1)
-       (setq timezone (buffer-substring (point) (point-max)))
-       (erase-buffer)
        (insert "\nFrom " (user-login-name) " "
! 	      (current-time-string) " " timezone "\n")
        (insert-buffer-substring rmailbuf)
        ;; Make sure messages are separated.
        (goto-char (point-max))
--- 323,334 ----
  		       (progn (forward-line 1) (point))))
        (set-buffer tembuf)
        (erase-buffer)
        (insert "\nFrom " (user-login-name) " "
! 	      (current-time-string))
!       (forward-word -1)
!       (insert (mail-get-timezone) " ")
!       (forward-word 1)
!       (insert "\n")
        (insert-buffer-substring rmailbuf)
        ;; Make sure messages are separated.
        (goto-char (point-max))

Newsgroups: gnu.emacs.bug