Use of hash variables in module call - puzzling behaviour

H

Henry Law

I have a piece of code that is to send mail using Mail::Internet from my
Linux server (Perl 5.8.0). It reads variables - the recipient, the
outbound mail server and so on - from an XML file into a hash.

Using the variables in the hash causes errors in Mail::Internet; using
equivalent variables from a hash created from data in the program does
not cause the same error. Odder still, the error doesn't occur at all
when I run the same program under ActiveState Perl in Windows.

Can someone help? Firstly I'm at a loss to understand why this might
be; secondly I've run out of ideas for debugging the thing.

The program below simulates the reading of the XML through the use of
__DATA__; it builds the Mail::Internet structures $header and $mail; it
then executes the smtp send using first a structure built in the program
itself ($G_server) and then the XML-derived structure ($g_server). The
program even checks that the corresponding elements in $g_server and
$G_server are the same ...

----------- sample program ------------
#! /usr/bin/perl

use strict;
use warnings;

use Mail::Internet;
use Mail::Header;
use XML::Simple;

my @data = <DATA>;
my $xml = XMLin(join (' ',@data));

my %g_server;

$g_server{adminuser} = $xml -> {adminuser};
$g_server{smtpserver} = $xml -> {smtpserver};
$g_server{localuser} = $xml -> {localuser};

my %G_server = (localuser=>'(e-mail address removed)',
adminuser=>'(e-mail address removed)',
smtpserver=>'smtp.bt.net');

my @message = ("Line 1\n","Line 2");

print ( $g_server{localuser} eq $G_server{localuser} ?
"localuser same\n" : "localuser different\n");
print ( $g_server{adminuser} eq $G_server{adminuser} ?
"adminuser same\n" : "adminuser different\n");
print ( $g_server{smtpserver} eq $G_server{smtpserver} ?
"smtpserver same\n" : "smtpserver different\n");


my $header = Mail::Header->new( ["From:$g_server{localuser}",
"Sender:$g_server{localuser}",
"To:$g_server{adminuser}",
"Subject:Testing"] );

my $mail = Mail::Internet->new(Header=>$header,Body=>\@message);

my @recipients;

print "Sending with G_server variables\n";
@recipients = $mail->smtpsend(Host=>$G_server{smtpserver},
MailFrom=>$G_server{localuser},
To=>$G_server{adminuser});
print "Mail sent to @recipients\n";

print "Sending with g_server variables\n";
@recipients = $mail->smtpsend(Host=>$g_server{smtpserver},
MailFrom=>$g_server{localuser},
To=>$g_server{adminuser});
print "Mail sent to @recipients\n";
__DATA__
<nfbserver>
<adminuser>[email protected]</adminuser>
<smtpserver>smtp.bt.net</smtpserver>
<localuser>[email protected]</localuser>
</nfbserver>

----------------- output under Linux ----------------
[nfb@neptune nfb]$ ./tryit.pl
localuser same
adminuser same
smtpserver same
Sending with G_server variables
Mail sent to (e-mail address removed)
Sending with g_server variables
Unrecognised line: (e-mail address removed) at blib/lib/Mail/Internet.pm
(autosplit into blib/lib/auto/Mail/Internet/smtpsend.al) line 616
---------------- ends ------------------

OK, I'm braced for someone finding a simple typo in my code ...
 
A

A. Sinan Unur

Can someone help? Firstly I'm at a loss to understand why this might
be; secondly I've run out of ideas for debugging the thing.
....
@recipients = $mail->smtpsend(Host=>$G_server{smtpserver},
MailFrom=>$G_server{localuser},
To=>$G_server{adminuser});

I can't see anything that is obviously wrong, and it would take me a
little too much effort to test this (as I do not have access to an SMTP
server that does not require SSL).

However, have you tried turning debug on?

@recipients = $mail->smtpsend(
Host => $G_server{smtpserver},
MailFrom => $G_server{localuser},
To => $G_server{adminuser},
Debug => 1,
);

I am not sure if that would help.

The actual source of the message seems to Mail::Address.pm (line 122 in
version 1.67).

I have access to a FreeBSD system (Mail::Address v.1.66) where I tried

asu1@recex:~ > cat m.pl
use strict;
use warnings;

use Data::Dumper;
use Mail::Address;

print Dumper (Mail::Address->parse('(e-mail address removed)') );

__END__

