X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2FMisc.pm;h=895681fb0431c5c19480cd954e10ce45e3579652;hb=f8f4c51eaa6f5aa3d49672fe7a17f19fa22494c0;hp=936f94a6e30dee4ab7f63025d190da36d1123702;hpb=7153190ee1bfeb6d3ad9e6da270a41a949333a7e;p=freeside.git diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index 936f94a6e..895681fb0 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -7,15 +7,17 @@ use Carp; use Data::Dumper; use IPC::Run qw( run timeout ); # for _pslatex use IPC::Run3; # for do_print... should just use IPC::Run i guess +use File::Temp; #do NOT depend on any FS:: modules here, causes weird (sometimes unreproducable #until on client machine) dependancy loops. put them in FS::Misc::Something #instead @ISA = qw( Exporter ); @EXPORT_OK = qw( generate_email send_email send_fax - states_hash counties state_label + states_hash counties cities state_label card_types generate_ps generate_pdf do_print + csv_from_fixed ); $DEBUG = 0; @@ -44,6 +46,8 @@ but are collected here to elimiate code duplication. Options: +=over 4 + =item from Sender address, required @@ -212,9 +216,10 @@ encoding which, if specified, overrides the default "7bit". use vars qw( $conf ); use Date::Format; -use Mail::Header; -use Mail::Internet 2.00; use MIME::Entity; +use Email::Sender::Simple qw(sendmail); +use Email::Sender::Transport::SMTP; +use Email::Sender::Transport::SMTP::TLS; use FS::UID; FS::UID->install_callback( sub { @@ -230,7 +235,6 @@ sub send_email { # join("\n", map { " $_: ". $options{$_} } keys %options ). "\n" } - $ENV{MAILADDRESS} = $options{'from'}; my $to = ref($options{to}) ? join(', ', @{ $options{to} } ) : $options{to}; my @mimeargs = (); @@ -283,7 +287,7 @@ sub send_email { $domain = $1; } else { warn 'no domain found in invoice from address '. $options{'from'}. - '; constructing Message-ID @example.com'; + '; constructing Message-ID (and saying HELO) @example.com'; $domain = 'example.com'; } my $message_id = join('.', rand()*(2**32), $$, time). "\@$domain"; @@ -329,101 +333,37 @@ sub send_email { } - my $smtpmachine = $conf->config('smtpmachine'); - $!=0; - - $message->mysmtpsend( 'Host' => $smtpmachine, - 'MailFrom' => $options{'from'}, - ); - -} - -#this kludges a "mysmtpsend" method into Mail::Internet for send_email above -#now updated for MailTools v2! -package Mail::Internet; - -use Mail::Address; -use Net::SMTP; -use Net::Domain; - -sub Mail::Internet::mysmtpsend($@) { - my ($self, %opt) = @_; - - my $host = $opt{Host}; - my $envelope = $opt{MailFrom}; # || mailaddress(); - my $quit = 1; - - my ($smtp, @hello); - - push @hello, Hello => $opt{Hello} - if defined $opt{Hello}; - - push @hello, Port => $opt{Port} - if exists $opt{Port}; - - push @hello, Debug => $opt{Debug} - if exists $opt{Debug}; - -# if(!defined $host) -# { local $SIG{__DIE__}; -# my @hosts = qw(mailhost localhost); -# unshift @hosts, split /\:/, $ENV{SMTPHOSTS} -# if defined $ENV{SMTPHOSTS}; -# -# foreach $host (@hosts) -# { $smtp = eval { Net::SMTP->new($host, @hello) }; -# last if defined $smtp; -# } -# } -# elsif(ref($host) && UNIVERSAL::isa($host,'Net::SMTP')) - if(ref($host) && UNIVERSAL::isa($host,'Net::SMTP')) - { $smtp = $host; - $quit = 0; - } - else - { #local $SIG{__DIE__}; - #$smtp = eval { Net::SMTP->new($host, @hello) }; - $smtp = Net::SMTP->new($host, @hello); - } - - unless ( defined($smtp) ) { - my $err = $!; - $err =~ s/Invalid argument/Unknown host/; - return "can't connect to $host: $err" - } - - my $head = $self->cleaned_header_dup; - - $head->delete('Bcc'); + #send the email - # Who is it to + my %smtp_opt = ( 'host' => $conf->config('smtpmachine'), + 'helo' => $domain, + ); - my @rcpt = map { ref $_ ? @$_ : $_ } grep { defined } @opt{'To','Cc','Bcc'}; - @rcpt = map { $head->get($_) } qw(To Cc Bcc) - unless @rcpt; + my($port, $enc) = split('-', ($conf->config('smtp-encryption') || '25') ); + $smtp_opt{'port'} = $port; - my @addr = map {$_->address} Mail::Address->parse(@rcpt); - #@addr or return (); - return 'No valid destination addresses found!' - unless(@addr); - - # Send it - - my $ok = $smtp->mail($envelope) - && $smtp->to(@addr) - && $smtp->data(join("", @{$head->header}, "\n", @{$self->body})); - - #$quit && $smtp->quit; - #$ok ? @addr : (); - if ( $ok ) { - $quit && $smtp->quit; - return ''; - } else { - return $smtp->code. ' '. $smtp->message; + my $transport; + if ( defined($enc) && $enc eq 'starttls' ) { + $smtp_opt{$_} = $conf->config("smtp-$_") for qw(username password); + $transport = Email::Sender::Transport::SMTP::TLS->new( %smtp_opt ); + } else { + if ( $conf->exists('smtp-username') && $conf->exists('smtp-password') ) { + $smtp_opt{"sasl_$_"} = $conf->config("smtp-$_") for qw(username password); } + $smtp_opt{'ssl'} = 1 if defined($enc) && $enc eq 'tls'; + $transport = Email::Sender::Transport::SMTP->new( %smtp_opt ); + } + + local $@; # just in case + eval { sendmail($message, { transport => $transport }) }; + + if(ref($@) and $@->isa('Email::Sender::Failure')) { + return ($@->code ? $@->code.' ' : '').$@->message + } + else { + return $@; + } } -package FS::Misc; -#eokludge =item send_fax OPTION => VALUE ... @@ -552,6 +492,7 @@ Returns a list of counties for this state and country. sub counties { my( $state, $country ) = @_; + map { $_ } #return num_counties($state, $country) unless wantarray; sort map { s/[\n\r]//g; $_; } map { $_->county } qsearch({ @@ -563,6 +504,28 @@ sub counties { }); } +=item cities COUNTY STATE COUNTRY + +Returns a list of cities for this county, state and country. + +=cut + +sub cities { + my( $county, $state, $country ) = @_; + + map { $_ } #return num_cities($county, $state, $country) unless wantarray; + sort map { s/[\n\r]//g; $_; } + map { $_->city } + qsearch({ + 'select' => 'DISTINCT city', + 'table' => 'cust_main_county', + 'hashref' => { 'county' => $county, + 'state' => $state, + 'country' => $country, + }, + }); +} + =item state_label STATE COUNTRY_OR_LOCALE_SUBCOUNRY_OBJECT =cut @@ -745,8 +708,7 @@ sub _pslatex { for ( 1, 2 ) { local($SIG{CHLD}) = sub {}; - #run( \@cmd, '>'=>'/dev/null', '2>'=>'/dev/null', timeout($timeout) ) - run( \@cmd, timeout($timeout) ) + run( \@cmd, '>'=>'/dev/null', '2>'=>'/dev/null', timeout($timeout) ) or die "pslatex $file.tex failed; see $file.log for details?\n"; } @@ -773,6 +735,65 @@ sub do_print { } +=item csv_from_fixed, FILEREF COUNTREF, [ LENGTH_LISTREF, [ CALLBACKS_LISTREF ] ] + +Converts the filehandle referenced by FILEREF from fixed length record +lines to a CSV file according to the lengths specified in LENGTH_LISTREF. +The CALLBACKS_LISTREF refers to a correpsonding list of coderefs. Each +should return the value to be substituted in place of its single argument. + +Returns false on success or an error if one occurs. + +=cut + +sub csv_from_fixed { + my( $fhref, $countref, $lengths, $callbacks) = @_; + + eval { require Text::CSV_XS; }; + return $@ if $@; + + my $ofh = $$fhref; + my $unpacker = new Text::CSV_XS; + my $total = 0; + my $template = join('', map {$total += $_; "A$_"} @$lengths) if $lengths; + + my $dir = "%%%FREESIDE_CACHE%%%/cache.$FS::UID::datasrc"; + my $fh = new File::Temp( TEMPLATE => "FILE.csv.XXXXXXXX", + DIR => $dir, + UNLINK => 0, + ) or return "can't open temp file: $!\n" + if $template; + + while ( defined(my $line=<$ofh>) ) { + $$countref++; + if ( $template ) { + my $column = 0; + + chomp $line; + return "unexpected input at line $$countref: $line". + " -- expected $total but received ". length($line) + unless length($line) == $total; + + $unpacker->combine( map { my $i = $column++; + defined( $callbacks->[$i] ) + ? &{ $callbacks->[$i] }( $_ ) + : $_ + } unpack( $template, $line ) + ) + or return "invalid data for CSV: ". $unpacker->error_input; + + print $fh $unpacker->string(), "\n" + or return "can't write temp file: $!\n"; + } + } + + if ( $template ) { close $$fhref; $$fhref = $fh } + + seek $$fhref, 0, 0; + ''; +} + + =back =head1 BUGS