Merge remote-tracking branch 'origin/devel' into devel
This commit is contained in:
		@@ -58,6 +58,7 @@ sub backupToStorage_Initialize {
 | 
			
		||||
      . 'bTS_Path '
 | 
			
		||||
      . 'bTS_Proto:http '
 | 
			
		||||
      . 'bTS_Type:Nextcloud,SynologyFileStation '
 | 
			
		||||
      . 'bTS_KeepLastBackups:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 '
 | 
			
		||||
      . 'disable:1 '
 | 
			
		||||
      . 'disabledForIntervals';
 | 
			
		||||
    $hash->{parseParams} = 1;
 | 
			
		||||
@@ -143,6 +144,7 @@ sub backupToStorage_Initialize {
 | 
			
		||||
        <li>bTS_User - remote User für den Login</li>
 | 
			
		||||
        <li>bTS_Path - remote Path wohin das uploadfile soll. z.B. Nextcloud </FHEM-Backup></li>
 | 
			
		||||
        <li>bTS_Type - Storage Type, default ist Nextcloud</li>
 | 
			
		||||
        <li>bTS_Type - Storage Type, default ist Nextcloud</li>
 | 
			
		||||
    </ul>
 | 
			
		||||
    <br>
 | 
			
		||||
    <a name="backupToStorageset"></a>
 | 
			
		||||
@@ -179,7 +181,7 @@ sub backupToStorage_Initialize {
 | 
			
		||||
  ],
 | 
			
		||||
  "release_status": "devepolment",
 | 
			
		||||
  "license": "GPL_2",
 | 
			
		||||
  "version": "v1.2.3",
 | 
			
		||||
  "version": "v1.3.1",
 | 
			
		||||
  "author": [
 | 
			
		||||
    "Marko Oldenburg <fhemsupport@cooltux.net>"
 | 
			
		||||
  ],
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
UPD 2021-11-09_12:56:24 6352 FHEM/98_backupToStorage.pm
 | 
			
		||||
UPD 2021-11-09_13:04:04 6498 FHEM/98_backupToStorage.pm
 | 
			
		||||
 
 | 
			
		||||
@@ -150,10 +150,10 @@ sub Define {
 | 
			
		||||
    return $@ unless ( FHEM::Meta::SetInternals($hash) );
 | 
			
		||||
    use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
 | 
			
		||||
 | 
			
		||||
    return qq{only one backupToStorage instance allowed}
 | 
			
		||||
    return q{only one backupToStorage instance allowed}
 | 
			
		||||
      if ( devspec2array('TYPE=backupToStorage') > 1 )
 | 
			
		||||
      ; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen
 | 
			
		||||
    return qq{too few parameters: define <name> backupToStorage}
 | 
			
		||||
    return q{too few parameters: define <name> backupToStorage}
 | 
			
		||||
      if ( scalar( @{$aArg} ) != 2 );
 | 
			
		||||
 | 
			
		||||
    my $name = shift @$aArg;
 | 
			
		||||
@@ -170,7 +170,7 @@ sub Undef {
 | 
			
		||||
    my $hash = shift;
 | 
			
		||||
    my $name = shift;
 | 
			
		||||
 | 
			
		||||
    Log3( $name, 3, qq{backupToStorage ($name) - delete device $name} );
 | 
			
		||||
    Log3( $name, 3, q{qbackupToStorage ($name) - delete device $name} );
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
@@ -296,24 +296,28 @@ sub Set {
 | 
			
		||||
      // return qq{set "$name" needs at least one argument};
 | 
			
		||||
 | 
			
		||||
    if ( lc $cmd eq 'addpassword' ) {
 | 
			
		||||
        return qq{please set Attribut bTS_User first}
 | 
			
		||||
        return q{please set Attribut bTS_User first}
 | 
			
		||||
          if ( AttrVal( $name, 'bTS_User', 'none' ) eq 'none' );
 | 
			
		||||
        return qq{usage: "$cmd" <password>} if ( scalar( @{$aArg} ) != 1 );
 | 
			
		||||
        return qq{usage: "$cmd" <password>}
 | 
			
		||||
          if ( scalar( @{$aArg} ) != 1 );
 | 
			
		||||
 | 
			
		||||
        StorePassword( $hash, $name, $aArg->[0] );
 | 
			
		||||
    }
 | 
			
		||||
    elsif ( lc $cmd eq 'deletepassword' ) {
 | 
			
		||||
        return qq{usage: $cmd} if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
        return qq{usage: $cmd}
 | 
			
		||||
          if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
 | 
			
		||||
        DeletePassword($hash);
 | 
			
		||||
    }
 | 
			
		||||
    elsif ( lc $cmd eq 'active' ) {
 | 
			
		||||
        return qq{usage: $cmd} if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
        return qq{usage: $cmd}
 | 
			
		||||
          if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
    
 | 
			
		||||
        readingsSingleUpdate( $hash, 'state', 'ready', 1 );
 | 
			
		||||
    }
 | 
			
		||||
    elsif ( lc $cmd eq 'inactive' ) {
 | 
			
		||||
        return qq{usage: $cmd} if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
        return qq{usage: $cmd}
 | 
			
		||||
          if ( scalar( @{$aArg} ) != 0 );
 | 
			
		||||
        
 | 
			
		||||
        readingsSingleUpdate( $hash, 'state', $cmd, 1 );
 | 
			
		||||
    }
 | 
			
		||||
@@ -399,8 +403,8 @@ sub PushToStorage {
 | 
			
		||||
 | 
			
		||||
    Log3( $name, 4, qq{backupToStorage ($name) - push to storage function} );
 | 
			
		||||
    
 | 
			
		||||
    return
 | 
			
		||||
      if ( ReadingsAge($name,'fhemBackupFile',1) > 180 );
 | 
			
		||||
    return Log3( $name, 4, qq{backupToStorage ($name) - fhemBackupFile Reading to old} )
 | 
			
		||||
      if ( ReadingsAge($name,'fhemBackupFile',1) > 3600 );
 | 
			
		||||
      
 | 
			
		||||
    Log3( $name, 4, qq{backupToStorage ($name) - after readings age return} );
 | 
			
		||||
 | 
			
		||||
@@ -445,7 +449,70 @@ sub PushToStorage {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Log3( $name, 4,
 | 
			
		||||
            qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")}
 | 
			
		||||
            qq{backupToStorage ($name) - execute command asynchronously (PID="$pid"})
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $hash->{".fhem"}{subprocess} = $subprocess;
 | 
			
		||||
 | 
			
		||||
        InternalTimer( gettimeofday() + 1,
 | 
			
		||||
            "FHEM::backupToStorage::PollChild", $hash );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Log3( $hash, 4,
 | 
			
		||||
        qq{backupToStorage ($name) - control passed back to main loop.} );
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub KeepLastN {
 | 
			
		||||
    my $hash = shift;
 | 
			
		||||
 | 
			
		||||
    my $name = $hash->{NAME};
 | 
			
		||||
 | 
			
		||||
    Log3( $name, 4, qq{backupToStorage ($name) - Keep Last N at Storage function} );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) {
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        require "SubProcess.pm";
 | 
			
		||||
        my $subprocess = SubProcess->new( { onRun => \&CleanUp } );
 | 
			
		||||
 | 
			
		||||
        my $backupFile = ReadingsVal( $name, 'fhemBackupFile', 'none' );
 | 
			
		||||
 | 
			
		||||
        my @fileNameAtStorage_array = split( '/', $backupFile );
 | 
			
		||||
        my $fileNameAtStorage = $fileNameAtStorage_array[$#fileNameAtStorage_array];
 | 
			
		||||
 | 
			
		||||
        $subprocess->{curl}                 = qx(which curl);
 | 
			
		||||
        chomp($subprocess->{curl});
 | 
			
		||||
        $subprocess->{type}                 = $hash->{STORAGETYPE};
 | 
			
		||||
        $subprocess->{host}                 = AttrVal( $name, 'bTS_Host', '' );
 | 
			
		||||
        $subprocess->{user}                 = AttrVal( $name, 'bTS_User', '' );
 | 
			
		||||
        $subprocess->{pass}                 = ReadPassword( $hash, $name );
 | 
			
		||||
        $subprocess->{path}                 = AttrVal( $name, 'bTS_Path', '' );
 | 
			
		||||
        $subprocess->{fileNameAtStorage}    = $fileNameAtStorage;
 | 
			
		||||
        $subprocess->{proto}                = AttrVal( $name, 'bTS_Proto', 'https' );
 | 
			
		||||
        $subprocess->{loglevel}             = AttrVal( $name, 'verbose', 3 );
 | 
			
		||||
        $subprocess->{keeplastn}            = AttrVal( $name, 'bTS_KeepLastBackups', 5 );
 | 
			
		||||
 | 
			
		||||
        my $pid = $subprocess->run();
 | 
			
		||||
 | 
			
		||||
        readingsSingleUpdate( $hash, 'state', ' clean up pass last N in progress', 1 );
 | 
			
		||||
 | 
			
		||||
        if ( !defined($pid) ) {
 | 
			
		||||
            Log3( $name, 1,
 | 
			
		||||
                qq{backupToStorage ($name) - Cannot execute command asynchronously} );
 | 
			
		||||
 | 
			
		||||
            CleanSubprocess($hash);
 | 
			
		||||
            readingsSingleUpdate( $hash, 'state',
 | 
			
		||||
                'Cannot execute command asynchronously', 1 );
 | 
			
		||||
            return undef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Log3( $name, 4,
 | 
			
		||||
            qq{backupToStorage ($name) - execute command asynchronously (PID="$pid"})
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $hash->{".fhem"}{subprocess} = $subprocess;
 | 
			
		||||
@@ -540,7 +607,7 @@ sub ExecuteNCupload {
 | 
			
		||||
    my $subprocess = shift;
 | 
			
		||||
 | 
			
		||||
    my $command = $subprocess->{curl};
 | 
			
		||||
    $command .= ' -k -u ';
 | 
			
		||||
    $command .= ' -k -X PUT -u ';
 | 
			
		||||
    $command .= $subprocess->{user} . ':' . $subprocess->{pass};
 | 
			
		||||
    $command .= ' -T ' . $subprocess->{backupfile};
 | 
			
		||||
    $command .= ' "' . $subprocess->{proto} . '://';
 | 
			
		||||
@@ -555,6 +622,81 @@ sub ExecuteNCupload {
 | 
			
		||||
    return ExecuteCommand($command);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub CleanUp {
 | 
			
		||||
    my $subprocess = shift;
 | 
			
		||||
    my $response   = {};
 | 
			
		||||
 | 
			
		||||
    if ( $subprocess->{type} eq 'Nextcloud' ) {
 | 
			
		||||
        my ($returnString,$returnCode) = ExecuteCleanUp($subprocess);
 | 
			
		||||
        
 | 
			
		||||
        print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: '
 | 
			
		||||
            . $returnCode
 | 
			
		||||
            . ' , returnString: '
 | 
			
		||||
            . $returnString . "\n"
 | 
			
		||||
          if ( $subprocess->{loglevel} > 4 );
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        if (  $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m
 | 
			
		||||
          and $returnString =~ /\s\s<o:hint xmlns:o="o:">(.*)<\/o:hint>/m ) {
 | 
			
		||||
            $response->{ncUpload} = $1;
 | 
			
		||||
        }
 | 
			
		||||
        elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m ) {
 | 
			
		||||
            $response->{ncUpload} = 'upload successfully';
 | 
			
		||||
        }
 | 
			
		||||
        elsif ( $returnString =~ /(curl:\s.*)/ ){
 | 
			
		||||
            $response->{ncUpload} = $1;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $response->{ncUpload} = 'unknown error';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $json = eval { encode_json($response) };
 | 
			
		||||
    if ($@) {
 | 
			
		||||
        print 'backupToStorage File Upload backupToStorage - JSON error: $@'
 | 
			
		||||
            . "\n";
 | 
			
		||||
        $json = '{"jsonerror":"$@"}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $subprocess->writeToParent($json);
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ExecuteNCfetchFileList {
 | 
			
		||||
    my $subprocess = shift;
 | 
			
		||||
 | 
			
		||||
    my $command = $subprocess->{curl};
 | 
			
		||||
    $command .= ' -k -X PROPFIND -u ';
 | 
			
		||||
    $command .= $subprocess->{user} . ':' . $subprocess->{pass};
 | 
			
		||||
    $command .= ' "' . $subprocess->{proto} . '://';
 | 
			
		||||
    $command .= $subprocess->{host};
 | 
			
		||||
    $command .= '/remote.php/dav/files/';
 | 
			
		||||
    $command .= $subprocess->{user};
 | 
			
		||||
    $command .= $subprocess->{path};
 | 
			
		||||
    $command .= '" --data \'<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:"><d:prop xmlns:oc="http://owncloud.org/ns"><d:getlastmodified/></d:prop></d:propfind>\'';
 | 
			
		||||
 | 
			
		||||
    return ExecuteCommand($command);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ExecuteNCremoveFile {
 | 
			
		||||
    my $subprocess = shift;
 | 
			
		||||
 | 
			
		||||
    my $command = $subprocess->{curl};
 | 
			
		||||
    $command .= ' -k -X DELETE -u ';
 | 
			
		||||
    $command .= $subprocess->{user} . ':' . $subprocess->{pass};
 | 
			
		||||
    $command .= ' "' . $subprocess->{proto} . '://';
 | 
			
		||||
    $command .= $subprocess->{host};
 | 
			
		||||
    $command .= '/remote.php/dav/files/';
 | 
			
		||||
    $command .= $subprocess->{user};
 | 
			
		||||
    $command .= $subprocess->{path};
 | 
			
		||||
    $command .= '/';
 | 
			
		||||
    $command .= $subprocess->{fileNameAtStorage};
 | 
			
		||||
    $command .= '"';
 | 
			
		||||
 | 
			
		||||
    return ExecuteCommand($command);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ExecuteCommand {
 | 
			
		||||
    my $command = join q{ }, @_;
 | 
			
		||||
    return ( $_ = qx{$command 2>&1}, $? >> 8 );
 | 
			
		||||
@@ -598,9 +740,10 @@ sub StorePassword {
 | 
			
		||||
    my $err = setKeyValue( $index, $enc_pwd );
 | 
			
		||||
    DoTrigger( $name, 'password add' );
 | 
			
		||||
 | 
			
		||||
    return qq{error while saving the password - $err} if ( defined($err) );
 | 
			
		||||
    return qq{error while saving the password - $err}
 | 
			
		||||
      if ( defined($err) );
 | 
			
		||||
 | 
			
		||||
    return qq{password successfully saved};
 | 
			
		||||
    return q{password successfully saved};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ReadPassword {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user