asu1@recex:~ > perl m.pl
$VAR1 = bless( [
'',
'(e-mail address removed)',
''
], 'Mail::Address' );
asu1@recex:~ >

Maybe you can try the same script on your Linux system
 
A

Anno Siegel

Henry Law said:
I have a piece of code that is to send mail using Mail::Internet from my
Linux server (Perl 5.8.0). It reads variables - the recipient, the
outbound mail server and so on - from an XML file into a hash.

Using the variables in the hash causes errors in Mail::Internet; using
equivalent variables from a hash created from data in the program does
not cause the same error. Odder still, the error doesn't occur at all
when I run the same program under ActiveState Perl in Windows.

Can someone help? Firstly I'm at a loss to understand why this might
be; secondly I've run out of ideas for debugging the thing.

I don't have the modules in question and was unable to install them
in a hurry, so what follows is unfounded speculation.

Are the strings in the hash returned from XMLin normal scalars?
They *could* be objects with overloaded stringification or tied
variables in which case something might rub them the wrong way.

Swap the "Sending with G_server variables" and "Sending with g_server
variables" blocks. It could be the second call that fails instead of
depending on which hash is used. Perhaps one of the objects involved
($mail or $header) is damaged after the first use.

Try mixed calls, for example taking adminuser from %G_server and the
others from %g_server.

Check versions (Perl, the modules) on the linux box against the
windows one.

That's all that comes to mind for now. I have added a couple of remarks
(untested) to the code below, but these are stylistic and have nothing
to do with debugging the problem.

Anno

The program below simulates the reading of the XML through the use of
__DATA__; it builds the Mail::Internet structures $header and $mail; it
then executes the smtp send using first a structure built in the program
itself ($G_server) and then the XML-derived structure ($g_server). The
program even checks that the corresponding elements in $g_server and
$G_server are the same ...

----------- sample program ------------
#! /usr/bin/perl

use strict;
use warnings;

use Mail::Internet;
use Mail::Header;
use XML::Simple;

my @data = <DATA>;
my $xml = XMLin(join (' ',@data));

No need for @data.

my $xml = XMLin join ' ', <DATA>;

or even

my $xml = XMLIN do{ local $/; <DATA> };

should do the same thing. The last one assumes that line feeds and spaces
are interchangeable as separators.
my %g_server;

$g_server{adminuser} = $xml -> {adminuser};
$g_server{smtpserver} = $xml -> {smtpserver};
$g_server{localuser} = $xml -> {localuser};

my %G_server = (localuser=>'(e-mail address removed)',
adminuser=>'(e-mail address removed)',
smtpserver=>'smtp.bt.net');

my @message = ("Line 1\n","Line 2");

print ( $g_server{localuser} eq $G_server{localuser} ?
"localuser same\n" : "localuser different\n");
print ( $g_server{adminuser} eq $G_server{adminuser} ?
"adminuser same\n" : "adminuser different\n");
print ( $g_server{smtpserver} eq $G_server{smtpserver} ?
"smtpserver same\n" : "smtpserver different\n");

print $g_server{ $_} eq $G_server{ $_} ?
"$_ same\n" : "$_ different\n" for
qw( localuser adminuser smtpserver);

my $header = Mail::Header->new( ["From:$g_server{localuser}",
"Sender:$g_server{localuser}",
"To:$g_server{adminuser}",
"Subject:Testing"] );

my $mail = Mail::Internet->new(Header=>$header,Body=>\@message);

my @recipients;

print "Sending with G_server variables\n";
@recipients = $mail->smtpsend(Host=>$G_server{smtpserver},
MailFrom=>$G_server{localuser},
To=>$G_server{adminuser});
print "Mail sent to @recipients\n";

print "Sending with g_server variables\n";
@recipients = $mail->smtpsend(Host=>$g_server{smtpserver},
MailFrom=>$g_server{localuser},
To=>$g_server{adminuser});
print "Mail sent to @recipients\n";
__DATA__
<nfbserver>
<adminuser>[email protected]</adminuser>
<smtpserver>smtp.bt.net</smtpserver>
<localuser>[email protected]</localuser>
</nfbserver>

----------------- output under Linux ----------------
[nfb@neptune nfb]$ ./tryit.pl
localuser same
adminuser same
smtpserver same
Sending with G_server variables
Mail sent to (e-mail address removed)
Sending with g_server variables
Unrecognised line: (e-mail address removed) at blib/lib/Mail/Internet.pm
(autosplit into blib/lib/auto/Mail/Internet/smtpsend.al) line 616
---------------- ends ------------------

