File Coverage

blib/lib/Docclient.pm
Criterion Covered Total %
statement 15 127 11.8
branch 0 24 0.0
condition 0 6 0.0
subroutine 5 16 31.2
pod 7 10 70.0
total 27 183 14.7


line stmt bran cond sub pod time code
1              
2             package Docclient;
3              
4 1     1   2153 use IO::Handle;
  1         10540  
  1         68  
5 1     1   1112 use RPC::PlClient;
  1         39156  
  1         38  
6 1     1   666 use Docclient::Config;
  1         4  
  1         32  
7              
8 1     1   6 use strict;
  1         2  
  1         39  
9 1     1   7 use vars qw( $errstr $DEBUG );
  1         2  
  1         1683  
10              
11             $Docclient::VERSION = '1.0';
12              
13             $DEBUG = 0;
14             sub debug ($) {
15 0 0   0 0   return unless $DEBUG;
16 0           my $txt = shift; $txt =~ s/([^\n])$/$1\n/; print STDERR $txt;
  0            
  0            
17             }
18              
19             sub new {
20 0     0 1   my $class = shift;
21 0           my %options = ( %Docclient::Config::Config, @_ );
22              
23 0           my %serveroptions;
24 0   0       $serveroptions{'peeraddr'} = ( $options{'host'} or $options{'server'});
25 0           $serveroptions{'peerport'} = $options{'port'};
26 0           $serveroptions{'version'} = 0.972; # required server version
27 0           $serveroptions{'logfile'} = undef;
28             ### $serveroptions{'debug'} = 10;
29              
30 0           my $self;
31              
32 0           eval {
33 0           debug "Connecting to server $serveroptions{'peeraddr'}:$serveroptions{'peerport'}";
34 0 0         my $client = eval { RPC::PlClient->new(
  0            
35             %serveroptions,
36             ### 'ServerClass' => 'Docserver::Srv',
37             'application' => 'Docserver::Srv',
38             ); }
39             or die "$@\n";
40              
41 0           debug 'Requesting Docserver';
42 0           my $obj = eval { $client->ClientObject('Docserver', 'new'); };
  0            
43 0 0         if ($@) {
44 0           my ($stderr) = $client->Call('errstr');
45 0           die $stderr;
46             }
47 0           debug 'Negotiating chunk size';
48 0           my $ChunkSize = $obj->preferred_chunk_size($options{'ChunkSize'});
49 0           $self = bless {
50             %options,
51             'obj' => $obj,
52             'ChunkSize' => $ChunkSize,
53             }, $class;
54             };
55 0 0         if ($@) {
56 0           $errstr = $@; return;
  0            
57             }
58 0           $self;
59             }
60              
61             sub put_file {
62 0     0 1   my ($self, $fh, $file, $size) = @_;
63 0           my $obj = $self->{'obj'};
64              
65 0 0         if (not defined $size) { $size = -1; }
  0            
66              
67 0           eval {
68 0           debug "Processing $file (size $size)";
69 0           $obj->input_file_length($size);
70              
71 0           my $buflen = $self->{'ChunkSize'};
72 0           debug "Setting chunk size to $buflen";
73 0           my $written = 0;
74 0   0       while ($size < 0 or $written < $size) {
75 0           my $buffer;
76 0           my $out = $fh->read($buffer, $buflen);
77 0 0         if ($out == 0) {
78 0           debug "Strange: read returned 0 after reading $written bytes\n";
79 0           last;
80             }
81 0           $written += $out;
82              
83 0           $obj->put($buffer);
84             }
85 0           debug "Written $written bytes";
86 0           return 1;
87             };
88              
89 0 0         if ($@) {
90 0           $self->{'errstr'} = "Error occured: $@";
91             }
92 0           return;
93             }
94              
95             sub put_scalar {
96 0     0 1   my ($self, $data) = @_;
97 0           my $obj = $self->{'obj'};
98 0           my $size = length $data;
99              
100 0           eval {
101 0           debug "Processing scalar data (size $size)";
102 0           $obj->input_file_length($size);
103              
104 0           my $buflen = $self->{'ChunkSize'};
105 0           debug "Setting chunk size to $buflen";
106 0           my $i = 0;
107 0           while ($i < $size) {
108 0           $obj->put(substr($data, $i, $buflen));
109 0           $i += $buflen;
110             }
111 0           return 1;
112             };
113              
114 0 0         if ($@) {
115 0           $self->{'errstr'} = "Error occured: $@";
116             }
117 0           return;
118             }
119              
120             sub convert {
121 0     0 1   my ($self, $in_format, $out_format) = @_;
122 0           my $obj = $self->{'obj'};
123 0           debug "Calling convert($in_format, $out_format)";
124             $obj->convert($in_format, $out_format)
125 0 0         or do { $self->{'errstr'} = $obj->errstr; return; };
  0            
  0            
126 0           return 1;
127             }
128              
129             sub get_to_file {
130 0     0 1   my ($self, $fh) = @_;
131 0           debug "Calling get_to_file($fh)";
132 0           my $obj = $self->{'obj'};
133 0           my $buflen = $self->{'ChunkSize'};
134              
135 0           my $result_length = $obj->result_length;
136 0           debug "Result length is $result_length\n";
137              
138 0           my $read = 0;
139 0           while ($read < $result_length) {
140 0           my $buffer = $obj->get($buflen);
141 0 0         if (length $buffer == 0) {
142 0           debug "Strange: read returned 0 after reading $read bytes\n";
143 0           last;
144             }
145 0           $read += length $buffer;
146 0           $fh->print($buffer);
147             }
148 0           return 1;
149             }
150              
151             sub get_to_scalar {
152 0     0 1   my ($self, $fh) = @_;
153 0           my $obj = $self->{'obj'};
154 0           my $buflen = $self->{'ChunkSize'};
155              
156 0           my $result_length = $obj->result_length;
157 0           debug "Result length is $result_length\n";
158              
159 0           my $result = '';
160 0           my $read = 0;
161 0           while ($read < $result_length) {
162 0           my $buffer = $obj->get($buflen);
163 0 0         if (length $buffer == 0) {
164 0           debug "Strange: read returned 0 after reading $read bytes\n";
165 0           last;
166             }
167 0           $read += length $buffer;
168 0           $result .= $buffer;
169             }
170 0           $result;
171             }
172              
173             sub finished {
174 0     0 1   shift->{'obj'}->finished;
175             }
176              
177             sub DESTROY {
178 0     0     shift->finished;
179             }
180              
181             sub errstr {
182 0     0 0   my $self = shift;
183 0 0         if (ref $self) { return $self->{'errstr'} }
  0            
184 0           return $Docclient::errstr;
185             }
186              
187             sub server_version {
188 0     0 0   shift->{'obj'}->server_version;
189             }
190              
191              
192             1;
193              
194             =head1 NAME
195              
196             Docclient.pm - client module for remote MS format conversions
197              
198             =head1 SYNOPSIS
199              
200             my $docclient = new Docclient(
201             'host' => 'machine.domain.cz',
202             'port' => 6745,
203             ) or die $Docclient::errstr;
204             my $filename = 'word.doc';
205             open FILE, $filename or die "Error reading $filename: $!\n";
206             binmode FILE;
207             $docclient->put_file(*FILE);
208             close FILE;
209             $docclient->convert('doc', 'txt') or die $docclient->errstr;
210             my $text = $docclient->get_to_scalar;
211             $docclient->finished;
212              
213             =head1 DESCRIPTION
214              
215             Docclient is a client part of a tool that makes it easy to send
216             a Word or Excel document to a Win* machine, open the module with
217             a native application and convert it using that proprietary software
218             to readable form, then deliver the converted document back to the
219             client machine. On the server machine, a Docserver application
220             (usually docserver.pl program) has to be running.
221              
222             From the comment line, you probably want to use the docclient.pl
223             script, but in case you want to write your own conversion tool or
224             want to use this inside of a bigger application, here's how:
225              
226             =head2 METHODS
227              
228             =over 4
229              
230             =item new
231              
232             First you create new Docclient object. You tell it what server machine
233             and port to use and it tries to connect to the server.
234             Parameters are passed as hash and are B for the server machine
235             name and B for TCP port the server is running on. The dafault is
236             stored in Docclient/Config.pm file, so you can have site-wide defaults
237             and only specify these parameters when you have to achieve something
238             special.
239              
240             If the new method fails (usually becaue it was not able to connect to
241             the server), it returns undef and the error message is stored in the
242             $Docclient::errstr string.
243              
244             After you've got your Docclient object, you can call methods on it.
245             You need to send your input document to the server, then run
246             a conversion or series of conversions and then retrieve the result
247             back from server.
248              
249             =item put_scalar
250              
251             If you've got the doc document in a perl scalar (because you've read
252             it from the CGI upload or so), you can call put_scalar with one
253             parameter being the document, and this method sends the document to
254             the server. If there is a error during the tramsmit, it can be
255             retrieved via $docclient->errstr method.
256              
257             =item put_file
258              
259             If you have the file on the disk (not read to perl scalar yet, just a
260             filehandle), you can use put_file with the filehandle as an argument.
261             It sends the data to the server just as put_scalar would.
262              
263             =item convert
264              
265             When you've got the input data on the server, you want to call convert
266             which will actually initiate the conversion on the server machine. The
267             convert method accepts two parameters, input_format and output_format.
268             You need to tell the convertor what format you think the file is in
269             and in what format you expect it back.
270              
271             Possible values for input_format are doc, xls or csv, for
272             output_format you can use txt, rft, doc6, doc95, html, ps and ps1
273             for Word documents and txt, csv, prn, xls5, xls95, html, ps and ps1
274             for Excel documents. Please note that availability of individual
275             formats depends on the versions of the MS software on the server. For
276             example, if you have old versions, they may not support the formats,
277             or if you don't have PostScript printer driver installed, you won't be
278             able to produce PostScript output.
279              
280             Upon error, B returns false and error message can be fetched
281             using $docclient->errstr method.
282              
283             =item get_to_scalar
284              
285             After the conversion was successfully finished, you retrieve the
286             result to a scalar by calling get_to_scalar method (without any
287             parameters).
288              
289             =item get_to_file
290              
291             You may prefer to directly send the result to output file, use
292             get_to_file with a filehandle parameter.
293              
294             =item finished
295              
296             After you've done with the file, call finished to clean after yourself
297             on the server side.
298              
299             After you've sent the file to the server (using put_file or put_scalar
300             methods), you can call convert (and subsequent get_to_* methods) with
301             various parameters many times to get different output formats for
302             single file. Method B deletes the temporary file on the
303             server.
304              
305             =back
306              
307             =head1 VERSION
308              
309             This documentation is believed to describe reasonably accurately
310             version 1.0 of Docclient.
311              
312             =head1 AUTHOR
313              
314             (c) 1998--2002 Jan Pazdziora, adelton@fi.muni.cz,
315             http://www.fi.muni.cz/~adelton/ at Faculty of Informatics, Masaryk
316             University in Brno, Czech Republic
317              
318             All rights reserved. This package is free software; you can
319             redistribute it and/or modify it under the same terms as Perl itself.
320              
321             =head1 SEE ALSO
322              
323             docclient(1), docserver(1), Docserver(3), Win32::OLE(3),
324             Win32::API(3)
325              
326             =cut
327