File Coverage

blib/lib/HyperWave/CSP.pm
Criterion Covered Total %
statement 53 576 9.2
branch 8 256 3.1
condition 6 28 21.4
subroutine 10 47 21.2
pod 24 26 92.3
total 101 933 10.8


line stmt bran cond sub pod time code
1             package HyperWave::CSP;
2             #
3             # Perl interface to the HyperWave server
4             #
5             # Copyright (c) 1998 Bek Oberin. All rights reserved.
6             #
7             # This program is free software; you can redistribute it and/or modify
8             # it under the same terms as Perl itself.
9             #
10             #
11             # Last updated by gossamer on Fri Mar 20 21:24:44 EST 1998
12             #
13              
14 1     1   721 use strict;
  1         2  
  1         31  
15 1     1   5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  1         1  
  1         201  
16              
17             require Exporter;
18              
19 1     1   511 use HyperWave::CSP::Message;
  1         2  
  1         24  
20              
21 1     1   914 use Socket;
  1         4098  
  1         540  
22 1     1   1041 use Symbol;
  1         904  
  1         69  
23 1     1   6 use Fcntl;
  1         2  
  1         271  
24 1     1   5 use Carp;
  1         2  
  1         51  
25 1     1   738 use Locale::Language;
  1         328145  
  1         7090  