OK, I'm braced for someone finding a simple typo in my code ...
 
H

Henry Law

Are the strings in the hash returned from XMLin normal scalars?
They *could* be objects with overloaded stringification or tied
variables in which case something might rub them the wrong way.
Worth a look. I ran the program under Perl debug and "x"ed the two hashes:
DB<2> x %g_server
0 'adminuser'
1 '(e-mail address removed)'
2 'smtpserver'
3 'smtp.bt.net'
4 'localuser'
5 '(e-mail address removed)'
DB<3> x %G_server
0 'adminuser'
1 '(e-mail address removed)'
2 'smtpserver'
3 'smtp.bt.net'
4 'localuser'
5 '(e-mail address removed)'
.... which looks OK to me, unless I'm missing something.
Swap the "Sending with G_server variables" and "Sending with g_server
variables" blocks. It could be the second call that fails instead of
depending on which hash is used. Perhaps one of the objects involved
($mail or $header) is damaged after the first use.
I had already tried that; it's the $g_server version that fails
consistently.
Try mixed calls, for example taking adminuser from %G_server and the
others from %g_server.
That's a good idea. I'll try when I'm at home this evening.
Check versions (Perl, the modules) on the linux box against the
windows one.
I know the Perl versions are the same; I'll hadn't thought about the
modules versions and will check.
That's all that comes to mind for now.
Thanks; very helpful.

I have added a couple of remarks
(untested) to the code below, but these are stylistic and have nothing
to do with debugging the problem.
.... which are welcome, thank you. Style is, well, a stylistic thing.
 
X

xhoster

I had already tried that; it's the $g_server version that fails
consistently.

That would have been my first recommendation. Second would be to abstract
away the repeated code, just to make sure there is not some subtle (or
invisible funky character) difference in the code which executes under the
two hashes.


foreach my $hashref (\%g_server, \%G_server) {
# etc.
@recipients = $mail->smtpsend(Host=>$hashref->{smtpserver},
MailFrom=>$hashref->{localuser},
To=>$hashref->{adminuser}
);
# etc.
};


Xho
 
A

Anno Siegel

All this is very puzzling, so I chased down an error with ParserDetails.ini
and got XML::Simple to install (plus Mail::Internet and Mail::Header).
However, I cannot reproduce the problem.

There are several variants of XML::Simple: SAX-based vs. (whatever)-based,
and Expat-supported or not. What I have is probably SAX without Expat.
What are you running?

Something else: Could some encoding deviltry be going on? I believe it
is possible for strings to be eq, but have different byte representations.
If that is possible at all it may be worth looking into.

Anno
 
H

Henry Law

