/* * Created by PyramIDE. * User: フランスのトトロ aka (David RENÉ) * Date: 12/07/2017 * Time: 01:28 * © David RENÉ */ read cipher/base64.anubis read tools/basis.anubis read tools/findstring.anubis read tools/streams.anubis read system/string.anubis read system/logger.anubis read system/data_io.anubis read web/mime.anubis read calexium_lib/net_services_protocols/logger_service.anubis read calexium_lib/mail/tools.anubis read calexium_lib/mail/decode_mail.anubis read calexium_lib/mail/encode_mail.anubis read calexium_lib/mail/lexers/fqa.anubis transmit calexium_lib/mail/types/generated/email_address.anubis transmit calexium_lib/mail/types/generated/email_to_send.anubis public type Mail_Structure: mail_header_content(String header, String content). public define Mail_Structure no_data_mail = mail_header_content("",""). //public type Email_Address: email_address(String name, String address). public type File_Attached : attached_file(String filename). //, RStream filestream). //public type Email_to_send : data_to_send( Email_Address from, List(Email_Address) to, List(Email_Address) cc, List(Email_Address) bcc, String subject, String content, List(File_Attached) files, Bool send_copy, //send copy to sender by bcc (useful when the email is sent by an automat) // String from, String reply_to ). define Bool is_element ( String element, List(String) list )= if list is { [] then false, [h . t] then if h = element then true else is_element(element, t) }. define Maybe(List($T2)) _do_to_list ( List($T1) list, $T1 -> Maybe($T2) to_do, List($T2) new_list )= if list is { [] then success(new_list), [h . t] then with is_done = to_do(h), if is_done is { failure then failure, success(done) then _do_to_list(t, to_do, [done . new_list]) } }. public define Maybe(List($T2)) do_to_list ( List($T1) list, $T1 -> Maybe($T2) to_do, )= with result = _do_to_list(list, to_do, []), if result is { failure then failure, success(new_list) then success(reverse(new_list)) }. define Maybe($T) last_element ( List($T) list )= if list is { [] then failure, [h . t] then if t is { [] then success(h), [h1 . t1] then last_element(t) } }. public define String address_to_string ( Email_Address mail )= (if mail.name = "" then "" else to_MIME_text("UTF-8", mail.name) + " ") + "<" + mail.address + ">" . define String get_mime_of_extensions ( String ext, List(MIME) mime_list )= if mime_list is { [] then "application/octet-stream", [h . t] then if h is mime(_,_, exts) then if is_element(ext, exts) then to_String(h) else get_mime_of_extensions(ext, t) }. define String get_mime ( String filename )= if last_element(split_by_token(filename, '.')) is { failure then "application/octet-stream", success(ext)then get_mime_of_extensions("." + ext, known_mime_types) }. define String limit_line_length ( String source, Int limit, String so_far ) = with l = length(source), if l > limit then if sub_string(source, 0, limit) is { failure then so_far, // impossible success(s) then if sub_string(source, limit, l - limit) is { failure then so_far + s, // impossible success(new_source) then limit_line_length(new_source, limit, so_far + s + crlf) } } else so_far + source. public define String limit_line_length ( String source, Int limit ) = limit_line_length(source, limit, ""). public define String data_file_multipart ( String filename, ByteArray data, ) = with data_file = limit_line_length(fast_base64_encode(data, false), 76), "Content-Type: " + get_mime(filename) + ";" + crlf + " name=\"" + filename + "\"" + crlf + //"Content-ID :" + crlf + "Content-Transfer-Encoding: base64" + crlf + "Content-Disposition: attachment;" + crlf + " filename=\"" + filename + "\"" + crlf + crlf + data_file + crlf . define String data_file_multipart ( File_ref file, )= with data_file = if read_from_file(file.path +"/"+file.name) is { cannot_find_file then constant_byte_array(0,0), read_error(data) then data ok(data) then data }, data_file_multipart(file.name, data_file) . if file(fullpath, read) is { failure then logError(debug_log, "Can't open mail '" + file_name + "'.");failure success(f) then success(f) } define String data_files_multipart ( List(File_ref) files, String boundary )= if files is { [] then "", [file_j . t] then "--" + boundary + crlf + data_file_multipart(file_j) + data_files_multipart(t, boundary) } . public define String str_utime_send_mail ( UTime t ) = with date_send = convert_time(t.seconds), if day_name(date_send.week_day) is { failure then "", success(the_day_name) then the_day_name + ", " }+ date_send.day + " " + if month_name(date_send.month) is { failure then to_decimal(date_send.month), success(the_month_name) then the_month_name }+ " " + date_send.year + " " + zero_pad_n(2, date_send.hour) + ":" + zero_pad_n(2, date_send.minute) + ":" + zero_pad_n(2, date_send.second) //+ " +0000" . public define String get_rfc822_date_format = str_utime_send_mail(unow). if capture_shell_command("date", ["-R"]) is { failure then str_utime_send_mail(unow), success(s) then if split_lines(s) is [h . t] then h else str_utime_send_mail(unow) }. define Int _next_ws_pos ( List(Word8) line, Int pos ) = if line is { [] then pos, [h . t] then if h = 32 | h = 9 then pos else _next_ws_pos(t, pos + 1) }. define String encode_plain_text_content ( List(String) lines, List(String) output, ) = if lines is { [] then join(crlf, reverse(output)), [line . t] then with l = length(line), pos = 75 - _next_ws_pos(reverse(explode(force(sub_string(line, 0, 75), line))), 1), if l > 76 then if sub_string(line, 0, pos) is { failure then (if pos < 0 then unique else println("sub_string 1 failure into encode_plain_text_content()")); encode_plain_text_content(t, [line . output]), success(l1) then if sub_string(line, pos + 1, l - pos - 1) is { failure then println("sub_string 2 failure into encode_plain_text_content()"); encode_plain_text_content(t, [line . output]), success(l2) then encode_plain_text_content([l2 . t], [l1 + " " . output]) } } else encode_plain_text_content(t, [line . output]) }. public define String encode_content ( String content, Bool is_html, ) = if is_html then join(crlf, split_lines(content)) + crlf else encode_plain_text_content(split_lines(content), []) + crlf. public define String compose_mail ( Email_to_send send ) = //with header_to_name = "To: ", if send is data_to_send(from, to_list, cc_list, bcc_list, subject, content, files, send_copy, reply_to) then with send_date = get_rfc822_date_format, text_type = if find("" + crlf + "User-Agent: Anubis XLib email sender" + crlf + "From: " + "<" + from.address + ">" + crlf + (if reply_to = "" then "" else "Reply-To: <" + reply_to +">" + crlf )+ "MIME-Version: 1.0" + crlf + //header_to_name + folding(to, 68 - length(header_to_name)) + crlf + "To: " + folding(to_list, address_to_string) + crlf + ( // with header_cc_name = "Cc: ", // header_cc_name + folding(cc_list, 68 - length(header_cc_name)) + crlf if cc_list is [] then "" else "Cc: " + folding(cc_list, address_to_string) + crlf ) + (if subject = "" then "" else "Subject: " + to_folded_base64_text("UTF-8", subject) + crlf ) + if is_multipart then with boundary = to_ascii(sha1((from, send_date))), "Content-Type: multipart/mixed;" + crlf + " boundary=\"" + boundary + "\"" + crlf + crlf + "This is a multi-part message in MIME format." + crlf + "--" + boundary + crlf + data_text + crlf + data_files_multipart(files, boundary) + "--" + boundary + "--" else data_text . define String message_header ( Data_IO d_io ) = if (Maybe(String))read_line(d_io) is { failure then "", success(line) then if length(line) = 0 then "" else line + message_header(d_io) }. public define String get_message_header ( String file_name )= //open the message file from the drive if (Maybe(RStream))file(file_name, read) is { failure then println("get_message_header: can't open mail ["+file_name+"] from disk."); "", //logError(debug_log, "get_message_header: can't open mail ["+file_name+"] from disk."); "", success(source) then message_header(make_data_io(source)) }. public define String get_message_header ( List(Data_IO) mail_parts )= //open the message file from the drive if rewind(mail_parts) then "get_message_header NOT YET Implemented. Please report that error to Calexium" else "". public define Mail_Structure separate_data_mail ( String mail )= if find(crlfcrlf, mail, 0) is { failure then mail_header_content("", mail), success(position) then mail_header_content( if sub_string(mmake_directoriesail, 0, position) is { failure then "", success(substring) then substring }, if sub_string(mail, position + 4 , length(mail) - (position + 4)) is { failure then mail, success(substring) then substring } ) }. public define List(String) list_of_mails ( String string_list, List(String) mails_list )= if find(",", string_list, 0) is { failure then [string_list . mails_list], success(separator) then if sub_string(string_list, 0, separator) is { failure then [], success(mail) then if sub_string(string_list, separator + 1, length(string_list) - (separator + 1)) is { failure then [], success(rest) then list_of_mails(rest, [mail . mails_list]) } } } . public define Maybe(Email_Address) parse_address ( String mail, )= if find("<", mail, 0) is { failure then with result_mail = trim(mail), if test_fqa(result_mail) then success(email_address("", result_mail)) else failure, success(separator_b) then if find(">", mail, separator_b + 1) is { failure then failure, success(separator_e) then with name_string = sub_string(mail, 0, separator_b), address_string = sub_string(mail, separator_b + 1, separator_e - separator_b - 1), if address_string is { failure then failure, success(add_str) then with name = if name_string is { failure then "", success(name_str) then trim(name_str) }, if test_fqa(add_str) then success(email_address(name, add_str)) else failure } } }.