-module(clamav). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/1, port/2, connection_timeout/2, reply_timeout/2, logger/2, ping/1, stats/1, version/1, instream/2]). -export_type([clam_scan_result/0, infected_file/0, clam_error/0, clam_response_parsing_error/0, clam_version_response/0]). -type clam_scan_result() :: clean | {virus_detected, list(infected_file())}. -type infected_file() :: {infected_file, binary(), binary()}. -type clam_error() :: {scan_error, binary()} | {cannot_parse_response, clam_response_parsing_error()} | {connection_error, mug:error()}. -type clam_response_parsing_error() :: {unexpected_response, binary()} | invalid_binary_data. -type clam_version_response() :: {clam_version_response, binary(), binary()}. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 39). -spec new(binary()) -> client_options:clam_av_client_options(). new(Host) -> {clam_av_client_options, Host, 3310, 10000, 10000, {logger, fun client_options:nil_log/1, fun client_options:nil_log/1, fun client_options:nil_log/1}}. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 50). -spec port(client_options:clam_av_client_options(), integer()) -> client_options:clam_av_client_options(). port(Client, Port) -> erlang:setelement(3, Client, Port). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 55). -spec connection_timeout(client_options:clam_av_client_options(), integer()) -> client_options:clam_av_client_options(). connection_timeout(Client, Connection_timeout) -> erlang:setelement(4, Client, Connection_timeout). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 63). -spec reply_timeout(client_options:clam_av_client_options(), integer()) -> client_options:clam_av_client_options(). reply_timeout(Client, Reply_timeout) -> erlang:setelement(5, Client, Reply_timeout). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 68). -spec logger(client_options:clam_av_client_options(), client_options:logger()) -> client_options:clam_av_client_options(). logger(Client, Logger) -> erlang:setelement(6, Client, Logger). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 74). -spec execute_adhoc_command(client_options:clam_av_client_options(), binary()) -> {ok, bitstring()} | {error, clam_error()}. execute_adhoc_command(Options, Command) -> _pipe = (common@internal:execute_command( Options, Command, fun(Socket) -> common@tcp:receive_bytes(Socket, Options, fun(Res) -> {ok, Res} end) end )), gleam@result:try_recover( _pipe, fun(E) -> {error, {connection_error, E}} end ). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 89). -spec ping(client_options:clam_av_client_options()) -> {ok, nil} | {error, clam_error()}. ping(Options) -> Res = execute_adhoc_command(Options, <<"PING"/utf8>>), case Res of {ok, Bits} -> Response_text = begin _pipe = Bits, gleam@bit_array:to_string(_pipe) end, case Response_text of {ok, <<"PONG"/utf8>>} -> {ok, nil}; {ok, Text} -> {error, {cannot_parse_response, {unexpected_response, Text}}}; _ -> {error, {cannot_parse_response, invalid_binary_data}} end; {error, Error} -> {error, Error} end. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 128). -spec stats(client_options:clam_av_client_options()) -> {ok, binary()} | {error, clam_error()}. stats(Options) -> Res = execute_adhoc_command(Options, <<"STATS"/utf8>>), case Res of {ok, Bits} -> case begin _pipe = Bits, gleam@bit_array:to_string(_pipe) end of {ok, Text} -> {ok, Text}; _ -> {error, {cannot_parse_response, invalid_binary_data}} end; {error, Error} -> {error, Error} end. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 141). -spec parse_version_response(binary()) -> {ok, clam_version_response()} | {error, clam_error()}. parse_version_response(Response_text) -> Split = begin _pipe = Response_text, gleam@string:split(_pipe, <<"/"/utf8>>) end, case Split of [Version, Database_version, _] -> {ok, {clam_version_response, begin _pipe@1 = Version, gleam@string:trim(_pipe@1) end, begin _pipe@2 = Database_version, gleam@string:trim(_pipe@2) end}}; _ -> {error, {cannot_parse_response, {unexpected_response, Response_text}}} end. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 110). -spec version(client_options:clam_av_client_options()) -> {ok, clam_version_response()} | {error, clam_error()}. version(Options) -> Res = execute_adhoc_command(Options, <<"VERSION"/utf8>>), case Res of {ok, Bits} -> Response_text = begin _pipe = Bits, gleam@bit_array:to_string(_pipe) end, case Response_text of {ok, Text} -> parse_version_response(Text); _ -> {error, {cannot_parse_response, invalid_binary_data}} end; {error, Error} -> {error, Error} end. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 235). -spec get_length_indicator(integer()) -> bitstring(). get_length_indicator(Length) -> <>. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 268). -spec parse_virus_detected( binary(), client_options:logger(), fun((clam_scan_result()) -> {ok, clam_scan_result()} | {error, clam_error()}) ) -> {ok, clam_scan_result()} | {error, clam_error()}. parse_virus_detected(Response, Logger, Callback) -> Files = begin _pipe = Response, _pipe@1 = gleam@string:split(_pipe, <<"FOUND"/utf8>>), _pipe@3 = gleam@list:filter( _pipe@1, fun(X) -> begin _pipe@2 = X, gleam@string:trim(_pipe@2) end /= <<""/utf8>> end ), gleam@list:map( _pipe@3, fun(File_result) -> File_parts = begin _pipe@4 = File_result, gleam@string:split(_pipe@4, <<":"/utf8>>) end, case File_parts of [File_name, Virus_name] -> {infected_file, begin _pipe@5 = File_name, gleam@string:trim(_pipe@5) end, begin _pipe@6 = Virus_name, gleam@string:trim(_pipe@6) end}; _ -> (erlang:element(2, Logger))( <<"Could not parse file result"/utf8>> ), {infected_file, <<"UNKNOWN"/utf8>>, <<"UNKNOWN"/utf8>>} end end ) end, Callback({virus_detected, Files}). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 240). -spec parse_scan_result( binary(), client_options:logger(), fun((clam_scan_result()) -> {ok, clam_scan_result()} | {error, clam_error()}) ) -> {ok, clam_scan_result()} | {error, clam_error()}. parse_scan_result(Response, Logger, Callback) -> Formatted_lower = begin _pipe = Response, string:lowercase(_pipe) end, case begin _pipe@1 = Formatted_lower, gleam_stdlib:string_ends_with(_pipe@1, <<"ok"/utf8>>) end of true -> Callback(clean); false -> case begin _pipe@2 = Formatted_lower, gleam_stdlib:string_ends_with(_pipe@2, <<"error"/utf8>>) end of true -> {error, {scan_error, Response}}; false -> case begin _pipe@3 = Formatted_lower, gleam_stdlib:string_ends_with(_pipe@3, <<"found"/utf8>>) end of true -> parse_virus_detected( Response, Logger, fun(Virus_detected) -> Callback(Virus_detected) end ); false -> {error, {cannot_parse_response, {unexpected_response, Response}}} end end end. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 208). -spec send_file( mug:socket(), bitstring(), client_options:clam_av_client_options(), fun(() -> {ok, GPH} | {error, mug:error()}) ) -> {ok, GPH} | {error, mug:error()}. send_file(Socket, File_contents, Options, Callback) -> Byte_size = erlang:byte_size(File_contents), Packet = begin _pipe = Byte_size, _pipe@1 = get_length_indicator(_pipe), _pipe@2 = gleam@bit_array:append(_pipe@1, File_contents), gleam@bit_array:append(_pipe@2, <<0:32/little>>) end, (erlang:element(4, erlang:element(6, Options)))( <<<<<<<<":: Uploading file of size "/utf8, (begin _pipe@3 = Byte_size, erlang:integer_to_binary(_pipe@3) end)/binary>>/binary, "B. (Total packet size "/utf8>>/binary, (begin _pipe@4 = Packet, _pipe@5 = erlang:byte_size(_pipe@4), erlang:integer_to_binary(_pipe@5) end)/binary>>/binary, "B)"/utf8>> ), common@tcp:send_bytes(Socket, Packet, Options, fun() -> Callback() end). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 186). -spec tcp_instream(client_options:clam_av_client_options(), bitstring()) -> {ok, bitstring()} | {error, mug:error()}. tcp_instream(Options, File_content) -> common@internal:execute_command( Options, <<"INSTREAM"/utf8>>, fun(Socket) -> (erlang:element(4, erlang:element(6, Options)))( <<":: Socket acquired"/utf8>> ), send_file( Socket, File_content, Options, fun() -> (erlang:element(4, erlang:element(6, Options)))( <<":: File upload complete"/utf8>> ), common@tcp:receive_bytes( Socket, Options, fun(Response_bytes) -> (erlang:element(4, erlang:element(6, Options)))( <<":: Received response"/utf8>> ), {ok, Response_bytes} end ) end ) end ). -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 159). -spec instream(client_options:clam_av_client_options(), bitstring()) -> {ok, clam_scan_result()} | {error, clam_error()}. instream(Options, File_content) -> Padded_file_content = gleam_stdlib:bit_array_pad_to_bytes(File_content), case tcp_instream(Options, Padded_file_content) of {ok, Response} -> case gleam@bit_array:to_string(Response) of {ok, Response_text} -> parse_scan_result( Response_text, erlang:element(6, Options), fun(Scan_result) -> {ok, Scan_result} end ); {error, _} -> {error, {cannot_parse_response, invalid_binary_data}} end; {error, Error} -> {error, {connection_error, Error}} end.