hacker has asked for the wisdom of the Perl Monks concerning the following question:

I've been working on an email-only interface to a tool I use daily, which has quite a few configuration options, which seems to confuse non-Unix users when they are initially exposed to it. My reason for making the email-only interface for this tool was to hide the complexity of the setup and configuration, but still allow users to gain access to the content this application provides. So far, the script works.. but there's a snag.

Right now, the user fills out a "template" which contains some necessary values, and sends it to an address on my server. This address is aliased to my perl script, which parses the 'From:' line, 'Subject', and body. Basically it's an auto-responder, similar to majordomo and other scripts that can parse an incoming message and respond based on what they find within.

I've been working on it for about a day and a half, and have been helped with some suggestions by tye, Zaxo, theorbtwo, and atcroft. Many thanks to them for the ideas. Basically I've run into a snag or limitation of what Config::Simple can handle with whitespace when parsing the elements out of the template.

Here's what the user fills out and sends along in their initial email:

[template] url = http://www.foo.com/ bpp = 4 maxdepth = 2 title = Foo filename = foo compression = zlib
This is then mailed to my "user" (the perl script) and parsed so I can gain access to the keys by name, using the following:
use Date::Manip; # Date functions use Mail::Internet; # parse incoming headers use Config::Simple; # read thing=otherthing values # For randomizing filenames use Digest::MD5 qw(md5 md5_hex md5_base64); my $date = UnixDate("today","%b %e, %Y at %T"); my $md5file = md5_hex($date); my $workpath = "/tmp"; my $message = new Mail::Internet ([<>]); my $from = $message->get('From'); my $subject = $message->get('Subject'); my @body = @{$message->body()}; # Config::Simple requires a file, so we create # a temporary scratch file here, and write the # contents of @body to it for storage open(INFILE, ">$workpath/$md5file.msg") or die "$!"; print INFILE @body; close ('INFILE'); my $cfg = newConfig::Simple( filename => "$workpath/$md5file.msg"); my $template = $cfg->param(-block=>'template'); $url = $template->{url}; $bpp = $template->{bpp}; $maxdepth = $template->{maxdepth}; $compression = $template->{compression}; $filename = $template->{filename}; $title = $template->{title}; unlink "$workdir/$md5file.msg";
At this point, I now have use of the scalars which were originally values in the email sent, and I can send a reply back to the user, using MIME::Lite (thanks to ar0n for suggesting the use of it over MIME::Entity) to send the email.

With $url and $maxdepth, I then fetch the content from $url to the specified $maxdepth with my spider, and pack it into a binary file, which is then attached to the reply to the user, using the following:

my $msg = MIME::Lite->new( From =>'Email Reflector <pler@domain.org>', To =>'me@domain.org', Subject =>"Document built on $date", Type =>'TEXT', Data =>"Document requested on $date" ); $msg->attach(Type =>'application/prs.plucker', Path =>"$workpath/$md5file.pdb", Filename =>"$title.pdb" ); $msg->send;
At this point, I can parse the user commands, manipulate the data and objects based on those commands, and return a response to the user, attaching the result file to the reply I send. All seems well, except..

When the 'value' specified in the original user-supplied template "wraps" to the next line, Config::Simple gets confused, and throws all kinds of errors. Here's an example:

[template] url = http://www.foo.com/some/long/path/longer/than/message/width bpp = 4 maxdepth = 2 title = Foo filename = foo compression = zlib
This will also fail when the url given wraps into several lines, such as those from MapQuest and similar services that use very long URI elements.

I think what I need to do is to replace any instance of '=\s+\n' with '=\s+' before I pass the 'key=value' strings to Config::Simple to parse. atcroft also suggested that I just remove any linefeeds if the line in question did not begin with 'key'.

Here's my query:

Thanks for any help you can provide, fellow monks.

Moved to SoPW per user request - dvergin 2002-07-21

Replies are listed 'Best First'.
Re: Parsing 'key=value' from incoming message "template"
by theorbtwo (Prior) on Jul 22, 2002 at 19:12 UTC

    I think this will work. Needs a lot of cleanup, but I think you can see the algo I'm using. (In purticular, the corner case should be at the top of the loop instead of the bottom, and it should be refactored into a sub.)

    #!perl use warnings; use strict; use IO::File; my @data; { my $fh = new IO::File "<testwrap.txt" or die "Can't open: $!"; @data = <$fh>; } my $line=""; my @unwrappeddata; foreach (@data) { chomp $_; if (m/^[^\s=]+\s+=\s+/) { $line .= "\n"; push @unwrappeddata, $line; print $line; $line = $_; } else { $line .= $_; } } $line .= "\n"; push @unwrappeddata, $line; print $line;


    Confession: It does an Immortal Body good.