Author: Manos Pitsidianakis [el13635@mail.ntua.gr]
Hash: 8e07843c4af4da933046fbf846513bb584062265
Timestamp: Fri, 28 Jul 2017 14:45:19 +0000 (5 years ago)

+1251 -71 +/-8 browse
mailbox: add threads
mailbox: add threads

Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
1diff --git a/.gitignore b/.gitignore
2index 08ec5e5..c3e41af 100644
3--- a/.gitignore
4+++ b/.gitignore
5 @@ -7,4 +7,3 @@ target/
6 **/*.rs.bk
7 .gdb_history
8 *.log
9-
10 diff --git a/COPYING b/COPYING
11new file mode 100644
12index 0000000..94a9ed0
13--- /dev/null
14+++ b/COPYING
15 @@ -0,0 +1,674 @@
16+ GNU GENERAL PUBLIC LICENSE
17+ Version 3, 29 June 2007
18+
19+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
20+ Everyone is permitted to copy and distribute verbatim copies
21+ of this license document, but changing it is not allowed.
22+
23+ Preamble
24+
25+ The GNU General Public License is a free, copyleft license for
26+ software and other kinds of works.
27+
28+ The licenses for most software and other practical works are designed
29+ to take away your freedom to share and change the works. By contrast,
30+ the GNU General Public License is intended to guarantee your freedom to
31+ share and change all versions of a program--to make sure it remains free
32+ software for all its users. We, the Free Software Foundation, use the
33+ GNU General Public License for most of our software; it applies also to
34+ any other work released this way by its authors. You can apply it to
35+ your programs, too.
36+
37+ When we speak of free software, we are referring to freedom, not
38+ price. Our General Public Licenses are designed to make sure that you
39+ have the freedom to distribute copies of free software (and charge for
40+ them if you wish), that you receive source code or can get it if you
41+ want it, that you can change the software or use pieces of it in new
42+ free programs, and that you know you can do these things.
43+
44+ To protect your rights, we need to prevent others from denying you
45+ these rights or asking you to surrender the rights. Therefore, you have
46+ certain responsibilities if you distribute copies of the software, or if
47+ you modify it: responsibilities to respect the freedom of others.
48+
49+ For example, if you distribute copies of such a program, whether
50+ gratis or for a fee, you must pass on to the recipients the same
51+ freedoms that you received. You must make sure that they, too, receive
52+ or can get the source code. And you must show them these terms so they
53+ know their rights.
54+
55+ Developers that use the GNU GPL protect your rights with two steps:
56+ (1) assert copyright on the software, and (2) offer you this License
57+ giving you legal permission to copy, distribute and/or modify it.
58+
59+ For the developers' and authors' protection, the GPL clearly explains
60+ that there is no warranty for this free software. For both users' and
61+ authors' sake, the GPL requires that modified versions be marked as
62+ changed, so that their problems will not be attributed erroneously to
63+ authors of previous versions.
64+
65+ Some devices are designed to deny users access to install or run
66+ modified versions of the software inside them, although the manufacturer
67+ can do so. This is fundamentally incompatible with the aim of
68+ protecting users' freedom to change the software. The systematic
69+ pattern of such abuse occurs in the area of products for individuals to
70+ use, which is precisely where it is most unacceptable. Therefore, we
71+ have designed this version of the GPL to prohibit the practice for those
72+ products. If such problems arise substantially in other domains, we
73+ stand ready to extend this provision to those domains in future versions
74+ of the GPL, as needed to protect the freedom of users.
75+
76+ Finally, every program is threatened constantly by software patents.
77+ States should not allow patents to restrict development and use of
78+ software on general-purpose computers, but in those that do, we wish to
79+ avoid the special danger that patents applied to a free program could
80+ make it effectively proprietary. To prevent this, the GPL assures that
81+ patents cannot be used to render the program non-free.
82+
83+ The precise terms and conditions for copying, distribution and
84+ modification follow.
85+
86+ TERMS AND CONDITIONS
87+
88+ 0. Definitions.
89+
90+ "This License" refers to version 3 of the GNU General Public License.
91+
92+ "Copyright" also means copyright-like laws that apply to other kinds of
93+ works, such as semiconductor masks.
94+
95+ "The Program" refers to any copyrightable work licensed under this
96+ License. Each licensee is addressed as "you". "Licensees" and
97+ "recipients" may be individuals or organizations.
98+
99+ To "modify" a work means to copy from or adapt all or part of the work
100+ in a fashion requiring copyright permission, other than the making of an
101+ exact copy. The resulting work is called a "modified version" of the
102+ earlier work or a work "based on" the earlier work.
103+
104+ A "covered work" means either the unmodified Program or a work based
105+ on the Program.
106+
107+ To "propagate" a work means to do anything with it that, without
108+ permission, would make you directly or secondarily liable for
109+ infringement under applicable copyright law, except executing it on a
110+ computer or modifying a private copy. Propagation includes copying,
111+ distribution (with or without modification), making available to the
112+ public, and in some countries other activities as well.
113+
114+ To "convey" a work means any kind of propagation that enables other
115+ parties to make or receive copies. Mere interaction with a user through
116+ a computer network, with no transfer of a copy, is not conveying.
117+
118+ An interactive user interface displays "Appropriate Legal Notices"
119+ to the extent that it includes a convenient and prominently visible
120+ feature that (1) displays an appropriate copyright notice, and (2)
121+ tells the user that there is no warranty for the work (except to the
122+ extent that warranties are provided), that licensees may convey the
123+ work under this License, and how to view a copy of this License. If
124+ the interface presents a list of user commands or options, such as a
125+ menu, a prominent item in the list meets this criterion.
126+
127+ 1. Source Code.
128+
129+ The "source code" for a work means the preferred form of the work
130+ for making modifications to it. "Object code" means any non-source
131+ form of a work.
132+
133+ A "Standard Interface" means an interface that either is an official
134+ standard defined by a recognized standards body, or, in the case of
135+ interfaces specified for a particular programming language, one that
136+ is widely used among developers working in that language.
137+
138+ The "System Libraries" of an executable work include anything, other
139+ than the work as a whole, that (a) is included in the normal form of
140+ packaging a Major Component, but which is not part of that Major
141+ Component, and (b) serves only to enable use of the work with that
142+ Major Component, or to implement a Standard Interface for which an
143+ implementation is available to the public in source code form. A
144+ "Major Component", in this context, means a major essential component
145+ (kernel, window system, and so on) of the specific operating system
146+ (if any) on which the executable work runs, or a compiler used to
147+ produce the work, or an object code interpreter used to run it.
148+
149+ The "Corresponding Source" for a work in object code form means all
150+ the source code needed to generate, install, and (for an executable
151+ work) run the object code and to modify the work, including scripts to
152+ control those activities. However, it does not include the work's
153+ System Libraries, or general-purpose tools or generally available free
154+ programs which are used unmodified in performing those activities but
155+ which are not part of the work. For example, Corresponding Source
156+ includes interface definition files associated with source files for
157+ the work, and the source code for shared libraries and dynamically
158+ linked subprograms that the work is specifically designed to require,
159+ such as by intimate data communication or control flow between those
160+ subprograms and other parts of the work.
161+
162+ The Corresponding Source need not include anything that users
163+ can regenerate automatically from other parts of the Corresponding
164+ Source.
165+
166+ The Corresponding Source for a work in source code form is that
167+ same work.
168+
169+ 2. Basic Permissions.
170+
171+ All rights granted under this License are granted for the term of
172+ copyright on the Program, and are irrevocable provided the stated
173+ conditions are met. This License explicitly affirms your unlimited
174+ permission to run the unmodified Program. The output from running a
175+ covered work is covered by this License only if the output, given its
176+ content, constitutes a covered work. This License acknowledges your
177+ rights of fair use or other equivalent, as provided by copyright law.
178+
179+ You may make, run and propagate covered works that you do not
180+ convey, without conditions so long as your license otherwise remains
181+ in force. You may convey covered works to others for the sole purpose
182+ of having them make modifications exclusively for you, or provide you
183+ with facilities for running those works, provided that you comply with
184+ the terms of this License in conveying all material for which you do
185+ not control copyright. Those thus making or running the covered works
186+ for you must do so exclusively on your behalf, under your direction
187+ and control, on terms that prohibit them from making any copies of
188+ your copyrighted material outside their relationship with you.
189+
190+ Conveying under any other circumstances is permitted solely under
191+ the conditions stated below. Sublicensing is not allowed; section 10
192+ makes it unnecessary.
193+
194+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
195+
196+ No covered work shall be deemed part of an effective technological
197+ measure under any applicable law fulfilling obligations under article
198+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
199+ similar laws prohibiting or restricting circumvention of such
200+ measures.
201+
202+ When you convey a covered work, you waive any legal power to forbid
203+ circumvention of technological measures to the extent such circumvention
204+ is effected by exercising rights under this License with respect to
205+ the covered work, and you disclaim any intention to limit operation or
206+ modification of the work as a means of enforcing, against the work's
207+ users, your or third parties' legal rights to forbid circumvention of
208+ technological measures.
209+
210+ 4. Conveying Verbatim Copies.
211+
212+ You may convey verbatim copies of the Program's source code as you
213+ receive it, in any medium, provided that you conspicuously and
214+ appropriately publish on each copy an appropriate copyright notice;
215+ keep intact all notices stating that this License and any
216+ non-permissive terms added in accord with section 7 apply to the code;
217+ keep intact all notices of the absence of any warranty; and give all
218+ recipients a copy of this License along with the Program.
219+
220+ You may charge any price or no price for each copy that you convey,
221+ and you may offer support or warranty protection for a fee.
222+
223+ 5. Conveying Modified Source Versions.
224+
225+ You may convey a work based on the Program, or the modifications to
226+ produce it from the Program, in the form of source code under the
227+ terms of section 4, provided that you also meet all of these conditions:
228+
229+ a) The work must carry prominent notices stating that you modified
230+ it, and giving a relevant date.
231+
232+ b) The work must carry prominent notices stating that it is
233+ released under this License and any conditions added under section
234+ 7. This requirement modifies the requirement in section 4 to
235+ "keep intact all notices".
236+
237+ c) You must license the entire work, as a whole, under this
238+ License to anyone who comes into possession of a copy. This
239+ License will therefore apply, along with any applicable section 7
240+ additional terms, to the whole of the work, and all its parts,
241+ regardless of how they are packaged. This License gives no
242+ permission to license the work in any other way, but it does not
243+ invalidate such permission if you have separately received it.
244+
245+ d) If the work has interactive user interfaces, each must display
246+ Appropriate Legal Notices; however, if the Program has interactive
247+ interfaces that do not display Appropriate Legal Notices, your
248+ work need not make them do so.
249+
250+ A compilation of a covered work with other separate and independent
251+ works, which are not by their nature extensions of the covered work,
252+ and which are not combined with it such as to form a larger program,
253+ in or on a volume of a storage or distribution medium, is called an
254+ "aggregate" if the compilation and its resulting copyright are not
255+ used to limit the access or legal rights of the compilation's users
256+ beyond what the individual works permit. Inclusion of a covered work
257+ in an aggregate does not cause this License to apply to the other
258+ parts of the aggregate.
259+
260+ 6. Conveying Non-Source Forms.
261+
262+ You may convey a covered work in object code form under the terms
263+ of sections 4 and 5, provided that you also convey the
264+ machine-readable Corresponding Source under the terms of this License,
265+ in one of these ways:
266+
267+ a) Convey the object code in, or embodied in, a physical product
268+ (including a physical distribution medium), accompanied by the
269+ Corresponding Source fixed on a durable physical medium
270+ customarily used for software interchange.
271+
272+ b) Convey the object code in, or embodied in, a physical product
273+ (including a physical distribution medium), accompanied by a
274+ written offer, valid for at least three years and valid for as
275+ long as you offer spare parts or customer support for that product
276+ model, to give anyone who possesses the object code either (1) a
277+ copy of the Corresponding Source for all the software in the
278+ product that is covered by this License, on a durable physical
279+ medium customarily used for software interchange, for a price no
280+ more than your reasonable cost of physically performing this
281+ conveying of source, or (2) access to copy the
282+ Corresponding Source from a network server at no charge.
283+
284+ c) Convey individual copies of the object code with a copy of the
285+ written offer to provide the Corresponding Source. This
286+ alternative is allowed only occasionally and noncommercially, and
287+ only if you received the object code with such an offer, in accord
288+ with subsection 6b.
289+
290+ d) Convey the object code by offering access from a designated
291+ place (gratis or for a charge), and offer equivalent access to the
292+ Corresponding Source in the same way through the same place at no
293+ further charge. You need not require recipients to copy the
294+ Corresponding Source along with the object code. If the place to
295+ copy the object code is a network server, the Corresponding Source
296+ may be on a different server (operated by you or a third party)
297+ that supports equivalent copying facilities, provided you maintain
298+ clear directions next to the object code saying where to find the
299+ Corresponding Source. Regardless of what server hosts the
300+ Corresponding Source, you remain obligated to ensure that it is
301+ available for as long as needed to satisfy these requirements.
302+
303+ e) Convey the object code using peer-to-peer transmission, provided
304+ you inform other peers where the object code and Corresponding
305+ Source of the work are being offered to the general public at no
306+ charge under subsection 6d.
307+
308+ A separable portion of the object code, whose source code is excluded
309+ from the Corresponding Source as a System Library, need not be
310+ included in conveying the object code work.
311+
312+ A "User Product" is either (1) a "consumer product", which means any
313+ tangible personal property which is normally used for personal, family,
314+ or household purposes, or (2) anything designed or sold for incorporation
315+ into a dwelling. In determining whether a product is a consumer product,
316+ doubtful cases shall be resolved in favor of coverage. For a particular
317+ product received by a particular user, "normally used" refers to a
318+ typical or common use of that class of product, regardless of the status
319+ of the particular user or of the way in which the particular user
320+ actually uses, or expects or is expected to use, the product. A product
321+ is a consumer product regardless of whether the product has substantial
322+ commercial, industrial or non-consumer uses, unless such uses represent
323+ the only significant mode of use of the product.
324+
325+ "Installation Information" for a User Product means any methods,
326+ procedures, authorization keys, or other information required to install
327+ and execute modified versions of a covered work in that User Product from
328+ a modified version of its Corresponding Source. The information must
329+ suffice to ensure that the continued functioning of the modified object
330+ code is in no case prevented or interfered with solely because
331+ modification has been made.
332+
333+ If you convey an object code work under this section in, or with, or
334+ specifically for use in, a User Product, and the conveying occurs as
335+ part of a transaction in which the right of possession and use of the
336+ User Product is transferred to the recipient in perpetuity or for a
337+ fixed term (regardless of how the transaction is characterized), the
338+ Corresponding Source conveyed under this section must be accompanied
339+ by the Installation Information. But this requirement does not apply
340+ if neither you nor any third party retains the ability to install
341+ modified object code on the User Product (for example, the work has
342+ been installed in ROM).
343+
344+ The requirement to provide Installation Information does not include a
345+ requirement to continue to provide support service, warranty, or updates
346+ for a work that has been modified or installed by the recipient, or for
347+ the User Product in which it has been modified or installed. Access to a
348+ network may be denied when the modification itself materially and
349+ adversely affects the operation of the network or violates the rules and
350+ protocols for communication across the network.
351+
352+ Corresponding Source conveyed, and Installation Information provided,
353+ in accord with this section must be in a format that is publicly
354+ documented (and with an implementation available to the public in
355+ source code form), and must require no special password or key for
356+ unpacking, reading or copying.
357+
358+ 7. Additional Terms.
359+
360+ "Additional permissions" are terms that supplement the terms of this
361+ License by making exceptions from one or more of its conditions.
362+ Additional permissions that are applicable to the entire Program shall
363+ be treated as though they were included in this License, to the extent
364+ that they are valid under applicable law. If additional permissions
365+ apply only to part of the Program, that part may be used separately
366+ under those permissions, but the entire Program remains governed by
367+ this License without regard to the additional permissions.
368+
369+ When you convey a copy of a covered work, you may at your option
370+ remove any additional permissions from that copy, or from any part of
371+ it. (Additional permissions may be written to require their own
372+ removal in certain cases when you modify the work.) You may place
373+ additional permissions on material, added by you to a covered work,
374+ for which you have or can give appropriate copyright permission.
375+
376+ Notwithstanding any other provision of this License, for material you
377+ add to a covered work, you may (if authorized by the copyright holders of
378+ that material) supplement the terms of this License with terms:
379+
380+ a) Disclaiming warranty or limiting liability differently from the
381+ terms of sections 15 and 16 of this License; or
382+
383+ b) Requiring preservation of specified reasonable legal notices or
384+ author attributions in that material or in the Appropriate Legal
385+ Notices displayed by works containing it; or
386+
387+ c) Prohibiting misrepresentation of the origin of that material, or
388+ requiring that modified versions of such material be marked in
389+ reasonable ways as different from the original version; or
390+
391+ d) Limiting the use for publicity purposes of names of licensors or
392+ authors of the material; or
393+
394+ e) Declining to grant rights under trademark law for use of some
395+ trade names, trademarks, or service marks; or
396+
397+ f) Requiring indemnification of licensors and authors of that
398+ material by anyone who conveys the material (or modified versions of
399+ it) with contractual assumptions of liability to the recipient, for
400+ any liability that these contractual assumptions directly impose on
401+ those licensors and authors.
402+
403+ All other non-permissive additional terms are considered "further
404+ restrictions" within the meaning of section 10. If the Program as you
405+ received it, or any part of it, contains a notice stating that it is
406+ governed by this License along with a term that is a further
407+ restriction, you may remove that term. If a license document contains
408+ a further restriction but permits relicensing or conveying under this
409+ License, you may add to a covered work material governed by the terms
410+ of that license document, provided that the further restriction does
411+ not survive such relicensing or conveying.
412+
413+ If you add terms to a covered work in accord with this section, you
414+ must place, in the relevant source files, a statement of the
415+ additional terms that apply to those files, or a notice indicating
416+ where to find the applicable terms.
417+
418+ Additional terms, permissive or non-permissive, may be stated in the
419+ form of a separately written license, or stated as exceptions;
420+ the above requirements apply either way.
421+
422+ 8. Termination.
423+
424+ You may not propagate or modify a covered work except as expressly
425+ provided under this License. Any attempt otherwise to propagate or
426+ modify it is void, and will automatically terminate your rights under
427+ this License (including any patent licenses granted under the third
428+ paragraph of section 11).
429+
430+ However, if you cease all violation of this License, then your
431+ license from a particular copyright holder is reinstated (a)
432+ provisionally, unless and until the copyright holder explicitly and
433+ finally terminates your license, and (b) permanently, if the copyright
434+ holder fails to notify you of the violation by some reasonable means
435+ prior to 60 days after the cessation.
436+
437+ Moreover, your license from a particular copyright holder is
438+ reinstated permanently if the copyright holder notifies you of the
439+ violation by some reasonable means, this is the first time you have
440+ received notice of violation of this License (for any work) from that
441+ copyright holder, and you cure the violation prior to 30 days after
442+ your receipt of the notice.
443+
444+ Termination of your rights under this section does not terminate the
445+ licenses of parties who have received copies or rights from you under
446+ this License. If your rights have been terminated and not permanently
447+ reinstated, you do not qualify to receive new licenses for the same
448+ material under section 10.
449+
450+ 9. Acceptance Not Required for Having Copies.
451+
452+ You are not required to accept this License in order to receive or
453+ run a copy of the Program. Ancillary propagation of a covered work
454+ occurring solely as a consequence of using peer-to-peer transmission
455+ to receive a copy likewise does not require acceptance. However,
456+ nothing other than this License grants you permission to propagate or
457+ modify any covered work. These actions infringe copyright if you do
458+ not accept this License. Therefore, by modifying or propagating a
459+ covered work, you indicate your acceptance of this License to do so.
460+
461+ 10. Automatic Licensing of Downstream Recipients.
462+
463+ Each time you convey a covered work, the recipient automatically
464+ receives a license from the original licensors, to run, modify and
465+ propagate that work, subject to this License. You are not responsible
466+ for enforcing compliance by third parties with this License.
467+
468+ An "entity transaction" is a transaction transferring control of an
469+ organization, or substantially all assets of one, or subdividing an
470+ organization, or merging organizations. If propagation of a covered
471+ work results from an entity transaction, each party to that
472+ transaction who receives a copy of the work also receives whatever
473+ licenses to the work the party's predecessor in interest had or could
474+ give under the previous paragraph, plus a right to possession of the
475+ Corresponding Source of the work from the predecessor in interest, if
476+ the predecessor has it or can get it with reasonable efforts.
477+
478+ You may not impose any further restrictions on the exercise of the
479+ rights granted or affirmed under this License. For example, you may
480+ not impose a license fee, royalty, or other charge for exercise of
481+ rights granted under this License, and you may not initiate litigation
482+ (including a cross-claim or counterclaim in a lawsuit) alleging that
483+ any patent claim is infringed by making, using, selling, offering for
484+ sale, or importing the Program or any portion of it.
485+
486+ 11. Patents.
487+
488+ A "contributor" is a copyright holder who authorizes use under this
489+ License of the Program or a work on which the Program is based. The
490+ work thus licensed is called the contributor's "contributor version".
491+
492+ A contributor's "essential patent claims" are all patent claims
493+ owned or controlled by the contributor, whether already acquired or
494+ hereafter acquired, that would be infringed by some manner, permitted
495+ by this License, of making, using, or selling its contributor version,
496+ but do not include claims that would be infringed only as a
497+ consequence of further modification of the contributor version. For
498+ purposes of this definition, "control" includes the right to grant
499+ patent sublicenses in a manner consistent with the requirements of
500+ this License.
501+
502+ Each contributor grants you a non-exclusive, worldwide, royalty-free
503+ patent license under the contributor's essential patent claims, to
504+ make, use, sell, offer for sale, import and otherwise run, modify and
505+ propagate the contents of its contributor version.
506+
507+ In the following three paragraphs, a "patent license" is any express
508+ agreement or commitment, however denominated, not to enforce a patent
509+ (such as an express permission to practice a patent or covenant not to
510+ sue for patent infringement). To "grant" such a patent license to a
511+ party means to make such an agreement or commitment not to enforce a
512+ patent against the party.
513+
514+ If you convey a covered work, knowingly relying on a patent license,
515+ and the Corresponding Source of the work is not available for anyone
516+ to copy, free of charge and under the terms of this License, through a
517+ publicly available network server or other readily accessible means,
518+ then you must either (1) cause the Corresponding Source to be so
519+ available, or (2) arrange to deprive yourself of the benefit of the
520+ patent license for this particular work, or (3) arrange, in a manner
521+ consistent with the requirements of this License, to extend the patent
522+ license to downstream recipients. "Knowingly relying" means you have
523+ actual knowledge that, but for the patent license, your conveying the
524+ covered work in a country, or your recipient's use of the covered work
525+ in a country, would infringe one or more identifiable patents in that
526+ country that you have reason to believe are valid.
527+
528+ If, pursuant to or in connection with a single transaction or
529+ arrangement, you convey, or propagate by procuring conveyance of, a
530+ covered work, and grant a patent license to some of the parties
531+ receiving the covered work authorizing them to use, propagate, modify
532+ or convey a specific copy of the covered work, then the patent license
533+ you grant is automatically extended to all recipients of the covered
534+ work and works based on it.
535+
536+ A patent license is "discriminatory" if it does not include within
537+ the scope of its coverage, prohibits the exercise of, or is
538+ conditioned on the non-exercise of one or more of the rights that are
539+ specifically granted under this License. You may not convey a covered
540+ work if you are a party to an arrangement with a third party that is
541+ in the business of distributing software, under which you make payment
542+ to the third party based on the extent of your activity of conveying
543+ the work, and under which the third party grants, to any of the
544+ parties who would receive the covered work from you, a discriminatory
545+ patent license (a) in connection with copies of the covered work
546+ conveyed by you (or copies made from those copies), or (b) primarily
547+ for and in connection with specific products or compilations that
548+ contain the covered work, unless you entered into that arrangement,
549+ or that patent license was granted, prior to 28 March 2007.
550+
551+ Nothing in this License shall be construed as excluding or limiting
552+ any implied license or other defenses to infringement that may
553+ otherwise be available to you under applicable patent law.
554+
555+ 12. No Surrender of Others' Freedom.
556+
557+ If conditions are imposed on you (whether by court order, agreement or
558+ otherwise) that contradict the conditions of this License, they do not
559+ excuse you from the conditions of this License. If you cannot convey a
560+ covered work so as to satisfy simultaneously your obligations under this
561+ License and any other pertinent obligations, then as a consequence you may
562+ not convey it at all. For example, if you agree to terms that obligate you
563+ to collect a royalty for further conveying from those to whom you convey
564+ the Program, the only way you could satisfy both those terms and this
565+ License would be to refrain entirely from conveying the Program.
566+
567+ 13. Use with the GNU Affero General Public License.
568+
569+ Notwithstanding any other provision of this License, you have
570+ permission to link or combine any covered work with a work licensed
571+ under version 3 of the GNU Affero General Public License into a single
572+ combined work, and to convey the resulting work. The terms of this
573+ License will continue to apply to the part which is the covered work,
574+ but the special requirements of the GNU Affero General Public License,
575+ section 13, concerning interaction through a network will apply to the
576+ combination as such.
577+
578+ 14. Revised Versions of this License.
579+
580+ The Free Software Foundation may publish revised and/or new versions of
581+ the GNU General Public License from time to time. Such new versions will
582+ be similar in spirit to the present version, but may differ in detail to
583+ address new problems or concerns.
584+
585+ Each version is given a distinguishing version number. If the
586+ Program specifies that a certain numbered version of the GNU General
587+ Public License "or any later version" applies to it, you have the
588+ option of following the terms and conditions either of that numbered
589+ version or of any later version published by the Free Software
590+ Foundation. If the Program does not specify a version number of the
591+ GNU General Public License, you may choose any version ever published
592+ by the Free Software Foundation.
593+
594+ If the Program specifies that a proxy can decide which future
595+ versions of the GNU General Public License can be used, that proxy's
596+ public statement of acceptance of a version permanently authorizes you
597+ to choose that version for the Program.
598+
599+ Later license versions may give you additional or different
600+ permissions. However, no additional obligations are imposed on any
601+ author or copyright holder as a result of your choosing to follow a
602+ later version.
603+
604+ 15. Disclaimer of Warranty.
605+
606+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
607+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
608+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
609+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
610+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
611+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
612+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
613+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
614+
615+ 16. Limitation of Liability.
616+
617+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
618+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
619+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
620+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
621+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
622+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
623+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
624+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
625+ SUCH DAMAGES.
626+
627+ 17. Interpretation of Sections 15 and 16.
628+
629+ If the disclaimer of warranty and limitation of liability provided
630+ above cannot be given local legal effect according to their terms,
631+ reviewing courts shall apply local law that most closely approximates
632+ an absolute waiver of all civil liability in connection with the
633+ Program, unless a warranty or assumption of liability accompanies a
634+ copy of the Program in return for a fee.
635+
636+ END OF TERMS AND CONDITIONS
637+
638+ How to Apply These Terms to Your New Programs
639+
640+ If you develop a new program, and you want it to be of the greatest
641+ possible use to the public, the best way to achieve this is to make it
642+ free software which everyone can redistribute and change under these terms.
643+
644+ To do so, attach the following notices to the program. It is safest
645+ to attach them to the start of each source file to most effectively
646+ state the exclusion of warranty; and each file should have at least
647+ the "copyright" line and a pointer to where the full notice is found.
648+
649+ <one line to give the program's name and a brief idea of what it does.>
650+ Copyright (C) <year> <name of author>
651+
652+ This program is free software: you can redistribute it and/or modify
653+ it under the terms of the GNU General Public License as published by
654+ the Free Software Foundation, either version 3 of the License, or
655+ (at your option) any later version.
656+
657+ This program is distributed in the hope that it will be useful,
658+ but WITHOUT ANY WARRANTY; without even the implied warranty of
659+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
660+ GNU General Public License for more details.
661+
662+ You should have received a copy of the GNU General Public License
663+ along with this program. If not, see <http://www.gnu.org/licenses/>.
664+
665+ Also add information on how to contact you by electronic and paper mail.
666+
667+ If the program does terminal interaction, make it output a short
668+ notice like this when it starts in an interactive mode:
669+
670+ <program> Copyright (C) <year> <name of author>
671+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
672+ This is free software, and you are welcome to redistribute it
673+ under certain conditions; type `show c' for details.
674+
675+ The hypothetical commands `show w' and `show c' should show the appropriate
676+ parts of the General Public License. Of course, your program's commands
677+ might be different; for a GUI interface, you would use an "about box".
678+
679+ You should also get your employer (if you work as a programmer) or school,
680+ if any, to sign a "copyright disclaimer" for the program, if necessary.
681+ For more information on this, and how to apply and follow the GNU GPL, see
682+ <http://www.gnu.org/licenses/>.
683+
684+ The GNU General Public License does not permit incorporating your program
685+ into proprietary programs. If your program is a subroutine library, you
686+ may consider it more useful to permit linking proprietary applications with
687+ the library. If this is what you want to do, use the GNU Lesser General
688+ Public License instead of this License. But first, please read
689+ <http://www.gnu.org/philosophy/why-not-lgpl.html>.
690 diff --git a/Cargo.toml b/Cargo.toml
691index 9dee76d..d5eea16 100644
692--- a/Cargo.toml
693+++ b/Cargo.toml
694 @@ -6,6 +6,8 @@ authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
695 [dependencies]
696 mailparse = "0.5.1"
697 maildir = "0.1.1"
698+ chrono = "0.4"
699+
700 [dependencies.ncurses]
701 features = ["wide"]
702 optional = false
703 diff --git a/src/mailbox/mod.rs b/src/mailbox/mod.rs
704new file mode 100644
705index 0000000..5806bfc
706--- /dev/null
707+++ b/src/mailbox/mod.rs
708 @@ -0,0 +1,391 @@
709+ /*
710+ * meli - mailbox module.
711+ *
712+ * Copyright 2017 Manos Pitsidianakis
713+ *
714+ * This file is part of meli.
715+ *
716+ * meli is free software: you can redistribute it and/or modify
717+ * it under the terms of the GNU General Public License as published by
718+ * the Free Software Foundation, either version 3 of the License, or
719+ * (at your option) any later version.
720+ *
721+ * meli is distributed in the hope that it will be useful,
722+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
723+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
724+ * GNU General Public License for more details.
725+ *
726+ * You should have received a copy of the GNU General Public License
727+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
728+ */
729+
730+ extern crate maildir;
731+ extern crate mailparse;
732+ use self::mailparse::*;
733+ use std::cmp::Ordering;
734+ use std::option::Option;
735+ use std::collections::HashMap;
736+ use std;
737+
738+ type UnixTimestamp = i64;
739+
740+ pub struct Mail {
741+ entry: maildir::MailEntry,
742+ subject: std::string::String,
743+ pub message_id: std::string::String,
744+ pub references: Vec<std::string::String>,
745+ date: UnixTimestamp,
746+ thread: usize,
747+ }
748+
749+ /*a Mailbox represents a folder of mail. Currently only Maildir is supported.*/
750+ pub struct Mailbox{
751+ pub collection: Box<Vec<Mail>>,
752+ pub threaded_collection: Vec<usize>,
753+ threads: Vec<Thread>,
754+ length: usize,
755+ }
756+
757+ /* a Thread struct is needed to describe the Thread tree forest during creation
758+ * of threads. Because of Rust's memory model, we store indexes of other node
759+ * instead of references and every reference is passed through the Thread owner
760+ * (a Vec<Thread>).
761+ *
762+ * message refers to a Mail entry in a Vec. If it's empty, the Thread is
763+ * nonexistent in our Mailbox but we know it exists (for example we have a copy
764+ * of a reply to a mail but we don't have its copy.
765+ */
766+ #[derive(Clone,Copy,Debug)]
767+ pub struct Thread {
768+ id: usize,
769+ message: Option<usize>,
770+ parent: Option<usize>,
771+ first_child: Option<usize>,
772+ next_sibling: Option<usize>,
773+ date: UnixTimestamp,
774+ indentation: usize,
775+ }
776+
777+ impl Thread {
778+ pub fn get_message(&self) -> Option<usize> {
779+ self.message
780+ }
781+ pub fn get_parent(&self) -> Option<usize> {
782+ self.parent
783+ }
784+ pub fn get_first_child(&self) -> Option<usize> {
785+ self.first_child
786+ }
787+ pub fn get_next_sibling(&self) -> Option<usize> {
788+ self.next_sibling
789+ }
790+ pub fn has_children(&self) -> bool {
791+ self.first_child.is_some()
792+ }
793+ pub fn has_sibling(&self) -> bool {
794+ self.next_sibling.is_some()
795+ }
796+ pub fn has_message(&self) -> bool {
797+ self.message.is_some()
798+ }
799+ pub fn set_indentation(&mut self, i: usize) {
800+ self.indentation = i;
801+ }
802+ pub fn get_indentation(&self) -> usize {
803+ self.indentation
804+ }
805+ pub fn is_descendant(&self, threads: &Vec<Thread>, other: Thread) -> bool {
806+ match self.first_child {
807+ Some(v) => {
808+ if threads[v] == other {
809+ return true;
810+ }
811+ if threads[v].clone().is_descendant(&threads, other) {
812+ return true;
813+ }
814+ },
815+ None => {}
816+ }
817+ match self.next_sibling {
818+ Some(v) => {
819+ if threads[v] == other {
820+ return true;
821+ }
822+ if threads[v].clone().is_descendant(threads, other) {
823+ return true;
824+ }
825+ },
826+ None => {}
827+ }
828+
829+ return false;
830+
831+
832+ }
833+ }
834+
835+ impl PartialEq for Thread {
836+ fn eq(&self, other: &Thread) -> bool {
837+ self.id == other.id
838+ }
839+ }
840+
841+ impl Mailbox {
842+ pub fn new(path: &str) -> Mailbox {
843+ let maildir = maildir::Maildir::from(path);
844+ let iter = maildir.list_cur();
845+ let mut collection: Box<Vec<Mail>> = Box::new(Vec::new());
846+ let mut threads: Vec<Thread> = Vec::new();
847+ let mut id_table: HashMap<std::string::String, usize> = HashMap::new();
848+ let mut idx = 0;
849+ for x in iter {
850+ let mut e = x.unwrap();
851+ let d = e.headers().unwrap().get_first_value("Date").unwrap();
852+
853+ let m_id = match e.headers().unwrap().get_first_value("Message-Id") {
854+ Ok(v) => {
855+ match v {
856+ Some(v) => {
857+ v
858+ },
859+ None => idx.to_string()
860+ }
861+ }
862+ Err(_) => {
863+ idx.to_string()
864+ }
865+ };
866+ let mut references: Vec<std::string::String> = Vec::new();
867+ match e.headers().unwrap().get_first_value("References") {
868+ Ok(v) => {
869+ match v {
870+ Some(v) => {
871+ references.append(&mut v.split_whitespace().map(|x| x.to_string()).collect());
872+ }
873+ None => {}
874+ }
875+ }
876+ Err(_) => {
877+ }
878+ };
879+ match e.headers().unwrap().get_first_value("In-Reply-To:") {
880+ Ok(v) => {
881+ match v {
882+ Some(v) => {
883+ references.push(v);
884+ }
885+ None => {}
886+ }
887+ }
888+ Err(_) => {
889+ }
890+ };
891+ let subject = match e.headers().unwrap().get_first_value("Subject") {
892+ Ok(v) => {
893+ match v
894+ {
895+ Some(v) => v.clone(),
896+ None => std::string::String::from("")
897+ }
898+ },
899+ Err(x) => panic!(x)
900+ };
901+ collection.push(
902+ Mail {
903+ entry: e,
904+ subject: subject,
905+ references: references,
906+ message_id: m_id,
907+ date: dateparse(&d.unwrap()).unwrap(),
908+ thread: 0,
909+ });
910+ idx += 1;
911+ }
912+ idx = 0;
913+
914+ collection.sort_by(|a, b| b.date.cmp(&a.date));
915+ for (i, x) in collection.iter_mut().enumerate() {
916+ let x_index;
917+ let m_id = x.message_id.clone();
918+ if id_table.contains_key(&m_id) {
919+ let c = id_table.get(&m_id).unwrap();
920+ /* the already existing Thread should be empty, since we're
921+ * seeing this message for the first time
922+ * Store this message in the Thread's message slot. */
923+ threads[*c].message = Some(i);
924+ threads[*c].date = x.date;
925+ x.thread = *c;
926+ x_index = *c;
927+ } else {
928+ /* Create a new Thread object holding this message */
929+ threads.push(
930+ Thread {
931+ message: Some(i),
932+ id: idx,
933+ parent: None,
934+ first_child: None,
935+ next_sibling: None,
936+ date: x.date,
937+ indentation: 0,
938+ });
939+ x_index = idx;
940+ x.thread = idx;
941+ id_table.insert(m_id, x_index);
942+ idx += 1;
943+ }
944+ /* For each element in the message's References field:
945+ *
946+ * Find a Thread object for the given Message-ID:
947+ * If there's one in id_table use that;
948+ * Otherwise, make (and index) one with a null Message.
949+ *
950+ * Link the References field's Threads together in the order implied by the References header.
951+ * If they are already linked, don't change the existing links.
952+ * Do not add a link if adding that link would introduce a loop: that is, before asserting A->B, search down the children of B to see if A is reachable, and also search down the children of A to see if B is reachable. If either is already reachable as a child of the other, don't add the link.
953+ */
954+ if x.references.len() == 0 {
955+ continue;
956+ }
957+ let r_to = x.references[x.references.len() - 1].clone();
958+ let parent_id =
959+ if id_table.contains_key(&r_to) {
960+
961+ let p = id_table.get(&r_to).unwrap();
962+ if threads[*p].is_descendant(&threads, threads[x_index]) ||
963+ threads[x_index].is_descendant(&threads, threads[*p]) {
964+ continue;
965+ }
966+ if threads[*p].first_child.is_none() {
967+ threads[*p].first_child = Some(x_index);
968+ } else {
969+ let mut fc = threads[*p].first_child.unwrap();
970+ while threads[fc].next_sibling.is_some() {
971+ fc = threads[fc].next_sibling.unwrap();
972+ }
973+ threads[fc].next_sibling = Some(x_index);
974+ threads[fc].parent = Some(*p);
975+ }
976+ *p
977+ } else {
978+ threads.push(
979+ Thread {
980+ message: None,
981+ id: idx,
982+ parent: None,
983+ first_child: Some(x_index),
984+ next_sibling: None,
985+ date: x.date,
986+ indentation: 0,
987+ });
988+ id_table.insert(r_to.clone(), idx);
989+ idx += 1;
990+ idx-1
991+ };
992+ /* update thread date */
993+ let mut parent_iter = parent_id;
994+ loop {
995+ let mut p = &mut threads[parent_iter];
996+ p.date = x.date;
997+ if p.parent.is_none() {
998+ break;
999+ } else {
1000+ parent_iter = p.get_parent().unwrap();
1001+ }
1002+ }
1003+ threads[x_index].parent = Some(parent_id);
1004+ }
1005+ /* Walk over the elements of id_table, and gather a list of the Thread objects that have
1006+ * no parents. */
1007+ let mut root_set = Vec::new();
1008+ for (_,v) in id_table.iter() {
1009+ if threads[*v].parent.is_none() {
1010+ root_set.push(*v);
1011+ }
1012+ }
1013+ root_set.sort_by(|a, b| threads[*b].date.cmp(&threads[*a].date));
1014+
1015+ let mut threaded_collection: Vec<usize> = Vec::new();
1016+ fn build_threaded(threads: &mut Vec<Thread>, indentation: usize, threaded: &mut Vec<usize>, index: usize) {
1017+
1018+ let thread = threads[index];
1019+
1020+ if thread.has_message() {
1021+ threads[index].set_indentation(indentation);
1022+ if !threaded.contains(&index) {
1023+ threaded.push(index);
1024+ }
1025+ }
1026+ if thread.has_children() {
1027+ let mut fc = thread.get_first_child().unwrap();
1028+ loop {
1029+ build_threaded(threads, indentation + 1, threaded, fc);
1030+ let thread_ = threads[fc];
1031+ if !thread_.has_sibling() {
1032+ break;
1033+ }
1034+ fc = thread_.get_next_sibling().unwrap();
1035+ }
1036+ }
1037+ }
1038+ for i in &root_set {
1039+ build_threaded(&mut threads, 0, &mut threaded_collection, *i);
1040+ }
1041+
1042+ let length = collection.len();
1043+ Mailbox {
1044+ collection: collection,
1045+ threads: threads,
1046+ length: length,
1047+ threaded_collection: threaded_collection,
1048+ }
1049+ }
1050+ pub fn get_length(&self) -> usize {
1051+ self.length
1052+ }
1053+ pub fn get_threaded_mail(&self, i: usize) -> usize {
1054+ let thread = self.threads[self.threaded_collection[i]];
1055+ thread.get_message().unwrap()
1056+ }
1057+ pub fn get_mail_and_thread(&mut self, i: usize) -> (&mut Mail, Thread) {
1058+
1059+ let ref mut x = self.collection.as_mut_slice()[i];
1060+ let thread = self.threads[x.get_thread()].clone();
1061+ (x, thread)
1062+ }
1063+ pub fn get_thread(&self, i: usize) -> Thread {
1064+ self.threads[i].clone()
1065+ }
1066+ }
1067+
1068+ impl Mail {
1069+ pub fn get_entry(&mut self) -> &mut maildir::MailEntry {
1070+ &mut self.entry
1071+ }
1072+ pub fn get_date(&self) -> i64 {
1073+ self.date
1074+ }
1075+ pub fn get_subject(&self) -> &str {
1076+ &self.subject
1077+ }
1078+ pub fn get_thread(&self) -> usize {
1079+ self.thread
1080+ }
1081+ }
1082+
1083+ impl Eq for Mail {}
1084+ impl Ord for Mail {
1085+ fn cmp(&self, other: &Mail) -> Ordering {
1086+ self.date.cmp(&other.date)
1087+ }
1088+ }
1089+ impl PartialOrd for Mail {
1090+ fn partial_cmp(&self, other: &Mail) -> Option<Ordering> {
1091+ Some(self.cmp(other))
1092+ }
1093+ }
1094+
1095+ impl PartialEq for Mail {
1096+ fn eq(&self, other: &Mail) -> bool {
1097+ self.date == other.date
1098+ }
1099+ }
1100 diff --git a/src/main.rs b/src/main.rs
1101index 3a23353..6f70087 100644
1102--- a/src/main.rs
1103+++ b/src/main.rs
1104 @@ -10,9 +10,8 @@ fn main() {
1105 let locale_conf = ncurses::LcCategory::all;
1106 ncurses::setlocale(locale_conf, "en_US.UTF-8");
1107 ui::initialize();
1108- let maildir = maildir::Maildir::from("./Inbox");
1109- let iter = maildir.list_cur();
1110- let mut index = Index::new(iter);
1111+ let mailbox = Mailbox::new("PATH");
1112+ let mut index = Index::new(mailbox);
1113 ncurses::refresh();
1114
1115 index.draw();
1116 diff --git a/src/ui/index.rs b/src/ui/index.rs
1117index e1ea655..f8e9c4f 100644
1118--- a/src/ui/index.rs
1119+++ b/src/ui/index.rs
1120 @@ -1,26 +1,46 @@
1121+ /*
1122+ * meli - ui module.
1123+ *
1124+ * Copyright 2017 Manos Pitsidianakis
1125+ *
1126+ * This file is part of meli.
1127+ *
1128+ * meli is free software: you can redistribute it and/or modify
1129+ * it under the terms of the GNU General Public License as published by
1130+ * the Free Software Foundation, either version 3 of the License, or
1131+ * (at your option) any later version.
1132+ *
1133+ * meli is distributed in the hope that it will be useful,
1134+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1135+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1136+ * GNU General Public License for more details.
1137+ *
1138+ * You should have received a copy of the GNU General Public License
1139+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
1140+ */
1141 extern crate ncurses;
1142 extern crate maildir;
1143 extern crate mailparse;
1144- use mailparse::*;
1145+ extern crate chrono;
1146+ use mailbox::*;
1147
1148+ use self::chrono::NaiveDateTime;
1149+
1150+ /* Index represents a UI list of mails */
1151 pub struct Index {
1152- mailbox: Vec<(usize, maildir::MailEntry)>,
1153- length: usize,
1154+ mailbox: Mailbox,
1155
1156 win: ncurses::WINDOW,
1157 pad: ncurses::WINDOW,
1158 screen_width: i32,
1159 screen_height: i32,
1160
1161+ threaded: bool,
1162+
1163 cursor_idx: usize,
1164 }
1165 impl Index {
1166- pub fn new(iter: maildir::MailEntries) -> Index {
1167- let mut collection: Vec<(usize, maildir::MailEntry)> = Vec::new();
1168- for (i, x) in iter.enumerate() {
1169- collection.push((i, x.unwrap()));
1170- }
1171- let length = collection.len();
1172+ pub fn new(mailbox: Mailbox) -> Index {
1173 let mut screen_height = 0;
1174 let mut screen_width = 0;
1175 /* Get the screen bounds. */
1176 @@ -28,20 +48,20 @@ impl Index {
1177 // let win = ncurses::newwin( ncurses::LINES(), ncurses::COLS()-30, 0, 30);
1178 let win = ncurses::newwin(0, 0, 0, 0);
1179 ncurses::getmaxyx(win, &mut screen_height, &mut screen_width);
1180+ //eprintln!("length is {}\n", length);
1181+ let pad = ncurses::newpad(mailbox.get_length() as i32, screen_width);
1182 ncurses::wbkgd(
1183- win,
1184+ pad,
1185 ' ' as ncurses::chtype |
1186 ncurses::COLOR_PAIR(super::COLOR_PAIR_DEFAULT) as ncurses::chtype,
1187 );
1188- //eprintln!("length is {}\n", length);
1189- let pad = ncurses::newpad(length as i32, screen_width);
1190 Index {
1191- mailbox: collection,
1192- length: length,
1193+ mailbox: mailbox,
1194 win: win,
1195 pad: pad,
1196 screen_width: 0,
1197 screen_height: 0,
1198+ threaded: true,
1199 cursor_idx: 0,
1200 }
1201 }
1202 @@ -53,13 +73,30 @@ impl Index {
1203
1204 ncurses::wclear(self.pad);
1205
1206- for &mut (i, ref mut x) in self.mailbox.as_mut_slice() {
1207- if i == self.cursor_idx {
1208- ncurses::wattron(self.pad, ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1209+ let mut idx = 0;
1210+ if self.threaded {
1211+ /* Draw threaded view. */
1212+ for i in self.mailbox.threaded_collection.iter() {
1213+ let container = self.mailbox.get_thread(*i);
1214+
1215+ assert!(container.has_message(), true);
1216+ let x = &self.mailbox.collection[container.get_message().unwrap()];
1217+ if idx == self.cursor_idx {
1218+ Index::draw_entry(self.pad, x, idx, container.get_indentation(), false, true);
1219+ } else {
1220+ Index::draw_entry(self.pad, x, idx, container.get_indentation(), false, false);
1221+ }
1222+ idx += 1;
1223+
1224 }
1225- Index::draw_entry(self.pad, x, i);
1226- if i == self.cursor_idx {
1227- ncurses::wattroff(self.pad, ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1228+ } else {
1229+ for x in self.mailbox.collection.as_mut_slice() {
1230+ if idx == self.cursor_idx {
1231+ Index::draw_entry(self.pad, x, idx, 0, false, true);
1232+ } else {
1233+ Index::draw_entry(self.pad, x, idx, 0, false, false);
1234+ }
1235+ idx += 1;
1236 }
1237 }
1238 ncurses::getmaxyx(self.win, &mut self.screen_height, &mut self.screen_width);
1239 @@ -94,7 +131,7 @@ impl Index {
1240 }
1241 }
1242 ncurses::KEY_DOWN => {
1243- if self.cursor_idx < self.length - 1 {
1244+ if self.cursor_idx < self.mailbox.get_length() - 1 {
1245 self.cursor_idx += 1;
1246 } else {
1247 return;
1248 @@ -109,16 +146,26 @@ impl Index {
1249 ncurses::wmove(self.pad, self.cursor_idx as i32, 0);
1250 /* Borrow x from self.mailbox in separate scopes or else borrow checker complains */
1251 {
1252- let (_, ref mut x) = self.mailbox.as_mut_slice()[self.cursor_idx];
1253- ncurses::wattron(self.pad, ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1254- Index::draw_entry(self.pad, x, self.cursor_idx);
1255- ncurses::wattroff(self.pad, ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1256+ let i: usize =
1257+ if self.threaded {
1258+ self.mailbox.get_threaded_mail(self.cursor_idx)
1259+ } else {
1260+ self.cursor_idx
1261+ };
1262+ let (ref mut x, thread) = self.mailbox.get_mail_and_thread(i);
1263+ Index::draw_entry(self.pad, x, self.cursor_idx, thread.get_indentation(), false, true);
1264 }
1265 /* Draw previous highlighted entry normally */
1266 ncurses::wmove(self.pad, prev_idx as i32, 0);
1267 {
1268- let (_, ref mut x) = self.mailbox.as_mut_slice()[prev_idx];
1269- Index::draw_entry(self.pad, x, prev_idx);
1270+ let i: usize =
1271+ if self.threaded {
1272+ self.mailbox.get_threaded_mail(prev_idx)
1273+ } else {
1274+ prev_idx
1275+ };
1276+ let (ref mut x, thread) = self.mailbox.get_mail_and_thread(i);
1277+ Index::draw_entry(self.pad, x, prev_idx, thread.get_indentation(), false, false);
1278 }
1279
1280 /* Calculate the pad row of the first entry to be displayed in the window */
1281 @@ -134,14 +181,16 @@ impl Index {
1282 * ┌- i
1283 * │ i+1
1284 * │ i+2
1285- * r ┥ ...
1286+ * r ┤ ...
1287 * │ n
1288 * │ .. ┐
1289- * │ i-2 ├ 'dead' entries (must be empty)
1290+ * │ i-2 ├ 'dead' entries (must be cleared)
1291 * └ i-1 ┘
1292 */
1293- if pminrow != pminrow_prev && pminrow + self.screen_height > self.length as i32 {
1294- /* touch Index window (tell ncurses to redraw the entire window in next refresh */
1295+ if pminrow != pminrow_prev &&
1296+ pminrow + self.screen_height > self.mailbox.get_length() as i32 {
1297+ /* touch Index window (tell ncurses to redraw the entire window in
1298+ * next refresh) */
1299 ncurses::touchwin(self.win);
1300 ncurses::wrefresh(self.win);
1301 }
1302 @@ -155,29 +204,54 @@ impl Index {
1303 self.screen_width - 1,
1304 );
1305 }
1306- fn draw_entry(win: ncurses::WINDOW, entry: &mut maildir::MailEntry, i: usize) {
1307+ fn draw_entry(win: ncurses::WINDOW, mail: &Mail, i: usize, indent: usize,
1308+ has_sibling: bool, highlight: bool) {
1309+ if highlight {
1310+ ncurses::wattron(win,
1311+ ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1312+ }
1313 ncurses::waddstr(win, &format!("{}\t", i));
1314- let d = entry.headers().unwrap().get_first_value("Date").unwrap();
1315- match d {
1316- Some(t) => {
1317- ncurses::waddstr(win, &t.to_string());
1318- }
1319- _ => {}
1320+ let dt = NaiveDateTime::from_timestamp(mail.get_date(), 0);
1321+ ncurses::waddstr(win, &dt.format("%Y-%m-%d %H:%M:%S").to_string());
1322+ ncurses::waddch(win, '\t' as u64);
1323+ for _ in 0..indent {
1324+ ncurses::waddch(win, ' ' as u64);
1325 }
1326- ncurses::waddch(win, ' ' as u64);
1327- let c = entry.headers().unwrap().get_first_value("Subject").unwrap();
1328- match c {
1329- Some(t) => {
1330- ncurses::waddstr(win, &t.to_string());
1331+ if indent > 0 {
1332+ ncurses::wattron(win,
1333+ ncurses::COLOR_PAIR(super::COLOR_PAIR_THREAD_INDENT));
1334+ if has_sibling {
1335+ ncurses::waddstr(win, "│");
1336+ } else {
1337+ ncurses::waddstr(win, "└");
1338 }
1339- _ => {}
1340+ ncurses::waddstr(win, "->");
1341+ ncurses::wattroff(win,
1342+ ncurses::COLOR_PAIR(super::COLOR_PAIR_THREAD_INDENT));
1343 }
1344- ncurses::wprintw(win, "\n");
1345+ if highlight {
1346+ ncurses::wattron(win,
1347+ ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1348+ }
1349+ ncurses::waddstr(win, &format!("{:.85}",mail.get_subject()));
1350+ if highlight {
1351+ ncurses::wattroff(win,
1352+ ncurses::COLOR_PAIR(super::COLOR_PAIR_CURSOR));
1353+ }
1354+ ncurses::waddstr(win, "\n");
1355 }
1356 pub fn show_pager(&mut self) {
1357- ncurses::getmaxyx(self.win, &mut self.screen_height, &mut self.screen_width);
1358- let (_, ref mut mail) = self.mailbox[self.cursor_idx];
1359- let mut pager = super::pager::Pager::new(self.win, mail);
1360+ ncurses::getmaxyx(self.win,
1361+ &mut self.screen_height, &mut self.screen_width);
1362+ let x: &mut Mail;
1363+
1364+ if self.threaded {
1365+ let i = self.mailbox.get_threaded_mail(self.cursor_idx);
1366+ x = &mut self.mailbox.collection[i];
1367+ } else {
1368+ x = &mut self.mailbox.collection[self.cursor_idx];
1369+ }
1370+ let mut pager = super::pager::Pager::new(self.win, &mut x.get_entry());
1371 pager.scroll(ncurses::KEY_DOWN);
1372 pager.scroll(ncurses::KEY_UP);
1373 let mut ch = ncurses::getch();
1374 @@ -191,19 +265,14 @@ impl Index {
1375 }
1376 _ => {}
1377 }
1378- // ncurses::wprintw(pager, "test\n");
1379- //ncurses::wrefresh(pager);
1380 ch = ncurses::getch();
1381 }
1382- drop(pager);
1383+ drop(pager); // drop pager before next refresh
1384 ncurses::wrefresh(self.win);
1385 }
1386 }
1387- impl Drop for Index {
1388+ impl Drop for Index {
1389 fn drop(&mut self) {
1390- /* Final prompt before closing. */
1391- //ncurses::mv(self.screen_height - 1, 0);
1392- //prompt();
1393 ncurses::delwin(self.win);
1394 ncurses::delwin(self.pad);
1395 ncurses::endwin();
1396 diff --git a/src/ui/mod.rs b/src/ui/mod.rs
1397index 0617cd3..e302bcd 100644
1398--- a/src/ui/mod.rs
1399+++ b/src/ui/mod.rs
1400 @@ -1,3 +1,23 @@
1401+ /*
1402+ * meli - ui module.
1403+ *
1404+ * Copyright 2017 Manos Pitsidianakis
1405+ *
1406+ * This file is part of meli.
1407+ *
1408+ * meli is free software: you can redistribute it and/or modify
1409+ * it under the terms of the GNU General Public License as published by
1410+ * the Free Software Foundation, either version 3 of the License, or
1411+ * (at your option) any later version.
1412+ *
1413+ * meli is distributed in the hope that it will be useful,
1414+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1415+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1416+ * GNU General Public License for more details.
1417+ *
1418+ * You should have received a copy of the GNU General Public License
1419+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
1420+ */
1421 extern crate ncurses;
1422 pub mod index;
1423 pub mod pager;
1424 @@ -5,6 +25,7 @@ pub mod pager;
1425 pub static COLOR_PAIR_DEFAULT: i16 = 1;
1426 pub static COLOR_PAIR_CURSOR: i16 = 2;
1427 pub static COLOR_PAIR_HEADERS: i16 = 3;
1428+ pub static COLOR_PAIR_THREAD_INDENT: i16 = 4;
1429 pub fn initialize() {
1430 /* start ncurses */
1431 ncurses::initscr();
1432 @@ -18,6 +39,7 @@ pub fn initialize() {
1433 ncurses::init_pair(COLOR_PAIR_DEFAULT, 15, 0);
1434 ncurses::init_pair(COLOR_PAIR_CURSOR, 251, 235);
1435 ncurses::init_pair(COLOR_PAIR_HEADERS, 33, 0);
1436+ ncurses::init_pair(COLOR_PAIR_THREAD_INDENT, 5, 0);
1437
1438 /* Set the window's background color. */
1439 ncurses::bkgd(
1440 diff --git a/src/ui/pager.rs b/src/ui/pager.rs
1441index de9134d..e5bf57e 100644
1442--- a/src/ui/pager.rs
1443+++ b/src/ui/pager.rs
1444 @@ -1,7 +1,30 @@
1445+ /*
1446+ * meli - ui module.
1447+ *
1448+ * Copyright 2017 Manos Pitsidianakis
1449+ *
1450+ * This file is part of meli.
1451+ *
1452+ * meli is free software: you can redistribute it and/or modify
1453+ * it under the terms of the GNU General Public License as published by
1454+ * the Free Software Foundation, either version 3 of the License, or
1455+ * (at your option) any later version.
1456+ *
1457+ * meli is distributed in the hope that it will be useful,
1458+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1459+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1460+ * GNU General Public License for more details.
1461+ *
1462+ * You should have received a copy of the GNU General Public License
1463+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
1464+ */
1465 extern crate ncurses;
1466 extern crate maildir;
1467 extern crate mailparse;
1468- use mailparse::*;
1469+ use self::mailparse::*;
1470+
1471+ /* Pager represents the part of the UI that shows the mail headers and body for
1472+ * viewing */
1473 pub struct Pager {
1474 win: ncurses::WINDOW,
1475 pad: ncurses::WINDOW,
1476 @@ -12,8 +35,8 @@ pub struct Pager {
1477 }
1478
1479 impl Pager {
1480- pub fn new(parent: ncurses::WINDOW, entry: &mut maildir::MailEntry) -> Pager {
1481-
1482+ pub fn new(parent: ncurses::WINDOW,
1483+ entry: &mut maildir::MailEntry) -> Pager {
1484 let mut screen_height = 0;
1485 let mut screen_width = 0;
1486 ncurses::getmaxyx(parent, &mut screen_height, &mut screen_width);
1487 @@ -32,11 +55,15 @@ impl Pager {
1488 for _ in 1..screen_width + 1 {
1489 ncurses::waddstr(win, "─");
1490 }
1491- //ncurses::wprintw(win, "\n");
1492- let (mail_pad, rows, header_height) = Pager::print_entry(win, entry);
1493+ let (pad, rows, header_height) = Pager::print_entry(win, entry);
1494+ ncurses::wbkgd(
1495+ pad,
1496+ ' ' as ncurses::chtype |
1497+ ncurses::COLOR_PAIR(super::COLOR_PAIR_DEFAULT) as ncurses::chtype,
1498+ );
1499 ncurses::wrefresh(win);
1500 Pager {
1501- pad: mail_pad,
1502+ pad: pad,
1503 win: win,
1504 rows: rows,
1505 header_height: header_height,
1506 @@ -163,8 +190,7 @@ impl Pager {
1507 fn print_entry_content(
1508 win: ncurses::WINDOW,
1509 mail: &mut maildir::MailEntry,
1510- height: i32,
1511- ) -> (ncurses::WINDOW, i32, i32) {
1512+ height: i32) -> (ncurses::WINDOW, i32, i32) {
1513 let mut h = 0;
1514 let mut w = 0;
1515 /* height and width of self.win, the pager window */
1516 @@ -210,17 +236,15 @@ impl Pager {
1517 }
1518 fn print_entry(
1519 win: ncurses::WINDOW,
1520- mail: &mut maildir::MailEntry,
1521- ) -> (ncurses::WINDOW, i32, i32) {
1522+ mail: &mut maildir::MailEntry) -> (ncurses::WINDOW, i32, i32) {
1523 let header_height = Pager::print_entry_headers(win, mail);
1524 Pager::print_entry_content(win, mail, header_height + 2)
1525 }
1526 }
1527
1528-
1529 impl Drop for Pager {
1530 fn drop(&mut self) {
1531- //ncurses::touchwin(self.win);
1532+ ncurses::wclear(self.win);
1533 ncurses::delwin(self.win);
1534 ncurses::delwin(self.pad);
1535 }