diff --git a/fhem/FHEM/70_Pushover.pm b/fhem/FHEM/70_Pushover.pm index 9a0760f1e..8ddc9c86c 100644 --- a/fhem/FHEM/70_Pushover.pm +++ b/fhem/FHEM/70_Pushover.pm @@ -354,18 +354,35 @@ sub Pushover_SendCommand($$;$\%) { $http_proto = "http"; } - $cmd .= "&" if ( $cmd ne "" ); - $cmd .= "token=" . $hash->{APP_TOKEN}; + my %header = ( + Agent => 'FHEM-Pushover/1.0.0', + 'User-Agent' => 'FHEM-Pushover/1.0.0', + Accept => 'application/json;charset=UTF-8', + 'Accept-Charset' => 'UTF-8', + ); + + my $multipart = 0; + if ( $cmd =~ /^--(.+)\r?\nContent-Disposition:/im ) { + $multipart = 1; + + $header{'Content-Type'} = "multipart/form-data; boundary=" . $1; + Log3 $name, 5, + "Pushover $name: Sending as content type " . $header{'Content-Type'}; + } if ( !defined( $type->{USER_KEY} ) ) { - $cmd .= "&user=" . $hash->{USER_KEY}; + $cmd = Pushover_HttpForm( $cmd, $multipart, + { "user" => $hash->{USER_KEY}, "token" => $hash->{APP_TOKEN} } ); } else { Log3 $name, 4, "Pushover $name: USER_KEY found in device name: " . $type->{USER_KEY}; - $cmd .= "&user=" . $type->{USER_KEY}; + $cmd = Pushover_HttpForm( $cmd, $multipart, + { "user" => $type->{USER_KEY}, "token" => $hash->{APP_TOKEN} } ); } + $cmd .= "--" if ($multipart); + my $URL; my $response; my $return; @@ -417,12 +434,7 @@ sub Pushover_SendCommand($$;$\%) { callback => \&Pushover_ReceiveCommand, httpversion => "1.1", loglevel => AttrVal( $name, "httpLoglevel", 4 ), - header => { - Agent => 'FHEM-Pushover/1.0.0', - 'User-Agent' => 'FHEM-Pushover/1.0.0', - Accept => 'application/json;charset=UTF-8', - 'Accept-Charset' => 'UTF-8', - }, + header => \%header, # sslargs => { # SSL_verify_mode => 'SSL_verify_PEER', @@ -455,12 +467,7 @@ sub Pushover_SendCommand($$;$\%) { callback => \&Pushover_ReceiveCommand, httpversion => "1.1", loglevel => AttrVal( $name, "httpLoglevel", 4 ), - header => { - Agent => 'FHEM-Pushover/1.0.0', - 'User-Agent' => 'FHEM-Pushover/1.0.0', - Accept => 'application/json;charset=UTF-8', - 'Accept-Charset' => 'UTF-8', - }, + header => \%header, } ); } @@ -1097,6 +1104,8 @@ sub Pushover_SetMessage2 ($$$$) { if ( defined( $h->{cancel_id} ) && $values{priority} && $values{priority} == 2 ); + + $values{attachment} = $h->{attachment} ? $h->{attachment} : undef; } # glances @@ -1159,98 +1168,25 @@ sub Pushover_SetMessage2 ($$$$) { ); } - my $body; - $body = "title=" . urlEncode( $values{title} ) - if ( defined( $values{title} ) ); + # set timestamp if desired + $values{timestamp} = int( time() ) + if ( !$values{timestamp} + && 1 == AttrVal( $hash->{NAME}, "timestamp", 0 ) ); - if ( $values{message} ) { - if ( $values{message} =~ /^\s*nohtml:\s*(.*)$/i ) { - Log3 $name, 4, - "Pushover $name: explicitly ignoring HTML tags in message"; - $values{message} = $1; - } - elsif ( $values{message} =~ - m/\<(\/|)[biu]\>|\<(\/|)font(.+)\>|\<(\/|)a(.*)\>|\/i ) - { - Log3 $name, 4, "Pushover $name: handling message with HTML content"; - $body .= "&html=1"; - - # replace \n by
but ignore \\n - $values{message} =~ s/(?/g; - } - - # HttpUtil's urlEncode() does not handle \n but would escape % - # so we encode first - $values{message} = urlEncode( $values{message} ); - - # replace any URL-encoded \n with their hex equivalent but ignore \\n - $values{message} =~ s/(? 2 ); $values{priority} = -2 if ( $values{priority} < -2 ); - $body .= "&priority=" . $values{priority}; + + # callback + if ( $callback && $values{priority} > 1 ) { + Log3 $name, 5, + "Pushover $name: Adding emergency callback URL $callback"; + $values{callback} = $callback; + } } - if ( $values{sound} ) { - $body .= "&sound=" . $values{sound}; - } - - if ( defined( $values{retry} ) ) { - $body .= "&retry=" . $values{retry}; - } - - if ( defined( $values{expire} ) ) { - $body .= "&expire=" . $values{expire}; - + if ( $values{expire} ) { $values{cbNr} = round( time(), 0 ) + $values{expire}; my $cbReading = "cb_" . $values{cbNr}; until ( ReadingsVal( $name, $cbReading, "" ) eq "" ) { @@ -1259,19 +1195,6 @@ sub Pushover_SetMessage2 ($$$$) { } } - if ( $values{timestamp} ) { - $body .= "×tamp=" . $values{timestamp}; - } - elsif ( 1 == AttrVal( $hash->{NAME}, "timestamp", 0 ) ) { - $body .= "×tamp=" . int( time() ); - } - - if ( $callback && $values{priority} && $values{priority} > 1 ) { - Log3 $name, 5, - "Pushover $name: Adding emergency callback URL $callback"; - $body .= "&callback=" . $callback; - } - if ( $values{url_title} && $values{action} && defined( $values{expire} ) ) @@ -1300,13 +1223,43 @@ sub Pushover_SetMessage2 ($$$$) { "Pushover $name: Adding supplementary URL '$values{url_title}' ($url) with " . "action '$values{action}' (expires after $values{expire} => " . "$values{cbNr})"; - $body = - $body - . "&url_title=" - . urlEncode( $values{url_title} ) . "&url=" - . urlEncode($url); + + $values{url} = $url; } + # generate body text + my $body; + my $multipart = 0; + $multipart = 1 if ( $values{attachment} ); + + if ( defined( $values{message} ) ) { + if ( $values{message} =~ /^\s*nohtml:\s*(.*)$/i ) { + Log3 $name, 4, + "Pushover $name: explicitly ignoring HTML tags in message"; + $values{message} = $1; + } + elsif ( $values{message} =~ + m/\<(\/|)[biu]\>|\<(\/|)font(.+)\>|\<(\/|)a(.*)\>|\/i ) + { + Log3 $name, 4, "Pushover $name: handling message with HTML content"; + $body = Pushover_HttpForm( $body, $multipart, "html", "1" ); + + # replace \n by
but ignore \\n + $values{message} =~ s/(?/g; + } + } + + if ( defined( $values{attachment} ) ) { + my $path = + "file://" + . AttrVal( $name, "storage", AttrVal( "global", "modpath", "." ) ); + $path .= "/" unless ( $path =~ /\/$/ ); + + $values{attachment} = $path . $values{attachment}; + } + + $body = Pushover_HttpForm( $body, $multipart, \%values ); + # cleanup callback readings keys %{ $hash->{READINGS} }; while ( my ( $key, $value ) = each %{ $hash->{READINGS} } ) { @@ -1396,6 +1349,82 @@ sub Pushover_CancelMessage ($$$$) { return $return; } +sub Pushover_HttpForm ($$$;$) { + my ( $ret, $multipart, $h, $v ) = @_; + $h = { $h => $v } unless ( ref $h eq "HASH" ); + + my $boundary = "--msgsgmnt"; + + keys %$h; + while ( my ( $n, $val ) = each %$h ) { + next unless ( defined($val) ); + $v = $val; + + # multipart/form-data + if ($multipart) { + $ret = "--$boundary" + unless ( $ret && $ret ne "" ); + + if ( $multipart eq "2" || $v =~ /^file:\/\/(.*)/i ) { + $v = $1 if ( defined($1) ); + next unless ( $v =~ /(\w|[-.])+$/ ); + my $fn = $0; + + my ( $err, @content ) = + FileRead( { FileName => $v, ForceType => "file" } ); + if ( defined($err) ) { + Log 5, "Pushover_HttpForm: Unable to read file $v: $err"; + next; + } + + my $MIMEtype = filename2MIMEType($v); + $v = join( $/, @content ); + $ret .= + "\r\nContent-Disposition: form-data; " + . "name=\"$n\"; " + . "filename=\"$fn\"" + . "\r\nContent-Type: $MIMEtype"; + } + else { + $ret .= "\r\nContent-Disposition: form-data; name=\"$n\""; + $v =~ s/\\n/\r\n/g; + } + + $ret .= "\r\n\r\n$v\r\n--$boundary"; + } + + # application/x-www-form-urlencoded + else { + $ret = Pushover_HttpUri( $ret, $n, $v ); + } + + } + + return $ret; +} + +sub Pushover_HttpUri ($$;$) { + my ( $uri, $h, $v ) = @_; + $h = { $h => $v } unless ( ref $h eq "HASH" ); + + keys %$h; + while ( my ( $n, $val ) = each %$h ) { + $v = urlEncode($val); + + # replace any URL-encoded \n with their hex equivalent + # but ignore \\n + $v =~ s/(?cancel_id  - type: text - Custom ID to immediate expire messages with priority >=2 and disable reoccuring notification.
timestamp  - type: integer - A Unix timestamp of your message's date and time to display to the user, rather than the time your message is received by the Pushover servers. Takes precendence over attribute timestamp=1.
sound      - type: text - The name of one of the sounds supported by device clients to override the user's default sound choice.
+ attachment      - type: text - Path to an image file that should be attached to the message. The base path is relative to the FHEM directory and may be overwritten using the storage attribute.

