Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Nov 2001 21:42:54 -0800 (PST)
From:      David Wolfskill <dhw@whistle.com>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        thomasoniii@yahoo.com
Subject:   ports/32372: Broken timezone specification generated by Bulkmail.pm
Message-ID:  <200111290542.fAT5gsg16522@pau-amma.whistle.com>

next in thread | raw e-mail | index | archive | help

>Number:         32372
>Category:       ports
>Synopsis:       Broken timezone specification generated by Bulkmail.pm
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Nov 28 21:50:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     David Wolfskill
>Release:        FreeBSD 4.1.1-STABLE i386
>Organization:
Whistle Communications
>Environment:

	Use the /usr/ports/mail/p5-Mail-Bulkmail (Mail::Bulkmail) port.

>Description:

	The Bulkmail.pm module generates its own Date: header for the
	messages it sends.  One of the fields in the Date: header is the
	time specification, which includes a "timezone" specification,
	which denotes the number of hours and minutes the time in
	question is offset from UTC (GMT), as well as the direction of
	that offset.

	The module has a function ("Tz", starting at line 703) to
	compute the above-mentioned offset.  The function will, under
	some circumstances, produce and return values that are not
	within the range -1200 to +1200, and has the (slight!)
	possibility of returning a value that is otherwise incorrect.
	(This latter is highly improbable, but easily fixed.)

	The Tz() function works by using the "hours" and "minutes" part
	of the current time; in particular, it examines and uses the
	difference between the "localtime()" and the "gmtime()" results.
	There are some problems, though:

	* There is code to check to see if the magnitude of the
	  difference exceeds 12 hours.  However, in such a case, the
	  result is adjusted by 12 hours, rather than the 24 hours that
	  would be correct.  (For example, sending a message at 1703
	  hrs. local time, from a time zone that is 8 hrs. west of GMT
	  -- so that the time in question is 0103 hrs. UTC/GMT the
	  following day -- would yield a difference of 16 hrs.  Since
	  this is >12, the code then subtracts that difference (16) from
	  12, yielding -4.  Rather, the code should subtract 24 from the
	  difference in the ">12" case, yielding -8 hrs., which is
	  correct.)

	* Even though the "difference" is "corrected" (albeit
	  incorrectly, per the above), there is a sprintf() call
	  immediately afterward that clobbers the "correction" anyway,
	  so the reported offset in the above example will be "1600",
	  which is outside the range of -1200 to +1200.  Note that the
	  extent to which this result will be in error depends on the
	  magnitude of the offset between local time and UTC/GMT, as
	  well as the time of day of the experiment.

	* There is no provision to ensure that an offset that has a
	  non-zero "minutes" component actually has the direction of the
	  minutes component that agrees with the direction of the hours
	  component.  (For 0- or 30-minute offsets, this isn't likely to
	  matter much.)

	* Finally, the exceedingly improbable error is caused by the use
	  of two *different* calls to Perl's time() function (one for
	  the localtime() call; the other for the gmtime() call).  It is
	  possible, though (very!) unlikely that the two calls will be
	  made at times such that the results could be on either side of
	  a minute (or even hour) boundary.  The cure for this is to
	  invoke time() but once, save the value, and use that for each
	  of the localtime() and gmtime() calls.

>How-To-Repeat:

	Well, here are the salient headers from an example such as the
	one described above:

Received: from us.ibm.com (pau-amma.whistle.com [207.76.205.64])
	by gatekeeper.whistle.com (8.11.1/8.11.1) with SMTP id fAS13NE20829
	for <dhw@whistle.com>; Tue, 27 Nov 2001 17:03:23 -0800 (PST)
Message-Id: <200111280103.fAS13NE20829@gatekeeper.whistle.com>
Date: Tue, 27 Nov 2001 17:03:23 +1600

	Note the timezone specification in the Date: header vs. that in
	the Received: header.  Had this been done between 0000 - 1559
	hrs. PST (8 hrs. west of GMT), the error would not have been
	apparent.
>Fix:

	Apply the following patch to Bulkmail.pm:

--- Bulkmail.pm.orig	Fri Sep  7 12:28:16 2001
+++ Bulkmail.pm	Wed Nov 28 07:27:50 2001
@@ -704,16 +704,31 @@
 
 	my $self = shift or undef;
 	
-	my ($min, $hour, $isdst) = (localtime(time))[1,2,-1];
-	my ($gmin, $ghour, $gsdst) = (gmtime(time))[1,2, -1];
+	my $now = time;
+	my ($min, $hour, $isdst) = (localtime($now))[1,2,-1];
+	my ($gmin, $ghour, $gsdst) = (gmtime($now))[1,2, -1];
 	
-	my $diffhour = $hour - $ghour;
-	$diffhour = 12 - $diffhour if $diffhour > 12;
-	$diffhour = 12 + $diffhour if $diffhour < -12;
+	my $diffmin = ($hour - $ghour) * 60 + ($min - $gmin);
+	my $diffhour = int($diffmin / 60);
+	$diffmin -= $diffhour * 60;
+	if ($diffhour > 12) {
+		$diffhour -= 24;
+		if ($diffmin) {
+			$diffhour += 1;
+			$diffmin -= 60;
+		}
+	} elsif ($diffhour < -12) {
+		$diffhour += 24;
+		if ($diffmin) {
+			$diffhour -= 1;
+			$diffmin += 60;
+		}
+	}
+	$diffmin = abs($diffmin);
 	
-	($diffhour = sprintf("%03d", $hour - $ghour)) =~ s/^0/\+/;
+	($diffhour = sprintf("%03d%02d", $diffhour, $diffmin)) =~ s/^0/\+/;
 
-	return $diffhour . sprintf("%02d", $min - $gmin);
+	return $diffhour;
 
 };
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200111290542.fAT5gsg16522>