Merge pull request 'patch-rewrite' (#3) from patch-rewrite into dev
Reviewed-on: #3
This commit is contained in:
		| @@ -1,8 +1,8 @@ | |||||||
| ############################################################################### | ############################################################################### | ||||||
| # | # | ||||||
| # Developed with Kate | # Developed with VSCodium and richterger perl plugin | ||||||
| # | # | ||||||
| #  (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net)  | #  (c) 2020-2023 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) | ||||||
| #  All rights reserved | #  All rights reserved | ||||||
| # | # | ||||||
| #   Special thanks goes to: | #   Special thanks goes to: | ||||||
| @@ -29,28 +29,33 @@ | |||||||
| # | # | ||||||
| ############################################################################### | ############################################################################### | ||||||
|  |  | ||||||
| package main; | package FHEM::backupToStorage; | ||||||
|  |  | ||||||
| use strict; | use strict; | ||||||
| use warnings; | use warnings; | ||||||
| use utf8; | use utf8; | ||||||
| use FHEM::Meta; | use FHEM::Meta; | ||||||
|  |  | ||||||
| use FHEM::Services::backupToStorage; | require FHEM::Services::backupToStorage; | ||||||
|  |  | ||||||
| sub backupToStorage_Initialize { | #-- Run before package compilation | ||||||
|  | BEGIN { | ||||||
|  |     sub ::backupToStorage_Initialize { goto &Initialize } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | sub Initialize { | ||||||
|     my $hash = shift; |     my $hash = shift; | ||||||
|  |  | ||||||
| ## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname | ## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname | ||||||
|     #  und davor mit :: getrennt der eigentliche package Name des Modules |     #  und davor mit :: getrennt der eigentliche package Name des Modules | ||||||
|     $hash->{SetFn}      = \&FHEM::Services::backupToStorage::Set; |     $hash->{SetFn}             = \&FHEM::Services::backupToStorage::Set; | ||||||
|     $hash->{DefFn}      = \&FHEM::Services::backupToStorage::Define; |     $hash->{DefFn}             = \&FHEM::Services::backupToStorage::Define; | ||||||
|     $hash->{NotifyFn}   = \&FHEM::Services::backupToStorage::Notify; |     $hash->{NotifyFn}          = \&FHEM::Services::backupToStorage::Notify; | ||||||
|     $hash->{UndefFn}    = \&FHEM::Services::backupToStorage::Undef; |     $hash->{UndefFn}           = \&FHEM::Services::backupToStorage::Undef; | ||||||
|     $hash->{AttrFn}     = \&FHEM::Services::backupToStorage::Attr; |     $hash->{AttrFn}            = \&FHEM::Services::backupToStorage::Attr; | ||||||
|     $hash->{RenameFn}   = \&FHEM::Services::backupToStorage::Rename; |     $hash->{RenameFn}          = \&FHEM::Services::backupToStorage::Rename; | ||||||
|     $hash->{DeleteFn}   = \&FHEM::Services::backupToStorage::Delete; |     $hash->{DeleteFn}          = \&FHEM::Services::backupToStorage::Delete; | ||||||
|     $hash->{ShutdownFn} = \&FHEM::Services::backupToStorage::Shutdown; |     $hash->{ShutdownFn}        = \&FHEM::Services::backupToStorage::Shutdown; | ||||||
|     $hash->{NotifyOrderPrefix} = '51-';    # Order Nummer für NotifyFn |     $hash->{NotifyOrderPrefix} = '51-';    # Order Nummer für NotifyFn | ||||||
|     $hash->{AttrList} = |     $hash->{AttrList} = | ||||||
|         'bTS_Host ' |         'bTS_Host ' | ||||||
| @@ -76,13 +81,14 @@ sub backupToStorage_Initialize { | |||||||
|  |  | ||||||
| =begin html | =begin html | ||||||
|  |  | ||||||
| <a name="backupToStorage"></a> | <a id="backupToStorage"></a> | ||||||
| <h3>backupToStorage</h3> | <h3>backupToStorage</h3> | ||||||
| <ul> | <ul> | ||||||
|     The module offers the possibility to automatically load the created backup files from the backup module onto a storage.<br> |     The module offers the possibility to automatically load the created backup files from the backup module onto a storage.<br> | ||||||
|     <a name="backupToStoragedefine"></a> |     <a name="backupToStoragedefine"></a> | ||||||
|     <br> |     <br> | ||||||
|     <b>Define</b> |     <a id="backupToStorage-define"></a> | ||||||
|  |     <h4>Define</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <code>define <name> backupToStorage</code> |         <code>define <name> backupToStorage</code> | ||||||
|         <br> |         <br> | ||||||
| @@ -92,28 +98,46 @@ sub backupToStorage_Initialize { | |||||||
|         </ul> |         </ul> | ||||||
|         <br> |         <br> | ||||||
|     </ul> |     </ul> | ||||||
|     <a name="backupToStorageattributes"></a> |     <a id="backupToStorage-attr"></a> | ||||||
|     <b>Attributs</b> |     <h4>Attributs</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>bTS_Host - Server name where the storage is located</li> |         <a id="backupToStorage-attr-bTS_Host"></a> | ||||||
|         <li>bTS_User - remote user for login</li> |         <li><i>bTS_Host</i> | ||||||
|         <li>bTS_Path - remote path where the upload file should go. e.g. Nextcloud </FHEM-Backup></li> |             Server name where the storage is located | ||||||
|         <li>bTS_Type - Storage Type, default is Nextcloud</li> |         </li> | ||||||
|  |         <a id="backupToStorage-attr-bTS_User"></a> | ||||||
|  |         <li><i>bTS_User</i> | ||||||
|  |             remote user for login | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-attr-bTS_Path"></a> | ||||||
|  |         <li><i>bTS_Path</i> | ||||||
|  |             remote path where the upload file should go. e.g. Nextcloud </FHEM-Backup> | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-attr-bTS_Type"></a> | ||||||
|  |         <li><i>bTS_Type</i> | ||||||
|  |             Storage Type, default is Nextcloud | ||||||
|  |         </li> | ||||||
|     </ul> |     </ul> | ||||||
|     <br> |     <br> | ||||||
|     <a name="backupToStorageset"></a> |     <a id="backupToStorage-set"></a> | ||||||
|     <b>Set</b> |     <h4>Set</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>addpassword - puts the storage password in the keyfile / !!! don't use = !!!</li> |         <a id="backupToStorage-set-addpassword"></a> | ||||||
|         <li>deletepassword - removes the storage password from the keyfile</li> |         <li><i>addpassword</i> | ||||||
|  |             puts the storage password in the keyfile / !!! don't use = !!! | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-set-deletepassword"></a> | ||||||
|  |         <li><i>deletepassword</i> | ||||||
|  |             removes the storage password from the keyfile | ||||||
|  |         </li> | ||||||
|     </ul> |     </ul> | ||||||
|     <br> |     <br> | ||||||
|     <a name="backupToStoragereadings"></a> |     <a id="backupToStorage-readings"></a> | ||||||
|     <b>Readings</b> |     <b>Readings</b> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>state - shows the current status of the module</li> |         <li><b>state</b> - shows the current status of the module</li> | ||||||
|         <li>fhemBackupFile - the path of the last backup file is automatically set by the backup module</li> |         <li><b>fhemBackupFile</b> - the path of the last backup file is automatically set by the backup module</li> | ||||||
|         <li>uploadState - Status of the last upload.</li> |         <li><b>uploadState</b> - Status of the last upload.</li> | ||||||
|     </ul> |     </ul> | ||||||
| </ul> | </ul> | ||||||
|  |  | ||||||
| @@ -121,13 +145,14 @@ sub backupToStorage_Initialize { | |||||||
|  |  | ||||||
| =begin html_DE | =begin html_DE | ||||||
|  |  | ||||||
| <a name="backupToStorage"></a> | <a id="backupToStorage"></a> | ||||||
| <h3>backupToStorage</h3> | <h3>backupToStorage</h3> | ||||||
| <ul> | <ul> | ||||||
|     Das Modul bietet die Möglichkeit die erstellten Backupdateien vom Modul backup automatisiert auf ein Storage zu laden.<br> |     Das Modul bietet die Möglichkeit die erstellten Backupdateien vom Modul backup automatisiert auf ein Storage zu laden.<br> | ||||||
|     <a name="backupToStoragedefine"></a> |     <a name="backupToStoragedefine"></a> | ||||||
|     <br> |     <br> | ||||||
|     <b>Define</b> |     <a id="backupToStorage-define"></a> | ||||||
|  |     <h4>Define</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <code>define <name> backupToStorage</code> |         <code>define <name> backupToStorage</code> | ||||||
|         <br> |         <br> | ||||||
| @@ -137,29 +162,46 @@ sub backupToStorage_Initialize { | |||||||
|         </ul> |         </ul> | ||||||
|         <br> |         <br> | ||||||
|     </ul> |     </ul> | ||||||
|     <a name="backupToStorageattributes"></a> |     <a id="backupToStorage-attr"></a> | ||||||
|     <b>Attribute</b> |     <h4>Attribute</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>bTS_Host - Servername wo sich das Storage drauf befindet</li> |         <a id="backupToStorage-attr-bTS_Host"></a> | ||||||
|         <li>bTS_User - remote User für den Login</li> |         <li><i>bTS_Host</i> | ||||||
|         <li>bTS_Path - remote Path wohin das uploadfile soll. z.B. Nextcloud </FHEM-Backup></li> |             Servername wo sich das Storage drauf befindet | ||||||
|         <li>bTS_Type - Storage Type, default ist Nextcloud</li> |         </li> | ||||||
|         <li>bTS_Type - Storage Type, default ist Nextcloud</li> |         <a id="backupToStorage-attr-bTS_User"></a> | ||||||
|  |         <li><i>bTS_User</i> | ||||||
|  |             remote User für den Login | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-attr-bTS_Path"></a> | ||||||
|  |         <li><i>bTS_Path</i> | ||||||
|  |             remote Path wohin das uploadfile soll. z.B. Nextcloud </FHEM-Backup> | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-attr-bTS_Type"></a> | ||||||
|  |         <li><i>bTS_Type</i> | ||||||
|  |             Storage Type, default ist Nextcloud | ||||||
|  |         </li> | ||||||
|     </ul> |     </ul> | ||||||
|     <br> |     <br> | ||||||
|     <a name="backupToStorageset"></a> |     <a id="backupToStorage-set"></a> | ||||||
|     <b>Set</b> |     <h4>Set</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>addpassword - setzt das Storage Passwort ins Keyfile / !!!Keine = verwenden!!!</li> |         <a id="backupToStorage-set-addpassword"></a> | ||||||
|         <li>deletepassword - entfernt das Storage Passwort aus dem Keyfile</li> |         <li><i>addpassword</i><br> | ||||||
|  |             setzt das Storage Passwort ins Keyfile / !!!Keine = verwenden!!! | ||||||
|  |         </li> | ||||||
|  |         <a id="backupToStorage-set-deletepassword"></a> | ||||||
|  |         <li><i>deletepassword</i><br> | ||||||
|  |             entfernt das Storage Passwort aus dem Keyfile | ||||||
|  |         </li> | ||||||
|     </ul> |     </ul> | ||||||
|     <br> |     <br> | ||||||
|     <a name="backupToStoragereadings"></a> |     <a id="backupToStorage-readings"></a> | ||||||
|     <b>Readings</b> |     <h4>Readings</h4> | ||||||
|     <ul> |     <ul> | ||||||
|         <li>state - zeigt den aktuellen Status des Modules an</li> |         <li><b>state</b> - zeigt den aktuellen Status des Modules an</li> | ||||||
|         <li>fhemBackupFile - der Pfad des letzten Backupfiles, wird automatisch vom backup Modul gesetzt</li> |         <li><b>fhemBackupFile</b> - der Pfad des letzten Backupfiles, wird automatisch vom backup Modul gesetzt</li> | ||||||
|         <li>uploadState - Status des letzten uploads.</li> |         <li><b>uploadState</b> - Status des letzten uploads.</li> | ||||||
|     </ul> |     </ul> | ||||||
| </ul> | </ul> | ||||||
|  |  | ||||||
| @@ -181,15 +223,15 @@ sub backupToStorage_Initialize { | |||||||
|   ], |   ], | ||||||
|   "release_status": "devepolment", |   "release_status": "devepolment", | ||||||
|   "license": "GPL_2", |   "license": "GPL_2", | ||||||
|   "version": "v1.3.1", |   "version": "v2.0.0", | ||||||
|   "author": [ |   "author": [ | ||||||
|     "Marko Oldenburg <fhemsupport@cooltux.net>" |     "Marko Oldenburg <fhemdevelopment@cooltux.net>" | ||||||
|   ], |   ], | ||||||
|   "x_fhem_maintainer": [ |   "x_fhem_maintainer": [ | ||||||
|     "CoolTux" |     "CoolTux" | ||||||
|   ], |   ], | ||||||
|   "x_fhem_maintainer_github": [ |   "x_fhem_maintainer_github": [ | ||||||
|     "LeonGaultier" |     "CoolTuxNet" | ||||||
|   ], |   ], | ||||||
|   "prereqs": { |   "prereqs": { | ||||||
|     "runtime": { |     "runtime": { | ||||||
|   | |||||||
| @@ -1,2 +1,2 @@ | |||||||
| UPD 2021-11-09_13:08:21 6508 FHEM/98_backupToStorage.pm | UPD 2023-01-05_20:43:08 7708 FHEM/98_backupToStorage.pm | ||||||
| UPD 2021-11-09_13:55:09 24286 lib/FHEM/Services/backupToStorage.pm | UPD 2023-01-05_20:06:46 23352 lib/FHEM/Services/backupToStorage.pm | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| ############################################################################### | ############################################################################### | ||||||
| # | # | ||||||
| # Developed with Kate | # Developed with VSCodium and richterger perl plugin | ||||||
| # | # | ||||||
| #  (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net) | #  (c) 2020-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) | ||||||
| #  All rights reserved | #  All rights reserved | ||||||
| # | # | ||||||
| #   Special thanks goes to: | #   Special thanks goes to: | ||||||
| @@ -37,7 +37,15 @@ use utf8; | |||||||
|  |  | ||||||
| use GPUtils qw(GP_Import); | use GPUtils qw(GP_Import); | ||||||
|  |  | ||||||
| use Data::Dumper;    #only for Debugging | BEGIN { | ||||||
|  |  | ||||||
|  |     # Import from main context | ||||||
|  |     GP_Import( | ||||||
|  |         qw( init_done | ||||||
|  |           defs | ||||||
|  |           ) | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
| # try to use JSON::MaybeXS wrapper | # try to use JSON::MaybeXS wrapper | ||||||
| #   for chance of better performance + open code | #   for chance of better performance + open code | ||||||
| @@ -45,15 +53,11 @@ eval { | |||||||
|     require JSON::MaybeXS; |     require JSON::MaybeXS; | ||||||
|     import JSON::MaybeXS qw( decode_json encode_json ); |     import JSON::MaybeXS qw( decode_json encode_json ); | ||||||
|     1; |     1; | ||||||
| }; | } or do { | ||||||
|  |  | ||||||
| if ($@) { |  | ||||||
|     $@ = undef; |  | ||||||
|  |  | ||||||
|     # try to use JSON wrapper |     # try to use JSON wrapper | ||||||
|     #   for chance of better performance |     #   for chance of better performance | ||||||
|     eval { |     eval { | ||||||
|  |  | ||||||
|         # JSON preference order |         # JSON preference order | ||||||
|         local $ENV{PERL_JSON_BACKEND} = |         local $ENV{PERL_JSON_BACKEND} = | ||||||
|           'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP' |           'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP' | ||||||
| @@ -62,10 +66,7 @@ if ($@) { | |||||||
|         require JSON; |         require JSON; | ||||||
|         import JSON qw( decode_json encode_json ); |         import JSON qw( decode_json encode_json ); | ||||||
|         1; |         1; | ||||||
|     }; |     } or do { | ||||||
|  |  | ||||||
|     if ($@) { |  | ||||||
|         $@ = undef; |  | ||||||
|  |  | ||||||
|         # In rare cases, Cpanel::JSON::XS may |         # In rare cases, Cpanel::JSON::XS may | ||||||
|         #   be installed but JSON|JSON::MaybeXS not ... |         #   be installed but JSON|JSON::MaybeXS not ... | ||||||
| @@ -73,10 +74,7 @@ if ($@) { | |||||||
|             require Cpanel::JSON::XS; |             require Cpanel::JSON::XS; | ||||||
|             import Cpanel::JSON::XS qw(decode_json encode_json); |             import Cpanel::JSON::XS qw(decode_json encode_json); | ||||||
|             1; |             1; | ||||||
|         }; |         } or do { | ||||||
|  |  | ||||||
|         if ($@) { |  | ||||||
|             $@ = undef; |  | ||||||
|  |  | ||||||
|             # In rare cases, JSON::XS may |             # In rare cases, JSON::XS may | ||||||
|             #   be installed but JSON not ... |             #   be installed but JSON not ... | ||||||
| @@ -84,10 +82,7 @@ if ($@) { | |||||||
|                 require JSON::XS; |                 require JSON::XS; | ||||||
|                 import JSON::XS qw(decode_json encode_json); |                 import JSON::XS qw(decode_json encode_json); | ||||||
|                 1; |                 1; | ||||||
|             }; |             } or do { | ||||||
|  |  | ||||||
|             if ($@) { |  | ||||||
|                 $@ = undef; |  | ||||||
|  |  | ||||||
|                 # Fallback to built-in JSON which SHOULD |                 # Fallback to built-in JSON which SHOULD | ||||||
|                 #   be available since 5.014 ... |                 #   be available since 5.014 ... | ||||||
| @@ -95,73 +90,41 @@ if ($@) { | |||||||
|                     require JSON::PP; |                     require JSON::PP; | ||||||
|                     import JSON::PP qw(decode_json encode_json); |                     import JSON::PP qw(decode_json encode_json); | ||||||
|                     1; |                     1; | ||||||
|                 }; |                 } or do { | ||||||
|  |  | ||||||
|                 if ($@) { |  | ||||||
|                     $@ = undef; |  | ||||||
|  |  | ||||||
|                     # Fallback to JSON::backportPP in really rare cases |                     # Fallback to JSON::backportPP in really rare cases | ||||||
|                     require JSON::backportPP; |                     require JSON::backportPP; | ||||||
|                     import JSON::backportPP qw(decode_json encode_json); |                     import JSON::backportPP qw(decode_json encode_json); | ||||||
|                     1; |                     1; | ||||||
|                 } |                 }; | ||||||
|             } |             }; | ||||||
|         } |         }; | ||||||
|     } |     }; | ||||||
| } | }; | ||||||
|  |  | ||||||
| ## Import der FHEM Funktionen |  | ||||||
| #-- Run before package compilation |  | ||||||
| BEGIN { |  | ||||||
|  |  | ||||||
|     # Import from main context |  | ||||||
|     GP_Import( |  | ||||||
|         qw( |  | ||||||
|           readingsSingleUpdate |  | ||||||
|           readingsBulkUpdate |  | ||||||
|           readingsBeginUpdate |  | ||||||
|           readingsEndUpdate |  | ||||||
|           ReadingsVal |  | ||||||
|           ReadingsAge |  | ||||||
|           gettimeofday |  | ||||||
|           InternalTimer |  | ||||||
|           defs |  | ||||||
|           modules |  | ||||||
|           IsDisabled |  | ||||||
|           setKeyValue |  | ||||||
|           getKeyValue |  | ||||||
|           getUniqueId |  | ||||||
|           Log3 |  | ||||||
|           CommandAttr |  | ||||||
|           attr |  | ||||||
|           AttrVal |  | ||||||
|           deviceEvents |  | ||||||
|           init_done |  | ||||||
|           devspec2array |  | ||||||
|           DoTrigger |  | ||||||
|           HttpUtils_NonblockingGet) |  | ||||||
|     ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| sub Define { | sub Define { | ||||||
|  |     use version 0.60; | ||||||
|  |  | ||||||
|     my $hash = shift // return; |     my $hash = shift // return; | ||||||
|     my $aArg = shift // return; |     my $aArg = shift // return; | ||||||
|  |  | ||||||
|     return $@ unless ( FHEM::Meta::SetInternals($hash) ); |     return $@ unless ( FHEM::Meta::SetInternals($hash) ); | ||||||
|     use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); |  | ||||||
|  |     $version = FHEM::Meta::Get( $hash, 'version' ); | ||||||
|  |     our $VERSION = $version; | ||||||
|  |  | ||||||
|     return q{only one backupToStorage instance allowed} |     return q{only one backupToStorage instance allowed} | ||||||
|       if ( devspec2array('TYPE=backupToStorage') > 1 ) |       if ( ::devspec2array('TYPE=backupToStorage') > 1 ) | ||||||
|       ; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen |       ; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen | ||||||
|     return q{too few parameters: define <name> backupToStorage} |     return q{too few parameters: define <name> backupToStorage} | ||||||
|       if ( scalar( @{$aArg} ) != 2 ); |       if ( scalar( @{$aArg} ) != 2 ); | ||||||
|  |  | ||||||
|     my $name = shift @$aArg; |     my $name = shift @$aArg; | ||||||
|     $hash->{VERSION}        = version->parse($VERSION)->normal; |     $hash->{VERSION}     = version->parse($VERSION)->normal; | ||||||
|     $hash->{NOTIFYDEV}      = 'global,' . $name; |     $hash->{NOTIFYDEV}   = 'global,' . $name; | ||||||
|     $hash->{STORAGETYPE}    = AttrVal( $name, 'bTS_Type', 'Nextcloud' ); |     $hash->{STORAGETYPE} = ::AttrVal( $name, 'bTS_Type', 'Nextcloud' ); | ||||||
|  |  | ||||||
|     Log3( $name, 3, qq{backupToStorage ($name) - defined} ); |     ::Log3( $name, 3, qq{backupToStorage ($name) - defined} ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| @@ -170,7 +133,7 @@ sub Undef { | |||||||
|     my $hash = shift; |     my $hash = shift; | ||||||
|     my $name = shift; |     my $name = shift; | ||||||
|  |  | ||||||
|     Log3( $name, 3, q{qbackupToStorage ($name) - delete device $name} ); |     ::Log3( $name, 3, q{qbackupToStorage ($name) - delete device $name} ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| @@ -180,7 +143,7 @@ sub Delete { | |||||||
|     my $name = shift; |     my $name = shift; | ||||||
|  |  | ||||||
|     HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) |     HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) | ||||||
|       if ( defined($hash->{helper}->{HttpUtilsParam}) ); |       if ( defined( $hash->{helper}->{HttpUtilsParam} ) ); | ||||||
|     DeletePassword($hash); |     DeletePassword($hash); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| @@ -190,7 +153,7 @@ sub Shutdown { | |||||||
|     my $hash = shift; |     my $hash = shift; | ||||||
|  |  | ||||||
|     HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) |     HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) | ||||||
|       if ( defined($hash->{helper}->{HttpUtilsParam}) ); |       if ( defined( $hash->{helper}->{HttpUtilsParam} ) ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| @@ -202,35 +165,31 @@ sub Notify { | |||||||
|     my $name    = $hash->{NAME}; |     my $name    = $hash->{NAME}; | ||||||
|     my $devname = $dev->{NAME}; |     my $devname = $dev->{NAME}; | ||||||
|     my $devtype = $dev->{TYPE}; |     my $devtype = $dev->{TYPE}; | ||||||
|     my $events  = deviceEvents( $dev, 1 ); |     my $events  = ::deviceEvents( $dev, 1 ); | ||||||
|      |  | ||||||
|     _CheckIsDisabledAfterSetAttr($hash) |     _CheckIsDisabledAfterSetAttr($hash) | ||||||
|         if ( ( |       if ( | ||||||
|                 ( |         ( | ||||||
|                     grep m{^DELETEATTR.$name.(disable|disabledForIntervals)$}xms, |             ( | ||||||
|                     @{$events} |                 grep { /^DELETEATTR.$name.(disable|disabledForIntervals)$/x } | ||||||
|                     or grep m{^ATTR.$name.(disable|disabledForIntervals).\S+$}xms, |                 @{$events} | ||||||
|                     @{$events} |                 or grep { /^ATTR.$name.(disable|disabledForIntervals).\S+$/x } | ||||||
|                 ) |                 @{$events} | ||||||
|                 && $devname eq 'global' |  | ||||||
|                 && $init_done |  | ||||||
|             ) |             ) | ||||||
|             || $devname eq $name |             && $devname eq 'global' | ||||||
|         ); |             && $init_done | ||||||
|  |         ) | ||||||
|  |         || $devname eq $name | ||||||
|  |       ); | ||||||
|  |  | ||||||
|     return if (    !$events |     return if ( !$events | ||||||
|                 || IsDisabled($name) ); |         || ::IsDisabled($name) ); | ||||||
|  |  | ||||||
|  |     ::Log3( $name, 4, | ||||||
|     Log3( $name, 4, |         qq{backupToStorage ($name) - Devname: $devname  Name: $name Notify: } ); | ||||||
|             qq{backupToStorage ($name) - |  | ||||||
|           Devname: $devname  |  | ||||||
|           Name: $name |  | ||||||
|           Notify: } . Dumper $events |  | ||||||
|     );    # mit Dumper |  | ||||||
|  |  | ||||||
|     PushToStorage($hash) |     PushToStorage($hash) | ||||||
|       if ( ( grep m{^backup.done(.+)?$}xms, @{$events} ) |       if ( ( grep { /^backup.done(.+)?$/x } @{$events} ) | ||||||
|         && $devname eq 'global' |         && $devname eq 'global' | ||||||
|         && $init_done ); |         && $init_done ); | ||||||
|  |  | ||||||
| @@ -239,16 +198,16 @@ sub Notify { | |||||||
|         ( |         ( | ||||||
|             ( |             ( | ||||||
|                 ( |                 ( | ||||||
|                     grep m{^DELETEATTR.$name.(bTS_Host|bTS_User)$}xms, |                     grep { /^DELETEATTR.$name.(bTS_Host|bTS_User)$/x } | ||||||
|                     @{$events} |                     @{$events} | ||||||
|                     or grep m{^ATTR.$name.(bTS_Host|bTS_User).\S+$}xms, |                     or grep { /^ATTR.$name.(bTS_Host|bTS_User).\S+$/x } | ||||||
|                     @{$events} |                     @{$events} | ||||||
|                 ) |                 ) | ||||||
|                 && $devname eq 'global' |                 && $devname eq 'global' | ||||||
|             ) |             ) | ||||||
|             || ( |             || ( | ||||||
|                 ( |                 ( | ||||||
|                     $devname eq $name && grep m{^password.(add|remove)$}xms, |                     $devname eq $name && grep { /^password.(add|remove)$/x } | ||||||
|                     @{$events} |                     @{$events} | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
| @@ -260,8 +219,8 @@ sub Notify { | |||||||
|         $hash, 'state', |         $hash, 'state', | ||||||
|         ( |         ( | ||||||
|             ( |             ( | ||||||
|                      AttrVal( $name, 'bTS_Host', 'none' ) eq 'none' |                      ::AttrVal( $name, 'bTS_Host', 'none' ) eq 'none' | ||||||
|                   || AttrVal( $name, 'bTS_User', 'none' ) eq 'none' |                   || ::AttrVal( $name, 'bTS_User', 'none' ) eq 'none' | ||||||
|                   || !defined( ReadPassword( $hash, $name ) ) |                   || !defined( ReadPassword( $hash, $name ) ) | ||||||
|             ) |             ) | ||||||
|             ? 'please set storage account credentials first' |             ? 'please set storage account credentials first' | ||||||
| @@ -271,16 +230,13 @@ sub Notify { | |||||||
|       ) |       ) | ||||||
|       if ( |       if ( | ||||||
|         ( |         ( | ||||||
|                ( grep m{^DEFINED.$name$}xms, @{$events} ) |                ( grep { /^DEFINED.$name$/x } @{$events} ) | ||||||
|             && $devname eq 'global' |             && $devname eq 'global' | ||||||
|             && $init_done |             && $init_done | ||||||
|         ) |         ) | ||||||
|         || ( |         || (   grep { /^INITIALIZED$/x } @{$events} | ||||||
|             grep m{^INITIALIZED$}xms, |             or grep { /^REREADCFG$/x } @{$events} | ||||||
|             @{$events} or grep m{^REREADCFG$}xms, |             or grep { /^MODIFIED.$name$/x } @{$events} ) | ||||||
|             @{$events} or grep m{^MODIFIED.$name$}xms, |  | ||||||
|             @{$events} |  | ||||||
|         ) |  | ||||||
|         && $devname eq 'global' |         && $devname eq 'global' | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
| @@ -297,7 +253,7 @@ sub Set { | |||||||
|  |  | ||||||
|     if ( lc $cmd eq 'addpassword' ) { |     if ( lc $cmd eq 'addpassword' ) { | ||||||
|         return q{please set Attribut bTS_User first} |         return q{please set Attribut bTS_User first} | ||||||
|           if ( AttrVal( $name, 'bTS_User', 'none' ) eq 'none' ); |           if ( ::AttrVal( $name, 'bTS_User', 'none' ) eq 'none' ); | ||||||
|         return qq{usage: "$cmd" <password>} |         return qq{usage: "$cmd" <password>} | ||||||
|           if ( scalar( @{$aArg} ) != 1 ); |           if ( scalar( @{$aArg} ) != 1 ); | ||||||
|  |  | ||||||
| @@ -312,22 +268,22 @@ sub Set { | |||||||
|     elsif ( lc $cmd eq 'active' ) { |     elsif ( lc $cmd eq 'active' ) { | ||||||
|         return qq{usage: $cmd} |         return qq{usage: $cmd} | ||||||
|           if ( scalar( @{$aArg} ) != 0 ); |           if ( scalar( @{$aArg} ) != 0 ); | ||||||
|      |  | ||||||
|         readingsSingleUpdate( $hash, 'state', 'ready', 1 ); |         readingsSingleUpdate( $hash, 'state', 'ready', 1 ); | ||||||
|     } |     } | ||||||
|     elsif ( lc $cmd eq 'inactive' ) { |     elsif ( lc $cmd eq 'inactive' ) { | ||||||
|         return qq{usage: $cmd} |         return qq{usage: $cmd} | ||||||
|           if ( scalar( @{$aArg} ) != 0 ); |           if ( scalar( @{$aArg} ) != 0 ); | ||||||
|          |  | ||||||
|         readingsSingleUpdate( $hash, 'state', $cmd, 1 ); |         readingsSingleUpdate( $hash, 'state', $cmd, 1 ); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         my $list    = 'active:noArg inactive:noArg'; |         my $list = 'active:noArg inactive:noArg'; | ||||||
|         $list       .= ( |         $list .= ( | ||||||
|                       defined( ReadPassword( $hash, $name ) ) |             defined( ReadPassword( $hash, $name ) ) | ||||||
|                         ? ' deletepassword:noArg' |             ? ' deletepassword:noArg' | ||||||
|                         : ' addpassword' |             : ' addpassword' | ||||||
|                       ); |         ); | ||||||
|  |  | ||||||
|         return qq{Unknown argument "$cmd", choose one of $list}; |         return qq{Unknown argument "$cmd", choose one of $list}; | ||||||
|     } |     } | ||||||
| @@ -336,52 +292,68 @@ sub Set { | |||||||
| } | } | ||||||
|  |  | ||||||
| sub Attr { | sub Attr { | ||||||
|     my $cmd         = shift; |     my $cmd  = shift; | ||||||
|     my $name        = shift; |     my $name = shift; | ||||||
|  |  | ||||||
|     my $hash        = $defs{$name}; |     my $hash     = $defs{$name}; | ||||||
|     my $attrName    = shift; |     my $attrName = shift; | ||||||
|     my $attrVal     = shift; |     my $attrVal  = shift; | ||||||
|  |  | ||||||
|  |     if (   $attrName eq 'disable' | ||||||
|  |         || $attrName eq 'disabledForIntervals' ) | ||||||
|  |     { | ||||||
|  |  | ||||||
|     if ( $attrName eq 'disable' |  | ||||||
|       || $attrName eq 'disabledForIntervals' ) { |  | ||||||
|        |  | ||||||
|         if ( $cmd eq 'set' ) { |         if ( $cmd eq 'set' ) { | ||||||
|             if ( $attrName eq 'disabledForIntervals' ) { |             if ( $attrName eq 'disabledForIntervals' ) { | ||||||
|                 return |                 return | ||||||
|     'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...' | 'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...' | ||||||
|                 if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/ ); |                   if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/x ); | ||||||
|                 Log3( $name, 3, qq{backupToStorage ($name) - disabledForIntervals} ); |                 ::Log3( $name, 3, | ||||||
|  |                     qq{backupToStorage ($name) - disabledForIntervals} ); | ||||||
|             } |             } | ||||||
|             elsif ( $attrName eq 'disable' ) { |             elsif ( $attrName eq 'disable' ) { | ||||||
|                 Log3( $name, 3, qq{backupToStorage ($name) - disabled} ); |                 ::Log3( $name, 3, qq{backupToStorage ($name) - disabled} ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         InternalTimer( gettimeofday() + 1, |         ::InternalTimer( | ||||||
|             'FHEM::Services::backupToStorage::_CheckIsDisabledAfterSetAttr', $hash, 0 ); |             ::gettimeofday() + 1, | ||||||
|  |             'FHEM::Services::backupToStorage::_CheckIsDisabledAfterSetAttr', | ||||||
|  |             $hash, 0 | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|     elsif ( $attrName eq 'bTS_Type' ) { |     elsif ( $attrName eq 'bTS_Type' ) { | ||||||
|         InternalTimer( gettimeofday() + 1, |         ::InternalTimer( | ||||||
|             sub { $hash->{STORAGETYPE} = AttrVal($name,'bTS_Type','Nextcloud'); }, $hash, 0 ); |             ::gettimeofday() + 1, | ||||||
|  |             sub { | ||||||
|  |                 $hash->{STORAGETYPE} = | ||||||
|  |                   ::AttrVal( $name, 'bTS_Type', 'Nextcloud' ); | ||||||
|  |             }, | ||||||
|  |             $hash, | ||||||
|  |             0 | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
| sub _CheckIsDisabledAfterSetAttr { | sub _CheckIsDisabledAfterSetAttr { | ||||||
|     my $hash    = shift; |     my $hash = shift; | ||||||
|  |  | ||||||
|     my $name    = $hash->{NAME}; |     my $name  = $hash->{NAME}; | ||||||
|     my $state   = ( IsDisabled($name) |     my $state = ( | ||||||
|                     ? 'inactive' |         ::IsDisabled($name) | ||||||
|                     : 'ready' ); |         ? 'inactive' | ||||||
|                      |         : 'ready' | ||||||
|     Log3( $name, 3, qq{backupToStorage ($name) - _CheckIsDisabledAfterSetAttr} ); |     ); | ||||||
|  |  | ||||||
|     readingsSingleUpdate($hash, 'state', $state, 1) |     ::Log3( $name, 3, | ||||||
|       if ( ReadingsVal($name, 'state', 'ready' ) ne $state ); |         qq{backupToStorage ($name) - _CheckIsDisabledAfterSetAttr} ); | ||||||
|  |  | ||||||
|  |     readingsSingleUpdate( $hash, 'state', $state, 1 ) | ||||||
|  |       if ( ::ReadingsVal( $name, 'state', 'ready' ) ne $state ); | ||||||
|  |  | ||||||
|  |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
| sub Rename { | sub Rename { | ||||||
| @@ -391,7 +363,7 @@ sub Rename { | |||||||
|     my $hash = $defs{$new}; |     my $hash = $defs{$new}; | ||||||
|  |  | ||||||
|     StorePassword( $hash, $new, ReadPassword( $hash, $old ) ); |     StorePassword( $hash, $new, ReadPassword( $hash, $old ) ); | ||||||
|     setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); |     ::setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| @@ -401,66 +373,67 @@ sub PushToStorage { | |||||||
|  |  | ||||||
|     my $name = $hash->{NAME}; |     my $name = $hash->{NAME}; | ||||||
|  |  | ||||||
|     Log3( $name, 4, qq{backupToStorage ($name) - push to storage function} ); |     ::Log3( $name, 4, qq{backupToStorage ($name) - push to storage function} ); | ||||||
|      |  | ||||||
|     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} ); |  | ||||||
|  |  | ||||||
|  |     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} ); | ||||||
|  |  | ||||||
|     if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { |     if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { | ||||||
|      |  | ||||||
|      |  | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         require "SubProcess.pm"; |         require SubProcess; | ||||||
|         my $subprocess = SubProcess->new( { onRun => \&FileUpload } ); |         my $subprocess = SubProcess->new( { onRun => \&FileUpload } ); | ||||||
|  |  | ||||||
|         my $backupFile = ReadingsVal( $name, 'fhemBackupFile', 'none' ); |         my $backupFile = ::ReadingsVal( $name, 'fhemBackupFile', 'none' ); | ||||||
|  |  | ||||||
|         my @fileNameAtStorage_array = split( '/', $backupFile ); |         my @fileNameAtStorage_array = split( '/', $backupFile ); | ||||||
|         my $fileNameAtStorage = $fileNameAtStorage_array[$#fileNameAtStorage_array]; |         my $fileNameAtStorage = | ||||||
|  |           $fileNameAtStorage_array[$#fileNameAtStorage_array]; | ||||||
|  |  | ||||||
|         $subprocess->{curl}                 = qx(which curl); |         $subprocess->{curl} = qx(which curl); | ||||||
|         chomp($subprocess->{curl}); |         chomp( $subprocess->{curl} ); | ||||||
|         $subprocess->{fhemhost}             = qx(hostname -f); |         $subprocess->{fhemhost} = qx(hostname -f); | ||||||
|         chomp($subprocess->{fhemhost}); |         chomp( $subprocess->{fhemhost} ); | ||||||
|         $subprocess->{type}                 = $hash->{STORAGETYPE}; |         $subprocess->{type}              = $hash->{STORAGETYPE}; | ||||||
|         $subprocess->{host}                 = AttrVal( $name, 'bTS_Host', '' ); |         $subprocess->{host}              = ::AttrVal( $name, 'bTS_Host', '' ); | ||||||
|         $subprocess->{user}                 = AttrVal( $name, 'bTS_User', '' ); |         $subprocess->{user}              = ::AttrVal( $name, 'bTS_User', '' ); | ||||||
|         $subprocess->{pass}                 = ReadPassword( $hash, $name ); |         $subprocess->{pass}              = ReadPassword( $hash, $name ); | ||||||
|         $subprocess->{path}                 = AttrVal( $name, 'bTS_Path', '' ); |         $subprocess->{path}              = ::AttrVal( $name, 'bTS_Path', '' ); | ||||||
|         $subprocess->{backupfile}           = $backupFile; |         $subprocess->{backupfile}        = $backupFile; | ||||||
|         $subprocess->{fileNameAtStorage}    = $fileNameAtStorage; |         $subprocess->{fileNameAtStorage} = $fileNameAtStorage; | ||||||
|         $subprocess->{proto}                = AttrVal( $name, 'bTS_Proto', 'https' ); |         $subprocess->{proto}    = ::AttrVal( $name, 'bTS_Proto', 'https' ); | ||||||
|         $subprocess->{loglevel}             = AttrVal( $name, 'verbose', 3 ); |         $subprocess->{loglevel} = ::AttrVal( $name, 'verbose', 3 ); | ||||||
|  |  | ||||||
|         my $pid = $subprocess->run(); |         my $pid = $subprocess->run(); | ||||||
|  |  | ||||||
|         readingsSingleUpdate( $hash, 'state', ' file upload in progress', 1 ); |         readingsSingleUpdate( $hash, 'state', ' file upload in progress', 1 ); | ||||||
|  |  | ||||||
|         if ( !defined($pid) ) { |         if ( !defined($pid) ) { | ||||||
|             Log3( $name, 1, |             ::Log3( $name, 1, | ||||||
|                 qq{backupToStorage ($name) - Cannot execute command asynchronously} ); | qq{backupToStorage ($name) - Cannot execute command asynchronously} | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             CleanSubprocess($hash); |             CleanSubprocess($hash); | ||||||
|             readingsSingleUpdate( $hash, 'state', |             readingsSingleUpdate( $hash, 'state', | ||||||
|                 'Cannot execute command asynchronously', 1 ); |                 'Cannot execute command asynchronously', 1 ); | ||||||
|             return undef; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Log3( $name, 4, |         ::Log3( $name, 4, | ||||||
|             qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} | qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         $hash->{".fhem"}{subprocess} = $subprocess; |         $hash->{".fhem"}{subprocess} = $subprocess; | ||||||
|  |  | ||||||
|         InternalTimer( gettimeofday() + 1, |         ::InternalTimer( ::gettimeofday() + 1, | ||||||
|             "FHEM::Services::backupToStorage::PollChild", $hash ); |             "FHEM::Services::backupToStorage::PollChild", $hash ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Log3( $hash, 4, |     ::Log3( $hash, 4, | ||||||
|         qq{backupToStorage ($name) - control passed back to main loop.} ); |         qq{backupToStorage ($name) - control passed back to main loop.} ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| @@ -471,59 +444,61 @@ sub KeepLastN { | |||||||
|  |  | ||||||
|     my $name = $hash->{NAME}; |     my $name = $hash->{NAME}; | ||||||
|  |  | ||||||
|     Log3( $name, 4, qq{backupToStorage ($name) - Keep Last N at Storage function} ); |     ::Log3( $name, 4, | ||||||
|  |         qq{backupToStorage ($name) - Keep Last N at Storage function} ); | ||||||
|  |  | ||||||
|     if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { |     if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { | ||||||
|      |  | ||||||
|      |  | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         require "SubProcess.pm"; |         require SubProcess; | ||||||
|         my $subprocess = SubProcess->new( { onRun => \&CleanUp } ); |         my $subprocess = SubProcess->new( { onRun => \&CleanUp } ); | ||||||
|  |  | ||||||
|         my $backupFile = ReadingsVal( $name, 'fhemBackupFile', 'none' ); |         my $backupFile = ::ReadingsVal( $name, 'fhemBackupFile', 'none' ); | ||||||
|  |  | ||||||
|         my @fileNameAtStorage_array = split( '/', $backupFile ); |         my @fileNameAtStorage_array = split( '/', $backupFile ); | ||||||
|         my $fileNameAtStorage = $fileNameAtStorage_array[$#fileNameAtStorage_array]; |         my $fileNameAtStorage = | ||||||
|  |           $fileNameAtStorage_array[$#fileNameAtStorage_array]; | ||||||
|  |  | ||||||
|         $subprocess->{curl}                 = qx(which curl); |         $subprocess->{curl} = qx(which curl); | ||||||
|         chomp($subprocess->{curl}); |         chomp( $subprocess->{curl} ); | ||||||
|         $subprocess->{type}                 = $hash->{STORAGETYPE}; |         $subprocess->{type}              = $hash->{STORAGETYPE}; | ||||||
|         $subprocess->{host}                 = AttrVal( $name, 'bTS_Host', '' ); |         $subprocess->{host}              = ::AttrVal( $name, 'bTS_Host', '' ); | ||||||
|         $subprocess->{user}                 = AttrVal( $name, 'bTS_User', '' ); |         $subprocess->{user}              = ::AttrVal( $name, 'bTS_User', '' ); | ||||||
|         $subprocess->{pass}                 = ReadPassword( $hash, $name ); |         $subprocess->{pass}              = ReadPassword( $hash, $name ); | ||||||
|         $subprocess->{path}                 = AttrVal( $name, 'bTS_Path', '' ); |         $subprocess->{path}              = ::AttrVal( $name, 'bTS_Path', '' ); | ||||||
|         $subprocess->{fileNameAtStorage}    = $fileNameAtStorage; |         $subprocess->{fileNameAtStorage} = $fileNameAtStorage; | ||||||
|         $subprocess->{proto}                = AttrVal( $name, 'bTS_Proto', 'https' ); |         $subprocess->{proto}     = ::AttrVal( $name, 'bTS_Proto', 'https' ); | ||||||
|         $subprocess->{loglevel}             = AttrVal( $name, 'verbose', 3 ); |         $subprocess->{loglevel}  = ::AttrVal( $name, 'verbose', 3 ); | ||||||
|         $subprocess->{keeplastn}            = AttrVal( $name, 'bTS_KeepLastBackups', 5 ); |         $subprocess->{keeplastn} = ::AttrVal( $name, 'bTS_KeepLastBackups', 5 ); | ||||||
|  |  | ||||||
|         my $pid = $subprocess->run(); |         my $pid = $subprocess->run(); | ||||||
|  |  | ||||||
|         readingsSingleUpdate( $hash, 'state', ' clean up pass last N in progress', 1 ); |         readingsSingleUpdate( $hash, 'state', | ||||||
|  |             ' clean up pass last N in progress', 1 ); | ||||||
|  |  | ||||||
|         if ( !defined($pid) ) { |         if ( !defined($pid) ) { | ||||||
|             Log3( $name, 1, |             ::Log3( $name, 1, | ||||||
|                 qq{backupToStorage ($name) - Cannot execute command asynchronously} ); | qq{backupToStorage ($name) - Cannot execute command asynchronously} | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             CleanSubprocess($hash); |             CleanSubprocess($hash); | ||||||
|             readingsSingleUpdate( $hash, 'state', |             readingsSingleUpdate( $hash, 'state', | ||||||
|                 'Cannot execute command asynchronously', 1 ); |                 'Cannot execute command asynchronously', 1 ); | ||||||
|             return undef; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Log3( $name, 4, |         ::Log3( $name, 4, | ||||||
|             qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} | qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         $hash->{".fhem"}{subprocess} = $subprocess; |         $hash->{".fhem"}{subprocess} = $subprocess; | ||||||
|  |  | ||||||
|         InternalTimer( gettimeofday() + 1, |         ::InternalTimer( ::gettimeofday() + 1, | ||||||
|             "FHEM::Services::backupToStorage::PollChild", $hash ); |             "FHEM::Services::backupToStorage::PollChild", $hash ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Log3( $hash, 4, |     ::Log3( $hash, 4, | ||||||
|         qq{backupToStorage ($name) - control passed back to main loop.} ); |         qq{backupToStorage ($name) - control passed back to main loop.} ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| @@ -539,26 +514,29 @@ sub PollChild { | |||||||
|         my $json       = $subprocess->readFromChild(); |         my $json       = $subprocess->readFromChild(); | ||||||
|  |  | ||||||
|         if ( !defined($json) ) { |         if ( !defined($json) ) { | ||||||
|             Log3( $name, 5, |             ::Log3( $name, 5, | ||||||
|                     qq{backupToStorage ($name) - still waiting ($subprocess->{lasterror}).} | qq{backupToStorage ($name) - still waiting ($subprocess->{lasterror}).} | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|             InternalTimer( gettimeofday() + 1, |             ::InternalTimer( ::gettimeofday() + 1, | ||||||
|                 "FHEM::Services::backupToStorage::PollChild", $hash ); |                 "FHEM::Services::backupToStorage::PollChild", $hash ); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             Log3( $name, 4, |             ::Log3( $name, 4, | ||||||
|     qq{backupToStorage ($name) - got result from asynchronous parsing: $json} ); | qq{backupToStorage ($name) - got result from asynchronous parsing: $json} | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             $subprocess->wait(); |             $subprocess->wait(); | ||||||
|             Log3( $name, 4, |             ::Log3( $name, 4, | ||||||
|                 qq{backupToStorage ($name) - asynchronous finished.} ); |                 qq{backupToStorage ($name) - asynchronous finished.} ); | ||||||
|  |  | ||||||
|             CleanSubprocess($hash); |             CleanSubprocess($hash); | ||||||
|             WriteReadings( $hash, $json ); |             WriteReadings( $hash, $json ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
| ###################################### | ###################################### | ||||||
| @@ -569,23 +547,23 @@ sub FileUpload { | |||||||
|     my $response   = {}; |     my $response   = {}; | ||||||
|  |  | ||||||
|     if ( $subprocess->{type} eq 'Nextcloud' ) { |     if ( $subprocess->{type} eq 'Nextcloud' ) { | ||||||
|         my ($returnString,$returnCode) = ExecuteNCupload($subprocess); |         my ( $returnString, $returnCode ) = ExecuteNCupload($subprocess); | ||||||
|          |  | ||||||
|         print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' |         print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' | ||||||
|             . $returnCode |           . $returnCode | ||||||
|             . ' , returnString: ' |           . ' , returnString: ' | ||||||
|             . $returnString . "\n" |           . $returnString . "\n" | ||||||
|           if ( $subprocess->{loglevel} > 4 ); |           if ( $subprocess->{loglevel} > 4 ); | ||||||
|          |  | ||||||
|          |         if (    $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm | ||||||
|         if (  $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m |             and $returnString =~ /\s\s<o:hint xmlns:o="o:">(.*)<\/o:hint>/xm ) | ||||||
|           and $returnString =~ /\s\s<o:hint xmlns:o="o:">(.*)<\/o:hint>/m ) { |         { | ||||||
|             $response->{ncUpload} = $1; |             $response->{ncUpload} = $1; | ||||||
|         } |         } | ||||||
|         elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m ) { |         elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm ) { | ||||||
|             $response->{ncUpload} = 'upload successfully'; |             $response->{ncUpload} = 'upload successfully'; | ||||||
|         } |         } | ||||||
|         elsif ( $returnString =~ /(curl:\s.*)/ ){ |         elsif ( $returnString =~ /(curl:\s.*)/x ) { | ||||||
|             $response->{ncUpload} = $1; |             $response->{ncUpload} = $1; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
| @@ -596,7 +574,7 @@ sub FileUpload { | |||||||
|     my $json = eval { encode_json($response) }; |     my $json = eval { encode_json($response) }; | ||||||
|     if ($@) { |     if ($@) { | ||||||
|         print 'backupToStorage File Upload backupToStorage - JSON error: $@' |         print 'backupToStorage File Upload backupToStorage - JSON error: $@' | ||||||
|             . "\n"; |           . "\n"; | ||||||
|         $json = '{"jsonerror":"$@"}'; |         $json = '{"jsonerror":"$@"}'; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -618,7 +596,8 @@ sub ExecuteNCupload { | |||||||
|     $command .= $subprocess->{user}; |     $command .= $subprocess->{user}; | ||||||
|     $command .= $subprocess->{path}; |     $command .= $subprocess->{path}; | ||||||
|     $command .= '/'; |     $command .= '/'; | ||||||
|     $command .= $subprocess->{fhemhost} . '-' . $subprocess->{fileNameAtStorage}; |     $command .= | ||||||
|  |       $subprocess->{fhemhost} . '-' . $subprocess->{fileNameAtStorage}; | ||||||
|     $command .= '"'; |     $command .= '"'; | ||||||
|  |  | ||||||
|     return ExecuteCommand($command); |     return ExecuteCommand($command); | ||||||
| @@ -629,23 +608,23 @@ sub CleanUp { | |||||||
|     my $response   = {}; |     my $response   = {}; | ||||||
|  |  | ||||||
|     if ( $subprocess->{type} eq 'Nextcloud' ) { |     if ( $subprocess->{type} eq 'Nextcloud' ) { | ||||||
|         my ($returnString,$returnCode) = ExecuteCleanUp($subprocess); |         my ( $returnString, $returnCode ) = ExecuteCleanUp($subprocess); | ||||||
|          |  | ||||||
|         print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' |         print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' | ||||||
|             . $returnCode |           . $returnCode | ||||||
|             . ' , returnString: ' |           . ' , returnString: ' | ||||||
|             . $returnString . "\n" |           . $returnString . "\n" | ||||||
|           if ( $subprocess->{loglevel} > 4 ); |           if ( $subprocess->{loglevel} > 4 ); | ||||||
|          |  | ||||||
|          |         if (    $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm | ||||||
|         if (  $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m |             and $returnString =~ /\s\s<o:hint xmlns:o="o:">(.*)<\/o:hint>/xm ) | ||||||
|           and $returnString =~ /\s\s<o:hint xmlns:o="o:">(.*)<\/o:hint>/m ) { |         { | ||||||
|             $response->{ncUpload} = $1; |             $response->{ncUpload} = $1; | ||||||
|         } |         } | ||||||
|         elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m ) { |         elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm ) { | ||||||
|             $response->{ncUpload} = 'upload successfully'; |             $response->{ncUpload} = 'upload successfully'; | ||||||
|         } |         } | ||||||
|         elsif ( $returnString =~ /(curl:\s.*)/ ){ |         elsif ( $returnString =~ /(curl:\s.*)/x ) { | ||||||
|             $response->{ncUpload} = $1; |             $response->{ncUpload} = $1; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
| @@ -656,7 +635,7 @@ sub CleanUp { | |||||||
|     my $json = eval { encode_json($response) }; |     my $json = eval { encode_json($response) }; | ||||||
|     if ($@) { |     if ($@) { | ||||||
|         print 'backupToStorage File Upload backupToStorage - JSON error: $@' |         print 'backupToStorage File Upload backupToStorage - JSON error: $@' | ||||||
|             . "\n"; |           . "\n"; | ||||||
|         $json = '{"jsonerror":"$@"}'; |         $json = '{"jsonerror":"$@"}'; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -676,7 +655,8 @@ sub ExecuteNCfetchFileList { | |||||||
|     $command .= '/remote.php/dav/files/'; |     $command .= '/remote.php/dav/files/'; | ||||||
|     $command .= $subprocess->{user}; |     $command .= $subprocess->{user}; | ||||||
|     $command .= $subprocess->{path}; |     $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>\''; |     $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); |     return ExecuteCommand($command); | ||||||
| } | } | ||||||
| @@ -700,7 +680,8 @@ sub ExecuteNCremoveFile { | |||||||
| } | } | ||||||
|  |  | ||||||
| sub ExecuteCommand { | sub ExecuteCommand { | ||||||
|     my $command = join q{ }, @_; |     my @options = @_; | ||||||
|  |     my $command = join q{ }, @options; | ||||||
|     return ( $_ = qx{$command 2>&1}, $? >> 8 ); |     return ( $_ = qx{$command 2>&1}, $? >> 8 ); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -714,7 +695,9 @@ sub CleanSubprocess { | |||||||
|     my $name = $hash->{NAME}; |     my $name = $hash->{NAME}; | ||||||
|  |  | ||||||
|     delete( $hash->{".fhem"}{subprocess} ); |     delete( $hash->{".fhem"}{subprocess} ); | ||||||
|     Log3( $name, 4, qq{backupToStorage ($name) - clean Subprocess} ); |     ::Log3( $name, 4, qq{backupToStorage ($name) - clean Subprocess} ); | ||||||
|  |  | ||||||
|  |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
| sub StorePassword { | sub StorePassword { | ||||||
| @@ -723,10 +706,10 @@ sub StorePassword { | |||||||
|     my $password = shift; |     my $password = shift; | ||||||
|  |  | ||||||
|     my $index   = $hash->{TYPE} . "_" . $name . "_passwd"; |     my $index   = $hash->{TYPE} . "_" . $name . "_passwd"; | ||||||
|     my $key     = getUniqueId() . $index; |     my $key     = ::getUniqueId() . $index; | ||||||
|     my $enc_pwd = ""; |     my $enc_pwd = ""; | ||||||
|  |  | ||||||
|     if ( eval "use Digest::MD5;1" ) { |     if ( eval { use Digest::MD5; 1 } ) { | ||||||
|  |  | ||||||
|         $key = Digest::MD5::md5_hex( unpack "H*", $key ); |         $key = Digest::MD5::md5_hex( unpack "H*", $key ); | ||||||
|         $key .= Digest::MD5::md5_hex($key); |         $key .= Digest::MD5::md5_hex($key); | ||||||
| @@ -739,8 +722,8 @@ sub StorePassword { | |||||||
|         $key = $encode . $key; |         $key = $encode . $key; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     my $err = setKeyValue( $index, $enc_pwd ); |     my $err = ::setKeyValue( $index, $enc_pwd ); | ||||||
|     DoTrigger( $name, 'password add' ); |     ::DoTrigger( $name, 'password add' ); | ||||||
|  |  | ||||||
|     return qq{error while saving the password - $err} |     return qq{error while saving the password - $err} | ||||||
|       if ( defined($err) ); |       if ( defined($err) ); | ||||||
| @@ -753,30 +736,31 @@ sub ReadPassword { | |||||||
|     my $name = shift; |     my $name = shift; | ||||||
|  |  | ||||||
|     my $index = $hash->{TYPE} . "_" . $name . "_passwd"; |     my $index = $hash->{TYPE} . "_" . $name . "_passwd"; | ||||||
|     my $key   = getUniqueId() . $index; |     my $key   = ::getUniqueId() . $index; | ||||||
|     my ( $password, $err ); |     my ( $password, $err ); | ||||||
|  |  | ||||||
|     Log3( $name, 4, qq{backupToStorage ($name) - Read password from file} ); |     ::Log3( $name, 4, qq{backupToStorage ($name) - Read password from file} ); | ||||||
|  |  | ||||||
|     ( $err, $password ) = getKeyValue($index); |     ( $err, $password ) = ::getKeyValue($index); | ||||||
|  |  | ||||||
|     if ( defined($err) ) { |     if ( defined($err) ) { | ||||||
|  |  | ||||||
|         Log3( $name, 3, |         ::Log3( $name, 3, | ||||||
|             qq{backupToStorage ($name) - unable to read password from file: $err} | qq{backupToStorage ($name) - unable to read password from file: $err} | ||||||
|         ); |         ); | ||||||
|         return undef; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if ( defined($password) ) { |     if ( defined($password) ) { | ||||||
|         if ( eval "use Digest::MD5;1" ) { |         if ( eval { use Digest::MD5; 1 } ) { | ||||||
|             $key = Digest::MD5::md5_hex( unpack "H*", $key ); |             $key = Digest::MD5::md5_hex( unpack "H*", $key ); | ||||||
|             $key .= Digest::MD5::md5_hex($key); |             $key .= Digest::MD5::md5_hex($key); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         my $dec_pwd = ''; |         my $dec_pwd = ''; | ||||||
|  |  | ||||||
|         for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/g ) ) { |         for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/xg ) ) | ||||||
|  |         { | ||||||
|  |  | ||||||
|             my $decode = chop($key); |             my $decode = chop($key); | ||||||
|             $dec_pwd .= chr( ord($char) ^ ord($decode) ); |             $dec_pwd .= chr( ord($char) ^ ord($decode) ); | ||||||
| @@ -786,8 +770,8 @@ sub ReadPassword { | |||||||
|         return $dec_pwd; |         return $dec_pwd; | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         Log3( $name, 3, qq{backupToStorage ($name) - No password in file} ); |         ::Log3( $name, 3, qq{backupToStorage ($name) - No password in file} ); | ||||||
|         return undef; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| @@ -798,8 +782,8 @@ sub DeletePassword { | |||||||
|  |  | ||||||
|     my $name = $hash->{NAME}; |     my $name = $hash->{NAME}; | ||||||
|  |  | ||||||
|     setKeyValue( $hash->{TYPE} . "_" . $name . "_passwd", undef ); |     ::setKeyValue( $hash->{TYPE} . "_" . $name . "_passwd", undef ); | ||||||
|     DoTrigger( $name, 'password remove' ); |     ::DoTrigger( $name, 'password remove' ); | ||||||
|  |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| @@ -809,21 +793,17 @@ sub CheckAttributsForCredentials { | |||||||
|  |  | ||||||
|     my $name = $hash->{NAME}; |     my $name = $hash->{NAME}; | ||||||
|  |  | ||||||
|     my $ncUser = AttrVal( $name, 'bTS_User', 'none' ); |     my $ncUser = ::AttrVal( $name, 'bTS_User', 'none' ); | ||||||
|     my $ncPass = ReadPassword( $hash, $name ); |     my $ncPass = ReadPassword( $hash, $name ); | ||||||
|     my $ncHost = AttrVal( $name, 'bTS_Host', 'none' ); |     my $ncHost = ::AttrVal( $name, 'bTS_Host', 'none' ); | ||||||
|     my $status = 'ready'; |     my $status = 'ready'; | ||||||
|  |  | ||||||
|     $status = ( $status eq 'ready' |     $status = ( | ||||||
|                     && $ncUser eq 'none' |         $status eq 'ready' && $ncUser eq 'none' ? 'no user credential attribut' | ||||||
|                         ? 'no user credential attribut' |         : $status eq 'ready' | ||||||
|                         : $status eq 'ready' |           && $ncHost eq 'none' ? 'no host credential attribut' | ||||||
|                     && $ncHost eq 'none' |         : $status eq 'ready' && !defined($ncPass) ? 'no password set' | ||||||
|                         ? 'no host credential attribut' |         :                                           $status | ||||||
|                         : $status eq 'ready' |  | ||||||
|                     && !defined($ncPass) |  | ||||||
|                         ? 'no password set' |  | ||||||
|                         : $status |  | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     return readingsSingleUpdate( $hash, 'state', $status, 1 ); |     return readingsSingleUpdate( $hash, 'state', $status, 1 ); | ||||||
| @@ -837,14 +817,16 @@ sub WriteReadings { | |||||||
|  |  | ||||||
|     my $decode_json = eval { decode_json($json) }; |     my $decode_json = eval { decode_json($json) }; | ||||||
|     if ($@) { |     if ($@) { | ||||||
|         Log3( $name, 2, qq{backupToStorage ($name) - JSON error: $@} ); |         ::Log3( $name, 2, qq{backupToStorage ($name) - JSON error: $@} ); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     readingsBeginUpdate($hash); |     ::readingsBeginUpdate($hash); | ||||||
|     readingsBulkUpdate( $hash, 'state',       'ready' ); |     ::readingsBulkUpdate( $hash, 'state',       'ready' ); | ||||||
|     readingsBulkUpdate( $hash, 'uploadState', $decode_json->{ncUpload} ); |     ::readingsBulkUpdate( $hash, 'uploadState', $decode_json->{ncUpload} ); | ||||||
|     readingsEndUpdate( $hash, 1 ); |     ::readingsEndUpdate( $hash, 1 ); | ||||||
|  |  | ||||||
|  |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
| 1; | 1; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user