26              
27             require 'dumpvar.pl';
28              
29             @ISA = qw(Exporter);
30             @EXPORT = qw( Default_CSP_PORT );
31             @EXPORT_OK = qw();
32             $VERSION = "0.03.1";
33              
34             #
35             # Debug Levels:
36             # 0. Nothing
37             # 1. See full explanations of any errors
38             # 2. See entering of functions
39             # 3. See what's sent and received and a bunch more info
40             #
41             my $DEBUG = 0;
42              
43             =head1 NAME
44              
45             HyperWave::CSP - Communicate with a HyperWave server
46              
47             =head1 SYNOPSIS
48              
49             use HyperWave::CSP;
50            
51             $server = HyperWave::CSP->New("my.hyperwave.server");
52             $server->quit;
53              
54             =head1 DESCRIPTION
55              
56             C is a class implementing a simple HyperWave client in
57             Perl.
58              
59             =cut
60              
61             ###################################################################
62             # Some constants #
63             ###################################################################
64              
65             my $Default_CSP_Port = 418;
66              
67             my $Client_Info = "Perl Module HyperWave::CSP v$VERSION";
68              
69             # Which version of the HyperWave protocol we recognize.
70             my $Protocol_Version = "717L";
71              
72             # Hyperwave message numbers
73             my %MESSAGE = (
74             GETDOCBYANCHOR => 2,
75             GETCHILDCOLL => 3,
76             GETPARENT => 4,
77             GETCHILDDOCCOLL => 5,
78             GETOBJECT => 7,
79             GETANCHORS => 8,
80             GETOBJBYQUERY => 9,
81             GETOBJBYQUERYCOLL => 10,
82             OBJECTBYIDQUERY => 11,
83             GETTEXT => 12,
84             INSDOC => 14,
85             INSCOLL => 17,
86             GETSRCSBYDEST => 19,
87             MVCPDOCSCOLL => 22,
88             MVCPCOLLSCOLL => 23,
89             IDENTIFY => 24,
90             READY => 25,
91             COMMAND => 26,
92             CHANGEOBJECT => 27,
93             EDITTEXT => 28,
94             GETANDLOCK => 29,
95             UNLOCK => 30,
96             INCOLLECTIONS => 31,
97             INSERTOBJECT => 32,
98             INCOLLSCLUSTER => 33,
99             GETOBJBYFTQUERY => 34,
100             GETOBJBYFTQUERYCOLL => 35,
101             PIPEDOCUMENT => 36,
102             DELETEOBJECT => 37,
103             PUTDOCUMENT => 38,
104             GETREMOTE => 39,
105             GETREMOTECHILDREN => 40,
106             PIPEREMOTE => 41,
107             HG_BREAK => 42,
108             HG_MAPID => 43,
109             CHILDREN => 44,
110             GETCGI => 45,
111             PIPECGI => 46,
112             );
113              
114             my @SERVER_ERRORS = (
115             "Access denied",
116             "No documents?",
117             "No collection name",
118             "Object is not a document",
119             "No object received",
120             "No collections received",
121             "Connection to low-level database failed",
122             "Object not found",
123             "Collection already exists",
124             "Father collection disappeared",
125             "Father collection not a collection",
126             "Collection not empty",
127             "Destination not a collection",
128             "Source equals destination",
129             "Request pending",
130             "Timeout",
131             "Name not unique",
132             "Database now read-only; try again later",
133             "Object locked; try again later",
134             "Change of base-attribute",
135             "Attribute not removed",
136             "Attribute exists",
137             "Syntax error in command",
138             "No or unknown language specified",
139             "Wrong type in object",
140             "Client version too old",
141             "No connection to other server",
142             "Synchronization error",
143             "No path entry",
144             "Wrong path entry",
145             "Wrong password (server-to-server server authentication)",
146             "No more users for license",
147             "No more documents for this session and license",
148             "Remote server not responding",
149             "Query overflow",
150             "Break by user",
151             "Not implemented",
152             "No connection to fulltext server",
153             "Connection timed out",
154             "Something wrong with fulltext index",
155             "Query syntax error",
156             "No error",
157             "Request pending",
158             "No connection to document server",
159             "Wrong protocol version",
160             "Not initialized",
161             "Bad request",
162             "Bad document number",
163             "Cannot write to local store",
164             "Cannort read from local store",
165             "Store read error",
166             "Write error",
167             "Close error",
168             "Bad path",
169             "No path",
170             "Cannot open file",
171             "Cannot read from file",
172             "Cannot write to file",
173             "Could not connect to client",
174             "Could not accept connect to client",
175             "Could not read from socket",
176             "Could not write to socket",
177             "-- (unused) --",
178             "Received too much data",
179             "Received too few data",
180             "-- (unused) --",
181             "Not implemented",
182             "User break",
183             "Internal error",
184             "Invalid object",
185             "Job timed out",
186             "Cannot open port",
187             "Received no data",
188             "No port to handle this request",
189             "Document not cached",
190             "Bad cache type",
191             "Cannot write to cache",
192             "Cannot read from cache",
193             "Do not know what to read",
194             "Could not insert into cache",
195             "Could not connect to remote server",
196             "Lock refused"
197             );
198              
199              
200             ###################################################################
201             # Functions under here are member functions #
202             ###################################################################
203              
204             =head1 CONSTRUCTOR
205              
206             =item new ( [ HOST [, PORT [, USERNAME [, PASSWORD [, ENCRYPT [, LANGUAGE ] ] ] ] ] ] )
207              
208             This is the constructor for a new HyperWave object. C is the
209             name of the remote host to which a HyperWave connection is required.
210             If not given the environment variables C and then C
211             are checked, and if a host is not found then C is used.
212              
213             C is the HyperWave port to connect to, it defaults to the
214             environment variable C, then C and then to the
215             standard port 418 if nothing else is found.
216              
217             C and C are the HyperWave username and password,
218             they default to anonymous. C will eventually allow you to
219             pass the password in in encrypted form rather than plaintext, but is
220             not yet implemented.
221              
222             C also is not yet used, and defaults to the value of the
223             environment variable C and then to English.
224              
225             The constructor returns the open socket, or C if an error has
226             been encountered.
227              
228             =cut
229              
230             sub new {
231 1     1 1 52 my $proto = shift;
232 1         3 my $host = shift;
233 1         2 my $port = shift;
234 1   50     8 my $username = shift || "guest";
235 1   50     7 my $password = shift || "none";
236 1   50     7 my $encrypt = shift || 0;
237 1         3 my $language = shift;
238              
239 1   33     6 my $class = ref($proto) || $proto;
240 1         3 my $self = {};
241              
242 1 50       4 warn "new\n" if $DEBUG > 1;
243              
244 1   0     8 $self->{"host"} = $host || $ENV{HWHOST} || $ENV{HGHOST} || 'localhost';
245 1   33     21 $self->{"port"} = $port || $ENV{HWPORT} || $ENV{HGPORT} || $Default_CSP_Port;
246 1   50     19 $self->{"language"} =
247             &language2code($language || $ENV{HWLANGUAGE} || 'English');
248 1 50       148 if (!defined($self->{"language"})) {
249 0 0       0 warn "new: Unknown language name\n" if $DEBUG;
250 0         0 $self->{"error"} = "0.02";
251 0         0 return undef;
252             }
253              
254 1         6 $self->{"error"} = "0.02";
255 1         3 $self->{"server_error"} = 0;
256              
257             #
258             # Resolve things and open the connection
259             #
260 1 0       7 if (!($self->{"socket"} = &_open_hw_connection($self->{"host"}, $self->{"port"}))) {
261 0 0       0 warn "new: _open_hw_connection returned 0\n" if $DEBUG;
262 0         0 $self->{"error"} = "0.02";
263 0         0 return undef;
264             }
265              
266             #
267             # Initialize connection
268             #
269 0         0 my $message;
270 0 0       0 if (!($message = &_initialize_hw_connection($self->{"socket"}))) {
271 0 0       0 warn "new: _initialize_hw_connection returned 0\n" if $DEBUG;
272 0         0 $self->{"error"} = "0.02";
273 0         0 close($self->{"socket"});
274 0         0 return undef;
275             }
276              
277 0         0 $self->{"Protocol_Version"} = $message->msgid;
278 0 0       0 if ($message->msgid < $Protocol_Version) {
279 0 0       0 warn "new: server version '" . $message->msgid .
280             "' less than client version '$Protocol_Version'." if $DEBUG;
281             }
282              
283             #
284             # Identify ourselves
285             #
286             $message =
287 0         0 HyperWave::CSP::Message->new($MESSAGE{"IDENTIFY"}, &_hw_int($encrypt) .
288             &_hw_string($username) .
289             &_hw_string($password) .
290             &_hw_string($Client_Info));
291              
292 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
293 0         0 $self->{"error"} = "0.02";
294 0         0 warn "new: _send_hw_msg returned 0\n";
295 0         0 return undef;
296             }
297              
298 0         0 $message = &_receive_hw_msg($self->{"socket"});
299 0 0       0 if (!$message) {
300 0         0 $self->{"error"} = "0.02";
301 0         0 warn "new: _receive_hw_msg returned 0\n";
302 0         0 return undef;
303             }
304 0         0 my ($userid, $user) = $message->data =~ m/^(\S+) (\S+)\0$/;
305 0         0 $self->{"userid"} = $userid;
306 0         0 $self->{"username"} = $user;
307              
308 0 0       0 warn "new: username '$user' id '$userid' returned by server\n" if $DEBUG > 2;
309              
310 0         0 bless($self, $class);
311 0         0 return $self;
312             }
313              
314              
315             #
316             # destructor
317             #
318             sub DESTROY {
319 0     0   0 my $self = shift;
320              
321 0         0 shutdown($self->{"socket"}, 2);
322 0         0 close($self->{"socket"});
323              
324 0         0 return 1;
325             }
326              
327              
328             =head1 METHODS
329              
330             Unless otherwise stated all methods return either a I or
331             I value, with I meaning that the operation was a success.
332             When a method states that it returns a value, failure will be returned
333             as I or an empty list.
334              
335             =cut
336              
337             sub command {
338 0     0 0 0 my $self = shift;
339 0         0 my $command = shift;
340 0         0 my $response_required = shift;
341 0         0 my $extra_data = shift;
342              
343 0         0 my $data;
344 0         0 my $respond = 1;
345              
346 0 0       0 warn "command\n" if $DEBUG > 1;
347              
348 0 0       0 if (!$command) {
349 0         0 warn "command: no command specified";
350 0         0 return 0;
351             } else {
352 0         0 $data = &_hw_int($respond) . &_hw_string($command);
353             }
354              
355 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"COMMAND"}, $data);
356              
357 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
358 0         0 $self->{"error"} = "0.02";
359 0         0 warn "command: _send_hw_msg returned 0\n";
360 0         0 return 0;
361             }
362              
363 0 0       0 if ($response_required) {
364 0         0 $message = &_receive_hw_msg($self->{"socket"});
365 0 0       0 if (!$message) {
366 0         0 $self->{"error"} = "0.02";
367 0         0 warn "command: _receive_hw_msg returned 0\n";
368 0         0 return 0;
369             }
370 0         0 return $message->{"data"};
371              
372             } else {
373 0         0 return 1;
374             }
375             }
376              
377             =pod
378              
379             =item command_stat ( )
380              
381             Returns string containing various statistics for the server.
382              
383             =item command_ftstat ( )
384              
385             Returns string containing various statistics for the server.
386              
387             =item command_dcstat ( )
388              
389             Returns string containing various statistics for the server.
390              
391             =item command_who ( )
392              
393             Returns string containing current users for the server.
394              
395             =cut
396              
397             sub command_stat {
398 0     0 1 0 my $self = shift;
399 0         0 return $self->command("stat", 1);
400             }
401              
402             sub command_ftstat {
403 0     0 1 0 my $self = shift;
404 0         0 return $self->command("ftstat", 1);
405             }
406              
407             sub command_dcstat {
408 0     0 1 0 my $self = shift;
409 0         0 return $self->command("dcstat", 1);
410             }
411              
412             sub command_who {
413 0     0 1 0 my $self = shift;
414 0         0 return $self->command("who", 1);
415             }
416              
417             =pod
418              
419             =item get_objnum_by_name ( NAME )
420              
421             Returns object number for the document with NAME as an attribute,
422             or false on error.
423              
424             =cut
425              
426             sub get_objnum_by_name {
427 0     0 1 0 my $self = shift;
428 0         0 my $object_name = shift;
429              
430 0         0 my $count;
431             my $objids;
432              
433 0 0       0 warn "get_objnum_by_name\n" if $DEBUG > 1;
434              
435 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETOBJBYQUERY"},
436             &_hw_string("Name=$object_name"));
437              
438 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
439 0         0 warn "get_objnum_by_name: _send_hw_msg returned 0\n";
440 0         0 $self->{"error"} = "0.02";
441 0         0 return 0;
442             }
443              
444 0         0 $message = &_receive_hw_msg($self->{"socket"});
445 0 0       0 if (!$message) {
446 0         0 warn "get_objnum_by_name: _receive_hw_msg returned 0\n";
447 0         0 $self->{"error"} = "0.02";
448 0         0 return 0;
449             }
450              
451 0         0 ($self->{"server_error"}, $count, my $tmp, $objids) =
452             $message->data =~ /^(\d+) (\d+)( (.*))?$/;
453 0 0       0 if ($self->{"server_error"}) {
454 0         0 $self->{"error"} = "0.02";
455 0         0 return 0;
456             }
457              
458 0 0       0 if ($count = 0) {
    0          
459 0         0 warn "get_objnum_by_name: no objects found.\n";
460 0         0 $self->{"error"} = "0.02";
461 0         0 return 0;
462             } elsif ($count > 1) {
463 0         0 warn "get_objnum_by_name: more than one object found where 1 expected.\n";
464 0         0 $self->{"error"} = "0.02";
465 0         0 return 0;
466             }
467 0         0 return $objids;
468              
469             }
470              
471              
472             =pod
473              
474             =item get_url ( OBJNUM )
475              
476             Returns a guess at a URL that might work for the document OBJNUM to be
477             retreived via the HyperWave HTTP interface. Note that it is ONLY
478             a guess. For one thing, it depends on the HyperWave server running
479             a web interface on the default HTTP port.
480              
481             =cut
482             sub get_url {
483 0     0 1 0 my $self = shift;
484 0         0 my $objnum = shift;
485              
486 0 0       0 warn "get_url\n" if $DEBUG > 1;
487              
488 0         0 my $objrecord;
489              
490 0 0       0 if (!($objrecord = $self->get_attributes($objnum))) {
491 0         0 $self->{"error"} = "0.02";
492 0         0 warn "get_url: get_attributes returned 0";
493 0         0 return 0;
494             }
495 0         0 my %attributes;
496 0         0 $attributes{$1}=$2 while $objrecord =~ m/(.+)=(.+)\n?/g;
497              
498 0         0 return "http://" . $self->{"host"} . "/" . $attributes{'Name'};
499              
500             }
501              
502              
503             =pod
504              
505             =item get_attributes ( OBJNUM )
506              
507             Returns a string containing the attributes for OBJNUM. The string
508             is in form C.
509              
510             =cut
511             sub get_attributes {
512 0     0 1 0 my $self = shift;
513 0         0 my $objnum = shift;
514              
515 0         0 my $objrecord;
516              
517 0 0       0 warn "get_attributes\n" if $DEBUG > 1;
518              
519 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETOBJECT"},
520             &_hw_int($objnum));
521              
522 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
523 0         0 warn "get_attributes: _send_hw_msg returned 0\n";
524 0         0 $self->{"error"} = "0.02";
525 0         0 return 0;
526             }
527              
528 0         0 $message = &_receive_hw_msg($self->{"socket"});
529 0 0       0 if (!$message) {
530 0         0 warn "get_attributes: _receive_hw_msg returned 0\n";
531 0         0 $self->{"error"} = "0.02";
532 0         0 return 0;
533             }
534              
535 0         0 ($self->{"server_error"}, $objrecord) = $message->data =~ /^(\d+) (.*)\0$/s;
536 0 0       0 if ($self->{"server_error"} != 0) {
537 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
538 0         0 $self->{"error"} = "0.02";
539 0         0 return 0;
540             }
541              
542 0         0 return $objrecord;
543              
544             }
545              
546             =pod
547              
548             =item get_attributes_hash ( OBJNUM )
549              
550             Like get_attributes() except that the attributes are returned as a
551             hash.
552              
553             =cut
554             sub get_attributes_hash {
555 0     0 1 0 my $self = shift;
556 0         0 my $objnum = shift;
557              
558 0 0       0 warn "get_attributes_hash\n" if $DEBUG > 1;
559              
560 0         0 my $attributes = $self->get_attributes($objnum);
561 0 0       0 if (!$attributes) {
562 0         0 warn "get_attributes_hash: get_attributes returned 0\n";
563 0         0 $self->{"error"} = "0.02";
564 0         0 return 0;
565             }
566              
567 0         0 my %attributes;
568              
569 0         0 $attributes{$1}=$2 while $attributes =~ m/(.+?)=(.+)\n?/g;
570              
571 0         0 return %attributes;
572             }
573              
574              
575             =pod
576              
577             =item get_text ( OBJNUM )
578              
579             Returns body text for the objnum passed. This usually means HTML
580             sans anchors in practical terms.
581              
582             =cut
583             sub get_text {
584 0     0 1 0 my $self = shift;
585 0         0 my $objnum = shift;
586              
587 0         0 my $text;
588              
589 0 0       0 warn "get_text\n" if $DEBUG > 1;
590              
591 0         0 my $objrecord = $self->get_attributes($objnum);
592              
593 0 0       0 warn "objrecord: '$objrecord'\n" if $DEBUG > 2;
594              
595 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETTEXT"},
596             &_hw_string($objrecord));
597              
598 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
599 0         0 $self->{"error"} = "0.02";
600 0         0 warn "get_text: _send_hw_msg returned 0\n";
601 0         0 return 0;
602             }
603              
604 0         0 $message = &_receive_hw_msg($self->{"socket"});
605 0 0       0 if (!$message) {
606 0         0 $self->{"error"} = "0.02";
607 0         0 warn "get_text: _receive_hw_msg returned 0\n";
608 0         0 return 0;
609             }
610              
611 0         0 ($self->{"server_error"}, $text) = $message->data =~ /^(\d+) (.*)\0$/s;
612 0 0       0 if ($self->{"server_error"} != 0) {
613 0         0 $self->{"error"} = "0.02";
614 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
615 0         0 return 0;
616             }
617              
618 0         0 return $text;
619             }
620              
621             =pod
622              
623             =item get_html ( OBJNUM )
624              
625             Returns HTML text, including anchors, for the objnum passed.
626              
627             =cut
628             sub get_html {
629 0     0 1 0 my $self = shift;
630 0         0 my $objnum = shift;
631              
632 0         0 my %anchors;
633              
634 0 0       0 warn "get_html\n" if $DEBUG > 1;
635              
636 0         0 my %doc_attributes = $self->get_attributes_hash($objnum);
637              
638             # TODO this next isn't proper language handling!
639 0         0 my $title = $doc_attributes{'Title'} =~ s/^en://;
640              
641 0         0 my $html = $self->get_text($objnum);
642              
643             # sort anchors
644 0         0 my $anchors = $self->get_anchors($objnum);
645 0 0       0 if (!$anchors) {
646 0         0 warn "get_html: get_anchors returned 0\n";
647 0         0 return 0;
648             }
649              
650 0         0 foreach my $anchor (split(/\s+/,$anchors)) {
651 0         0 my %attributes = $self->get_attributes_hash($anchor);
652 0         0 my $position = $attributes{'Position'};
653 0         0 $anchors{$position} = \%attributes;
654             }
655              
656             # Add in anchors
657 0         0 foreach my $position (reverse sort keys %anchors) {
658 0         0 my %attributes = %{$anchors{$position}};
  0         0  
659 0         0 my ($startpos, $endpos) = $attributes{'Position'} =~ m/(\S*) (\S*)/;
660              
661 0 0       0 warn "finding anchors from " .
662             dumpvar::stringify(%attributes) . "\n" if $DEBUG > 2;
663              
664 0 0       0 if ($attributes{'LinkType'} eq 'intag') {
    0          
    0          
    0          
665             # internal links
666 0         0 my $tagattr = $attributes{'TagAttr'};
667 0         0 my $dest = $self->get_url(hex($attributes{'Dest'}));
668              
669 0 0       0 warn "get_html: we think it's a picture at '$dest'\n" if $DEBUG > 2;
670              
671 0         0 substr($html, hex($endpos), 0) = "0.02\"$dest\"";
672             } elsif ($attributes{'Hint'}) {
673             # external link
674 0         0 my $url;
675 0         0 ($url) = $attributes{'Hint'} =~ m/URL:(.*)/;
676              
677 0 0       0 warn "get_html: we think it's an external URL to '$url'\n" if $DEBUG > 2;
678              
679 0         0 substr($html, hex($endpos), 0) = "0.02";
680 0         0 substr($html, hex($startpos), 0) = "0.02\"$url\">";
681             } elsif ($attributes{'Dest'}) {
682             # internal links
683 0         0 my $url = $self->get_url(hex($attributes{'Dest'}));
684              
685 0 0       0 warn "get_html: we think it's an internal link to '$url'\n" if $DEBUG > 2;
686            
687 0         0 substr($html, hex($endpos), 0) = "0.02";
688 0         0 substr($html, hex($startpos), 0) = "0.02\"$url\">";
689             } elsif ($attributes{'Dest'} eq 'Anchor') {
690             # external link
691 0         0 my $url = $self->get_url(hex($attributes{'Dest'}));
692              
693 0 0       0 warn "get_html: we think it's an external anchor to '$url'\n" if $DEBUG > 2;
694              
695 0         0 substr($html, hex($endpos), 0) = "0.02";
696 0         0 substr($html, hex($startpos), 0) = "0.02\"$url\">";
697             } else {
698             # Umm??
699 0         0 $self->{"error"} = "0.02";
700 0 0       0 warn "get_html: unknown link:\n" if $DEBUG;
701              
702 0         0 substr($html, hex($endpos), 0) = "0.02";
703 0         0 substr($html, hex($startpos), 0) = "0.02\"???\">";
704             }
705              
706             }
707              
708             # TODO: Headers? tag stuff?
709 0         0 $html =~ s@^@\n\n$title\n\n\n@;
710              
711 0         0 return $html;
712             }
713              
714             =pod
715              
716             =item exec_cgi ( OBJNUM )
717              
718             Returns output of the CGI, for the objnum passed. Depends on the
719             CGI script not requiring input.
720              
721             =cut
722             sub exec_cgi {
723 0     0 1 0 my $self = shift;
724 0         0 my $objnum = shift;
725              
726 0         0 my $text;
727              
728 0         0 my $objrecord = $self->get_attributes($objnum);
729              
730 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETCGI"},
731             $objrecord);
732              
733 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
734 0         0 warn "exec_cgi: _send_hw_msg returned 0\n";
735 0         0 $self->{"error"} = "0.02";
736 0         0 return 0;
737             }
738              
739 0         0 $message = &_receive_hw_msg($self->{"socket"});
740 0 0       0 if (!$message) {
741 0         0 $self->{"error"} = "0.02";
742 0         0 warn "exec_cgi: _receive_hw_msg returned 0\n";
743 0         0 return 0;
744             }
745              
746 0         0 ($self->{"server_error"}, $text) = $message->data =~ /^(\d+) (.*)\0$/s;
747 0 0       0 if ($self->{"server_error"} != 0) {
748 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
749 0         0 $self->{"error"} = "0.02";
750 0         0 return 0;
751             }
752              
753 0         0 return $text;
754             }
755              
756             =pod
757              
758             =item insert_attribute ( OBJNUM, NAME, VALUE )
759              
760             Adds an attribute to the given objnum. Note that HyperWave allows
761             multiple attributes of the same name, so if you add an attribute that
762             already exists you'll end up with two. Use change_attribute if you
763             want to overwrite the old one.
764              
765             =cut
766             sub insert_attribute {
767 0     0 1 0 my $self = shift;
768 0         0 my $objnum = shift;
769 0         0 my $atrname = shift;
770 0         0 my $atrvalue = shift;
771              
772 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"CHANGEOBJECT"},
773             "add $atrname=$atrvalue");
774              
775 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
776 0         0 warn "insert_attribute: _send_hw_msg returned 0\n";
777 0         0 $self->{"error"} = "0.02";
778 0         0 return 0;
779             }
780              
781 0         0 $message = &_receive_hw_msg($self->{"socket"});
782 0 0       0 if (!$message) {
783 0         0 warn "insert_attribute: _receive_hw_msg returned 0\n";
784 0         0 $self->{"error"} = "0.02";
785 0         0 return 0;
786             }
787              
788 0         0 ($self->{"server_error"}) = $message->data =~ /^(\d+)$/s;
789 0 0       0 if ($self->{"server_error"} != 0) {
790 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
791 0         0 $self->{"error"} = "0.02";
792 0         0 return 0;
793             }
794              
795 0         0 return 1;
796             }
797              
798              
799             =pod
800              
801             =item remove_attribute ( OBJNUM, NAME, VALUE )
802              
803             Removes an attribute to the given objnum. Note that you DO need to
804             know the old value because HyperWave allows multiple attributes with
805             the same value.
806              
807             =cut
808             sub remove_attribute {
809 0     0 1 0 my $self = shift;
810 0         0 my $objnum = shift;
811 0         0 my $atrname = shift;
812 0         0 my $atrvalue = shift;
813              
814 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"CHANGEOBJECT"},
815             "rem $atrname=$atrvalue");
816              
817 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
818 0         0 warn "remove_attribute: _send_hw_msg returned 0\n";
819 0         0 $self->{"error"} = "0.02";
820 0         0 return 0;
821             }
822              
823 0         0 $message = &_receive_hw_msg($self->{"socket"});
824 0 0       0 if (!$message) {
825 0         0 warn "remove_attribute: _receive_hw_msg returned 0\n";
826 0         0 $self->{"error"} = "0.02";
827 0         0 return 0;
828             }
829              
830 0         0 ($self->{"server_error"}) = $message->data =~ /^(\d+)$/s;
831 0 0       0 if ($self->{"server_error"} != 0) {
832 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
833 0         0 $self->{"error"} = "0.02";
834 0         0 return 0;
835             }
836              
837 0         0 return 1;
838             }
839              
840             =pod
841              
842             =item change_attribute ( OBJNUM, NAME, OLD_VALUE, NEW_VALUE )
843              
844             Alters an attribute to the given objnum (NB: needs to know old value).
845              
846             =cut
847             sub change_attribute {
848 0     0 1 0 my $self = shift;
849 0         0 my $objnum = shift;
850 0         0 my $atrname = shift;
851 0         0 my $atroldvalue = shift;
852 0         0 my $atrnewvalue = shift;
853              
854 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"CHANGEOBJECT"},
855             "rem $atrname=$atroldvalue\add $atrname=$atrnewvalue");
856              
857 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
858 0         0 $self->{"error"} = "0.02";
859 0         0 warn "change_attribute: _send_hw_msg returned 0\n";
860 0         0 return 0;
861             }
862              
863 0         0 $message = &_receive_hw_msg($self->{"socket"});
864 0 0       0 if (!$message) {
865 0         0 $self->{"error"} = "0.02";
866 0         0 warn "change_attribute: _receive_hw_msg returned 0\n";
867 0         0 return 0;
868             }
869              
870 0         0 ($self->{"server_error"}) = $message->data =~ /^(\d+)$/s;
871 0 0       0 if ($self->{"server_error"} != 0) {
872 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
873 0         0 $self->{"error"} = "0.02";
874 0         0 return 0;
875             }
876              
877 0         0 return 1;
878             }
879              
880             =pod
881              
882             =item get_children ( OBJNUM )
883              
884             Returns objnums for all the children in the objnum passed. If the
885             object was a leaf node (ie: no children) you'll get a 0 back.
886              
887             =cut
888             sub get_children {
889 0     0 1 0 my $self = shift;
890 0         0 my $objnum = shift;
891              
892 0         0 my $children;
893             my $kidcount;
894              
895 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"CHILDREN"},
896             $objnum);
897              
898 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
899 0         0 warn "get_children: _send_hw_msg returned 0\n";
900 0         0 $self->{"error"} = "0.02";
901 0         0 return 0;
902             }
903              
904 0         0 $message = &_receive_hw_msg($self->{"socket"});
905 0 0       0 if (!$message) {
906 0         0 warn "get_children: _receive_hw_msg returned 0\n";
907 0         0 $self->{"error"} = "0.02";
908 0         0 return 0;
909             }
910              
911 0         0 ($self->{"server_error"}, $kidcount, $children) = $message->data =~ /^(\d+) (\d+) (.*)$/s;
912 0 0       0 if ($self->{"server_error"} != 0) {
913 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
914 0         0 $self->{"error"} = "0.02";
915 0         0 return 0;
916             }
917              
918 0 0       0 if (!$kidcount) {
919             # No error, just no children (prob'ly a leaf collection)
920 0         0 return 0;
921             }
922              
923 0         0 return $children;
924             }
925              
926             =pod
927              
928             =item get_parents ( OBJNUM )
929              
930             Returns objnums for all the parents in the objnum passed. If the
931             object had no parents (it was the root collection) you'll get a 0
932             back.
933              
934             =cut
935             sub get_parents {
936 0     0 1 0 my $self = shift;
937 0         0 my $objnum = shift;
938              
939 0         0 my $parents;
940             my $parentcount;
941 0         0 my $error;
942              
943 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETPARENT"},
944             $objnum);
945              
946 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
947 0         0 $self->{"error"} = "0.02";
948 0         0 warn "get_parents: _send_hw_msg returned 0\n";
949 0         0 return 0;
950             }
951              
952 0         0 $message = &_receive_hw_msg($self->{"socket"});
953 0 0       0 if (!$message) {
954 0         0 warn "get_parents: _receive_hw_msg returned 0\n";
955 0         0 $self->{"error"} = "0.02";
956 0         0 return 0;
957             }
958              
959 0         0 ($self->{"server_error"}, $parentcount, $parents) = $message->data =~ /^(\d+) (\d+) (.*)$/s;
960 0 0       0 if ($self->{"server_error"} != 0) {
961 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
962 0         0 $self->{"error"} = "0.02";
963 0         0 return 0;
964             }
965              
966 0 0       0 if (!$parentcount) {
967             # No error, just no parents (prob'ly a root collection)
968 0         0 return 0;
969             }
970              
971 0         0 return $parents;
972             }
973              
974             =pod
975              
976             =item get_anchors ( OBJNUM )
977              
978             Returns objnums for all the anchors in the document passed.
979              
980             =cut
981             sub get_anchors {
982 0     0 1 0 my $self = shift;
983 0         0 my $objnum = shift;
984              
985 0         0 my $acount;
986             my $anchors;
987 0         0 my $error;
988              
989 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"GETANCHORS"},
990             $objnum);
991              
992 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
993 0         0 $self->{"error"} = "0.02";
994 0         0 warn "get_anchors: _send_hw_msg returned 0\n";
995 0         0 return 0;
996             }
997              
998 0         0 $message = &_receive_hw_msg($self->{"socket"});
999 0 0       0 if (!$message) {
1000 0         0 warn "get_anchors: _receive_hw_msg returned 0\n";
1001 0         0 $self->{"error"} = "0.02";
1002 0         0 return 0;
1003             }
1004              
1005 0         0 ($self->{"server_error"}, $acount, $anchors) = $message->data =~ /^(\d+) (\d+) (.*)$/s;
1006 0 0       0 if ($self->{"server_error"} != 0) {
1007 0         0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n";
1008 0         0 $self->{"error"} = "0.02";
1009 0         0 return 0;
1010             }
1011              
1012 0 0       0 if (!$acount) {
1013             # No error, just no anchors
1014 0         0 return 0;
1015             }
1016              
1017 0         0 $anchors =~ s/\s*$//;
1018 0 0       0 warn "get_anchors: returning " .
1019             dumpvar::stringify($anchors) . "\n" if $DEBUG > 2;
1020              
1021 0         0 return $anchors;
1022             }
1023              
1024              
1025             =pod
1026              
1027             =item insert_object ( OBJRECORD );
1028              
1029             Inserts an object on the HyperWave server. Returns object ID of the
1030             new object.
1031              
1032             C should be in the form
1033             C and must contain certain
1034             parameters such as the parent object, name, document type, etc. It is
1035             suggested that you use one of the other insert_* commands as they provide
1036             a friendlier interface. This command is provided primarily for
1037             completeness.
1038              
1039             =cut
1040              
1041             sub insert_object {
1042 0     0 1 0 my $self = shift;
1043 0         0 my $objrecord = shift;
1044            
1045 0         0 my $message = HyperWave::CSP::Message->new($MESSAGE{"INSERTOBJECT"}, _hw_string($objrecord));
1046              
1047 0 0       0 if (!&_send_hw_msg($self->{"socket"}, $message)) {
1048 0         0 $self->{"error"} = "0.02";
1049 0 0       0 warn "insert_object: _send_hw_msg returned 0\n" if $DEBUG;
1050 0         0 return 0;
1051             }
1052              
1053 0         0 $message = &_receive_hw_msg($self->{"socket"});
1054 0 0       0 if (!$message) {
1055 0         0 $self->{"error"} = "0.02";
1056 0 0       0 warn "insert_object: _receive_hw_msg returned 0\n" if $DEBUG;
1057 0         0 return 0;
1058             }
1059              
1060 0         0 $message->data =~ /^(\d+) (\d+)?/s;
1061 0         0 $self->{"server_error"} = $1;
1062 0         0 my $objid = $2;
1063 0 0       0 if ($self->{"server_error"} != 0) {
1064 0         0 $self->{"error"} = "0.02";
1065 0 0       0 warn "Error '" . $self->{"server_error"} . "' from HyperWave.\n" if $DEBUG;
1066 0         0 return 0;
1067             }
1068              
1069 0         0 return $objid;
1070             }
1071              
1072             =pod
1073              
1074             =item insert_collection ( PARENT_OBJNUM, NAME [, OTHER_PARAMS ] )
1075              
1076             Inserts a collection on the HyperWave server. Returns object ID of
1077             the new collection.
1078              
1079             C is the object number (probably returned from
1080             get_objnum_by_name() of the collection to insert this collection into.
1081             C is the name attribute, this will become the apparent URL to
1082             somebody using the WaveMaster interface.
1083              
1084             C should be in the form
1085             C and so on. You might
1086             particularly want to set a Title for the collection.
1087              
1088             =cut
1089              
1090             sub insert_collection {
1091 0     0 1 0 my $self = shift;
1092 0         0 my $parentobjnum = shift;
1093 0         0 my $name = shift;
1094 0         0 my $objrecord = shift;
1095              
1096 0 0       0 warn "insert_collection\n" if $DEBUG > 1;
1097            
1098 0         0 return $self->insert_object("Parent=$parentobjnum\nName=$name\nType=Document\nDocumentType=Collection\n$objrecord");
1099              
1100             }
1101              
1102             =pod
1103              
1104             =item insert_image ( OBJNUM, PARENT, NAME )
1105              
1106             Adds a new picture. NOT YET IMPLEMENTED.
1107              
1108             =cut
1109             sub insert_image {
1110 0     0 1 0 my $self = shift;
1111 0         0 my $parentobjnum = shift;
1112 0         0 my $name = shift;
1113 0         0 my $objrecord = shift;
1114              
1115 0 0       0 warn "insert_collection\n" if $DEBUG > 1;
1116            
1117 0         0 return $self->insert_object("Parent=$parentobjnum\nName=$name\nType=Document\nDocumentType=Image\n$objrecord");
1118              
1119             }
1120              
1121             =pod
1122              
1123             =item insert_text ( OBJNUM, PARENT )
1124              
1125             Adds a new text object (no anchors). NOT YET IMPLEMENTED.
1126              
1127             =cut
1128             sub insert_text {
1129 0     0 1 0 my $self = shift;
1130 0         0 my $parentobjnum = shift;
1131 0         0 my $name = shift;
1132 0         0 my $objrecord = shift;
1133              
1134 0 0       0 warn "insert_collection\n" if $DEBUG > 1;
1135            
1136 0         0 return $self->insert_object("Parent=$parentobjnum\nName=$name\nType=Document\nDocumentType=text\n$objrecord");
1137              
1138             }
1139              
1140             =pod
1141              
1142             =item insert_html ( OBJNUM )
1143              
1144             Adds a new html object (we parse the anchors). NOT YET IMPLEMENTED.
1145              
1146             =cut
1147             sub insert_html {
1148 0     0 1 0 my $self = shift;
1149 0         0 my $parentobjnum = shift;
1150 0         0 my $name = shift;
1151              
1152             # TODO: 1. Parse anchors.
1153 0         0 my $objrecord = shift;
1154              
1155 0 0       0 warn "insert_collection\n" if $DEBUG > 1;
1156            
1157 0         0 return $self->insert_object("Parent=$parentobjnum\nName=$name\nType=Document\nDocumentType=text\n$objrecord");
1158              
1159             }
1160              
1161             =pod
1162              
1163             =item error ( )
1164              
1165             Returns a human-readable string describing the previous server
1166             error.
1167              
1168             =cut
1169             sub error_message {
1170 0     0 0 0 my $self = shift;
1171              
1172 0         0 return $self->{"error"};
1173             }
1174              
1175             =pod
1176              
1177             =item server_error_message ( )
1178              
1179             Returns a human-readable string describing the previous server
1180             error.
1181              
1182             =cut
1183             sub server_error_message {
1184 0     0 1 0 my $self = shift;
1185              
1186 0 0 0     0 if (!$self->{"server_error"}) {
    0 0        
    0 0        
    0          
1187 0         0 return "No Error";
1188             } elsif (($self->{"server_error"} >= 1) && ($self->{"server_error"} <= 37)) {
1189 0         0 return $SERVER_ERRORS[$self->{"server_error"} - 1];
1190             } elsif (($self->{"server_error"} >= 513) && ($self->{"server_error"} <= 516)) {
1191 0         0 return $SERVER_ERRORS[$self->{"server_error"} - 512 + 37];
1192             } elsif (($self->{"server_error"} >= 1024) && ($self->{"server_error"} <= 1064)) {
1193 0         0 return $SERVER_ERRORS[$self->{"server_error"} - 1024 + 37 + 4];
1194             } else {
1195 0         0 return "Unknown Error";
1196             }
1197              
1198             }
1199              
1200              
1201             ###################################################################
1202             # Functions under here are not member functions and not exported. #
1203             ###################################################################
1204              
1205             #
1206             # Used internally to construct things
1207             #
1208             sub _hw_string {
1209 0     0   0 return shift() . "\0";
1210             }
1211              
1212             sub _hw_int {
1213 0     0   0 return shift() . " ";
1214             }
1215              
1216             sub _hw_intarray {
1217 0     0   0 my @array = @_;
1218              
1219 0         0 my $output = "0.02";
1220 0         0 foreach (@array) {
1221 0         0 $output .= "$_ ";
1222             }
1223 0         0 return $output;
1224             }
1225              
1226             sub _hw_opaque {
1227 0     0   0 my $data = shift;
1228 0         0 return length($data) . " " . $data;
1229             }
1230              
1231             #
1232             # Connects to the server
1233             # Accepts a hostname and port, returns a connected socket or 0 on error
1234             #
1235             sub _open_hw_connection {
1236 1     1   2 my $server_host = shift;
1237 1         3 my $server_port = shift;
1238              
1239 1         5 my $socket = Symbol::gensym();
1240              
1241 1 50       45 warn "_open_hw_connection\n" if $DEBUG > 1;
1242              
1243 1 50       4 warn "_open_hw_connection: server = '$server_host', port = '$server_port'\n" if $DEBUG > 2;
1244              
1245             # Deal with a port specified from /etc/services list
1246 1 50       6 if ($server_port =~ /\D/) {
1247 0         0 $server_port = getservbyname($server_port, 'tcp');
1248 0 0       0 warn "_open_hw_connection: port resolved to: '$server_port'\n" if $DEBUG > 2;
1249             }
1250              
1251 1         2 my $iaddr;
1252 1 50       2124 if (!($iaddr = gethostbyname($server_host))) {
1253 0         0 warn "_open_hw_connection: gethostbyname: $!";
1254 0         0 return 0;
1255             }
1256              
1257 1         57 my $paddr = sockaddr_in($server_port, $iaddr);
1258 1         8701 my $proto = getprotobyname('tcp');
1259              
1260 1 50       72 socket($socket, PF_INET, SOCK_STREAM, $proto) ||
1261             croak "_open_hw_connection: socket: $!";
1262 1 50       111498 connect($socket, $paddr) || croak "_open_hw_connection: connect: $!";
1263              
1264 0           return $socket;
1265             }
1266              
1267              
1268             #
1269             # Negotiates connection type with the server
1270             # Accepts a socket, returns true/false
1271             #
1272             sub _initialize_hw_connection {
1273 0     0     my $socket = shift;
1274 0           my $user = shift;
1275 0           my $password = shift;
1276              
1277 0           my $message = HyperWave::CSP::Message->new;
1278 0           my $buf;
1279             my $server_string;
1280              
1281 0 0         warn "_initialize_hw_connection\n" if $DEBUG > 2;
1282              
1283 0 0         if (!&_hw_write($socket, 'F')) {
1284 0           warn "_initialize_hw_connection: _hw_write (1) returned 0\n";
1285 0           return 0;
1286             }
1287              
1288 0 0         if (!($buf = &_hw_read($socket, 1))) {
1289 0           warn "_initialize_hw_connection: _hw_read (1) returned 0\n";
1290 0           return 0;
1291             }
1292 0 0         warn "_initialize_hw_connection: _hw_read gave us " .
1293             dumpvar::stringify($buf) . "\n" if $DEBUG > 2;
1294              
1295 0 0         if (!&_send_ready($socket)) {
1296 0           warn "_initialize_hw_connection: _send_ready returned 0\n";
1297 0           return 0;
1298             }
1299              
1300 0 0         if (!($message = &_receive_ready($socket))) {
1301 0           warn "_initialize_hw_connection: _receive_ready returned 0\n";
1302 0           return 0;
1303             }
1304              
1305 0           $message->data =~ m/^0 \$([^\$]+)\$(.*)\0$/;
1306 0 0         if ($1 eq "ServerString") {
    0          
1307 0           $server_string = $2;
1308             } elsif ($1 eq "Reorganization") {
1309             # NB: Whatever calls this function should check for this
1310             # in the return value, so we only warn that it happens for
1311             # information purposes.
1312 0 0         warn "_initialize_hw_connection: server not accepting connections."
1313             if $DEBUG;
1314             } else {
1315 0           warn "_initialize_hw_connection: unknown data in ready message.";
1316 0           $message->dump;
1317             }
1318              
1319 0 0         warn "_initialize_hw_connection: server_string: " .
1320             dumpvar::stringify($server_string) . "\n" if $DEBUG > 2;
1321              
1322 0           return $message;
1323             }
1324              
1325              
1326             #
1327             # Reads up to the number of bytes from the socket
1328             # returns 0 on failure, otherwise the buffer read
1329             #
1330             sub _hw_read {
1331 0     0     my $socket = shift;
1332 0           my $length_to_read = shift;
1333              
1334 0 0         warn "_hw_read\n" if $DEBUG > 2;
1335              
1336 0           my $buff1 = "0.02";
1337 0           my $tries_remaining = 5;
1338              
1339             # loop until it's all read, or we timeout
1340 0 0         if (!defined(sysread($socket, $buff1, $length_to_read))) {
1341 0           warn "_hw_read: sysread: $!";
1342             }
1343 0           $length_to_read -= length($buff1);
1344 0           my $buffer = $buff1;
1345 0   0       while ($length_to_read && $tries_remaining) {
1346 0           sleep(5);
1347 0           $tries_remaining--;
1348 0           $buff1 = "0.02";
1349 0 0         if (!defined(sysread($socket, $buff1, $length_to_read))) {
1350 0           warn "_hw_read: sysread: $!";
1351             }
1352 0           $length_to_read -= length($buff1);
1353 0           $buffer .= $buff1;
1354 0 0         warn "_hw_read: read = \"0.02\" of " .
1355             $length_to_read . "\n" if $DEBUG > 2;
1356             }
1357              
1358 0 0         if (!$tries_remaining) {
1359 0 0         warn "_hw_read: ran out of tries!\n" if $DEBUG;
1360 0           return 0;
1361             }
1362              
1363 0 0         warn "_hw_read: returning = '$buffer'\n" if $DEBUG > 2;
1364 0           return $buffer;
1365              
1366             }
1367              
1368              
1369             #
1370             # Write the buffer to the socket
1371             #
1372             sub _hw_write {
1373 0     0     my $socket = shift;
1374 0           my $buffer = shift;
1375              
1376 0 0         warn "_hw_write\n" if $DEBUG > 2;
1377            
1378 0 0         warn "_hw_write: sending " .
1379             dumpvar::stringify($buffer) . "\n" if $DEBUG > 2;
1380              
1381 0           my $length_sent;
1382              
1383 0 0         if (!defined(syswrite($socket, $buffer, length($buffer)))) {
1384 0           warn "_hw_write: syswrite: $!";
1385             }
1386              
1387 0           return 1;
1388             }
1389              
1390              
1391             #
1392             # Get a message
1393             #
1394             sub _receive_hw_msg {
1395 0     0     my $socket = shift;
1396              
1397 0 0         warn "_receive_hw_msg\n" if $DEBUG > 1;
1398              
1399 0           my $buffer;
1400             my $length;
1401 0           my $message = HyperWave::CSP::Message->new;
1402              
1403             # initial length field plus separating space
1404 0 0         if (!($length = &_hw_read($socket, 11))) {
1405 0           warn "_receive_hw_msg: _hw_read(1) returned 0\n";
1406 0           return 0;
1407             }
1408 0 0         if (!($length =~ s/\s*(\d+)\s/$1/)) {
1409 0           warn "_receive_hw_msg: _hw_read(1) returned wrong data '$length'\n";
1410 0           return 0;
1411             }
1412 0           $message->length($length);
1413              
1414 0 0         warn "_receive_hw_msg: got length '$length'\n" if $DEBUG > 2;
1415              
1416             # everything else
1417 0 0         if (!($buffer = &_hw_read($socket, $message->length - 11))) {
1418 0           warn "_receive_hw_msg: _hw_read(2) returned 0\n";
1419 0           return 0;
1420             }
1421 0           $buffer =~ m/^\s*(\d+)\s+(\d+)\s+(.*)$/s;
1422 0           $message->msgid($1);
1423 0           $message->msgtype($2);
1424 0           $message->data($3);
1425              
1426 0 0         $message->dump("receive_hw_message") if $DEBUG > 2;
1427              
1428 0           return $message;
1429             }
1430              
1431              
1432             #
1433             # Receives a 'ready' message from the server
1434             #
1435             sub _receive_ready {
1436 0     0     my $socket = shift;
1437              
1438 0 0         warn "_receive_ready\n" if $DEBUG > 1;
1439              
1440 0           my $message = _receive_hw_msg($socket);
1441 0 0         if (!$message) {
1442 0           warn "_receive_ready: _receive_hw_msg returned 0\n";
1443 0           return 0;
1444             }
1445              
1446 0 0         if (!$message->msgid) {
1447 0           warn "_receive_ready: _receive_hw_msg returned error\n";
1448 0           return 0;
1449             }
1450              
1451 0 0         if ($message->msgtype() != $MESSAGE{"READY"}) {
1452 0           warn "_receive_ready: _receive_hw_msg returned wrong message\n";
1453 0           return 0;
1454             }
1455              
1456 0           return $message;
1457             }
1458              
1459              
1460             #
1461             # Send a message
1462             #
1463             sub _send_hw_msg {
1464 0     0     my $socket = shift;
1465 0           my $message = shift;
1466              
1467 0 0         warn "_send_hw_msg\n" if $DEBUG > 1;
1468              
1469 0 0         if (!&_hw_write($socket, $message->as_string)) {
1470 0           warn "_send_hw_msg: _hw_write returned 0\n";
1471 0           return 0;
1472             }
1473              
1474 0           return 1;
1475             }
1476              
1477              
1478              
1479             #
1480             # Send a 'ready' message
1481             #
1482             sub _send_ready {
1483 0     0     my $socket = shift;
1484              
1485 0 0         warn "_send_ready\n" if $DEBUG > 1;
1486              
1487 0           my $ready_msg = HyperWave::CSP::Message->new($MESSAGE{"READY"});
1488 0           $ready_msg->msgid($Protocol_Version);
1489              
1490 0 0         if (!&_send_hw_msg($socket, $ready_msg)) {
1491 0           warn "_send_ready: _send_hw_msg returned 0\n";
1492 0           return 0;
1493             }
1494              
1495 0           return 1;
1496             }
1497              
1498             =pod
1499              
1500             =head1 SEE ALSO
1501              
1502             =head1 AUTHOR
1503              
1504             Bek Oberin
1505              
1506             =head1 COPYRIGHT
1507              
1508             Copyright (c) 1998 Bek Oberin. All rights reserved.
1509              
1510             This program is free software; you can redistribute it and/or modify
1511             it under the same terms as Perl itself.
1512              
1513             =cut
1514              
1515             #
1516             # End code.
1517             #
1518             1;