File Coverage

blib/lib/Slackware/Slackget/Network/Connection.pm
Criterion Covered Total %
statement 9 163 5.5
branch 0 104 0.0
condition 0 30 0.0
subroutine 3 23 13.0
pod 17 17 100.0
total 29 337 8.6


line stmt bran cond sub pod time code
1             package Slackware::Slackget::Network::Connection;
2              
3 2     2   14620 use warnings;
  2         4  
  2         66  
4 2     2   52 use strict;
  2         3  
  2         38  
5 2     2   7 use Slackware::Slackget::Status ;
  2         2  
  2         4182  
6              
7             =head1 NAME
8              
9             Slackware::Slackget::Network::Connection - A wrapper for network operation in slack-get
10              
11             =head1 VERSION
12              
13             Version 1.0.0
14              
15             =cut
16              
17             our $VERSION = '1.0.0';
18             our $ENABLE_DEPRECATED_COMPATIBILITY_MODE=0;
19             our $DEBUG= $ENV{SG_DAEMON_DEBUG};
20              
21             # my %equiv = (
22             # 'normal' => 'IO::Socket::INET',
23             # 'secure' => 'IO::Socket::SSL',
24             # 'ftp' => 'Net::FTP',
25             # 'http' => 'LWP::Simple'
26             # );
27              
28             our @ISA = qw();
29              
30             =head1 SYNOPSIS
31              
32             This class is anoter wrapper for slack-get. It will encapsulate all network operation. This class can chang a lot before the release and it may be rename in Slackware::Slackget::NetworkConnection.
33              
34             =head2 Some words about subclass
35              
36             WARNING: The Slackware::Slackget::Network::Connection::* "drivers" API changed with version 1.0.0
37              
38             This class use subclass like Slackware::Slackget::Network::Connection::HTTP or Slackware::Slackget::Network::Connection::FTP as "drivers" for a specific protocol.
39              
40             You can add a "driver" class for a new protocol easily by creating a module in the Slackware::Slackget::Network::Connection:: namespace.
41              
42             You must know that all class the Slackware::Slackget::Network::Connection::* must implements the following methods (the format is : <method name(<arguments>)> : <returned value>, parmameters between [] are optionnals):
43              
44             - __test_server : a float (the server response time)
45             - __fetch_file([$remote_filename],[$local_file]) : a boolean (1 or 0). NOTE: this method store the fetched file on the hard disk. If $local_file is not defined, fetch() must store the file in <config:update-directory> or in "download_directory" (constructor parameter).
46             - __get_file([$remote_filename]) : the file content
47              
48             Moreover, this "driver" have to respect the namming convention : the protocol name it implements in upper case (for example, if you implements a driver for the rsync:// protocol the module must be called Slackware::Slackget::Network::Connection::RSYNC.pm).
49              
50             =head1 CONSTRUCTOR
51              
52             =head2 new
53              
54             WARNING: Since version 1.0.0 of this module you can't instanciate a Slackware::Slackget::Network::Connection object with a constructor with 1 argument. The followinf syntax is deprecated and no longer supported :
55              
56             my $connection = Slackware::Slackget::Network::Connection->new('http://www.nymphomatic.org/mirror/linuxpackages/Slackware-10.1/');
57              
58             You can force this class to behave like the old version by setting $Slackware::Slackget::Network::Connection::ENABLE_DEPRECATED_COMPATIBILITY_MODE to 1 *BEFORE* calling the constructor.
59              
60             This constructor take the followings arguments :
61              
62             host : a hostname (mandatory)
63             path : a path on the remote host
64             files : a arrayref wich contains a list of files to download
65             config : a reference to a Slackware::Slackget::Config object (mandatory if "download_directory" is not defined)
66             download_directory : a directory where this object can store fetched files (mandatory if "config" is not defined)
67             InlineStates : a hashref which contains the reference to event handlers (mandatory)
68            
69              
70             use Slackware::Slackget::Network::Connection;
71            
72             (1)
73             my $connection = Slackware::Slackget::Network::Connection->new(
74             host => 'http://www.nymphomatic.org',
75             path => '/mirror/linuxpackages/Slackware-10.1/',
76             files => ['FILELIST.TXT','PACKAGES.TXT','CHECKSUMS.md5'], # Be carefull that it's the files parameter not file. file is the current working file.
77             config => $config,
78             InlineStates => {
79             progress => \&handle_progress ,
80             download_error => \&handle_download_error ,
81             download_finished => \&handle_download_finished,
82             }
83             );
84             $connection->fetch_all or die "An error occur during the download\n";
85            
86             or (the recommended way) :
87            
88             (2)
89             my $connection = Slackware::Slackget::Network::Connection->new(
90             host => 'http://www.nymphomatic.org',
91             path => '/mirror/linuxpackages/Slackware-10.1/',
92             config => $config,
93             InlineStates => {
94             progress => \&handle_progress ,
95             download_error => \&handle_download_error ,
96             download_finished => \&handle_download_finished,
97             }
98             );
99             my $file = $connection->get_file('FILELIST.TXT') or die "[ERROR] unable to download FILELIST.TXT\n";
100            
101             Instead of using the "config" parameter you can use "download_directory" :
102            
103             my $connection = Slackware::Slackget::Network::Connection->new(
104             host => 'http://www.nymphomatic.org',
105             path => '/mirror/linuxpackages/Slackware-10.1/',
106             download_directory => "/tmp/",
107             InlineStates => {
108             progress => \&handle_progress ,
109             download_error => \&handle_download_error ,
110             download_finished => \&handle_download_finished,
111             }
112             );
113             my $file = $connection->get_file('FILELIST.TXT') or die "[ERROR] unable to download FILELIST.TXT\n";
114            
115             or :
116            
117             my $status = $connection->fetch('FILELIST.TXT',"$config->{common}->{'update-directory'}/".$server->shortname."/cache/FILELIST.TXT");
118             die "[ERROR] unable to download FILELIST.TXT\n" unless ($status);
119              
120             The global way (1) is not recommended because of the lake of control on the downloaded file. For example, if there is only 1 download which fail, fetch_all will return undef and you don't know which download have failed.
121              
122              
123             The recommended way is to give to the constructor the following arguments :
124              
125             host : the host (with the protocol, do not provide 'ftp.lip6.fr' provide ftp://ftp.lip6.fr. The protocol will be automatically extracted and used to load the correct "driver")
126             path : the path to the working directory on the server (Ex: '/pub/linux/distributions/slackware/slackware-10.1/'). Don't provide a 'file' argument.
127             config : the Slackware::Slackget::Config object of the application
128             mode : a mode between 'normal' or 'secure'. This is only when you attempt to connect to a daemon (front-end/daemon or daemon/daemon connection). 'secure' use SSL connection (** not yet implemented **).
129             InlineStates : see above.
130              
131             =cut
132              
133             sub new
134             {
135 0     0 1   my ($class,@args) = @_ ;
136 0 0         print STDOUT "[Slackware::Slackget::Network::Connection] debug is enabled\n" if($DEBUG);
137 0           my $self={};
138 0           bless($self,$class);
139             # print "scalar: ",scalar(@args),"\n";
140 0 0 0       if(scalar(@args) < 1){
    0          
141 0           warn "[Slackware::Slackget::Network::Connection] you must provide arguments to the constructor. Please have a look at the documentation :\n\tperldoc Slackware::Slackget::Network::Connection\n" ;
142 0           return undef ;
143             }
144             elsif(scalar(@args) == 1 && $ENABLE_DEPRECATED_COMPATIBILITY_MODE){
145 0 0         print "[Slackware::Slackget::Network::Connection] [debug] ENABLE_DEPRECATED_COMPATIBILITY_MODE is activate.\n" if($DEBUG);
146 0 0         if(is_url($self,$args[0])){
147 0 0         parse_url($self,$args[0]) or return undef; # here is a really paranoid test because if this test fail it fail before (at is_url), so the "or return undef" is "de trop"
148 0 0         _load_network_module($self) or return undef;
149             }
150             else{
151 0           return undef;
152             }
153             }
154             else{
155 0 0         print "[Slackware::Slackget::Network::Connection] [debug] we are working in \"new mode\"\n" if($DEBUG);
156 0           my %args = @args;
157             # warn "[Slackware::Slackget::Network::Connection] You need to provide a \"config\" parameter with a valid Slackware::Slackget::Config object reference.\n" if(!defined($args{config}) && ref($args{config}) ne 'Slackware::Slackget::Config') ;
158 0 0 0       if(exists($args{host}) && ((exists($args{config}) && ref($args{config}) eq 'Slackware::Slackget::Config') || defined($args{download_directory})) ) #(exists($args{path}) || exists($args{file}) ) &&
      0        
159             {
160 0 0         $self->{DATA}->{download_directory}=$args{download_directory} if(defined($args{download_directory}));
161 0 0         print "[Slackware::Slackget::Network::Connection] [debug] parsing url\n" if($DEBUG);
162 0 0         parse_url($self,$args{host}) or return undef;
163 0 0         print "[Slackware::Slackget::Network::Connection] [debug] going to load network's drivers\n" if($DEBUG);
164 0 0         _load_network_module($self) or return undef;
165 0 0         print "[Slackware::Slackget::Network::Connection] [debug] going to fill the internal data section\n" if($DEBUG);
166 0           _fill_data_section($self,\%args);
167 0 0 0       if(defined($args{InlineStates}) && ref($args{InlineStates}) eq 'HASH'){
168 0           $self->{InlineStates} = $args{InlineStates};
169 0           foreach ('progress','download_error','download_finished'){
170 0 0         print "[Slackware::Slackget::Network::Connection] [debug] testing InlineStates/$_\n" if($DEBUG);
171 0 0 0       unless(exists($self->{InlineStates}->{$_}) && defined($self->{InlineStates}->{$_})){
172 0           warn "[Slackware::Slackget::Network::Connection] you must provide a sub reference as InlineStates->$_.\n";
173 0           return undef;
174             }
175             }
176             }
177             else{
178 0           warn "[Slackware::Slackget::Network::Connection] you must provide some InlineStates.\n";
179 0           return undef;
180             }
181             }
182             else
183             {
184 0           warn "[Slackware::Slackget::Network::Connection] you must provide the following parameters to the constructor :\n\thost\n\tconfig or download_directory\n" ;
185 0           return undef ;
186             }
187 0           %args = ();
188             }
189 0           $self->{OVAR} = {};
190 0 0         $self->__init_subclass if($self->can('__init_subclass'));
191 0           @args = ();
192             # $self->{STATUS} = {
193             # 0 => "All's good\n";
194             # }
195 0           return $self;
196             }
197              
198             =head1 EVENTS
199              
200             Since the version 1.0.0 this class is event driven. To manage those events *YOU HAVE* to pass an InlineStates argument to the constructor (L<new>).
201              
202             There is 3 events generated by this class :
203              
204             * progress : this event is throw when a progress is detected on file download. The handler will receive the followings parameters (in this order) : the downloaded filename, the amount of data downloaded, the total size of the remote file.
205            
206             * download_error : this is throw when an error occured during download. The handler will receive the following parameters (in this order) : the downloaded filename, a Slackware::Slackget::Status object.
207            
208             *download_finished : this is throw when a download finished successfully. The handler will receive the following parameters (in this order) : the downloaded filename, a Slackware::Slackget::Status object.
209              
210             =head1 FUNCTIONS
211              
212             =head2 is_url
213              
214             Take a string as argument and return TRUE (1) if $string is an http or ftp URL and FALSE (0) else
215              
216             print "$string is a valid URL\n" if($connection->is_url($string)) ;
217              
218             =cut
219              
220             sub is_url {
221 0     0 1   my ($self,$url)=@_;
222 0 0 0       if( defined($self) && $self->can('_validate_url') ){
223 0 0         if( $self->_validate_url($url) ){
224 0           return 1;
225             }
226             }
227 0 0         if($url=~ /file:\/\/(.+)/)
    0          
228             {
229 0           return 1;
230             }
231             elsif($url=~ /^(.+):\/\/([^\/]+){1}(\/.*)?$/){
232 0           return 1;
233             }
234             else{
235 0           return 0 ;
236             }
237             }
238              
239             =head2 parse_url
240              
241             extract the following informations from $url :
242              
243             - the protocol
244             - the server
245             - the file (with its total path)
246              
247             For example :
248              
249             $connection->parse_url("ftp://ftp.lip6.fr/pub/linux/distributions/slackware/slackware-current/slackware/n/dhcp-3.0.1-i486-1.tgz");
250              
251             Will extract :
252              
253             - protocol = ftp
254             - host = ftp.lip6.fr
255             - file = /pub/linux/distributions/slackware/slackware-current/slackware/n/dhcp-3.0.1-i486-1.tgz
256              
257             This method return TRUE (1) if all goes well, else return FALSE (0)
258              
259             =cut
260              
261             sub parse_url {
262 0     0 1   my ($self,$url)=@_;
263 0 0         return 0 unless(defined($url));
264 0 0         if($url=~ /file:\/\/(.+)/)
    0          
265             {
266 0           $self->{DATA}->{protocol} = 'file';
267 0           $self->{DATA}->{file} = $1;
268 0 0         print "[Slackware::Slackget::Network::Connection] [debug] file is set to $self->{DATA}->{file} fo object $self\n" if($DEBUG);
269             #if we can extract a file name and a directory path we do.
270 0 0 0       if(defined($self->{DATA}->{file}) && $self->{DATA}->{file}=~ /^(.+\/)([^\/]*)$/i)
271             {
272 0           $self->{DATA}->{path} = $1;
273 0           $self->{DATA}->{file} = $2;
274 0 0         if($DEBUG){
275 0           print "[Slackware::Slackget::Network::Connection] [debug] path is set to $self->{DATA}->{path} fo object $self\n";
276 0           print "[Slackware::Slackget::Network::Connection] [debug] file is set to $self->{DATA}->{file} fo object $self\n";
277             }
278             }
279 0 0         return undef unless($self->{DATA}->{path});
280 0           return 1;
281             }
282             elsif(my @tmp = $url=~ /^(.+):\/\/([^\/]+){1}(\/.*)?$/){
283 0           $self->{DATA}->{protocol} = $1;
284 0           $self->{DATA}->{host} = $2;
285 0           $self->{DATA}->{file} = $3;
286 0 0         if($DEBUG){
287 0           print "[Slackware::Slackget::Network::Connection] [debug] protocol is set to $self->{DATA}->{protocol} fo object $self\n";
288 0           print "[Slackware::Slackget::Network::Connection] [debug] host is set to $self->{DATA}->{host} fo object $self\n";
289 0           print "[Slackware::Slackget::Network::Connection] [debug] file is set to $self->{DATA}->{file} fo object $self\n";
290             }
291             #if we can extract a file name and a directory path we do.
292 0 0 0       if(defined($self->{DATA}->{file}) && $self->{DATA}->{file}=~ /^(.*\/)([^\/]*)$/i)
293             {
294 0           $self->{DATA}->{path} = $1;
295 0           $self->{DATA}->{file} = $2;
296             }
297            
298 0           return 1;
299             }
300             else{
301 0           return 0 ;
302             }
303             }
304              
305             =head2 strip_slash
306              
307             Remove extra slash (/) in the URL and return the URL.
308              
309             my $url = $connection->strip_slash('http://ftp.infinityperl.org//slackware-repository////CHECKSUMS.md5') ;
310              
311             =cut
312              
313             sub strip_slash
314             {
315 0     0 1   my ($self,$url) = @_;
316 0           $url=~ s/\/+/\//g;
317 0 0         if($url=~ /\/{2,}/)
318             {
319 0           $self->strip_slash($url);
320             }
321             else
322             {
323 0           $url=~ s/http:\//http:\/\//;
324 0           $url=~ s/ftp:\//ftp:\/\//;
325 0           $url=~ s/file:\//ftp:\/\//;
326 0           return $url;
327             }
328             }
329              
330             sub _load_network_module {
331 0     0     my $self = shift;
332 0           my $driver='Slackware::Slackget::Network::Connection::'.uc($self->{DATA}->{protocol});
333 0 0         print "[Slackware::Slackget::Network::Connection] [debug] preparing to load $driver driver.\n" if($DEBUG);
334 0           eval "require $driver;";
335 0 0         if($@){
336 0           warn "[Slackware::Slackget::Network::Connection] driver for the network protocol '$self->{DATA}->{protocol}' is not available ($@).\n" ;
337 0           return undef ;
338             }
339             else{
340 0           push @ISA, $driver ;
341 0 0         print "[Slackware::Slackget::Network::Connection] [debug] checking if driver $self->{DATA}->{protocol} support all required methods.\n" if($DEBUG);
342 0 0         return undef unless($self->_check_driver_support_methods);
343             }
344 0           return 1;
345             }
346              
347             sub _check_driver_support_methods {
348 0     0     my $self = shift ;
349 0           foreach ('__fetch_file','__get_file','__test_server'){
350 0 0         return undef unless($self->can($_)) ;
351 0 0         print "[Slackware::Slackget::Network::Connection] [debug] driver $self->{DATA}->{protocol} support $_() method.\n" if($DEBUG);
352             }
353 0           return 1;
354             }
355              
356             sub _fill_data_section {
357 0     0     my $self = shift;
358 0           my $args = shift;
359 0           foreach (keys(%{$args})){
  0            
360 0 0         $self->{DATA}->{$_} = $args->{$_} if(!(defined($self->{DATA}->{$_})));
361             }
362             }
363              
364             =head2 DEBUG_show_data_section
365              
366             =cut
367              
368             sub DEBUG_show_data_section
369             {
370 0     0 1   my $self = shift;
371 0           print "===> DATA section of $self <===\n";
372 0           foreach (keys(%{$self->{DATA}}))
  0            
373             {
374 0           print "$_ : $self->{DATA}->{$_}";
375             }
376 0           print "===> END DATA section <===\n";
377             }
378              
379             =head2 test_server
380              
381             This method test the response time of the mirror, by making a new connection to the server and downloading the FILELIST.TXT file. Be aware of the fact that after testing the connection you will have a new connection (if you were previously connected the previous connection is closed).
382              
383             my $time = $connection->test_server() ;
384              
385             This method call the <DRIVER>->__test_server() method.
386              
387             =cut
388              
389             sub test_server {
390 0     0 1   my $self = shift;
391 0           $self->__test_server ;
392             }
393              
394             =head2 get_file
395              
396             Download and return a given file.
397              
398             my $file = $connection->get_file('PACKAGES.TXT') ;
399              
400             This method also generate events based on the returned value. If nothing is returned it throw the "download_error" event, else it throw the "download_finished" event.
401              
402             At this for the moment this method throw a "progress" event with a progress value set at -1.
403              
404             This method call the <DRIVER>->__get_file() method.
405              
406             =cut
407              
408             sub get_file {
409 0     0 1   my ($self,$file) = @_;
410 0           $self->post_event('progress',$file,-1,-9999);
411 0           my $state = Slackware::Slackget::Status->new(codes => {
412             0 => "All goes well.\n",
413             1 => "An error occured, we recommend to change this server's host.\n"
414             });
415 0           my $content = $self->__get_file($file);
416 0 0         if(defined($content)){
417 0           $state->current(0);
418 0           $self->post_event('download_finished',$file,$state);
419 0           return \$content;
420             }else{
421 0           $state->current(1);
422 0           $self->post_event('download_error',$file,$state);
423 0           undef($content);
424 0           return undef;
425             }
426             }
427              
428             =head2 fetch_file
429              
430             Download and store a given file.
431              
432             $connection->fetch_file() ; # download the file $connection->file and store it at $config->{common}->{'update-directory'}/$connection->file, this way is not recommended
433             or
434             $connection->fetch_file($remote_file) ; # download the file $remote_file and store it at $config->{common}->{'update-directory'}/$connection->file, this way is not recommended
435             or
436             $connection->fetch_file('PACKAGES.TXT',"$config->{common}->{'update-directory'}/".$current_specialfilecontainer_object->id."/PACKAGES.TXT") ; # This is the recommended way.
437             # This is equivalent to : $connection->fetch_file($remote_file,$local_file) ;
438              
439             This method return a Slackware::Slackget::Status object with the following object declaration :
440              
441             my $status = Slackware::Slackget::Status->new(codes => {
442             0 => "All goes well.\n",
443             1 => "An error occured "
444             });
445              
446             A more explicit error string can be concatenate to state 1. This method also generate events based on the returned value. If nothing is returned it throw the "download_error" event, else it throw the "download_finished" event.
447              
448             All codes greater or equal than 1 should be considered as errors codes.
449              
450             At this for the moment this method throw a "progress" event with a progress value set at -1.
451              
452             This method call the <DRIVER>->__fetch_file() method.
453              
454             =cut
455              
456             sub fetch_file {
457 0     0 1   my ($self,$file,@args) = @_;
458 0           $self->post_event('progress',$file,-1,-9999);
459 0           my $status = $self->__fetch_file($file,@args);
460 0 0         if($status->current > 0){
461 0           $self->post_event('download_error',$file,$status);
462             }else{
463 0           $self->post_event('download_finished',$file,$status);
464             }
465 0           return $status;
466             }
467              
468             =head2 fetch_all
469              
470             This method fetch all files declare in the "files" parameter of the constructor.
471              
472             $connection->fetch_all or die "Unable to fetch all files\n";
473              
474             This method save all files in the $config->{common}->{'update-directory'} (or in the "download_directory") directory (so you have to manage yourself the files deletion/replacement problems).
475              
476             =cut
477              
478             sub fetch_all {
479 0     0 1   my $self = shift ;
480 0           foreach (@{$self->files}){
  0            
481 0 0         $self->fetch_file($_) or return undef;
482             }
483 0           return 1 ;
484             }
485              
486             =head2 post_event
487              
488              
489             =cut
490              
491             sub post_event {
492 0     0 1   my ($self,$event,@args)=@_;
493 0           $self->{InlineStates}->{$event}->(@args,$self);
494             }
495              
496             =head1 ACCESSORS
497              
498             All accessors can get or set a value. You can use them like that :
499              
500             $proto->my_accessor('a value'); # to set the value of the parameter controlled by this accessor
501            
502             my $value = $proto->my_accessor ; # to get the value of the parameter controlled by this accessor
503              
504             The common accessors are :
505              
506             =cut
507              
508             =head2 protocol
509              
510             return the protocol of the current Connection object as a string :
511              
512             my $proto = $connection->protocol ;
513              
514             =cut
515              
516             sub protocol {
517 0 0   0 1   return $_[1] ? $_[0]->{DATA}->{protocol}=$_[1] : $_[0]->{DATA}->{protocol};
518             }
519              
520             =head2 host
521              
522             return the host of the current Connection object as a string :
523              
524             my $host = $connection->host ;
525              
526             =cut
527              
528             sub host {
529 0 0   0 1   return $_[1] ? $_[0]->{DATA}->{host}=$_[1] : $_[0]->{DATA}->{host};
530             }
531              
532             =head2 file
533              
534             return the file of the current Connection object as a string :
535              
536             my $file = $connection->file ;
537              
538             =cut
539              
540             sub file {
541 0 0   0 1   return $_[1] ? $_[0]->{DATA}->{file}=$_[1] : $_[0]->{DATA}->{file};
542             }
543              
544             =head2 files
545              
546             return the list of files of the current Connection object as an array reference :
547              
548             my $arrayref = $connection->files ;
549              
550             =cut
551              
552             sub files {
553 0 0   0 1   return $_[1] ? $_[0]->{DATA}->{files}=$_[1] : $_[0]->{DATA}->{files};
554             }
555              
556             =head2 path
557              
558             return or set the path of the current Connection object as a string :
559              
560             my $path = $connection->path ;
561              
562             =cut
563              
564             sub path {
565 0 0   0 1   return $_[1] ? $_[0]->{DATA}->{path}=$_[1] : $_[0]->{DATA}->{path};
566             }
567              
568             =head2 download_directory
569              
570             set or return the download_directory for the current Connection object as string :
571              
572             my $dl_dir = $connection->download_directory ;
573              
574             =cut
575              
576             sub download_directory {
577 0     0 1   my ($self,$dir) = @_;
578 0 0 0       if(defined($dir) && -e $dir){
579 0           $self->{DATA}->{config}->{common}->{'update-directory'} = undef;
580 0           $self->{DATA}->{download_directory} = undef;
581 0           $self->{DATA}->{download_directory} = $dir;
582 0           return $self->{DATA}->{download_directory};
583             }
584 0 0 0       if(defined($self->{DATA}->{download_directory}) && -e $self->{DATA}->{download_directory}){
    0          
585 0           return $self->{DATA}->{download_directory} ;
586             }
587             elsif(defined($self->{DATA}->{config})){
588 0           return $self->{DATA}->{config}->{common}->{'update-directory'} ;
589             }
590 0           return undef;
591             }
592              
593             =head2 object_extra_data
594              
595             This accessor allow you to store and retrieve random data in the connection object.
596              
597             For example, the slack-get daemon (sg_daemon) use the media id to keep tracks of all connection objects and
598             for the reverse resolution, it need to identify the media id from the Connection object. It's done by the following code :
599              
600             $connection->object_extra_data('shortname', $media->shortname());
601              
602             Extra data are not stored in the same space than object data.
603              
604             =cut
605              
606             sub object_extra_data {
607 0     0 1   my ($self,$var,$val) = @_;
608 0 0         if(defined($val)){
609 0           $self->{OVAR}->{$var} = $val;
610             }else{
611 0           return $self->{OVAR}->{$var};
612             }
613             }
614              
615             =head1 AUTHOR
616              
617             DUPUIS Arnaud, C<< <a.dupuis@infinityperl.org> >>
618              
619             =head1 BUGS
620              
621             Please report any bugs or feature requests to
622             C<bug-Slackware-Slackget@rt.cpan.org>, or through the web interface at
623             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Slackware-Slackget>.
624             I will be notified, and then you'll automatically be notified of progress on
625             your bug as I make changes.
626              
627             =head1 SUPPORT
628              
629             You can find documentation for this module with the perldoc command.
630              
631             perldoc Slackware::Slackget
632              
633              
634             You can also look for information at:
635              
636             =over 4
637              
638             =item * Infinity Perl website
639              
640             L<http://www.infinityperl.org/category/slack-get>
641              
642             =item * slack-get specific website
643              
644             L<http://slackget.infinityperl.org>
645              
646             =item * RT: CPAN's request tracker
647              
648             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Slackware-Slackget>
649              
650             =item * AnnoCPAN: Annotated CPAN documentation
651              
652             L<http://annocpan.org/dist/Slackware-Slackget>
653              
654             =item * CPAN Ratings
655              
656             L<http://cpanratings.perl.org/d/Slackware-Slackget>
657              
658             =item * Search CPAN
659              
660             L<http://search.cpan.org/dist/Slackware-Slackget>
661              
662             =back
663              
664             =head1 ACKNOWLEDGEMENTS
665              
666             Thanks to Bertrand Dupuis (yes my brother) for his contribution to the documentation.
667              
668             =head1 COPYRIGHT & LICENSE
669              
670             Copyright 2005 DUPUIS Arnaud, All Rights Reserved.
671              
672             This program is free software; you can redistribute it and/or modify it
673             under the same terms as Perl itself.
674              
675             =cut
676              
677             1; # End of Slackware::Slackget::Network::Connection