1/* maildir 2 Author: Gimenez, Christian. 3 4 Copyright (C) 2016 Gimenez, Christian 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19 09 nov 2016 20*/ 21 22 23:- module(maildir, [ 24 get_flags/3, set_flags/3, add_flags/3, 25 list_mails/3, 26 in_maildir_type/2, 27 search_mail/4 28 ]).
39:- license(gplv3). 40 41:- ensure_loaded(library(dcg/basics)). 42:- ensure_loaded(library(log)).
49mailfile(Basename, Flags) --> string_without(`:`, Basename), `:`, string(Flags).
56mailfile_terms(Filepath, Basename, FlagsLst) :-
57 atom_codes(Filepath, FilepathCodes),
58 mailfile(BasenameCodes, FlagsLst, FilepathCodes, []),!,
59 atom_codes(Basename, BasenameCodes).
64maildir_decode(MaildirType, Basename, Flags, Filepath) :-
65 atom_codes(Filepath, FilepathCodes),
66 mailfile(BasenameCodes, FlagsCodes, FilepathCodes, []),
67 atom_codes(Basename, BasenameCodes), atom_codes(Flags, FlagsCodes),
68 in_maildir_type(Filepath, MaildirType).
info starting with "1,": Experimental semantics.
info starting with "2,": Each character after the comma is an independent flag.
Flag "P" (passed): the user has resent/forwarded/bounced this message to someone else. Flag "R" (replied): the user has replied to this message. Flag "S" (seen): the user has viewed this message, though perhaps he didn't read all the way through it. Flag "T" (trashed): the user has moved this message to the trash; the trash will be emptied by a later user action. Flag "D" (draft): the user considers this message a draft; toggled at user discretion. Flag "F" (flagged): user-defined flag; toggled at user discretion.
New flags may be defined later. Flags must be stored in ASCII order: e.g., "2,FRS".
*/
91flag2(C, Meaning) :-
92 number(C),
93 atom_codes(C2, [C]), 94 flag2(C2, Meaning)
94. 95flag2('P', passed). 96flag2('R', replied). 97flag2('S', seen). 98flag2('T', trashed). 99flag2('D', draft). 100flag2('F', flagged).
108flags_meaning([], []). 109flags_meaning([T1|R1], [T2|R2]) :- 110 flag2(T2, T1),!, 111 flags_meaning(R1, R2).
121get_flags(Filename, Basename, Flags) :-
122 mailfile_terms(Filename, Basename, FlagsChars),
123 append(`2,`, FlagsChars2, FlagsChars),
124 sort(FlagsChars2, SortedFlagsC),
125 flags_meaning(Flags, SortedFlagsC).
132set_flags(Basename, Flags, Filename) :-
133 flags_meaning(Flags, FlagsC),
134 sort(FlagsC, SortedFlagsC),
135 atomic_list_concat(SortedFlagsC, SortedFlags),
136 atomic_list_concat([Basename, ':2,', SortedFlags], Filename).
If Filename has no Flags (i.e. is in new directory ) it will add the ':2,' format. */
146add_flags(Filename, NewFlags, NewFilename) :- 147 get_flags(Filename, Basename, Flags),!, % red cut 148 add_flags_int(Flags, NewFlags, AddedFlags), 149 set_flags(Basename, AddedFlags, NewFilename). 150add_flags(Filename, NewFlags, NewFilename) :-
152 set_flags(Filename, NewFlags, NewFilename)
152. 153
159add_flags_int([], NewFlags, AddedFlags) :- 160 sort(NewFlags, AddedFlags), !. 161add_flags_int(Flags, [], AddedFlags) :- 162 sort(Flags, AddedFlags), !. 163add_flags_int(Flags, [F|Rest], Rest2) :- 164 member(F, Flags),!, % red cut 165 add_flags_int(Flags, Rest, Rest2). 166add_flags_int(Flags, [F|Rest], [F|Rest2]) :- 167 % \+ member(F, Flags),!, % True always! 168 add_flags_int(Flags, Rest, Rest2).
176maildir_type(cur). 177maildir_type(new). 178maildir_type(tmp).
186list_mails(Dir, Type, LstMails) :-
187 maildir_type(Type),
188 atomic_list_concat([Dir, '/', Type, '/*'], Wildcard),
189 expand_file_name(Wildcard, LstMails).
198in_maildir_type(Filepath, Maildir_Type) :-
199 maildir_type(Maildir_Type),
200 file_directory_name(Filepath, Dirs),
201 file_base_name(Dirs, Maildir_Type).
Condition must be a predicate with 1 arguments: Mailpath.
search_mail('~/Maildir/', cur, to_substr("someone"), L).
Will search all mails on `~/Maildir/cur` whose "To" field have "someone" as substring. */
219search_mail(Mailbox, Type, Condition, LstMails) :-
220 list_mails(Mailbox, Type, LstMails1),
221
222 length(LstMails1, Amount),
223 format(atom(A), '(~w/~w) Searching on ~w mails for ~w...',
224 [Mailbox, Type, Amount, Condition]),
225 log_message(maildir:search_mail, A),
226
227 has_condition(Condition, LstMails1, LstMails).
233has_condition(_Condition, [], []). 234has_condition(Condition, [Mail|Rest], [Mail|Rest2]) :- 235 call(Condition, Mail),!, %red cut 236 has_condition(Condition, Rest, Rest2). 237has_condition(Condition, [_Mail|Rest], Rest2) :-
239 has_condition(Condition, Rest, Rest2)
maildir: Maildir implementation
Maildir implementation for reading e-mails under the Maildir format.