Examples:
@@ -1637,12 +1671,13 @@ sub Pushover_CancelMessage ($$$$) { title      - Typ: Text - Dein Nachrichten Titel, andernfalls wird der App Name wie in der Pushover API festgelegt verwendet.
action     - Typ: Text - Entweder ein auszuführendes FHEM Kommando, wenn der Empfänger den Link anklickt oder eine supplementary URL, die mit der Nachricht zusammen angezeigt werden soll.
url_title  - Typ: Text - Ein Titel für das FHEM Kommando oder die supplementary URL, andernfalls wird die URL direkt angezeigt.
- priority   - Type: Integer - Sende mit -2, um keine/n Benachrichtigung/Alarm zu generieren. Sende mit -1, um immer eine lautlose Benachrichtigung zu senden. Sende mit 1, um die Nachricht mit hoher Priorität anzuzeigen und die Ruhezeiten des Empfängers zu umgehen. Oder sende mit 2, um zusätzlich eine Bestätigung des Empfängers anzufordern.
- retry      - Type: Integer - Verpflichtend bei einer Nachrichten Priorität >= 2.
- expire     - Type: Integer - Verpflichtend bei einer Nachrichten Priorität >= 2.
- cancel_id  - type: text - Benutzerdefinierte ID, um Nachrichten mit einer Priorität >= 2 sofort ablaufen zu lassen und die wiederholte Benachrichtigung auszuschalten.
- timestamp  - Type: Integer - Ein Unix Zeitstempfel mit Datum und Uhrzeit deiner Nachricht, die dem Empfänger statt der Uhrzeit des Einganges auf den Pushover Servern angezeigt wird. Hat Vorrang bei gesetztem Attribut timestamp=1.
+ priority   - Typ: Integer - Sende mit -2, um keine/n Benachrichtigung/Alarm zu generieren. Sende mit -1, um immer eine lautlose Benachrichtigung zu senden. Sende mit 1, um die Nachricht mit hoher Priorität anzuzeigen und die Ruhezeiten des Empfängers zu umgehen. Oder sende mit 2, um zusätzlich eine Bestätigung des Empfängers anzufordern.
+ retry      - Typ: Integer - Verpflichtend bei einer Nachrichten Priorität >= 2.
+ expire     - Typ: Integer - Verpflichtend bei einer Nachrichten Priorität >= 2.
+ cancel_id  - Typ: Text - Benutzerdefinierte ID, um Nachrichten mit einer Priorität >= 2 sofort ablaufen zu lassen und die wiederholte Benachrichtigung auszuschalten.
+ timestamp  - Typ: Integer - Ein Unix Zeitstempfel mit Datum und Uhrzeit deiner Nachricht, die dem Empfänger statt der Uhrzeit des Einganges auf den Pushover Servern angezeigt wird. Hat Vorrang bei gesetztem Attribut timestamp=1.
sound      - Typ: Text - Der Name eines vom Empfängergerät unterstützten Klangs, um den vom Empfänger ausgewählten Klang zu überschreiben.
+ attachment      - Typ: Text - Pfad zu einer Bilddatei, welche an die Nachricht angehängt werden soll. Der Basispfad ist relativ zum FHEM Verzeichnis und kann über das storage Attribut überschrieben werden.

Beispiele: