-module(gleambox). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([get_headers/1, get_header/2, parse/1, maildir_iterator/1, maildir_iterate/1, main/0]). -export_type([m_box/0, mail/0]). -type m_box() :: {m_box, gleam@dict:dict(binary(), binary()), binary()} | invalid_m_box. -type mail() :: {mail, {ok, binary()} | {error, nil}, {ok, binary()} | {error, nil}, {ok, binary()} | {error, nil}, {ok, binary()} | {error, nil}, {ok, birl:time()} | {error, nil}, {ok, binary()} | {error, nil}, {ok, gleam@dict:dict(binary(), binary())} | {error, nil}} | invalid_mail. -spec get_headers(m_box()) -> {ok, gleam@dict:dict(binary(), binary())} | {error, nil}. get_headers(Mbox) -> case Mbox of invalid_m_box -> {error, nil}; {m_box, Headers, _} -> {ok, Headers} end. -spec get_header(m_box(), binary()) -> {ok, binary()} | {error, nil}. get_header(Mbox, Key) -> case Mbox of {m_box, Headers, _} -> _pipe = Headers, gleam@dict:get(_pipe, Key); invalid_m_box -> {error, nil} end. -spec parse_body(binary()) -> {ok, binary()} | {error, nil}. parse_body(Mboxcontents) -> case gleam@string:split_once(Mboxcontents, <<"\n\n"/utf8>>) of {ok, Pair} -> _pipe = gleam@pair:second(Pair), {ok, _pipe}; {error, _} -> {error, nil} end. -spec get_header_dict(binary()) -> {binary(), binary()}. get_header_dict(S) -> _pipe = S, _pipe@1 = gleam@string:split_once(_pipe, <<": "/utf8>>), gleam@result:unwrap(_pipe@1, {<<""/utf8>>, <<""/utf8>>}). -spec remove_dead_space(binary(), binary()) -> binary(). remove_dead_space(Acc, Matched_content) -> _assert_subject = gleam@regex:from_string(<<"\\s+"/utf8>>), {ok, Dead_space} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gleambox"/utf8>>, function => <<"remove_dead_space"/utf8>>, line => 98}) end, _pipe = Dead_space, _pipe@1 = gleam@regex:split(_pipe, Matched_content), _pipe@2 = gleam@string:join(_pipe@1, <<" "/utf8>>), gleam@string:replace(Acc, Matched_content, _pipe@2). -spec fix_multiline_values(binary()) -> binary(). fix_multiline_values(S) -> _assert_subject = gleam@regex:compile( <<": [^\n]+\n\\s+[^\n]+$"/utf8>>, {options, true, true} ), {ok, Multi_line_value} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gleambox"/utf8>>, function => <<"fix_multiline_values"/utf8>>, line => 86}) end, _pipe = Multi_line_value, _pipe@1 = gleam@regex:scan(_pipe, S), _pipe@2 = gleam@list:map( _pipe@1, fun(Match) -> erlang:element(2, Match) end ), _pipe@3 = gleam@list:scan(_pipe@2, S, fun remove_dead_space/2), _pipe@4 = gleam@list:first(_pipe@3), gleam@result:unwrap(_pipe@4, <<"bar"/utf8>>). -spec parse_headers(binary()) -> {ok, gleam@dict:dict(binary(), binary())} | {error, nil}. parse_headers(Mboxcontents) -> case gleam@string:split_once(Mboxcontents, <<"\n\n"/utf8>>) of {ok, Pair} -> _pipe = gleam@pair:first(Pair), _pipe@1 = fix_multiline_values(_pipe), _pipe@2 = gleam@string:split(_pipe@1, <<"\n"/utf8>>), _pipe@3 = gleam@list:map(_pipe@2, fun get_header_dict/1), _pipe@4 = maps:from_list(_pipe@3), {ok, _pipe@4}; {error, _} -> {error, nil} end. -spec parse(binary()) -> m_box(). parse(Mboxcontents) -> Headers = parse_headers(Mboxcontents), Body = parse_body(Mboxcontents), case {Headers, Body} of {{ok, Parsed_headers}, {ok, Parsed_body}} -> {m_box, Parsed_headers, Parsed_body}; {_, _} -> invalid_m_box end. -spec read_file(binary()) -> binary(). read_file(File_path) -> _pipe = File_path, _pipe@1 = simplifile:read(_pipe), gleam@result:unwrap(_pipe@1, <<""/utf8>>). -spec maildir_iterator(binary()) -> gleam@iterator:iterator(binary()). maildir_iterator(Mbox_path) -> _pipe = Mbox_path, _pipe@1 = simplifile:get_files(_pipe), _pipe@2 = gleam@result:lazy_unwrap(_pipe@1, fun gleam@list:new/0), _pipe@3 = gleam@iterator:from_list(_pipe@2), gleam@iterator:map(_pipe@3, fun read_file/1). -spec maildir_iterate(binary()) -> gleam@iterator:iterator({binary(), binary()}). maildir_iterate(Maildir_path) -> case simplifile:get_files(Maildir_path) of {ok, Maillist} -> _pipe = gleam@iterator:from_list(Maillist), gleam@iterator:map(_pipe, fun(Path) -> {Path, read_file(Path)} end); {error, _} -> _pipe@1 = {<<""/utf8>>, <<""/utf8>>}, _pipe@2 = gleam@list:wrap(_pipe@1), gleam@iterator:from_list(_pipe@2) end. -spec mbox_to_mail(m_box()) -> mail(). mbox_to_mail(Mbox) -> case Mbox of invalid_m_box -> invalid_mail; {m_box, Headers, Body} -> {mail, gleam@dict:get(Headers, <<"From"/utf8>>), gleam@dict:get(Headers, <<"To"/utf8>>), gleam@dict:get(Headers, <<"Subject"/utf8>>), gleam@dict:get(Headers, <<"Message-ID"/utf8>>), case gleam@dict:get(Headers, <<"Date"/utf8>>) of {ok, Date_str} -> birl:parse(Date_str); {error, _} -> {error, nil} end, {ok, Body}, begin _pipe = Mbox, get_headers(_pipe) end} end. -spec main() -> nil. main() -> _pipe = maildir_iterate( <<"/home/payas/.mail/Gmail/[Gmail]/All Mail/cur"/utf8>> ), gleam@iterator:each( _pipe, fun(Mboxpair) -> case parse(gleam@pair:second(Mboxpair)) of invalid_m_box -> gleam@io:debug( <<"ERR MBOX: "/utf8, (gleam@pair:first(Mboxpair))/binary>> ); {m_box, Headers, Body} -> case mbox_to_mail({m_box, Headers, Body}) of invalid_mail -> gleam@io:debug( <<"ERR MAIL: "/utf8, (gleam@pair:first(Mboxpair))/binary>> ); _ -> gleam@io:debug( <<"SUCCESS: "/utf8, (gleam@pair:first(Mboxpair))/binary>> ) end end end ).