-module(clamav). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([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", 37). -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", 52). -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", 91). -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", 104). -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", 73). -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", 198). -spec get_length_indicator(integer()) -> bitstring(). get_length_indicator(Length) -> <>. -file("/home/runner/work/gleam-clamav/gleam-clamav/src/clamav.gleam", 231). -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", 203). -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", 171). -spec send_file( mug:socket(), bitstring(), client_options:clam_av_client_options(), fun(() -> {ok, GPC} | {error, mug:error()}) ) -> {ok, GPC} | {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", 149). -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", 122). -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.