File Coverage

lib/Device/ScanShare.pm
Criterion Covered Total %
statement 172 215 80.0
branch 52 110 47.2
condition 17 40 42.5
subroutine 28 36 77.7
pod 11 19 57.8
total 280 420 66.6


line stmt bran cond sub pod time code
1             package Device::ScanShare;
2 1     1   16303 use vars qw($VERSION $DEBUG);
  1         2  
  1         57  
3 1     1   4 use File::Path;
  1         1  
  1         62  
4 1     1   5 use Cwd;
  1         5  
  1         70  
5 1     1   5 use strict;
  1         1  
  1         22  
6 1     1   5 use Carp;
  1         1  
  1         3081  
7             $VERSION = sprintf "%d.%03d", q$Revision: 1.14 $ =~ /(\d+)/g;
8             $DEBUG = 0;
9              
10              
11 0     0 0 0 sub DEBUG : lvalue { $DEBUG }
12 46 50   46 0 106 sub debug { $DEBUG and printf "@_\n"; 1 }
  46         65  
13              
14 0 0   0 0 0 sub debog { $DEBUG and printf STDERR "# %s(), @_\n", (caller(1))[3] ; 1 }
  0         0  
15              
16             sub new {
17 1     1 1 10369 my ($class, $self ) = (shift, shift);
18 1   50     21 $self ||= {};
19              
20 1 50       14 $self->{userdirs_abs_path}
21             or croak('missing "userdirs_abs_path" argument to constructor.');
22            
23 1         11 bless $self, $class;
24              
25 1         16 my $b = $self->base_path;
26 1         19 debug("base_path() $b");
27            
28 1         4 return $self;
29             }
30              
31             sub base_path {
32 21     21 0 1184 my $self = shift;
33 21         24 my $arg = shift;
34 21 50       58 $self->{base_path} = $arg if defined $arg;
35              
36 21 100       84 unless( defined $self->{base_path} ){
37            
38 1         8 $self->{base_path} = $self->{userdirs_abs_path};
39 1 50       39 $self->{base_path}=~s/\/[^\/]+txt$//i
40             or die($!." cant etablish basepath for $self->{base_path}");
41             }
42 21         1088 $self->{base_path};
43             }
44              
45              
46 5     5 0 811 sub to_abs_unixpath { _to_abs_unixpath( $_[0]->base_path, $_[1] ) }
47 5     5 0 18 sub to_rel_unixpath { _to_rel_unixpath( $_[0]->base_path, $_[1] ) }
48 0     0 0 0 sub to_rel_windowspath { _to_rel_windowspath( $_[0]->base_path, $_[1] ) }
49            
50              
51             # helper subs - NOT YET IMPLEMENTED
52              
53              
54             sub _to_rel_windowspath {
55 0     0   0 my ($basepath, $arg )= @_;
56 0 0       0 $arg or die('missing arg');
57              
58             # could be username, windows path. unix path, rel path, whatever
59             # we need to resolve to windows path to match into the entries
60              
61 0 0       0 _is_windowspath($arg)
62             and return $arg;
63              
64 0 0 0     0 my $rel = _to_rel_unixpath($basepath,$arg)
65             or warn("cant resolve $arg to rel unixpath")
66             and return;
67              
68 0         0 $rel=~s/\//\\/g;
69 0         0 $rel;
70             }
71              
72             sub _is_windowspath {
73 0     0   0 my $arg = shift;
74 0 0       0 $arg or confess("missing arg");
75 0 0       0 $arg=~/\\/ or return 0;
76 0 0       0 $arg=~/\// and return 0;
77 0         0 1;
78             }
79              
80             sub _is_unixpath {
81 5     5   8 my($arg) = @_;
82 5 50       10 $arg or confess('missing arg');
83              
84 5 50       48 $arg=~/\\/ and return 0;
85              
86 0 0       0 $arg=~/^\// and return 1;
87             }
88              
89             sub _to_abs_unixpath {
90 10     10   94 my($basepath,$arg) = @_;
91 10 50       25 $arg or confess('missing arg');
92              
93 10         50 $arg=~s/\\/\//g;
94              
95 10 50       249 if( -d "$basepath/$arg" ){
96 10         33 debug("exists when we add basepath '$arg'");
97 10         1129 return Cwd::abs_path("$basepath/$arg");
98             }
99 0 0       0 my $a = Cwd::abs_path($arg) or return;
100 0 0       0 -d $a and return $a;
101 0         0 debug("'$a' is not dir");
102              
103 0         0 return;
104             }
105              
106             sub _to_rel_unixpath {
107 5     5   8 my ($basepath,$arg) = @_;
108 5 50       11 $arg or die('missing arg');
109              
110 5 50 33     14 _is_unixpath($arg) or
111             $arg = _to_abs_unixpath($basepath, $arg)
112             or return;
113 5 50 0     53 $arg=~s/^$basepath\/// or warn("Cant match $basepath into $arg") and return;
114              
115 5         22 $arg;
116             }
117              
118             # end helpersubs - NOT YET IMPLEMENTED
119              
120              
121              
122              
123             # METHODS
124             sub user_delete {
125 1     1 1 17 my ($self, $windowspath) = (shift, shift);
126 1 50       20 $windowspath or croak("missing path argument for entry to remove in user_delete_by_path()");
127 1         26 $windowspath=~s/\//\\/g;
128              
129 1         7428 my $basepath = $self->base_path;
130 1         15 $basepath=~s/\//\\/g;
131 1         59 $windowspath=~s/^\Q$basepath\E\\//; # just in case
132              
133 1         6 my $unixpath = $windowspath;
134 1         3 $unixpath=~s/\\/\//g;
135              
136 1         14 debug("deleting user windowspath '$windowspath'");
137              
138 1 50       14 exists $self->_data->{$windowspath} or return;
139 1         7 delete $self->_data->{$windowspath};
140              
141             #rmdir($self->{base_path}."/$unixpath") or print STDERR "removed $windowspath from USERDIRS.TXT but could not delete directory ($$self{base_path}$/unixpath) because it is not empty? $!";
142              
143 1         11 $self->save;
144 1         17 return 1;
145             }
146              
147              
148              
149             sub get_user {
150 24     24 1 47 my ($self,$windowspath) = (shift,shift);
151 24 50       117 $windowspath or confess('missing arg');
152 24         52 $windowspath=~s/\//\\/g;
153 24 100       58 exists $self->_data->{$windowspath} or return;
154            
155            
156 23         53 my $h = $self->_data->{$windowspath};
157            
158 23   66     77 $h->{abs_unixpath} ||= $self->to_abs_unixpath($h->{path});
159 23   66     60 $h->{rel_unixpath} ||= $self->to_rel_unixpath($h->{path});
160              
161 23         40 $h;
162             }
163              
164              
165             sub user_add {
166 5     5 1 26 my ($self, $argv) = (shift, shift);
167              
168 5 50       34 $argv->{label} or confess('provide label for this new entry - user_add()');
169 5 50       18 $argv->{path} or confess('provide path to this entry - user_add()'); # this is coming in windows\like
170 5   33     67 $argv->{host} ||= $self->{default_host};
171              
172 5         65 debug("user_add() label:$argv->{label} path:$argv->{path} host: $argv->{host}");
173              
174              
175              
176             # PATH ARG IS FULL PATH?
177 5 50       101 if ($argv->{path}=~/^\//){
178 5         40 debug("user_add() provided full path as argument '$argv->{path}'");
179              
180 5 100 50     672 my $abs = Cwd::abs_path($argv->{path})
181             or warn("path $argv->{path} is not on disk")
182             and return 0;
183            
184 4 50 0     22 my $base = Cwd::abs_path($self->base_path)
185             or warn("base $argv->{base} is not on disk")
186             and return 0;
187            
188 4 50 0     82 $abs=~s/^$base\///
189             or warn("can't resolve [$abs] to within [$base]?")
190             and return 0;
191 4         9 $argv->{path} = $abs;
192 4         17 debug("resolved to '$abs'");
193             }
194              
195 4         13 my $unixpath = $argv->{path};
196 4         8 my $windowspath = $argv->{path};
197              
198 4         14 $windowspath=~s/\//\\/g;
199 4         8 $unixpath=~s/\\/\//g; # we need to convert so that if
200             # path/is/here
201             # path\is\here
202             # either way we get the unix/path and the windows\path
203              
204 4         15 debug("unixpath $unixpath");
205 4         12 debug("windowspath $windowspath");
206              
207              
208 4 50       22 if( exists $self->_data->{$windowspath}){
209 0         0 warn("path '$windowspath' is already present.");
210 0         0 return 0;
211             }
212             ### user exists
213              
214              
215              
216 4 100 66     19 $self->exists_label($argv->{label})
217             and warn("Cannot add label:$argv->{label} path:$argv->{path} host: $argv->{host}, label is being used.")
218             and return 0;
219              
220              
221 3         12 my $b = $self->base_path;
222 3 50       75 unless( -d "$b/$unixpath"){
223 0 0       0 File::Path::mkpath("$b/$unixpath")
224             or die($!." cannot create $b/$unixpath for user_add() ");
225 0         0 debug("note $b/$unixpath did not exist and was created.");
226             }
227              
228 3         16 $self->_data->{$windowspath} = {
229             label => $argv->{label},
230             path => $windowspath,
231             };
232              
233 3         12 $self->save;
234 3         45 return 1;
235             }
236              
237             sub create {
238 1     1 1 2 my $self = shift;
239 1 50 0     6 ! $self->exists
240             or warn("Cannot create, already on disk: ".$self->userdirs_abs_path)
241             and return 0;
242 1         5 $self->save;
243             }
244              
245             sub exists_label {
246 4     4 1 19 my ($self,$arg)= @_;
247 4 50       11 defined $arg or croak("missing arg");
248            
249 4         5 for my $h ( @{$self->get_users} ){
  4         17  
250 4 100       41 return 1 if ( $h->{label} eq $arg );
251             }
252 3         21 0;
253             }
254              
255             *exists_path = \&get_user;
256              
257              
258             # HELPERS
259 0     0   0 sub _arg_is_path { $_[0]=~/\/|\\/ }
260 0     0   0 sub _arg_is_label { $_[0]!~/\/|\\/ }
261              
262              
263              
264             sub save {
265 6     6 1 644 my $self = shift;
266             # must re sort by label on save only, entry could have been made that needs new sorting
267              
268             #reset id, count
269 6         18 $self->{id} =0;
270              
271             #start output, get the header
272 6 50       33 my $savefile = $self->_get_header or die('no header?'); # start with that
273              
274             # has to turn them into line numbers etc
275 6         11 for (@{$self->get_users}){
  6         28  
276 10         26 $savefile.= $self->_hash_to_line($_)."\n";
277             }
278              
279 6 50       20 my $l = length($savefile) or die("savefile has nothing?");
280              
281 6         19 my $temp = $self->userdirs_abs_path.".tmp";
282 6         47 my $abs = $self->userdirs_abs_path;
283              
284              
285 6         41 debug("opening $temp for writing $l chars");
286              
287 6 50       1371 open(SVF, '>', $temp)
288             or confess("$!, cannot open file for writing: $temp");
289 6         101 print SVF $savefile."\n";
290 6         500 close SVF;
291            
292 6         38 debug("Saved $temp");
293            
294            
295 6 50       788 rename($temp, $abs)
296             or die("cannot rename $temp to $abs, $!");
297 6 50       16 if ($DEBUG){
298 0 0       0 -f $abs or die("not on disk! $abs");
299 0         0 warn("Saved $abs\n");
300             }
301            
302 6         38 return 1;
303             }
304              
305              
306              
307              
308              
309             sub get_users {
310 15     15 1 31 my $self = shift;
311              
312 15         27 my @records = ();
313              
314 15         22 for ( sort { $self->_data->{$a}->{label} cmp $self->_data->{$b}->{label} } keys %{$self->_data} ){
  11         43  
  15         41  
315 23         65 my $hash = $self->get_user($_);
316 23         64 push @records, $hash;
317             }
318            
319             #notes.. why not do this in _read? beacuse if you do and then make changes, they won't show up.
320              
321 15         163 return \@records;
322             }
323              
324              
325             sub count {
326 6     6 1 8 my $self = shift;
327 6         9 my $count = scalar keys %{$self->_data} ;
  6         16  
328 6   100     25 $count ||=0;
329 6         12 return $count;
330             }
331              
332              
333 6 100   6 1 13 sub exists { -f $_[0]->userdirs_abs_path ? 1 : 0 }
334 24     24 1 231 sub userdirs_abs_path { $_[0]->{userdirs_abs_path} }
335              
336              
337              
338              
339              
340              
341             # private methods....
342              
343             sub _hash_to_line {
344 10     10   18 my ($self, $hash) = (shift, shift);
345 10   100     48 $self->{id} ||= 0; # init id marker to save each entry line if it has no value.
346              
347              
348              
349 10         15 $hash->{path}=~s/\//\\/g; # make into windowspath just in case it's not
350              
351 10         16 $self->{id}++; # increment id
352 10   66     39 $hash->{host} ||= $self->{default_host};
353 10   50     47 $hash->{end} ||= 0;
354 10         43 my $line = $hash->{label}.'='
355             .$hash->{path}.','.$hash->{label}.','
356             .$hash->{host}.','.$self->{id}
357             .','.$hash->{end};
358              
359 10         35 return $line;
360             }
361              
362             sub _original_line_to_hash {
363 0     0   0 my $line = shift;
364 0         0 $line=~s/^\s+|\s+$//g;
365 0         0 my $hash = {};
366              
367 0 0       0 $line=~s/^([^=]+)=// or die($line ." seems imporperly formatted?");
368 0         0 $hash->{label} = $1;
369            
370 0         0 my @vals = split(/,/, $line);
371 0         0 $hash->{path} = $vals[0];
372 0         0 $hash->{label2} = $vals[1];
373 0         0 $hash->{host} = $vals[2];
374 0         0 $hash->{id} = $vals[3];
375 0         0 $hash->{end} = $vals[4];
376            
377              
378 0         0 return $hash;
379             }
380              
381              
382              
383              
384              
385              
386             # this is ONLY called when we are saving
387             # to auto generate the next id count, etc
388             sub _get_header {
389 6     6   9 my $self = shift;
390            
391 6         26 my $nextid = ( $self->count +1);
392            
393 6         129 my $out= "[PreferredServer]\n"
394             ."Server=$$self{server}\n"
395             ."[RoutingID]\n"
396             ."NextID=$nextid\n"
397             ."[Users]\n";
398 6         19 return $out;
399             }
400              
401              
402              
403             sub _data {
404 99     99   124 my $self = shift;
405            
406 99 100       226 unless( defined $self->{data} ){
407              
408 3 100       11 if( !$self->exists ){
409 2         5 warn("Not on disk yet: ".$self->userdirs_abs_path);
410 2         14 return {};
411             }
412            
413             # we just want the users from this, not header stuff
414            
415 1         4 my @lines = grep { $self->_is_user_line($_) } array_slurp($self->userdirs_abs_path);
  6         12  
416              
417             scalar @lines
418 1 50       5 or warn("note: ".$self->userdirs_abs_path." has no user line entries.");
419              
420 1         2 my $data = {};
421              
422 0         0 map {
423 1         3 my $hash = _original_line_to_hash($_);
424 0         0 $data->{ $hash->{path} } = $hash;
425            
426             } @lines;
427            
428            
429 1         5 $self->{data} = $data;
430             }
431 97         422 return $self->{data};
432             }
433              
434              
435             sub _is_user_line {
436 6     6   7 my $self = shift;
437 6         7 my $line = shift;
438             #hack to get "Server" from file
439 6 100       15 if ($line=~/^Server\=([\d\.\w]+)$/i ){
440 1         8 $self->{server} = $1;
441 1         3 return 0;
442             }
443 5 100       20 if ( $line =~/^\[\w+\]|^NextID=/i){ return 0; }
  4         14  
444 1 50       8 $line=~/^[^\[\]\/\\=]+=/ or return 0;
445 0         0 return 1;
446             }
447              
448              
449             sub array_slurp {
450 1     1 0 2 my $abs = shift;
451 1 50       3 $abs or confess("Missing argument");
452             #local $/;
453 1 50 0     36 open(FILE,'<',$abs) or warn("Cannot open file for reading: '$abs', $!") and return;
454 1         24 my @lines = ;
455 1         10 close FILE;
456 1         6 return @lines;
457             }
458              
459              
460              
461             1;
462