|
|
@ -1,18 +1,166 @@ |
|
|
|
#!/usr/local/bin/perl |
|
|
|
# WANT_JSON |
|
|
|
|
|
|
|
# yamd - client Yandex.Mail for Domain API |
|
|
|
# Run as stand-alone application or as Ansible module |
|
|
|
# |
|
|
|
# Copyright 2018 Sergey Kiselev <root@digital-freak.ru> |
|
|
|
# |
|
|
|
# Redistribution and use in source and binary forms, with or without |
|
|
|
# modification, are permitted provided that the following conditions are met: |
|
|
|
# |
|
|
|
# 1. Redistributions of source code must retain the above copyright notice, |
|
|
|
# this list of conditions and the following disclaimer. |
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright notice, |
|
|
|
# this list of conditions and the following disclaimer in the documentation |
|
|
|
# and/or other materials provided with the distribution. |
|
|
|
# 3. Neither the name of the copyright holder nor the names of its |
|
|
|
# contributors may be used to endorse or promote products derived from this |
|
|
|
# software without specific prior written permission. |
|
|
|
# |
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
|
|
# POSSIBILITY OF SUCH DAMAGE. |
|
|
|
|
|
|
|
use strict; |
|
|
|
use warnings; |
|
|
|
|
|
|
|
use File::Basename; |
|
|
|
|
|
|
|
use YAML::XS qw/Load LoadFile/; |
|
|
|
use JSON::XS; |
|
|
|
use Types::Serialiser; |
|
|
|
|
|
|
|
use LWP::UserAgent; |
|
|
|
use HTTP::Request; |
|
|
|
use YAML::XS qw/LoadFile/; |
|
|
|
|
|
|
|
our $api_url = "https://pddimp.yandex.ru/api2/admin"; |
|
|
|
our $query_options = LoadFile("./yamd_query_options.yml") |
|
|
|
or die "Query parameters file not found\n"; |
|
|
|
our $task_file = shift or die "Usage: yamd.pl <file.yml>\n"; |
|
|
|
our $task = %{LoadFile($task_file)}{yamd} |
|
|
|
or die "Unable to open file '$task_file'\n"; |
|
|
|
our $query_options = Load(<<EOYAML |
|
|
|
--- |
|
|
|
default_content_type: 'application/x-www-form-urlencoded' |
|
|
|
deputy: |
|
|
|
list: |
|
|
|
query_type: 'GET' |
|
|
|
add: |
|
|
|
query_type: 'POST' |
|
|
|
delete: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
dkim: |
|
|
|
status: |
|
|
|
query_type: 'GET' |
|
|
|
disable: |
|
|
|
query_type: 'POST' |
|
|
|
enable: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
dns: |
|
|
|
list: |
|
|
|
query_type: 'GET' |
|
|
|
add: |
|
|
|
query_type: 'POST' |
|
|
|
del: |
|
|
|
query_type: 'POST' |
|
|
|
edit: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
domain: |
|
|
|
details: |
|
|
|
query_type: 'GET' |
|
|
|
domains: |
|
|
|
query_type: 'GET' |
|
|
|
registration_status: |
|
|
|
query_type: 'GET' |
|
|
|
delete: |
|
|
|
query_type: 'POST' |
|
|
|
register: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
logo: |
|
|
|
check: |
|
|
|
query_type: 'GET' |
|
|
|
del: |
|
|
|
query_type: 'POST' |
|
|
|
set: |
|
|
|
content_type: 'multipart/form-data' |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
settings: |
|
|
|
set_country: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
email: |
|
|
|
counters: |
|
|
|
query_type: 'GET' |
|
|
|
list: |
|
|
|
query_type: 'GET' |
|
|
|
add: |
|
|
|
query_type: 'POST' |
|
|
|
del: |
|
|
|
query_type: 'POST' |
|
|
|
edit: |
|
|
|
query_type: 'POST' |
|
|
|
get_oauth_token: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
ml: |
|
|
|
list: |
|
|
|
query_type: 'GET' |
|
|
|
subscribers: |
|
|
|
query_type: 'GET' |
|
|
|
add: |
|
|
|
query_type: 'POST' |
|
|
|
del: |
|
|
|
query_type: 'POST' |
|
|
|
get_can_send_on_behalf: |
|
|
|
query_type: 'POST' |
|
|
|
set_can_send_on_behalf: |
|
|
|
query_type: 'POST' |
|
|
|
subscribe: |
|
|
|
query_type: 'POST' |
|
|
|
unsubscribe: |
|
|
|
query_type: 'POST' |
|
|
|
|
|
|
|
import: |
|
|
|
check_imports: |
|
|
|
query_type: 'GET' |
|
|
|
check_settings: |
|
|
|
query_type: 'GET' |
|
|
|
start_import_file: |
|
|
|
content_type: 'multipart/form-data' |
|
|
|
query_type: 'POST' |
|
|
|
start_one_import: |
|
|
|
query_type: 'POST' |
|
|
|
stop_all_imports: |
|
|
|
query_type: 'POST' |
|
|
|
EOYAML |
|
|
|
); |
|
|
|
|
|
|
|
our $task_file = shift or die "Usage: " . basename($0) . "<file.yml\n"; |
|
|
|
our $task = undef; |
|
|
|
|
|
|
|
{ |
|
|
|
my ($filename, $path, $suffix) = fileparse($task_file); |
|
|
|
|
|
|
|
if ($path =~ 'ansible' && $filename == 'args') { |
|
|
|
# Calling from Ansible with args in the JSON-file |
|
|
|
open(my $fh, "<", $task_file); |
|
|
|
$task = decode_json(<$fh>); |
|
|
|
close $fh; |
|
|
|
} else { |
|
|
|
# Stand-alone running with args in the YAML-file |
|
|
|
$task = %{LoadFile($task_file)}{yamd} |
|
|
|
or die "Unable to open file '" . $task_file ."'\n"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
foreach my $check ("domain", "token", "service", "query") { |
|
|
|
if (!defined $task->{$check}) { |
|
|
@ -57,66 +205,71 @@ my $ua = new LWP::UserAgent; |
|
|
|
my $request = new HTTP::Request($request_type => $request_url); |
|
|
|
|
|
|
|
if ( $task->{service} eq "domain" && |
|
|
|
$task->{sub_service} eq "logo" && |
|
|
|
$task->{query} eq "set" ) { |
|
|
|
my $boundary = 'X'; |
|
|
|
my @rand = ('a'..'z', 'A'..'Z'); |
|
|
|
for (0..14) { $boundary .= $rand[rand(@rand)]; } |
|
|
|
|
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type . "; boundary=" . $boundary |
|
|
|
); |
|
|
|
|
|
|
|
my $field = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="domain"', |
|
|
|
'Content-Type' => 'text/plain; charset=utf-8' |
|
|
|
]); |
|
|
|
$field->add_content_utf8($task->{domain}); |
|
|
|
$request->add_part($field); |
|
|
|
|
|
|
|
open(my $fh, '<', $task->{options}->{file}); |
|
|
|
my $file_content = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="file"; filename="logo"', |
|
|
|
'Content-Type' => 'application/octet-stream' |
|
|
|
]); |
|
|
|
$file_content->add_content($_) while <$fh>; |
|
|
|
$request->add_part($file_content); |
|
|
|
|
|
|
|
close $fh; |
|
|
|
$task->{sub_service} eq "logo" && |
|
|
|
$task->{query} eq "set" ) { |
|
|
|
{ |
|
|
|
my $boundary = 'X'; |
|
|
|
my @rand = ('a'..'z', 'A'..'Z'); |
|
|
|
for (0..14) { $boundary .= $rand[rand(@rand)]; } |
|
|
|
|
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type . "; boundary=" . $boundary |
|
|
|
); |
|
|
|
|
|
|
|
my $field = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="domain"', |
|
|
|
'Content-Type' => 'text/plain; charset=utf-8' |
|
|
|
]); |
|
|
|
$field->add_content_utf8($task->{domain}); |
|
|
|
$request->add_part($field); |
|
|
|
|
|
|
|
open(my $fh, '<', $task->{options}->{file}); |
|
|
|
my $file_content = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="file"; filename="logo"', |
|
|
|
'Content-Type' => 'application/octet-stream' |
|
|
|
]); |
|
|
|
$file_content->add_content($_) while <$fh>; |
|
|
|
$request->add_part($file_content); |
|
|
|
|
|
|
|
close $fh; |
|
|
|
} |
|
|
|
} elsif ( $task->{service} eq "import" && |
|
|
|
$task->{query} eq "start_import_file" ) { |
|
|
|
my $boundary = 'X'; |
|
|
|
my @rand = ('a'..'z', 'A'..'Z'); |
|
|
|
for (0..14) { $boundary .= $rand[rand(@rand)]; } |
|
|
|
|
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type . "; boundary=" . $boundary |
|
|
|
); |
|
|
|
|
|
|
|
open(my $fh, '<', $task->{options}->{file}); |
|
|
|
my $file_content = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="import_list_file"; filename="import_list_file"', |
|
|
|
'Content-Type' => 'text/plain', |
|
|
|
]); |
|
|
|
$file_content->add_content($_) while <$fh>; |
|
|
|
|
|
|
|
$request->add_part($file_content); |
|
|
|
|
|
|
|
close $fh; |
|
|
|
} else { |
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type |
|
|
|
); |
|
|
|
|
|
|
|
my $request_content = "domain=" . $task->{domain}; |
|
|
|
foreach my $k (keys %{$task->{options}}) { |
|
|
|
$request_content .= "&" . $k . "=" . $task->{options}->{$k}; |
|
|
|
$task->{query} eq "start_import_file" ) { |
|
|
|
{ |
|
|
|
my $boundary = 'X'; |
|
|
|
my @rand = ('a'..'z', 'A'..'Z'); |
|
|
|
for (0..14) { $boundary .= $rand[rand(@rand)]; } |
|
|
|
|
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type . "; boundary=" . $boundary |
|
|
|
); |
|
|
|
|
|
|
|
open(my $fh, '<', $task->{options}->{file}); |
|
|
|
my $file_content = new HTTP::Message([ |
|
|
|
'Content-Disposition' => 'form-data; name="import_list_file"; filename="import_list_file"', |
|
|
|
'Content-Type' => 'text/plain', |
|
|
|
]); |
|
|
|
$file_content->add_content($_) while <$fh>; |
|
|
|
$request->add_part($file_content); |
|
|
|
|
|
|
|
close $fh; |
|
|
|
} |
|
|
|
} else { |
|
|
|
{ |
|
|
|
$request->header( |
|
|
|
'PddToken' => $task->{token}, |
|
|
|
'Content-type' => $request_content_type |
|
|
|
); |
|
|
|
|
|
|
|
$request->content($request_content); |
|
|
|
my $request_content = "domain=" . $task->{domain}; |
|
|
|
foreach my $k (keys %{$task->{options}}) { |
|
|
|
$request_content .= "&" . $k . "=" . $task->{options}->{$k}; |
|
|
|
} |
|
|
|
|
|
|
|
$request->content($request_content); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
my $response = $ua->request($request); |
|
|
|