Anno said:
All this is very puzzling, so I chased down an error with ParserDetails.ini
and got XML::Simple to install (plus Mail::Internet and Mail::Header).
However, I cannot reproduce the problem.
Anno, thank you for taking the trouble to do that on my behalf. I'm not
terribly surprised, though, that you couldn't reproduce the problem
since it only happens to me on Linux and not on Windows. (Come to that,
I have another Linux machine around - I'll see what happens on there)
There are several variants of XML::Simple: SAX-based vs. (whatever)-based,
and Expat-supported or not. What I have is probably SAX without Expat.
What are you running?
Hmm; not sure how to find that out. I used the "-m" flag on perldoc
which showed this header at the top of the module:

$Id: Simple.pm,v 1.20 2004/04/05 09:12:47

.... which seems to suggest v1.20 but I don't know about Expat.
According to the perldoc it does support SAX though.
Something else: Could some encoding deviltry be going on? I believe it
is possible for strings to be eq, but have different byte representations.
If that is possible at all it may be worth looking into.

Anything's worth looking into just now; and that is possible since the
original XML file was created on Windows - but I thought it was just
plain single-byte ASCII. I'll look at the XML with a hex editor to make
sure.

As a result of the correspondence on this I've got a long list of "what
happens if" diagnostics, which I'll have a go at over a day or so. If
that fails I shall adopt the last resort of the frustrated programmer
and assign the problem to the usual cause*. Then I'll look for a
work-round of some kind - maybe assigning the offending variables to an
intermediate variable would get round the problem. In the mean time,
thanks.

* i.e. Spacemen
 
H

Henry Law

Something else: Could some encoding deviltry be going on? I believe it
is possible for strings to be eq, but have different byte representations.
If that is possible at all it may be worth looking into.

OK, it's official: my Perl compiler is enchanted. I'll not post the
whole program, since other people's environments can't reproduce the
problem anyway, but you'll see what I'm up against. Any ideas on where
to go from here would be most welcome.

----------- non-runnable fragment -----------
# Succeeds
my $local = eval '$hash_xml{localuser}';
sendit ( $local,
$hash_gen{adminuser},
'smtp.bt.net'
);

# Fails
$local = $hash_xml{localuser};
sendit ( $local,
$hash_gen{adminuser},
'smtp.bt.net'
);

sub sendit {
my ($localuser,$adminuser,$smtpserver) = @_;
print "sendit:$localuser, $adminuser, $smtpserver\n";
print "Local user in hex ",unpack("H*",$localuser),"\n";
print "Admin user in hex ",unpack("H*",$adminuser),"\n";
my $header = (... the mail sending code as before)
---------------- output ----------------
[nfb@neptune nfb]$ ./tryit.pl
sendit:[email protected], (e-mail address removed), smtp.bt.net
Local user in hex 6e6662406e657074756e652e6c617773686f7573652e6f7267
Admin user in hex 706f73746d6173746572406c617773686f7573652e6f7267
Mail sent to (e-mail address removed)
sendit:[email protected], (e-mail address removed), smtp.bt.net
Local user in hex 6e6662406e657074756e652e6c617773686f7573652e6f7267
Admin user in hex 706f73746d6173746572406c617773686f7573652e6f7267
Unrecognised line: (e-mail address removed) at blib/lib/Mail/Internet.pm
(autosplit into blib/lib/auto/Mail/Internet/smtpsend.al) line 616
-------------- ends ----------------
So the parameters being supplied to the "sendit" subroutine are
identical at the hexadecimal level, yet one version works and the other
doesn't.

BTW it's not that the first successful invocation spoils it for all
subsequent invocations: I have versions which send successfully three or
more times, only to fail when the variable comes from the XML hash.

At least I can see the workround now - use "eval" to fill a temporary
variable. Nasty but seemingly effective. Maybe I should reinstall Perl
on the Linux machine but life's too short right now.

Yours, Mystified of Manchester
 
A

Anno Siegel

Henry Law said:
OK, it's official: my Perl compiler is enchanted. I'll not post the
whole program, since other people's environments can't reproduce the
problem anyway, but you'll see what I'm up against. Any ideas on where
to go from here would be most welcome.

----------- non-runnable fragment -----------
# Succeeds
my $local = eval '$hash_xml{localuser}';
sendit ( $local,
$hash_gen{adminuser},
'smtp.bt.net'
);

# Fails
$local = $hash_xml{localuser};
sendit ( $local,
$hash_gen{adminuser},
'smtp.bt.net'
);

[...]

Strange indeed.

All I can think of is to apply random transformations to the string
(copy it, append '', make it a hash key and retrieve it, capture it
in a regex, ...) and see if anything has an effect.

One more thing. The error message is
Unrecognised line: (e-mail address removed) at blib/lib/Mail/Internet.pm
(autosplit into blib/lib/auto/Mail/Internet/smtpsend.al) line 616

An installed program shouldn't reside in blib/... but wherever the
Perl library resides and the path shouldn't be relative. This looks
like a pre-installation version is used for some reason.

Anno
 
H

Henry Law

Anno said:
Strange indeed.

I installed Mail::Internet on another Linux server I have and tried my
tryit.pl program there - worked perfectly. So the problem manifests
itself on only my development server, and I have adopted the work-round
described below. Sooner or later I'll re-install it (probably at FC4)
and that will cure the problem I'm sure.

Many thanks to the many and various people who helped me localise the
problem and tried to find a solution.
All I can think of is to apply random transformations to the string
(copy it, append '', make it a hash key and retrieve it, capture it
in a regex, ...) and see if anything has an effect.

On the offending server that's what I've done. I probably over-did it,
but I wrote a little subroutine which copied the characters of the
offending variable one by one into a new variable and returned it.
Whatever hex was on the old hash variable is thus destroyed and my
program works.
One more thing. The error message is



An installed program shouldn't reside in blib/... but wherever the
Perl library resides and the path shouldn't be relative. This looks
like a pre-installation version is used for some reason.

Hmm; that was the CPAN installer wot did that. Maybe the problem lies
there; the re-install will sort it out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top