From 0a6e9a0f9d18b8074aadaadab279dfe696d8802b Mon Sep 17 00:00:00 2001 From: Payas Relekar Date: Sun, 28 Jul 2024 18:48:44 +0530 Subject: [PATCH] Add Header type and use Header list in place of Mail.to --- src/gleambox.gleam | 86 ++++++++++++++++++++++++---------------------- src/header.gleam | 41 ++++++++++++++++++++++ 2 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 src/header.gleam diff --git a/src/gleambox.gleam b/src/gleambox.gleam index 9fc57fc..5a6151b 100644 --- a/src/gleambox.gleam +++ b/src/gleambox.gleam @@ -1,30 +1,30 @@ import birl.{type Time} import gleam/dict.{type Dict} +import gleam/io import gleam/iterator.{type Iterator} import gleam/list +import gleam/option.{type Option} import gleam/pair import gleam/regex import gleam/result import gleam/string +import header.{type Header} import simplifile -// import gleam/io - pub type MBox { - MBox(headers: Dict(String, String), body: String) + MBox(headers: List(Header), body: String) InvalidMBox } pub type Mail { Mail( from: Result(String, Nil), - to: Result(String, Nil), - // TODO: convert to List(String) + to: List(String), subject: Result(String, Nil), message_id: Result(String, Nil), date: Result(Time, Nil), body: Result(String, Nil), - headers: Result(Dict(String, String), Nil), + headers: Result(List(Header), Nil), ) InvalidMail } @@ -40,7 +40,7 @@ pub fn parse_mbox(mboxcontents: String) -> MBox { } } -fn get_headers(mbox: MBox) -> Result(Dict(String, String), Nil) { +fn get_headers(mbox: MBox) -> Result(List(Header), Nil) { case mbox { InvalidMBox -> Error(Nil) MBox(headers, _) -> Ok(headers) @@ -55,7 +55,7 @@ fn parse_body(mboxcontents: String) -> Result(String, Nil) { } } -fn parse_headers(mboxcontents: String) -> Result(Dict(String, String), Nil) { +fn parse_headers(mboxcontents: String) -> Result(List(Header), Nil) { case string.split_once(mboxcontents, "\n\n") { Ok(pair) -> pair.first(pair) @@ -63,14 +63,14 @@ fn parse_headers(mboxcontents: String) -> Result(Dict(String, String), Nil) { |> fix_multiline_values |> string.split("\n") // convert to dict of headers - |> list.map(get_header_dict) - |> dict.from_list + |> list.map(get_header_tuple) + |> list.map(header.from_tuple) |> Ok Error(_) -> Error(Nil) } } -fn get_header_dict(s: String) -> #(String, String) { +fn get_header_tuple(s: String) -> #(String, String) { s |> string.split_once(": ") |> result.unwrap(or: #("", "")) @@ -97,34 +97,36 @@ fn remove_dead_space(acc: String, matched_content: String) -> String { } // TODO: better error -pub fn maildir_iterate(maildir_path: String) -> Iterator(#(String, String)) { - case simplifile.get_files(maildir_path) { - Ok(maillist) -> - iterator.from_list(maillist) - |> iterator.map(fn(path) { #(path, read_file(path)) }) - Error(_) -> #("", "") |> list.wrap |> iterator.from_list - } -} - -// pub fn main() { -// maildir_iterate("/home/payas/.mail/Gmail/[Gmail]/All Mail/cur") -// |> iterator.each(fn(mboxpair) { -// case parse(pair.second(mboxpair)) { -// InvalidMBox -> io.debug("ERR MBOX: " <> pair.first(mboxpair)) -// MBox(headers, body) -> -// case mbox_to_mail(MBox(headers, body)) { -// InvalidMail -> io.debug("ERR MAIL: " <> pair.first(mboxpair)) -// _ -> io.debug("SUCCESS: " <> pair.first(mboxpair)) -// } -// } -// }) +// fn maildir_iterate(maildir_path: String) -> Iterator(#(String, String)) { +// case simplifile.get_files(maildir_path) { +// Ok(maillist) -> +// iterator.from_list(maillist) +// |> iterator.map(fn(path) { #(path, read_file(path)) }) +// Error(_) -> #("", "") |> list.wrap |> iterator.from_list +// } // } -fn read_file(file_path: String) -> String { - file_path - |> simplifile.read - |> result.unwrap(or: "") -} +// pub fn main() { +// maildir_iterate("/home/payas/.mail/Gmail/[Gmail]/All Mail/cur") +// |> iterator.each(fn(mboxpair) { +// case parse_mbox(pair.second(mboxpair)) { +// InvalidMBox -> io.debug("ERR MBOX: " <> pair.first(mboxpair)) +// MBox(headers, body) -> +// case mbox_to_mail(MBox(headers, body)) { +// InvalidMail -> io.debug("ERR MAIL: " <> pair.first(mboxpair)) +// _ -> io.debug("SUCCESS: " <> pair.first(mboxpair)) +// Mail(_, to, _, _, _, _, _) -> +// io.debug(to) |> list.first |> result.unwrap("") +// } +// } +// }) +// } + +// fn read_file(file_path: String) -> String { + // file_path + // |> simplifile.read + // |> result.unwrap(or: "") +// } pub fn parse_mail(mboxcontents: String) -> Mail { case parse_mbox(mboxcontents) { @@ -138,11 +140,11 @@ fn mbox_to_mail(mbox: MBox) -> Mail { InvalidMBox -> InvalidMail MBox(headers, body) -> Mail( - from: dict.get(headers, "From"), - to: dict.get(headers, "To"), - message_id: dict.get(headers, "Message-ID"), - subject: dict.get(headers, "Subject"), - date: case dict.get(headers, "Date") { + from: header.get_first_by_name(headers, "From"), + to: header.get_by_name(headers, "To"), + message_id: header.get_first_by_name(headers, "Message-ID"), + subject: header.get_first_by_name(headers, "Subject"), + date: case header.get_first_by_name(headers, "Date") { Ok(date_str) -> birl.parse(date_str) Error(_) -> Error(Nil) }, diff --git a/src/header.gleam b/src/header.gleam new file mode 100644 index 0000000..58d5d95 --- /dev/null +++ b/src/header.gleam @@ -0,0 +1,41 @@ +import gleam/iterator +import gleam/order +import gleam/pair +import gleam/string + +pub type Header { + Header(name: String, body: String) +} + +pub fn from_tuple(tuple: #(String, String)) -> Header { + Header(name: pair.first(tuple), body: pair.second(tuple)) +} + +pub fn get_by_name(headers: List(Header), name: String) -> List(String) { + headers + |> iterator.from_list + |> iterator.filter(fn(header) { + case string.compare(header.name, name) { + order.Eq -> True + _ -> False + } + }) + |> iterator.map(fn(header) { header.body }) + |> iterator.to_list +} + +pub fn get_first_by_name( + headers: List(Header), + name: String, +) -> Result(String, Nil) { + headers + |> iterator.from_list + |> iterator.filter(fn(header) { + case string.compare(header.name, name) { + order.Eq -> True + _ -> False + } + }) + |> iterator.map(fn(header) { header.body }) + |> iterator.first +}