--- /dev/null
+/ChangeLog
+/.claws-mail
+/claws-mail
+/run
+/debug
+/vfolder.geany
+/*.tar.gz
+/*.tar.bz2
+/aclocal.m4
+/autom4te.cache
+/confdefs.h
+/config.cache
+/config/config.guess
+/config/config.sub
+/config/depcomp
+/config.guess
+/config.h
+/config.h.in
+/config/install-sh
+/config.log
+/config/ltmain.sh
+/config/Makefile
+/config/Makefile.in
+/config/missing
+/config/mkinstalldirs
+/config.status
+/config.sub
+/configure
+/.cproject
+/depcomp
+/libtool
+/ltmain.sh
+/Makefile
+/Makefile.in
+/patches
+/*.patchset
+/.project
+/.settings
+/src/.deps
+/src/.libs
+/src/Makefile
+/src/Makefile.in
+/src/*.o
+/src/Makefile
+/src/Makefile.in
+/src/*.swp
+/src/tags
+/src/TAGS
+/src/ylwrap
+/stamp-h
+/stamp-h1
+/stamp-h2
+/stamp-h.in
+/*.swp
+/tags
+/TAGS
+/tools/Makefile
+/tools/Makefile.in
+/version
--- /dev/null
+Michael Rasmussen <mir@datanom.net>
+
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- /dev/null
+Installation
+============
+
+This program requires GTK+ 2.16 or higher to be compiled.
+
+Build it
+========
+
+If you're using a package-based system, please make sure that gtk-devel
+and glib-devel (or similar) packages are installed before the compilation
+(you may also require flex (lex) and bison (yacc)).
+
+To compile and install, just type:
+
+% ./configure
+% make
+% su
+Password: [Enter password]
+# make install
+
+To run, just type:
+
+% claws-mail
+
+Additional libraries or programs
+================================
+only needed if you require the additional functionality
+
+Bogofilter
+ for Bogofilter plugin support
+ http://bogofilter.sourceforge.net/
+Bsfilter
+ for Bsfilter plugin support
+ http://sourceforge.jp/projects/bsfilter/
+Canberra (>= 0.6)
+ for some sound features of Notification plugin
+ http://0pointer.de/lennart/projects/libcanberra/
+compface
+ for X-Face support
+ http://freshmeat.net/projects/compface/
+Clam AntiVirus daemon
+ for Clamd plugin support
+ http://www.clamav.net/
+D-Bus (>= 0.60)
+ for interprocess communication support
+ http://www.freedesktop.org/wiki/Software/dbus
+Enchant (and dictionaries) (>= 1.0.0)
+ for spell-checker support
+ http://www.abisource.com/enchant/
+GData (>= 0.6.4)
+ for GData plugin support
+ https://live.gnome.org/libgdata/
+GnuPG (>= 1.2.1) and GPGME (>= 0.4.5)
+ for GnuPG and S/MIME plugin support
+ http://www.gnupg.org/
+ ftp://ftp.gnupg.org/gcrypt/gpgme/
+GnuTLS (>= 0.4.2)
+ for SSL support
+ http://www.gnu.org/software/gnutls/
+GTK+ WebKit (>= 1.0)
+ for Fancy plugin support
+ http://trac.webkit.org/wiki/WebKitGTK/
+Gs tool
+ for PostScript feature of PDF Viewer plugin
+ http://pages.cs.wisc.edu/~ghost/
+Indicate (>= 0.3.0)
+ for indicator feature of Notification plugin
+ https://launchpad.net/libindicator/
+J-Pilot
+ for J-Pilot support
+ http://www.jpilot.org/
+LCDproc daemon
+ for lcdproc feature of Notification plugin
+ http://www.lcdproc.org
+libEtPan! (>= 0.57)
+ for IMAP4, NNTP and Mailmbox plugin support
+ http://www.etpan.org
+Network Manager (>= 0.6.2)
+ for support for detection of network connection changes
+ http://www.gnome.org/projects/NetworkManager/
+OpenLDAP (>= 2.0.7)
+ for LDAP support
+ http://www.openldap.org/
+Perl (>= 5.8.0)
+ for perl plugin support
+ http://www.perl.org/
+Poppler (>= 0.4.2)
+ for PDF Viewer plugin support
+ http://poppler.freedesktop.org/
+GnuTLS (>= 0.4.2)
+ for SSL support
+ http://www.gnu.org/software/gnutls/
+PyGTK (>= 2.10.3)
+ for Python plugin support
+ http://www.pygtk.org/
+Python
+ for Python plugin support
+ http://python.org/
+SpamAssassin
+ for SpamAssassin plugin support
+ http://spamassassin.apache.org/
+
+Options for configure script
+============================
+Most options are automatically enabled if the dependencies
+are matched.
+
+ --with-config-dir=RCDIR local config dir (default: ~/.claws-mail)
+ --disable-compface disable compface (X-Face) support
+ --disable-ipv6 disable IPv6 support
+ --disable-gnutls disable GnuTLS support
+ --disable-libetpan disable IMAP4 and NNTP support
+ --disable-gnomeprint disable libgnomeprint support
+ --disable-enchant disable Enchant support
+ --disable-ldap disable LDAP support
+ --disable-jpilot disable JPilot support
+ --disable-startup-notification disable startup notification support
+ --disable-valgrind disable valgrind support for debugging
+ --enable-crash-dialog enable crash dialog
+ --disable-startup-notification disable startup notification support
+ --disable-trayicon-plugin do not build System Tray Icon plugin
+ --disable-spamassassin-plugin do not build SpamAssassin plugin
+ --disable-pgpcore-plugin do not build PGP/Core plugin
+ --disable-pgpmime-plugin do not build PGP/MIME plugin
+ --disable-pgpinline-plugin do not build PGP/Inline plugin
+ --disable-smime-plugin do not build S/Mime plugin
+ --disable-bogofilter-plugin do not build Bogofilter plugin
+ --disable-address_keeper-plugin do not build Address Keeper plugin
+ --disable-archive-plugin do not build Archive plugin
+ --disable-att_remover-plugin do not build Att Remover plugin
+ --disable-attachwarner-plugin do not build Attachwarner plugin
+ --disable-bsfilter-plugin do not build BSfilter plugin
+ --disable-clamd-plugin do not build Clamd plugin
+ --disable-fancy-plugin do not build Fancy plugin
+ --disable-fetchinfo-plugin do not build Fetchinfo plugin
+ --disable-gdata-plugin do not build GData plugin
+ --disable-mailmbox-plugin do not build MailMbox plugin
+ --disable-newmail-plugin do not build NewMail plugin
+ --disable-notification-plugin do not build Notification plugin
+ --disable-pdf_viewer-plugin do not build PDF Viewer plugin
+ --disable-perl-plugin do not build Perl plugin
+ --disable-python-plugin do not build Python plugin
+ --disable-rssyl-plugin do not build RSSyl plugin
+ --disable-spamassassin-plugin do not build SpamAssassin plugin
+ --disable-spam_report-plugin do not build Spam Report plugin
+ --disable-tnef_parse-plugin do not build TNEF Parse plugin
+ --disable-vcalendar-plugin do not build vCalendar plugin
+ --disable-manual do not build user manuals
+ --disable-nls do not use Native Language Support
+
+For other options, refer to ./configure --help .
+
+
--- /dev/null
+SUBDIRS = config src
+
+EXTRA_DIST = \
+ config/config.rpath \
+ AUTHORS \
+ COPYING \
+ ChangeLog \
+ INSTALL \
+ NEWS \
+ README \
+ TODO
+
--- /dev/null
+No news is good news:-)
--- /dev/null
+#!/bin/sh
+
+aclocal \
+ && libtoolize --copy --force \
+ && autoheader \
+ && automake --add-missing --foreign --copy \
+ && autoconf \
+ && ./configure --enable-maintainer-mode $@
--- /dev/null
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.60)
+AC_INIT(src/vfolder.h)
+AC_CONFIG_AUX_DIR(config)
+AM_MAINTAINER_MODE
+
+PACKAGE=vfolder
+
+dnl plugin version
+
+MAJOR_VERSION=0
+MINOR_VERSION=1
+MICRO_VERSION=0
+EXTRA_VERSION=0
+
+if test \( $EXTRA_VERSION -eq 0 \); then
+ if test \( $MICRO_VERSION -eq 0 \); then
+ VERSION=${MAJOR_VERSION}.${MINOR_VERSION}
+ else
+ VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}
+ fi
+else
+ if test \( $MICRO_VERSION -eq 0 \); then
+ VERSION=${MAJOR_VERSION}.${MINOR_VERSION}cvs${EXTRA_VERSION}
+ else
+ VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}cvs${EXTRA_VERSION}
+ fi
+fi
+
+AC_DEFINE_UNQUOTED(VFOLDERVERSION, "$VERSION", [plugin version])
+AC_DEFINE_UNQUOTED(VFOLDERPACKAGE, "Claws Mail vfolder", [package])
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
+AC_DEFINE_UNQUOTED(PLUGINVERSION, "$VERSION", [plugin version])
+
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_CC_STDC
+AC_LANG_C
+AC_ISC_POSIX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+# Checks for libraries.
+#
+# Find pkg-config
+#
+AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+if test x$PKG_CONFIG = xno ; then
+ AC_MSG_ERROR([*** pkg-config not found. See http://www.freedesktop.org/software/pkgconfig/])
+fi
+
+#
+# Check for claws-mail
+#
+PKG_CHECK_MODULES(CLAWS_MAIL, claws-mail >= 3.8.0.0)
+AC_SUBST(CLAWS_MAIL_CFLAGS)
+AC_SUBST(CLAWS_MAIL_LIBS)
+if test -z $prefix || test "${prefix}" = "NONE" ; then
+ prefix=$( $PKG_CONFIG --variable=prefix claws-mail )
+ CLAWS_MAIL_PLUGINDIR=$( $PKG_CONFIG --variable=plugindir claws-mail )
+else
+ CLAWS_MAIL_PLUGINDIR='${libdir}/claws-mail/plugins'
+fi
+AC_SUBST(CLAWS_MAIL_PLUGINDIR)
+
+if test $USE_MAINTAINER_MODE = yes; then
+ CFLAGS="-g -Wall -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED"
+else
+ CFLAGS="$CFLAGS -O2 -Wall"
+fi
+
+ALL_LINGUAS=""
+AC_DEFINE_UNQUOTED(TEXTDOMAIN, "$PACKAGE", [Gettext textdomain])
+AM_GNU_GETTEXT_VERSION([0.15])
+AM_GNU_GETTEXT([external])
+
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.12])
+
+GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
+AC_SUBST(GLIB_GENMARSHAL)
+
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.16)
+
+# Checks for header files.
+AC_HEADER_STDC
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+
+AC_SUBST(VERSION)
+AC_SUBST(PLUGINVERSION)
+AC_SUBST(MAJOR_VERSION)
+AC_SUBST(MINOR_VERSION)
+AC_SUBST(MICRO_VERSION)
+AC_SUBST(EXTRA_VERSION)
+
+AC_CONFIG_COMMANDS(
+ [summary],
+ [[echo ""
+ echo "Vfolder will be compiled with these settings:"
+ echo ""
+ echo -e "CFLAGS: ${CFLAGS}"
+ echo -e "Vfolder version: ${VERSION}"
+ echo ""
+ echo -e "Now run make to build vfolder plugin"
+ echo ""
+ echo -e "Please send bugs or feature requests to the maintainer(s)."
+ echo -e "Email addresses can be found in the AUTHORS file."
+ echo ""]],
+ [
+ CFLAGS="$CFLAGS".
+ VERSION="$VERSION".
+ ]
+)
+
+AC_OUTPUT([
+ Makefile
+ config/Makefile
+ src/Makefile
+])
+
--- /dev/null
+plugindir = $(CLAWS_MAIL_PLUGINDIR)
+
+INCLUDES = @GLIB_CFLAGS@ \
+ -I$(top_srcdir) -I$(top_builddir)
+ -I$(top_srcdir)/src -I$(top_builddir)/src
+
+plugin_LTLIBRARIES = vfolder.la
+
+vfolder_la_SOURCES = \
+ vfolder.c \
+ vfolder_init.c \
+ vfolder_gtk.c \
+ vfolder_prop.c
+
+nodist_include_HEADERS = \
+ gettext.h \
+ vfolder_gtk.h \
+ vfolder_prop.h
+
+vfolderincludedir = $(includedir)/claws-mail/plugins/@PACKAGE@
+vfolderinclude_HEADERS = \
+ vfolder.h
+
+vfolder_la_LDFLAGS = \
+ -avoid-version -module \
+ $(GTK_LIBS)
+
+vfolder_la_LIBADD =
+
+AM_CPPFLAGS = \
+ $(CLAWS_MAIL_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS) \
+ -DLOCALEDIR=\""$(localedir)"\"
--- /dev/null
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+#define _(str) dgettext(TEXTDOMAIN, str)
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
+ <libintl.h>, which chokes if dcgettext is defined as a macro. So include
+ it now, to make later inclusions of <libintl.h> a NOP. */
+#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
+# include <cstdlib>
+# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
+# include <libintl.h>
+# endif
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#define _(str) str
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#define N_(str) str
+
+#endif /* _LIBGETTEXT_H */
--- /dev/null
+/*
+ * $Id: $
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ *
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+#include "procmsg.h"
+#include "procheader.h"
+#include "folder.h"
+#include "alertpanel.h"
+#include "main.h"
+#include "localfolder.h"
+#include "statusbar.h"
+
+#include "vfolder.h"
+#include "vfolder_gtk.h"
+#include "vfolder_prop.h"
+
+typedef struct {
+ LocalFolder folder;
+} VFolder;
+
+FolderClass vfolder_class;
+static gboolean existing_tree_found = FALSE;
+static GList* vfolders = NULL;
+
+static void vfolder_get_last_num(Folder *folder, FolderItem *item)
+{
+ gchar *path;
+ DIR *dp;
+ struct dirent *d;
+ gint max = 0;
+ gint num;
+
+ g_return_if_fail(item != NULL);
+
+ debug_print("vfolder_get_last_num(): Scanning %s ...\n", item->path);
+ path = folder_item_get_path(item);
+ g_return_if_fail(path != NULL);
+ if( change_dir(path) < 0 ) {
+ g_free(path);
+ return;
+ }
+ g_free(path);
+
+ if( (dp = opendir(".")) == NULL ) {
+ FILE_OP_ERROR(item->path, "opendir");
+ return;
+ }
+
+ while( (d = readdir(dp)) != NULL ) {
+ if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
+ if( max < num )
+ max = num;
+ }
+ }
+ closedir(dp);
+
+ debug_print("Last number in dir %s = %d\n", item->path, max);
+ item->last_num = max;
+}
+
+static void vfolder_init_read_func(FolderItem* item, gpointer data) {
+ g_return_if_fail(item != NULL);
+
+ if (! IS_VFOLDER_FOLDER_ITEM(item))
+ return;
+
+ existing_tree_found = TRUE;
+
+ if (folder_item_parent(item) == NULL)
+ return;
+
+ vfolder_folder_item_props_read(VFOLDER_ITEM(item));
+ vfolder_set_msgs_filter(VFOLDER_ITEM(item));
+
+/* if (! IS_VFOLDER_FROZEN(VFOLDER_ITEM(item))) {
+ folder_item_scan(VFOLDER_ITEM(item)->source);
+ }*/
+}
+
+static void vfolder_make_rc_dir(void) {
+ gchar* vfolder_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, NULL);
+
+ if (! is_dir_exist(vfolder_dir)) {
+ if (make_dir(vfolder_dir) < 0) {
+ g_warning("couldn't create directory %s\n", vfolder_dir);
+ }
+
+ debug_print("created directorty %s\n", vfolder_dir);
+ }
+
+ g_free(vfolder_dir);
+}
+
+static void vfolder_create_default_mailbox(void) {
+ Folder* root = NULL;
+
+ vfolder_make_rc_dir();
+
+ root = folder_new(vfolder_folder_get_class(), VFOLDER_DEFAULT_MAILBOX, NULL);
+
+ g_return_if_fail(root != NULL);
+
+ folder_add(root);
+}
+
+static gboolean vfolder_scan_required(Folder* folder, FolderItem* item) {
+ return TRUE;
+}
+
+static Folder* vfolder_new_folder(const gchar* name, const gchar* path) {
+ VFolder* folder;
+
+ debug_print("VFolder: new_folder\n");
+
+ vfolder_make_rc_dir();
+
+ folder = g_new0(VFolder, 1);
+ FOLDER(folder)->klass = &vfolder_class;
+ folder_init(FOLDER(folder), name);
+
+ return FOLDER(folder);
+}
+
+static void vfolder_destroy_folder(Folder* _folder)
+{
+ VFolder* folder = VFOLDER(_folder);
+
+ folder_local_folder_destroy(LOCAL_FOLDER(folder));
+}
+
+static gint vfolder_remove_folder(Folder* folder, FolderItem* item) {
+ GDir* dp;
+ const gchar* name;
+ gchar* cwd;
+ gint ret = -1;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(item != NULL, -1);
+ g_return_val_if_fail(item->path != NULL, -1);
+ g_return_val_if_fail(item->stype == F_NORMAL, -1);
+
+ debug_print("VFolder: removing folder item %s\n", item->path);
+
+ gchar* path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+ VFOLDER_DIR, G_DIR_SEPARATOR_S, item->name, NULL);
+ remove_numbered_files(path, item->last_num - item->total_msgs + 1, item->last_num);
+
+ folder_item_remove(item);
+
+ cwd = g_get_current_dir();
+
+ if (change_dir(path) < 0 ) {
+ g_free(path);
+ return ret;
+ }
+
+ if( (dp = g_dir_open(".", 0, NULL)) == NULL ) {
+ FILE_OP_ERROR(path, "g_dir_open");
+ change_dir(cwd);
+ g_free(cwd);
+ return ret;
+ }
+
+ while ((name = g_dir_read_name(dp)) != NULL) {
+ debug_print("Removing: %s\n", name);
+ claws_unlink(name);
+ }
+ g_dir_close(dp);
+ change_dir(cwd);
+ if (g_rmdir(path) == 0)
+ ret = 0;
+
+ g_free(cwd);
+ g_free(path);
+
+ return ret;
+}
+
+static void vfolder_remove_hashtables(VFolderItem* item) {
+ if (item->me_to_claws) {
+ g_hash_table_destroy(item->me_to_claws);
+ item->me_to_claws = NULL;
+ }
+ if (item->claws_to_me) {
+ g_hash_table_destroy(item->claws_to_me);
+ item->claws_to_me = NULL;
+ }
+}
+
+static gboolean vfolder_remove_msg_from_bridge(VFolderItem* item,
+ guint src,
+ guint dest) {
+ gboolean ret = FALSE;
+
+ debug_print("Removing from hashtable: src->%u dest->%u\n", src, dest);
+ ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(dest));
+ ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(src));
+
+ return (ret == FALSE);
+}
+/*
+static gboolean vfolder_remove_msg_bridge_claws(VFolderItem* item, guint num) {
+ return vfolder_remove_msg_from_bridge_rel(item, num, TRUE);
+}
+
+static gboolean vfolder_remove_msg_bridge_vfolder(VFolderItem* item, guint num) {
+ return vfolder_remove_msg_from_bridge_rel(item, num, FALSE);
+}
+*/
+static void vfolder_free_hashtable_data(gpointer data) {
+ g_free(data);
+}
+
+static MsgBridge* vfolder_create_bridge(guint src, guint dest) {
+ MsgBridge* bridge;
+
+ bridge = g_new0(MsgBridge, 1);
+ bridge->my_num = dest;
+ bridge->claws_num = src;
+
+ return bridge;
+}
+
+static GHashTable* vfolder_hashtable_new() {
+ return g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, vfolder_free_hashtable_data);
+}
+
+static gboolean vfolder_add_msg_to_message_bridge(VFolderItem* item,
+ guint src,
+ guint dest) {
+ gboolean ret = FALSE;
+ MsgBridge* bridge;
+
+ if (! item->me_to_claws)
+ item->me_to_claws = vfolder_hashtable_new();
+ if (! item->claws_to_me)
+ item->claws_to_me = vfolder_hashtable_new();
+
+ debug_print("Adding to hashtable: src->%u dest->%u\n", src, dest);
+ bridge = vfolder_create_bridge(src, dest);
+ g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(dest), bridge);
+
+ bridge = vfolder_create_bridge(src, dest);
+ g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(src), bridge);
+
+ return ret;
+}
+
+static FolderItem* vfolder_item_new(Folder* folder) {
+ VFolderItem* vitem;
+
+ debug_print("VFolder: item_new\n");
+
+ vitem = g_new0(VFolderItem, 1);
+
+ gchar* id = folder_get_identifier(folder);
+ gchar* cmp = g_strconcat("#", VFOLDER_DIR, G_DIR_SEPARATOR_S, NULL);
+ if (id && strcmp(cmp, id) != 0) {
+ debug_print("Creating folder item: %s\n", id);
+ g_free(id);
+ vfolders = g_list_prepend(vfolders, vitem);
+ }
+ g_free(cmp);
+
+ return FOLDER_ITEM(vitem);
+}
+
+static void vfolder_item_destroy(Folder* folder, FolderItem* item) {
+ VFolderItem* vitem = VFOLDER_ITEM(item);
+
+ g_return_if_fail(vitem != NULL);
+
+ debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders));
+ vfolders = g_list_remove(vfolders, vitem);
+ debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders));
+
+ g_free(vitem->filter);
+
+ vfolder_remove_hashtables(vitem);
+ vitem->source = NULL;
+
+ g_free(item);
+ item = NULL;
+}
+
+static FolderItem* vfolder_create_folder(Folder* folder,
+ FolderItem* parent,
+ const gchar* name) {
+ gchar* path = NULL;
+ FolderItem* newitem = NULL;
+
+ g_return_val_if_fail(folder != NULL, NULL);
+ g_return_val_if_fail(parent != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ if (parent->no_sub)
+ return NULL;
+
+ path = g_strconcat((parent->path != NULL) ? parent->path : "", ".",
+ name, NULL);
+ newitem = folder_item_new(folder, name, path);
+ newitem->no_sub = TRUE;
+
+ folder_item_append(parent, newitem);
+ g_free(path);
+
+ return newitem;
+}
+
+static gchar* vfolder_item_get_path(Folder* folder, FolderItem* item) {
+ gchar* result;
+ result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR,
+ G_DIR_SEPARATOR_S, item->name, NULL);
+ return result;
+}
+
+static gint vfolder_get_num_list(Folder* folder, FolderItem* item,
+ MsgNumberList** list, gboolean* old_uids_valid) {
+ gchar* path;
+ DIR* dp;
+ struct dirent* d;
+ gint num, nummsgs = 0;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ debug_print("VFolder: scanning '%s'...\n", item->path);
+
+ *old_uids_valid = TRUE;
+
+ path = folder_item_get_path(item);
+ g_return_val_if_fail(path != NULL, -1);
+ if (change_dir(path) < 0 ) {
+ g_free(path);
+ return -1;
+ }
+ g_free(path);
+
+ if( (dp = opendir(".")) == NULL ) {
+ FILE_OP_ERROR(item->path, "opendir");
+ return -1;
+ }
+
+ while ((d = readdir(dp)) != NULL ) {
+ if( (num = to_number(d->d_name)) > 0 ) {
+ debug_print("Adding %d to list\n", num);
+ *list = g_slist_prepend(*list, GINT_TO_POINTER(num));
+ nummsgs++;
+ }
+ }
+ closedir(dp);
+
+ return nummsgs;
+}
+
+static gint vfolder_create_tree(Folder* folder) {
+ FolderItem* rootitem;
+ GNode* rootnode;
+
+ vfolder_make_rc_dir();
+
+ if (!folder->node) {
+ rootitem = folder_item_new(folder, folder->name, NULL);
+ rootitem->folder = folder;
+ rootnode = g_node_new(rootitem);
+ folder->node = rootnode;
+ rootitem->node = rootnode;
+ } else {
+ rootitem = FOLDER_ITEM(folder->node->data);
+ rootnode = folder->node;
+ }
+
+ debug_print("VFolder: created new vfolder tree\n");
+ return 0;
+}
+
+static gint vfolder_scan_tree(Folder *folder) {
+ g_return_val_if_fail(folder != NULL, -1);
+
+ folder->outbox = NULL;
+ folder->draft = NULL;
+ folder->queue = NULL;
+ folder->trash = NULL;
+
+ debug_print("VFolder: scanning tree\n");
+ vfolder_create_tree(folder);
+
+ return 0;
+}
+
+static gchar* vfolder_get_new_msg_filename(FolderItem* dest) {
+ gchar* destfile;
+ gchar* destpath;
+
+ destpath = folder_item_get_path(dest);
+ g_return_val_if_fail(destpath != NULL, NULL);
+
+ if( !is_dir_exist(destpath) )
+ make_dir_hier(destpath);
+
+ for( ; ; ) {
+ destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR,
+ dest->last_num + 1);
+ if( is_file_entry_exist(destfile) ) {
+ dest->last_num++;
+ g_free(destfile);
+ } else
+ break;
+ }
+
+ g_free(destpath);
+
+ return destfile;
+}
+
+static gint vfolder_add_msgs(Folder* folder, FolderItem* dest, GSList* file_list,
+ GHashTable* relation) {
+ gchar* destfile;
+ GSList* cur;
+ MsgFileInfo* fileinfo;
+ gint r = -1;
+ VFolderItem* vitem;
+
+ g_return_val_if_fail(dest != NULL, -1);
+ g_return_val_if_fail(file_list != NULL, -1);
+
+ vitem = VFOLDER_ITEM(dest);
+ if( dest->last_num < 0 ) {
+ vfolder_get_last_num(folder, dest);
+ if( dest->last_num < 0 ) return -1;
+ }
+
+ for( cur = file_list; cur != NULL; cur = cur->next ) {
+ fileinfo = (MsgFileInfo *)cur->data;
+
+ destfile = vfolder_get_new_msg_filename(dest);
+ if (! destfile)
+ goto bail;
+
+#ifdef G_OS_UNIX
+ if (! vitem->deep_copy)
+ r = symlink(fileinfo->file, destfile);
+
+ if (r < 0) {
+ if (! vitem->deep_copy) {
+ g_warning("Requested sparse folder is not possible.\n"
+ "Using plain file copy instead\n");
+ }
+#endif
+ if (copy_file(fileinfo->file, destfile, TRUE) < 0) {
+ g_warning("can't copy message %s to %s\n", fileinfo->file, destfile);
+ g_free(destfile);
+ destfile = NULL;
+ goto bail;
+ }
+ vitem->deep_copy = TRUE;
+
+#ifdef G_OS_UNIX
+ }
+#endif
+
+ if( relation != NULL )
+ g_hash_table_insert(relation, fileinfo,
+ GINT_TO_POINTER(dest->last_num + 1) );
+ g_free(destfile);
+ vfolder_add_msg_to_message_bridge(vitem,
+ fileinfo->msginfo->msgnum, dest->last_num + 1);
+ dest->last_num++;
+ vfolder_folder_item_props_write(VFOLDER_ITEM(dest));
+ }
+
+bail:
+
+ return (destfile) ? dest->last_num : -1;
+}
+
+static gint vfolder_add_msg(Folder* folder, FolderItem* dest, const gchar* file,
+ MsgFlags* flags) {
+ gint ret;
+ GSList file_list;
+ MsgFileInfo fileinfo;
+
+ g_return_val_if_fail(file != NULL, -1);
+
+ fileinfo.msginfo = NULL;
+ fileinfo.file = (gchar *)file;
+ fileinfo.flags = flags;
+ file_list.data = &fileinfo;
+ file_list.next = NULL;
+
+ ret = vfolder_add_msgs(folder, dest, &file_list, NULL);
+ return ret;
+}
+
+static gint vfolder_copy_msgs(Folder *folder, FolderItem *dest,
+ MsgInfoList *msglist, GHashTable *relation) {
+ MsgInfo *msginfo;
+ FolderItem *src;
+ GSList* cur = NULL;
+ gint last_num = 0;
+
+ g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1);
+
+ if (! VFOLDER_ITEM(dest)->deep_copy)
+ return -1;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(msglist != NULL, -1);
+
+ if( dest->last_num < 0 ) {
+ vfolder_get_last_num(folder, dest);
+ if( dest->last_num < 0 ) return -1;
+ }
+
+ msginfo = (MsgInfo *)msglist->data;
+ g_return_val_if_fail(msginfo->folder != NULL, -1);
+
+ statusbar_print_all(_("Copying messages..."));
+
+ src = msginfo->folder;
+ if (src->folder != dest->folder) {
+ GSList *infolist = NULL, *cur;
+ int res = -1;
+ for (cur = msglist; cur; cur = cur->next) {
+ msginfo = (MsgInfo *)cur->data;
+ MsgFileInfo *fileinfo = g_new0(MsgFileInfo, 1);
+ fileinfo->file = procmsg_get_message_file(msginfo);
+ fileinfo->flags = &(msginfo->flags);
+ infolist = g_slist_prepend(infolist, fileinfo);
+ }
+ infolist = g_slist_reverse(infolist);
+ res = folder_item_add_msgs(dest, infolist, FALSE);
+ for (cur = infolist; cur; cur = cur->next) {
+ MsgFileInfo *info = (MsgFileInfo *)cur->data;
+ g_free(info->file);
+ g_free(info);
+ }
+ g_slist_free(infolist);
+ statusbar_pop_all();
+ return res;
+ }
+
+ for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
+ MsgInfo* msginfo = (MsgInfo *)cur->data;
+
+ /* put the local file in the folder cache, so that we don't
+ * have to fetch it back later. */
+ if (msginfo) {
+ gchar *cache_path = folder_item_get_path(msginfo->folder);
+ debug_print("cache_path: %s\n", cache_path);
+ gchar *real_file = g_strconcat(
+ cache_path, G_DIR_SEPARATOR_S,
+ itos(msginfo->msgnum), NULL);
+ debug_print("real_file: %s\n", real_file);
+ gchar *cache_file = NULL;
+ g_free(cache_path);
+ cache_path = folder_item_get_path(dest);
+ debug_print("cache_path: %s\n", cache_path);
+ cache_file = vfolder_get_new_msg_filename(dest);
+ debug_print("cache_file: %s\n", cache_file);
+ if (!is_dir_exist(cache_path))
+ make_dir_hier(cache_path);
+ if (is_file_exist(real_file) && is_dir_exist(cache_path)) {
+ g_hash_table_insert(relation, msginfo, GINT_TO_POINTER(dest->last_num));
+ if (dest->last_num > last_num)
+ last_num = dest->last_num;
+ copy_file(real_file, cache_file, TRUE);
+ debug_print("copied to cache: %s\n", cache_file);
+ }
+ g_free(real_file);
+ g_free(cache_file);
+ g_free(cache_path);
+ }
+ }
+ statusbar_pop_all();
+
+ //dest->cache_dirty = 1;
+ //folder_item_update_thaw();
+
+ return last_num;
+}
+
+static gint vfolder_copy_msg(Folder* folder, FolderItem* dest, MsgInfo* msginfo) {
+ GSList msglist;
+
+ g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1);
+
+ if (! VFOLDER_ITEM(dest)->deep_copy)
+ return -1;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(msginfo != NULL, -1);
+
+ g_return_val_if_fail(msginfo != NULL, -1);
+
+ msglist.data = msginfo;
+ msglist.next = NULL;
+
+ return vfolder_copy_msgs(folder, dest, &msglist, NULL);
+}
+
+static gchar* vfolder_fetch_msg(Folder* folder, FolderItem* item, gint num) {
+ gchar* snum = g_strdup_printf("%d", num);
+ gchar* file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR,
+ G_DIR_SEPARATOR_S, item->name, G_DIR_SEPARATOR_S, snum, NULL);
+
+ debug_print("VFolder: fetch_msg: '%s'\n", file);
+
+ g_free(snum);
+
+ return file;
+}
+
+static MsgInfo* vfolder_get_msginfo(Folder* folder, FolderItem* item, gint num) {
+ MsgInfo* msginfo = NULL;
+ gchar* file;
+ MsgFlags flags;
+
+ debug_print("VFolder: get_msginfo: %d\n", num);
+
+ g_return_val_if_fail(folder != NULL, NULL);
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(num > 0, NULL);
+
+ file = vfolder_fetch_msg(folder, item, num);
+ if (! g_file_test(file, G_FILE_TEST_EXISTS)) {
+ g_free(file);
+ return NULL;
+ }
+
+ flags.perm_flags = MSG_NEW | MSG_UNREAD;
+ flags.tmp_flags = 0;
+
+ msginfo = procheader_parse_file(file, flags, TRUE, TRUE);
+
+ if (msginfo)
+ msginfo->msgnum = num;
+
+ if (!msginfo->folder)
+ msginfo->folder = item;
+
+ g_free(file);
+
+ return msginfo;
+}
+
+static gint vfolder_remove_msg(Folder* folder, FolderItem* item, gint num)
+{
+ gboolean need_scan = FALSE;
+ gchar *file, *tmp;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ file = vfolder_fetch_msg(folder, item, num);
+ g_return_val_if_fail(file != NULL, -1);
+
+ need_scan = vfolder_scan_required(folder, item);
+
+ /* are we doing a folder move ? */
+ tmp = g_strdup_printf("%s.tmp", file);
+ if (is_file_exist(tmp)) {
+ claws_unlink(tmp);
+ g_free(tmp);
+ g_free(file);
+ return 0;
+ }
+ g_free(tmp);
+
+ if( claws_unlink(file) < 0 ) {
+ FILE_OP_ERROR(file, "unlink");
+ g_free(file);
+ return -1;
+ }
+
+ MsgInfo* msginfo = vfolder_find_msg_from_vfolder_num(VFOLDER_ITEM(item), num);
+ if (msginfo) {
+ vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), msginfo->msgnum, num);
+ vfolder_folder_item_props_write(VFOLDER_ITEM(item));
+ }
+ else {
+ MsgBridge* bridge = g_hash_table_lookup(VFOLDER_ITEM(item)->me_to_claws, GUINT_TO_POINTER(num));
+ if (bridge) {
+ vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), bridge->claws_num, num);
+ vfolder_folder_item_props_write(VFOLDER_ITEM(item));
+ }
+ }
+
+ if( !need_scan )
+ item->mtime = time(NULL);
+
+ g_free(file);
+
+ return 0;
+}
+
+static gint vfolder_remove_all_msg(Folder* folder, FolderItem* item) {
+ GSList *msg_list, *list;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ msg_list = folder_item_get_msg_list(item);
+ if (msg_list) {
+ for (list = msg_list; list; list = g_slist_next(list)) {
+ MsgInfo* msginfo = (MsgInfo *) list->data;
+ folder_item_remove_msg(item, msginfo->msgnum);
+ }
+ }
+ g_slist_free(msg_list);
+
+ vfolder_remove_hashtables(VFOLDER_ITEM(item));
+
+ return 0;
+}
+
+static gboolean vfolder_subscribe_uri(Folder* folder, const gchar* uri) {
+ return FALSE;
+}
+
+static void vfolder_print_hash_table(GHashTable* hash) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (hash) {
+ g_hash_table_iter_init (&iter, hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ guint key = GPOINTER_TO_UINT(key);
+ MsgBridge* bridge = (MsgBridge *) value;
+ fprintf(stderr, "key: %u ----- me: %u -> claws: %u\n",
+ key, bridge->my_num, bridge->claws_num);
+ }
+ }
+}
+
+static MsgInfo* vfolder_find_msg_from_num_rel(VFolderItem* item,
+ guint msgnum,
+ gboolean claws_to_me) {
+ MsgInfo* msginfo = NULL;
+ GHashTable* hash;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ if (msgnum < 1)
+ return NULL;
+
+ vfolder_print_hash_table(item->claws_to_me);
+ vfolder_print_hash_table(item->me_to_claws);
+
+ if (claws_to_me)
+ hash = item->claws_to_me;
+ else
+ hash = item->me_to_claws;
+
+ MsgBridge* msgbridge = g_hash_table_lookup(hash, GUINT_TO_POINTER(msgnum));
+
+ if (msgbridge) {
+ if (claws_to_me)
+ msginfo = folder_item_get_msginfo(FOLDER_ITEM(item), msgbridge->my_num);
+ else
+ msginfo = folder_item_get_msginfo(item->source, msgbridge->claws_num);
+ }
+
+ return msginfo;
+}
+
+gboolean vfolder_replace_key_in_bridge(VFolderItem* item, guint from, guint to) {
+ gboolean ret = FALSE;
+ MsgBridge *bridge, *old;
+
+ if (! item->me_to_claws || ! item->claws_to_me)
+ return TRUE;
+
+ old = g_hash_table_lookup(item->claws_to_me, GUINT_TO_POINTER(from));
+ if (!old)
+ return TRUE;
+
+ debug_print("Replace key in hashtable: from->%u to->%u\n", from, to);
+ bridge = vfolder_create_bridge(to, old->my_num);
+
+ ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(old->my_num));
+ if (!ret) {
+ g_free(bridge);
+ return TRUE;
+ }
+ ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(old->claws_num));
+ if (!ret) {
+ bridge->claws_num = from;
+ g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge);
+ return TRUE;
+ }
+
+ g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(bridge->claws_num), bridge);
+ g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge);
+
+ return ret;
+}
+
+gboolean vfolder_add_message_to_bridge(VFolderItem* item, MsgBridge* bridge) {
+ if (!item || !bridge)
+ return TRUE;
+
+ return vfolder_add_msg_to_message_bridge(item, bridge->claws_num, bridge->my_num);
+}
+
+MsgInfo* vfolder_find_msg_from_claws_num(VFolderItem* item, guint msgnum) {
+ return vfolder_find_msg_from_num_rel(item, msgnum, TRUE);
+}
+
+MsgInfo* vfolder_find_msg_from_vfolder_num(VFolderItem* item, guint msgnum) {
+ return vfolder_find_msg_from_num_rel(item, msgnum, FALSE);
+}
+
+GList* vfolder_get_vfolder_items(void) {
+ return g_list_copy(vfolders);
+}
+
+VFolderItem* vfolder_get_vfolder_item(const gchar* name) {
+ VFolderItem* item = NULL;
+ gchar* folder_name = NULL;
+ gchar* this_name = NULL;
+ GList* list = vfolders;
+
+ if (! name)
+ folder_name = g_strdup(VFOLDER_DEFAULT_MAILBOX);
+ else
+ folder_name = g_strdup(name);
+
+ while (list && item == NULL) {
+ this_name = FOLDER_ITEM(list->data)->name;
+ if (this_name && strcmp(folder_name, this_name) == 0)
+ item = VFOLDER_ITEM(list->data);
+ else
+ list = list->next;
+ }
+
+ g_free(folder_name);
+
+ return item;
+}
+
+GList* vfolder_get_vfolder_from_source(FolderItem* source) {
+ GList* items = NULL;
+ FolderItem* src = NULL;
+ GList* list = vfolders;
+ gchar* src_id = NULL;
+
+ if (! source)
+ return NULL;
+
+ src_id = folder_item_get_identifier(source);
+ if (!src_id)
+ return NULL;
+
+ while (list) {
+ src = VFOLDER_ITEM(list->data)->source;
+ if (strcmp(folder_item_get_identifier(src), src_id) == 0) {
+ items = g_list_prepend(items, list->data);
+ }
+ list = list->next;
+ }
+
+ return items;
+}
+
+typedef struct { GSList* msgnumlist; guint remove; } RemoveInfo;
+static void find_msg_to_remove(gpointer key, gpointer value, gpointer user_data) {
+ RemoveInfo* remove_info = (RemoveInfo *) user_data;
+
+ if (remove_info->remove == 0) {
+ if (g_slist_index(remove_info->msgnumlist, key) < 0) {
+ MsgBridge* bridge = (MsgBridge *) value;
+ remove_info->remove = bridge->my_num;
+ }
+ }
+};
+
+static void vfolder_add_msg_to_folder(VFolderItem* item) {
+ GSList *msgnumlist, *cur;
+ GSList file_list;
+ MsgFileInfo fileinfo;
+ MsgInfoList msgs;
+
+ if (! item->msg_filter_func)
+ return;
+
+ msgnumlist = folder_item_get_number_list(item->source);
+ for (cur = msgnumlist; cur; cur = g_slist_next(cur)) {
+ MsgBridge* bridge = g_hash_table_lookup(item->claws_to_me, cur->data);
+ if (! bridge) {
+ msgs.data = folder_item_get_msginfo(item->source, GPOINTER_TO_UINT(cur->data));
+ msgs.next = NULL;
+ MsgInfoList* list = item->msg_filter_func(&msgs, item);
+ if (list) {
+ fileinfo.msginfo = list->data;
+ fileinfo.file = procmsg_get_message_file_path(fileinfo.msginfo);
+ fileinfo.flags = &fileinfo.msginfo->flags;
+ file_list.data = &fileinfo;
+ file_list.next = NULL;
+ vfolder_add_msgs(item->source->folder, FOLDER_ITEM(item), &file_list, NULL);
+ FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_ADDMSG;
+ g_slist_free(list);
+ }
+ }
+ }
+ g_slist_free(msgnumlist);
+}
+
+static void vfolder_remove_msg_from_folder(VFolderItem* item) {
+ RemoveInfo remove_info;
+ remove_info.msgnumlist = folder_item_get_number_list(item->source);
+ remove_info.remove = 0;
+ g_hash_table_foreach(item->claws_to_me, find_msg_to_remove, &remove_info);
+ vfolder_remove_msg(FOLDER_ITEM(item)->folder, FOLDER_ITEM(item), remove_info.remove);
+ g_slist_free(remove_info.msgnumlist);
+ FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_REMOVEMSG;
+}
+
+void vfolder_folder_item_update_msgs(VFolderItem* item, FolderItemUpdateFlags flag) {
+ guint c;
+
+ if (item->frozen || item->updating)
+ return;
+
+ if (item->claws_to_me) {
+ item->updating = TRUE;
+ switch (flag) {
+ case F_ITEM_UPDATE_MSGCNT:
+ break;
+ case F_ITEM_UPDATE_CONTENT:
+ c = g_hash_table_size(item->claws_to_me);
+ if (c < item->source->total_msgs) {
+ /* add messages */
+ vfolder_add_msg_to_folder(item);
+ }
+ else if (c > item->source->total_msgs) {
+ /* remove messages */
+ vfolder_remove_msg_from_folder(item);
+ }
+ break;
+ case F_ITEM_UPDATE_ADDMSG:
+ vfolder_add_msg_to_folder(item);
+ break;
+ case F_ITEM_UPDATE_REMOVEMSG:
+ vfolder_remove_msg_from_folder(item);
+ break;
+ case F_ITEM_UPDATE_NAME:
+ break;
+ }
+ item->updating = FALSE;
+ }
+}
+
+FolderClass* vfolder_folder_get_class() {
+ if (vfolder_class.idstr == NULL ) {
+ vfolder_class.type = F_UNKNOWN;
+ vfolder_class.idstr = "vfolder";
+ vfolder_class.uistr = "VFolder";
+
+ /* Folder functions */
+ vfolder_class.new_folder = vfolder_new_folder;
+ vfolder_class.destroy_folder = vfolder_destroy_folder;
+ vfolder_class.set_xml = folder_set_xml;
+ vfolder_class.get_xml = folder_get_xml;
+ vfolder_class.scan_tree = vfolder_scan_tree;
+ vfolder_class.create_tree = vfolder_create_tree;
+
+ /* FolderItem functions */
+ vfolder_class.item_new = vfolder_item_new;
+ vfolder_class.item_destroy = vfolder_item_destroy;
+ vfolder_class.item_get_path = vfolder_item_get_path;
+ vfolder_class.create_folder = vfolder_create_folder;
+ vfolder_class.rename_folder = NULL;
+ vfolder_class.remove_folder = vfolder_remove_folder;
+ vfolder_class.get_num_list = vfolder_get_num_list;
+ vfolder_class.scan_required = vfolder_scan_required;
+
+ /* Message functions */
+ vfolder_class.get_msginfo = vfolder_get_msginfo;
+ vfolder_class.fetch_msg = vfolder_fetch_msg;
+ vfolder_class.copy_msgs = vfolder_copy_msgs;
+ vfolder_class.copy_msg = vfolder_copy_msg;
+ vfolder_class.add_msg = vfolder_add_msg;
+ vfolder_class.add_msgs = vfolder_add_msgs;
+ vfolder_class.remove_msg = vfolder_remove_msg;
+ vfolder_class.remove_msgs = NULL;
+ vfolder_class.remove_all_msg = vfolder_remove_all_msg;
+ vfolder_class.change_flags = NULL;
+ vfolder_class.subscribe = vfolder_subscribe_uri;
+ debug_print("VFolder: registered folderclass\n");
+ }
+
+ return &vfolder_class;
+}
+
+/* Local functions */
+
+gboolean vfolder_init(void) {
+ gchar* error = g_new0(gchar, 1);
+
+ folder_register_class(vfolder_folder_get_class());
+
+ if (! vfolder_gtk_init(&error)) {
+ alertpanel_error("%s", error);
+ vfolder_done();
+ return FALSE;
+ }
+
+ folder_func_to_all_folders((FolderItemFunc)vfolder_init_read_func, NULL);
+
+ if (existing_tree_found == FALSE)
+ vfolder_create_default_mailbox();
+
+ return TRUE;
+}
+
+void vfolder_done(void) {
+
+ vfolder_gtk_done();
+
+ if (!claws_is_exiting())
+ folder_unregister_class(vfolder_folder_get_class());
+}
--- /dev/null
+/*
+ * $Id: $
+ */
+
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VFOLDER_H__
+#define __VFOLDER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include "folder.h"
+#include <procmsg.h>
+#include "gettext.h"
+
+/* Name of directory in rcdir where VFolder will store its data. */
+#define VFOLDER_DIR "vfolder"
+
+/* Parent mailbox name */
+#define VFOLDER_DEFAULT_MAILBOX _("Virtual folders")
+
+typedef enum {
+ SEARCH_HEADERS = 1, /* from/to/subject */
+ SEARCH_BODY = 2, /* message */
+ SEARCH_BOTH = 4 /* both */
+} SearchType;
+
+typedef struct {
+ guint my_num;
+ guint claws_num;
+} MsgBridge;
+
+/*typedef enum {
+ BEFORE_ADDING_MSG = 1,
+ BEFORE_DELETING_MSG = 2,
+ AFTER_ADDING_MSG = 4,
+ AFTER_DELETING_MSG = 8
+} ChangeAction;
+*/
+
+typedef struct _VFolderItem VFolderItem;
+typedef MsgInfoList* (*MSGFILTERFUNC) (MsgInfoList* msgs, VFolderItem* item);
+
+struct _VFolderItem {
+ FolderItem item;
+
+ gchar* filter; /* Regex used to select messages */
+ gboolean frozen; /* Automatic update or not */
+ gboolean deep_copy; /* Copy messages or use reference */
+ SearchType search;
+ gboolean updating; /* Is this VFolder currently updating */
+
+ FolderItem* source; /* Source folder for virtual folder */
+// MsgInfoList* msginfos; /* List of MsgInfo */
+ GHashTable* me_to_claws; /* Hashtable containing MsgBridge */
+ GHashTable* claws_to_me; /* Hashtable containing MsgBridge */
+ MSGFILTERFUNC msg_filter_func; /* Active filter function */
+};
+
+gboolean vfolder_init(void);
+void vfolder_done(void);
+
+FolderClass* vfolder_folder_get_class(void);
+VFolderItem* vfolder_get_vfolder_item(const gchar* name);
+GList* vfolder_get_vfolder_items(void);
+GList* vfolder_get_vfolder_from_source(FolderItem* source);
+gboolean vfolder_add_message_to_bridge(VFolderItem* item, MsgBridge* bridge);
+gboolean vfolder_replace_key_in_bridge(VFolderItem* item, guint from, guint to);
+MsgInfo* vfolder_find_msg_from_claws_num(VFolderItem* item, guint msgnum);
+MsgInfo* vfolder_find_msg_from_vfolder_num(VFolderItem* item, guint msgnum);
+void vfolder_folder_item_update_msgs(VFolderItem* item, FolderItemUpdateFlags flag);
+
+#define VFOLDER_ITEM(obj) ((VFolderItem *)obj)
+#define VFOLDER(obj) ((VFolder *)obj)
+
+#define IS_VFOLDER_FOLDER(folder) \
+ ((folder) && (folder->klass == vfolder_folder_get_class()))
+#define IS_VFOLDER_FOLDER_ITEM(item) \
+ ((item) && (item->folder->klass == vfolder_folder_get_class()))
+#define IS_VFOLDER_MSGINFO(msginfo) \
+ ((msginfo) && (msginfo->folder) && IS_VFOLDER_FOLDER_ITEM(msginfo->folder))
+#define IS_VFOLDER_FROZEN(item) ((item) && (item->frozen))
+#define IS_VFOLDER_DEEP_COPY(item) ((item) && (item->deep_copy))
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/*
+ * $Id: $
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ *
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gtk/menu.h"
+#include "gtk/gtk.h"
+#include "mainwindow.h"
+#include "inputdialog.h"
+#include "folder.h"
+#include "folderview.h"
+#include "alertpanel.h"
+#include "hooks.h"
+#include "utils.h"
+#include "summaryview.h"
+
+#include "gettext.h"
+#include "main.h"
+#include "gtkutils.h"
+
+#include "vfolder_gtk.h"
+#include "vfolder.h"
+#include "vfolder_prop.h"
+
+#define CONFIG_GROUP "VFolder"
+
+static guint folder_hook_id;
+static guint item_hook_id;
+static guint msginfo_hook_id;
+static GSList* widgets = NULL;
+
+typedef struct {
+ MsgInfoList* list;
+ VFolderItem* item;
+ gchar* file;
+} AddMsgData;
+
+typedef struct {
+ GtkWidget* widget;
+ GtkAction* action;
+} MenuItem;
+
+static char* vfolder_popup_menu_labels[] = {
+ N_("_Refresh folder"),
+ N_("Refresh _all folders"),
+ N_("Folder pr_operties..."),
+ N_("Rena_me..."),
+ N_("_Create new folder..."),
+ N_("_Delete folder..."),
+ NULL
+};
+
+static GtkActionEntry vfolder_popup_entries[] = {
+ {"FolderViewPopup/RefreshFolder", NULL, NULL, NULL, NULL, NULL /*G_CALLBACK(vfolder_refresh_cb)*/ },
+ {"FolderViewPopup/RefreshAllFolders", NULL, NULL, NULL, NULL, NULL /*G_CALLBACK(vfolder_refresh_cb)*/ },
+
+ {"FolderViewPopup/FolderProperties", NULL, NULL, NULL, NULL, G_CALLBACK(vfolder_properties_cb) },
+
+ {"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, NULL /*G_CALLBACK(vfolder_refresh_cb)*/ },
+
+ {"FolderViewPopup/NewFolder", NULL, NULL, NULL, NULL, G_CALLBACK(vfolder_new_folder_cb) },
+ {"FolderViewPopup/RemoveFolder", NULL, NULL, NULL, NULL, G_CALLBACK(vfolder_remove_folder_cb) },
+};
+
+static void vfolder_add_menuitems(GtkUIManager *ui_manager, FolderItem *item) {
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshFolder", "FolderViewPopup/RefreshFolder", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshAllFolders", "FolderViewPopup/RefreshAllFolders", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVF1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "FolderProperties", "FolderViewPopup/FolderProperties", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVF2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVF3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFolder", "FolderViewPopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveFolder", "FolderViewPopup/RemoveFolder", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVF4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+}
+
+static void vfolder_set_sensitivity(GtkUIManager *ui_manager, FolderItem *item) {
+#define SET_SENS(name, sens) \
+ cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
+
+ VFolderItem *ritem = (VFolderItem *)item;
+ SET_SENS("FolderViewPopup/RefreshFolder", folder_item_parent(item) != NULL && ! ritem->frozen);
+ SET_SENS("FolderViewPopup/RefreshAllFolders", folder_item_parent(item) == NULL && ! ritem->frozen);
+ SET_SENS("FolderViewPopup/FolderProperties", folder_item_parent(item) != NULL);
+ SET_SENS("FolderViewPopup/RenameFolder", folder_item_parent(item) != NULL);
+ SET_SENS("FolderViewPopup/NewFolder", TRUE);
+ SET_SENS("FolderViewPopup/RemoveFolder", folder_item_parent(item) != NULL);
+
+#undef SET_SENS
+}
+
+static FolderViewPopup vfolder_popup = {
+ "vfolder",
+ "<vfolder>",
+ vfolder_popup_entries,
+ G_N_ELEMENTS(vfolder_popup_entries),
+ NULL, 0,
+ NULL, 0, 0, NULL,
+ vfolder_add_menuitems,
+ vfolder_set_sensitivity
+};
+
+static void vfolder_fill_popup_menu_labels(void) {
+ gint i;
+
+ for (i = 0; vfolder_popup_menu_labels[i] != NULL; i++) {
+ (vfolder_popup_entries[i]).label = _(vfolder_popup_menu_labels[i]);
+ }
+}
+
+static void gslist_menu_item_free(GSList** menu_list) {
+ GSList* list;
+
+ if (! menu_list || ! *menu_list)
+ return;
+
+ for (list = *menu_list; list; list = g_slist_next(list)) {
+ MenuItem* menu = (MenuItem *) list->data;
+ g_free(menu);
+ }
+
+ g_slist_free(*menu_list);
+ *menu_list = NULL;
+}
+
+static MsgBridge* vfolder_split_file_id(gchar* id) {
+ MsgBridge* resp = NULL;
+
+ if (! id)
+ return NULL;
+
+ gchar** tokens = g_strsplit(id, ":", 0);
+ if (g_strv_length(tokens) != 2)
+ goto bail;
+
+ resp = g_new0(MsgBridge, 1);
+ resp->my_num = to_number(tokens[0]);
+ resp->claws_num = to_number(tokens[1]);
+
+bail:
+ g_strfreev(tokens);
+ return resp;
+}
+
+static gboolean get_menu_widgets() {
+ MainWindow* mainwindow;
+ MenuItem* menuitem = NULL;
+ GtkWidget* widget;
+
+ mainwindow = mainwindow_get_mainwindow();
+ if (mainwindow && mainwindow->ui_manager) {
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Move/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Move/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else
+ return FALSE;
+
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Trash/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Trash/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else {
+ gslist_menu_item_free(&widgets);
+ return FALSE;
+ }
+
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Delete/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menus/SummaryViewPopup/Delete/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else {
+ gslist_menu_item_free(&widgets);
+ return FALSE;
+ }
+
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menu/Message/Move/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menu/Message/Move/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else {
+ gslist_menu_item_free(&widgets);
+ return FALSE;
+ }
+
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menu/Message/Trash/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menu/Message/Trash/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else {
+ gslist_menu_item_free(&widgets);
+ return FALSE;
+ }
+
+ widget = gtk_ui_manager_get_widget(
+ mainwindow->ui_manager, "/Menu/Message/Delete/");
+ if (widget) {
+ menuitem = g_new0(MenuItem, 1);
+ menuitem->widget = widget;
+ menuitem->action = gtk_ui_manager_get_action(
+ mainwindow->ui_manager, "/Menu/Message/Delete/");
+ widgets = g_slist_prepend(widgets, menuitem);
+ }
+ else {
+ gslist_menu_item_free(&widgets);
+ return FALSE;
+ }
+
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+/*
+static gboolean vfolder_widgets_is_visible() {
+ gboolean visible = TRUE;
+
+ if (widgets && widgets->data) {
+ MenuItem* menu = (MenuItem *) widgets->data;
+ visible = gtk_widget_get_visible(menu->widget);
+ }
+
+ return visible;
+}
+
+static gboolean vfolder_hide_widgets(VFolderItem* item) {
+ GSList* list;
+ MainWindow* mainwindow;
+
+// if (! item->deep_copy) {
+ for (list = widgets; list; list = g_slist_next(list)) {
+ MenuItem* menu = (MenuItem *) list->data;
+ gtk_widget_hide(menu->widget);
+ gtk_action_block_activate(menu->action);
+ }
+
+ mainwindow = mainwindow_get_mainwindow();
+ if (mainwindow && mainwindow->toolbar) {
+ if (mainwindow->toolbar->trash_btn)
+ gtk_widget_hide(mainwindow->toolbar->trash_btn);
+ if (mainwindow->toolbar->delete_btn)
+ gtk_widget_hide(mainwindow->toolbar->delete_btn);
+ }
+// }
+ return TRUE;
+}
+*/
+static gboolean vfolder_show_widgets(VFolderItem* item) {
+ GSList* list;
+ MainWindow* mainwindow;
+
+// if (! item->deep_copy) {
+ for (list = widgets; list; list = g_slist_next(list)) {
+ MenuItem* menu = (MenuItem *) list->data;
+ gtk_widget_show(menu->widget);
+ gtk_action_unblock_activate(menu->action);
+ }
+
+ mainwindow = mainwindow_get_mainwindow();
+ if (mainwindow && mainwindow->toolbar) {
+ if (mainwindow->toolbar->trash_btn)
+ gtk_widget_show(mainwindow->toolbar->trash_btn);
+ if (mainwindow->toolbar->delete_btn)
+ gtk_widget_show(mainwindow->toolbar->delete_btn);
+ }
+// }
+ return TRUE;
+}
+/*
+static gchar* vfolder_get_message_file_path(VFolderItem* item, MsgInfo* msg) {
+ gchar* path;
+ GSList* list = NULL, *cur;
+ Folder* folder;
+ gboolean old_uid;
+ guint last = 0;
+
+ if (item->deep_copy) {
+ path = procmsg_get_message_file_path(msg);
+ }
+ else {
+ gchar* root = folder_item_get_path(msg->to_folder);
+ folder = msg->to_folder->folder;
+ guint num = folder->klass->get_num_list(folder, msg->to_folder, &list, &old_uid);
+ if (num >= 0) {
+ for (cur = list, last = 0; cur; cur = g_slist_next(cur)) {
+ guint tmp = GPOINTER_TO_UINT(cur->data);
+ if (tmp > last)
+ last = tmp;
+ }
+ }
+ g_slist_free(list);
+
+ path = g_strdup_printf("%s%s%u", root, G_DIR_SEPARATOR_S, last + 1);
+ g_free(root);
+ }
+ return path;
+}
+*/
+
+/*
+static void vfolder_item_update(AddMsgData* msgdata) {
+ MsgInfoList* cur;
+ GSList update;
+ MsgFileInfo fileinfo;
+
+ if (!msgdata->item || !msgdata->list->data)
+ return;
+
+ for (cur = msgdata->list; cur; cur = g_slist_next(cur)) {
+ MsgInfo* msg = (MsgInfo *) cur->data;
+ if (MSG_IS_DELETED(msg->flags)) {
+ folder_item_remove_msg(FOLDER_ITEM(msgdata->item), msg->msgnum);
+ }
+ else {
+ fileinfo.msginfo = msg;
+ fileinfo.flags = &msg->flags;
+ fileinfo.file = msgdata->file;
+ update.data = &fileinfo;
+ update.next = NULL;
+ folder_item_scan(msg->folder);
+ gint n = folder_item_add_msgs(FOLDER_ITEM(msgdata->item), &update, FALSE);
+ gchar* p = strrchr(fileinfo.file, G_DIR_SEPARATOR);
+ p += 1;
+ guint num = to_number((const gchar *) p);
+ vfolder_replace_key_in_bridge(msgdata->item, msg->msgnum, num);
+ FOLDER_ITEM(msgdata->item)->last_num = n;
+ }
+ }
+
+ //procmsg_message_file_list_free(list);
+ //item->msginfos = folder_item_get_msg_list(FOLDER_ITEM(item));
+}
+*/
+/*
+static void add_msg_data_free(AddMsgData** rec) {
+ if (rec && *rec) {
+ AddMsgData* data = *rec;
+ g_slist_free(data->list);
+ g_free(data->file);
+ g_free(data);
+ *rec = NULL;
+ }
+}
+*/
+/*
+static void vfolder_update_affected_folder_items(MsgInfo* msginfo) {
+ GList *vfolders, *cur;
+ GSList* cur_msg;
+ gchar* src;
+ AddMsgData* data;
+ MsgInfo* msg;
+
+ if (! msginfo)
+ return;
+
+ if (MSG_IS_NEW(msginfo->flags) ||
+ MSG_IS_MOVE(msginfo->flags) ||
+ MSG_IS_COPY(msginfo->flags) ||
+ MSG_IS_DELETED(msginfo->flags)) {
+ vfolders = vfolder_get_vfolder_items();
+ for (cur = vfolders; cur; cur = g_list_next(cur)) {
+ data = g_new0(AddMsgData, 1);
+ VFolderItem* vitem = VFOLDER_ITEM(cur->data);
+ if (MSG_IS_MOVE(msginfo->flags) || MSG_IS_COPY(msginfo->flags))
+ src = folder_item_get_identifier(msginfo->to_folder);
+ else
+ src = folder_item_get_identifier(msginfo->folder);
+ gchar* shadow = folder_item_get_identifier(vitem->source);
+ debug_print("cmp %s : %s\n", src, shadow);
+ if (src && shadow && strcmp(src, shadow) == 0) {
+ if (MSG_IS_DELETED(msginfo->flags)) {
+ msg = vfolder_find_msg_from_claws_num(vitem, msginfo->msgnum);
+ if (msg)
+ data->list = g_slist_append(data->list, msg);
+ else {
+ add_msg_data_free(&data);
+ g_slist_free(add_msg_data);
+ add_msg_data = NULL;
+ g_free(src);
+ g_free(shadow);
+ return;
+ }
+ }
+ else {
+ data->list = g_slist_append(data->list, msginfo);
+ data->item = vitem;
+ data->file = vfolder_get_message_file_path(vitem, msginfo);
+ add_msg_data = g_slist_prepend(add_msg_data, data);
+ }
+ if (data->list && MSG_IS_DELETED(msginfo->flags)) {
+ GSList* list = vfolder_filter_msgs_list(data->list, vitem);
+ if (list && list->data) {
+ MsgInfo* msg = (MsgInfo *) list->data;
+ MSG_SET_PERM_FLAGS(msg->flags, MSG_DELETED);
+ }
+ g_slist_free(data->list);
+ data->list = list;
+ data->item = vitem;
+ vfolder_item_update(data);
+ add_msg_data_free(&data);
+ g_slist_free(add_msg_data);
+ add_msg_data = NULL;
+ }
+ }
+ g_free(src);
+ g_free(shadow);
+ }
+ }
+ if (add_msg_data) {
+ for (cur_msg = add_msg_data; cur_msg; cur_msg = g_slist_next(cur_msg)) {
+ data = (AddMsgData *) cur_msg->data;
+ GSList* list = vfolder_filter_msgs_list(data->list, data->item);
+ g_slist_free(data->list);
+ data->list = list;
+ vfolder_item_update(data);
+ add_msg_data_free(&data);
+ }
+ g_slist_free(add_msg_data);
+ add_msg_data = NULL;
+ }
+}
+*/
+static gboolean vfolder_folder_update_hook(gpointer source, gpointer data) {
+ FolderUpdateData* hookdata;
+
+ g_return_val_if_fail(source != NULL, FALSE);
+ hookdata = (FolderUpdateData *) source;
+
+ if (! hookdata->folder || IS_VFOLDER_FOLDER(hookdata->folder))
+ return FALSE;
+
+ if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
+ /* TODO: check if the removed folder item is foundation for vfolder */
+ debug_print("FOLDER_REMOVE_FOLDERITEM\n");
+ }
+
+ if (hookdata->update_flags & FOLDER_REMOVE_FOLDER) {
+ /* TODO: check if the removed folder is foundation for vfolder */
+ debug_print("FOLDER_REMOVE_FOLDER\n");
+ }
+
+ if (hookdata->update_flags & FOLDER_TREE_CHANGED) {
+ /* TODO: check if the removed folder is foundation for vfolder */
+ debug_print("FOLDER_TREE_CHANGED\n");
+ }
+
+ if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
+ /* TODO: check if the removed folder is foundation for vfolder */
+ debug_print("FOLDER_RENAME_FOLDERITEM\n");
+ }
+
+ return FALSE;
+}
+
+static gboolean vfolder_folder_item_update_hook(gpointer source, gpointer data) {
+ FolderItemUpdateData* hookdata;
+// gint save_state = -1;
+ GList *items, *cur;
+// gboolean r;
+// MainWindow* mainwindow;
+
+ g_return_val_if_fail(source != NULL, FALSE);
+ hookdata = (FolderItemUpdateData *) source;
+
+ if (! hookdata->item || IS_VFOLDER_FOLDER_ITEM(hookdata->item))
+ return FALSE;
+
+ if (hookdata->update_flags & F_ITEM_UPDATE_REMOVEMSG ) {
+ debug_print("F_ITEM_UPDATE_REMOVEMSG\n");
+ items = vfolder_get_vfolder_from_source(hookdata->item);
+ if (items) {
+ for (cur = items; cur; cur = g_list_next(cur)) {
+ vfolder_folder_item_update_msgs(VFOLDER_ITEM(cur->data), F_ITEM_UPDATE_REMOVEMSG);
+ }
+ g_list_free(items);
+ }
+ }
+
+ else if (hookdata->update_flags & F_ITEM_UPDATE_CONTENT) {
+ debug_print("F_ITEM_UPDATE_CONTENT\n");
+ items = vfolder_get_vfolder_from_source(hookdata->item);
+ if (items) {
+ for (cur = items; cur; cur = g_list_next(cur)) {
+ vfolder_folder_item_update_msgs(VFOLDER_ITEM(cur->data), F_ITEM_UPDATE_CONTENT);
+ }
+ g_list_free(items);
+ }
+ //mainwindow = mainwindow_get_mainwindow();
+ //summary_execute(mainwindow->summaryview);
+ }
+
+ else if (hookdata->update_flags & F_ITEM_UPDATE_ADDMSG) {
+ debug_print("F_ITEM_UPDATE_ADDMSG\n");
+ items = vfolder_get_vfolder_from_source(hookdata->item);
+ if (items) {
+ for (cur = items; cur; cur = g_list_next(cur)) {
+ vfolder_folder_item_update_msgs(VFOLDER_ITEM(cur->data), F_ITEM_UPDATE_ADDMSG);
+ }
+ g_list_free(items);
+ }
+ }
+
+ else if (hookdata->update_flags & F_ITEM_UPDATE_MSGCNT) {
+ debug_print("F_ITEM_UPDATE_MSGCNT\n");
+/* if (IS_VFOLDER_FOLDER_ITEM(item)) {
+
+ if (! (VFOLDER_ITEM(item))->deep_copy) {
+ if (! (VFOLDER_ITEM(item))->active) {
+ r = vfolder_hide_widgets(VFOLDER_ITEM(item));
+ if (r)
+ VFOLDER_ITEM(item)->active = TRUE;
+ }
+ else {
+ r = vfolder_show_widgets(VFOLDER_ITEM(item));
+ if (r)
+ VFOLDER_ITEM(item)->active = FALSE;
+ }
+
+ if (r)
+ save_state = 1;
+ else
+ save_state = 0;
+ }
+ else
+ vfolder_show_widgets(VFOLDER_ITEM(item));
+ }
+ else {
+ if (!vfolder_widgets_is_visible())
+ vfolder_show_widgets(VFOLDER_ITEM(item));
+ }*/
+/*
+ items = vfolder_get_vfolder_from_source(hookdata->item);
+ if (items) {
+ for (cur = items; cur; cur = g_list_next(cur)) {
+ vfolder_folder_item_update_msgs(VFOLDER_ITEM(cur->data), F_ITEM_UPDATE_MSGCNT);
+ }
+ g_list_free(items);
+ }
+*/
+ }
+
+ else if (hookdata->update_flags & F_ITEM_UPDATE_NAME) {
+ /* TODO: need update? */
+ debug_print("F_ITEM_UPDATE_NAME\n");
+ items = vfolder_get_vfolder_from_source(hookdata->item);
+ if (items) {
+ for (cur = items; cur; cur = g_list_next(cur)) {
+ vfolder_folder_item_update_msgs(VFOLDER_ITEM(cur->data), F_ITEM_UPDATE_NAME);
+ }
+ g_list_free(items);
+ }
+ }
+
+ else {
+ /* Unhandled callback */
+ debug_print("Unhandled FolderItem callback\n");
+ }
+/*
+ if (!save_state) {
+ MainWindow* mainwindow = mainwindow_get_mainwindow();
+ alertpanel_error(_("%s: Could not hide dangerous actions"), hookdata->item->name);
+ summary_lock(mainwindow->summaryview);
+ }
+*/
+ return FALSE;
+}
+/*
+static gboolean vfolder_msg_info_update_hook(gpointer source, gpointer data) {
+ MsgInfoUpdate* hookdata;
+ MainWindow* mainwindow;
+ MsgInfo* msginfo;
+
+ g_return_val_if_fail(source != NULL, FALSE);
+ hookdata = (MsgInfoUpdate *) source;
+ msginfo = hookdata->msginfo;
+
+ g_return_val_if_fail(msginfo != NULL, TRUE);
+
+ if (IS_VFOLDER_MSGINFO(msginfo))
+ return FALSE;
+
+ debug_print("\n\nPermflag: %u Tmpflag: %u (scanned: %u)\n\n\n",
+ (guint32) msginfo->flags.perm_flags, (guint32) msginfo->flags.tmp_flags, 1U << 31);
+ if (MSG_IS_NEW(msginfo->flags)) {
+ debug_print("MSG_IS_NEW\n");
+ vfolder_update_affected_folder_items(msginfo);
+ mainwindow = mainwindow_get_mainwindow();
+ summary_execute(mainwindow->summaryview);
+ }
+
+ if (MSG_IS_DELETED(msginfo->flags)) {
+ debug_print("MSG_IS_DELETED\n");
+ vfolder_update_affected_folder_items(msginfo);
+ mainwindow = mainwindow_get_mainwindow();
+ summary_execute(mainwindow->summaryview);
+ }
+
+ if (MSG_IS_MOVE(msginfo->flags)) {
+ debug_print("MSG_IS_MOVE\n");
+ vfolder_update_affected_folder_items(msginfo);
+ mainwindow = mainwindow_get_mainwindow();
+ summary_execute(mainwindow->summaryview);
+ }
+
+ if (MSG_IS_COPY(msginfo->flags)) {
+ debug_print("MSG_IS_COPY\n");
+ vfolder_update_affected_folder_items(msginfo);
+ mainwindow = mainwindow_get_mainwindow();
+ summary_execute(mainwindow->summaryview);
+ }
+
+// if (MSG_IS_POSTFILTERED(msginfo->flags)) {
+// debug_print("MSG_IS_POSTFILTERED\n");
+// vfolder_update_affected_folder_items(msginfo);
+// mainwindow = mainwindow_get_mainwindow();
+// summary_execute(mainwindow->summaryview);
+// }
+
+
+ return FALSE;
+}
+*/
+static gchar* vfolder_get_rc_file(VFolderItem* item) {
+ gchar* (*item_get_path) (Folder* folder, FolderItem* item);
+ gchar* path;
+ gchar* rc_file;
+
+ item_get_path = FOLDER_ITEM(item)->folder->klass->item_get_path;
+
+ path = item_get_path(FOLDER_ITEM(item)->folder, FOLDER_ITEM(item));
+ rc_file = g_strconcat(path, G_DIR_SEPARATOR_S, "folderitemrc", NULL);
+ g_free(path);
+
+ return rc_file;
+}
+
+FolderPropsResponse vfolder_folder_item_props_write(VFolderItem* item) {
+ gchar* rc_file;
+ GKeyFile* config;
+ gchar* id;
+ gchar* data = NULL;
+ FILE* fp;
+ gsize len = 0;
+ FolderPropsResponse resp = FOLDER_ITEM_PROPS_NO_ITEM;
+ gchar* numstr;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail(item != NULL, resp);
+
+ rc_file = vfolder_get_rc_file(item);
+ config = g_key_file_new();
+
+ if (item->filter)
+ g_key_file_set_string(config, CONFIG_GROUP, "filter", item->filter);
+
+ g_key_file_set_integer(config, CONFIG_GROUP, "searchtype", item->search);
+ g_key_file_set_boolean(config, CONFIG_GROUP, "frozen", item->frozen);
+ g_key_file_set_boolean(config, CONFIG_GROUP, "deep_copy", item->deep_copy);
+
+ if (item->source) {
+ id = folder_item_get_identifier(item->source);
+ if (id) {
+ g_key_file_set_string(config, CONFIG_GROUP, "source", id);
+ g_free(id);
+ }
+ }
+
+ if (item->claws_to_me && item->me_to_claws) {
+ numstr = NULL;
+ g_hash_table_iter_init(&iter, item->claws_to_me);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ len++;
+ MsgBridge* bridge = value;
+ if (numstr) {
+ gchar* tmp = g_strdup(numstr);
+ g_free(numstr);
+ numstr = g_strdup_printf("%s, %u:%u",
+ tmp, bridge->my_num, bridge->claws_num);
+ g_free(tmp);
+ }
+ else
+ numstr = g_strdup_printf("%u:%u", bridge->my_num, bridge->claws_num);
+ }
+
+ g_key_file_set_string(config, CONFIG_GROUP, "file_id_list", numstr);
+ g_free(numstr);
+ }
+
+ if (g_file_test(rc_file, G_FILE_TEST_EXISTS)) {
+ gchar* bakpath = g_strconcat(rc_file, ".bak", NULL);
+ if (g_rename(rc_file, bakpath) < 0) {
+ g_warning("%s: Could not create", bakpath);
+ resp = FOLDER_ITEM_PROPS_BACKUP_FAIL;
+ }
+ g_free(bakpath);
+ }
+
+// g_key_file_set_integer(config, CONFIG_GROUP, "filter-function", item->filter_func);
+
+ data = g_key_file_to_data(config, &len, NULL);
+ if (len < 1) {
+ g_warning("Could not get config data");
+ resp = FOLDER_ITEM_PROPS_READ_DATA_FAIL;
+ }
+ else {
+ fp = g_fopen(rc_file, "w");
+ if (fp == NULL) {
+ gchar* dir_path_end = g_strrstr(rc_file, G_DIR_SEPARATOR_S);
+ gchar* rc_dir = g_strndup(rc_file, dir_path_end - rc_file);
+ debug_print("rc_dir: %s\n", rc_dir);
+ int r = g_mkdir_with_parents(rc_dir, 0700);
+ if (r != 0)
+ resp = FOLDER_ITEM_PROPS_MAKE_RC_DIR_FAIL;
+ g_free(rc_dir);
+ if (resp == FOLDER_ITEM_PROPS_MAKE_RC_DIR_FAIL)
+ goto error;
+ fp = g_fopen(rc_file, "w");
+ if (fp == NULL) {
+ resp = FOLDER_ITEM_PROPS_MAKE_RC_DIR_FAIL;
+ goto error;
+ }
+ }
+ fwrite(data, len, 1, fp);
+ fclose(fp);
+ resp = FOLDER_ITEM_PROPS_OK;
+ }
+
+error:
+ g_free(data);
+
+ g_key_file_free(config);
+ g_free(rc_file);
+
+ return resp;
+}
+
+FolderPropsResponse vfolder_folder_item_props_read(VFolderItem* item) {
+ gchar* rc_file;
+ GKeyFile* config;
+ GError* error = NULL;
+ gchar *id, *msgnums;
+ gchar **list, **head;
+ FolderPropsResponse resp = FOLDER_ITEM_PROPS_NO_ITEM;
+ gint lastnum;
+
+ g_return_val_if_fail(item != NULL, resp);
+
+ rc_file = vfolder_get_rc_file(item);
+ config = g_key_file_new();
+
+ if (g_file_test(rc_file, G_FILE_TEST_EXISTS)) {
+ g_key_file_load_from_file(config, rc_file, G_KEY_FILE_KEEP_COMMENTS, &error);
+ if (error) {
+ g_warning("%s. Using defaults", error->message);
+ g_error_free(error);
+ resp = FOLDER_ITEM_PROPS_READ_USING_DEFAULT;
+ }
+ else {
+ item->filter = g_key_file_get_string(config, CONFIG_GROUP, "filter", NULL);
+ item->search = g_key_file_get_integer(config, CONFIG_GROUP, "searchtype", NULL);
+ item->frozen = g_key_file_get_boolean(config, CONFIG_GROUP, "frozen", NULL);
+ item->deep_copy = g_key_file_get_boolean(config, CONFIG_GROUP, "deep_copy", NULL);
+// item->filter_func = g_key_file_get_integer(config, CONFIG_GROUP, "filter_function", NULL);
+
+ id = g_key_file_get_string(config, CONFIG_GROUP, "source", NULL);
+ if (id) {
+ item->source = folder_find_item_from_identifier(id);
+ g_free(id);
+ }
+ msgnums = g_key_file_get_string(config, CONFIG_GROUP, "file_id_list", NULL);
+ if (msgnums) {
+ list = g_strsplit(msgnums, ",", 0);
+ head = list;
+ lastnum = -1;
+ while (*list) {
+ gchar* anum = g_strdup(*list++);
+ g_strstrip(anum);
+ MsgBridge* bridge = vfolder_split_file_id(anum);
+ g_free(anum);
+ if (lastnum < (gint) bridge->my_num)
+ lastnum = bridge->my_num;
+ if (bridge->my_num > 0) {
+ vfolder_add_message_to_bridge(item, bridge);
+ }
+ g_free(bridge);
+ }
+ FOLDER_ITEM(item)->last_num = lastnum;
+ g_strfreev(head);
+ g_free(msgnums);
+ }
+ resp = FOLDER_ITEM_PROPS_OK;
+ }
+ }
+
+ g_key_file_free(config);
+ g_free(rc_file);
+
+ return resp;
+}
+
+gboolean vfolder_gtk_init(gchar** error) {
+ vfolder_fill_popup_menu_labels();
+ folderview_register_popup(&vfolder_popup);
+
+ folder_hook_id = hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
+ vfolder_folder_update_hook, NULL);
+ if (folder_hook_id == -1) {
+ *error = g_strdup(_("Failed to register folder update hook"));
+ return FALSE;
+ }
+
+ item_hook_id = hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
+ vfolder_folder_item_update_hook, NULL);
+ if (item_hook_id == -1) {
+ *error = g_strdup(_("Failed to register folder item update hook"));
+ hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, folder_hook_id);
+ return FALSE;
+ }
+
+/* msginfo_hook_id = hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
+ vfolder_msg_info_update_hook, NULL);
+ if (msginfo_hook_id == -1) {
+ *error = g_strdup(_("Failed to register message info update hook"));
+ hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, folder_hook_id);
+ hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, item_hook_id);
+ return FALSE;
+ }*/
+
+ if (! get_menu_widgets()) {
+ *error = g_strdup(_("Failed to get menu widgets"));
+ hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, folder_hook_id);
+ hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, item_hook_id);
+ hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, msginfo_hook_id);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void vfolder_gtk_done(void) {
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+ FolderView *folderview = NULL;
+ FolderItem *fitem = NULL;
+
+ hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, folder_hook_id);
+ hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, item_hook_id);
+ //hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, msginfo_hook_id);
+
+ if (mainwin == NULL || claws_is_exiting())
+ return;
+
+ folderview = mainwin->folderview;
+ fitem = folderview->summaryview->folder_item;
+
+ if (fitem && IS_VFOLDER_FOLDER_ITEM(fitem)) {
+ vfolder_show_widgets(VFOLDER_ITEM(fitem));
+ gslist_menu_item_free(&widgets);
+
+ folderview_unselect(folderview);
+ summary_clear_all(folderview->summaryview);
+ }
+
+ folderview_unregister_popup(&vfolder_popup);
+}
+
+void vfolder_properties_cb(GtkAction* action, gpointer data) {
+ FolderView *folderview = (FolderView *)data;
+ FolderItem *item;
+
+ g_return_if_fail(folderview != NULL);
+
+ item = folderview_get_selected_item(folderview);
+
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->path != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ if (vfolder_edit_item_dialog(VFOLDER_ITEM(item))) {
+ /* TODO: update */
+ if (debug_get_mode()) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init(&iter, VFOLDER_ITEM(item)->me_to_claws);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ gchar* buf = g_new0(gchar, BUFSIZ);
+ MsgInfo* msginfo = vfolder_find_msg_from_vfolder_num(
+ VFOLDER_ITEM(item), GPOINTER_TO_UINT(key));
+ FILE* msg = procmsg_open_message(msginfo);
+ while (fread(buf, 1, BUFSIZ - 1, msg) > 0) {
+ fprintf(stderr, "%s", buf);
+ g_free(buf);
+ buf = g_new0(gchar, BUFSIZ);
+ }
+ fprintf(stderr, "\n");
+ if (buf)
+ g_free(buf);
+ fclose(msg);
+ }
+ }
+ vfolder_folder_item_props_write(VFOLDER_ITEM(item));
+ }
+}
+
+void vfolder_new_folder_cb(GtkAction* action, gpointer data) {
+ FolderView *folderview = (FolderView *)data;
+ GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
+ FolderItem *item;
+ FolderItem *new_item;
+ gchar *new_folder;
+ gchar *name;
+ gchar *p;
+
+ if (!folderview->selected) return;
+
+ item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
+ if (! item) {
+ item = FOLDER_ITEM(vfolder_get_vfolder_item(NULL));
+ }
+
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ if (item->no_sub) {
+ alertpanel_error(N_("Virtual folders cannot contain subfolders"));
+ return;
+ }
+
+ new_folder = input_dialog(_("New folder"),
+ _("Input the name of new folder:"),
+ _("NewFolder"));
+ if (!new_folder) return;
+ AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+
+ p = strchr(new_folder, G_DIR_SEPARATOR);
+ if (p) {
+ alertpanel_error(_("'%c' can't be included in folder name."),
+ G_DIR_SEPARATOR);
+ return;
+ }
+
+ name = trim_string(new_folder, 32);
+ AUTORELEASE_STR(name, {g_free(name); return;});
+
+ /* find whether the directory already exists */
+ if (folder_find_child_item_by_name(item, new_folder)) {
+ alertpanel_error(_("The folder '%s' already exists."), name);
+ return;
+ }
+
+ new_item = folder_create_folder(item, new_folder);
+ if (!new_item) {
+ alertpanel_error(_("Can't create the folder '%s'."), name);
+ return;
+ }
+
+ if (! vfolder_create_item_dialog(new_item)) {
+ //VFolderItem* vitem = VFOLDER_ITEM(new_item);
+ new_item->folder->klass->remove_folder(new_item->folder, new_item);
+ new_item = NULL;
+ return;
+ }
+
+ folder_write_list();
+}
+
+void vfolder_remove_folder_cb(GtkAction* action, gpointer data) {
+ FolderView *folderview = (FolderView *)data;
+ GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
+ FolderItem *item;
+ gchar *message, *name;
+ AlertValue avalue;
+ gchar *old_path = NULL;
+ gchar *old_id;
+
+ /* Silence lame warnings */
+ old_id = (old_path) ? NULL : old_path;
+
+ item = folderview_get_selected_item(folderview);
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->path != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ name = trim_string(item->name, 32);
+ AUTORELEASE_STR(name, {g_free(name); return;});
+ message = g_strdup_printf
+ (_("All folders and messages under '%s' will be permanently deleted. "
+ "Recovery will not be possible.\n\n"
+ "Do you really want to delete?"), name);
+ avalue = alertpanel_full(_("Delete folder"), message,
+ GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, FALSE,
+ NULL, ALERT_WARNING, G_ALERTDEFAULT);
+ g_free(message);
+ if (avalue != G_ALERTALTERNATE) return;
+
+ Xstrdup_a(old_path, item->path, return);
+ old_id = folder_item_get_identifier(item);
+
+ if (folderview->opened == folderview->selected ||
+ gtk_cmctree_is_ancestor(ctree,
+ folderview->selected,
+ folderview->opened)) {
+ summary_clear_all(folderview->summaryview);
+ folderview->opened = NULL;
+ }
+
+ if (item->folder->klass->remove_folder(item->folder, item) < 0) {
+ folder_item_scan(item);
+ alertpanel_error(_("Can't remove the folder '%s'."), name);
+ g_free(old_id);
+ return;
+ }
+
+ folder_write_list();
+
+ g_free(old_id);
+}
--- /dev/null
+/*
+ * $Id: $
+ */
+
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VFOLDER_GTK_H__
+#define __VFOLDER_GTK_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include "gettext.h"
+#include "vfolder.h"
+#include <gtk/gtk.h>
+
+typedef enum {
+ FOLDER_ITEM_PROPS_OK,
+ FOLDER_ITEM_PROPS_NO_ITEM,
+ FOLDER_ITEM_PROPS_BACKUP_FAIL,
+ FOLDER_ITEM_PROPS_READ_DATA_FAIL,
+ FOLDER_ITEM_PROPS_MAKE_RC_DIR_FAIL,
+ FOLDER_ITEM_PROPS_READ_USING_DEFAULT
+} FolderPropsResponse;
+
+gboolean vfolder_gtk_init(gchar** error);
+void vfolder_gtk_done(void);
+FolderPropsResponse vfolder_folder_item_props_read(VFolderItem* item);
+FolderPropsResponse vfolder_folder_item_props_write(VFolderItem* item);
+
+/* Callback functions */
+void vfolder_new_folder_cb(GtkAction* action, gpointer data);
+void vfolder_remove_folder_cb(GtkAction* action, gpointer data);
+void vfolder_properties_cb(GtkAction* action, gpointer data);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/*
+ * $Id: $
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ *
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettext.h"
+#include <gtk/gtk.h>
+
+#include "common/claws.h"
+#include "common/version.h"
+#include "plugin.h"
+#include "mimeview.h"
+#include "utils.h"
+#include "alertpanel.h"
+#include "statusbar.h"
+#include "menu.h"
+#include "vfolder.h"
+#include "vfolder_gtk.h"
+
+#define PLUGIN_NAME (_("VFolder"))
+
+static GtkActionEntry vfolder_main_menu[] = {{
+ "View/CreateVfolder",
+ NULL, N_("Create virtual folder..."),
+ "<Control>v", N_("Create a virtual folder"),
+ G_CALLBACK(vfolder_new_folder_cb)
+}};
+
+static gint main_menu_id = 0;
+
+gint plugin_init(gchar** error) {
+ debug_set_mode(TRUE);
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+
+#ifdef G_OS_UNIX
+ bindtextdomain(TEXTDOMAIN, LOCALEDIR);
+#else
+ bindtextdomain(TEXTDOMAIN, get_locale_dir());
+#endif
+ bind_textdomain_codeset(TEXTDOMAIN, "UTF-8");
+
+ if (!check_plugin_version(MAKE_NUMERIC_VERSION(0,0,1,0),
+ VERSION_NUMERIC, PLUGIN_NAME, error))
+ return -1;
+
+ gtk_action_group_add_actions(mainwin->action_group, vfolder_main_menu,
+ 1, (gpointer)mainwin);
+ MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/View", "CreateVfolder",
+ "View/CreateVfolder", GTK_UI_MANAGER_MENUITEM,
+ main_menu_id)
+
+ if (! vfolder_init()) {
+ debug_print("vfolder plugin unloading due to init errors\n");
+ plugin_done();
+ return -1;
+ }
+
+ debug_print("vfolder plugin loaded\n");
+
+ return 0;
+}
+
+gboolean plugin_done(void) {
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+
+ vfolder_done();
+
+ if (mainwin == NULL)
+ return FALSE;
+
+ MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "View/CreateVfolder", main_menu_id);
+ main_menu_id = 0;
+
+ debug_print("vfolder plugin unloaded\n");
+
+ debug_set_mode(FALSE);
+ return TRUE;
+}
+
+const gchar* plugin_licence(void) {
+ return "GPL3+";
+}
+
+const gchar* plugin_version(void) {
+ return PLUGINVERSION;
+}
+
+const gchar* plugin_type(void) {
+ return "GTK2";
+}
+
+const gchar* plugin_name(void) {
+ return PLUGIN_NAME;
+}
+
+const gchar* plugin_desc(void) {
+ return _("This plugin adds virtual folder support to Claws Mail.\n"
+ "\n"
+ "1) Select one or more mail folder(s) to use as the basic mail pool\n"
+ "2) Define a filter\n"
+ "3) Specify name for virtual folder\n"
+ "4) Press create and wait until the scanning of the mail pool finishes\n"
+ "\n"
+ "The VFolder will be updated periodically and when claws-mail is initially opened\n"
+ "Manual update is available from the context menu of the VFolder.\n"
+ "\n"
+ "The supported folder types are MH and IMAP.\n"
+ "Messages in a VFolder cannot be updated.\n"
+ "\n"
+ "To activate the archiving feature go to /View/Create virtual folder\n"
+ "\n"
+ "Default options can be set in /Configuration/Preferences/Plugins"
+ "/vfolder"
+ );
+}
+
+struct PluginFeature* plugin_provides(void) {
+ static struct PluginFeature features[] =
+ { {PLUGIN_UTILITY, N_("VFolder")},
+ {PLUGIN_FOLDERCLASS, N_("VFolder")},
+ {PLUGIN_NOTHING, NULL} };
+ return features;
+}
--- /dev/null
+/*
+ * $Id: $
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ *
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gtk/gtk.h"
+#include "glib.h"
+
+#include "gettext.h"
+#include "gtkutils.h"
+#include "mainwindow.h"
+#include "foldersel.h"
+#include "alertpanel.h"
+
+#include "vfolder_gtk.h"
+#include "vfolder.h"
+#include "vfolder_prop.h"
+
+#define HEADERS N_("Message _Headers")
+#define BODY N_("_Message body")
+#define BOTH N_("_Both")
+
+typedef struct {
+ GtkWidget* filter;
+ GtkWidget* frozen;
+ GtkWidget* deep_copy;
+ GtkWidget* source;
+ GtkWidget* label_btn;
+ GtkWidget* message_btn;
+ GtkWidget* both_btn;
+} PropsDialog;
+
+static void add_current_config(VFolderItem* item, PropsDialog* props) {
+ if (item->filter)
+ gtk_entry_set_text(GTK_ENTRY(props->filter), item->filter);
+ if (item->source) {
+ gchar* id = folder_item_get_identifier(item->source);
+ if (id) {
+ gtk_entry_set_text(GTK_ENTRY(props->source), id);
+ g_free(id);
+ }
+ }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->frozen), item->frozen);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->deep_copy), item->deep_copy);
+ switch (item->search) {
+ case SEARCH_BODY:
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->message_btn), TRUE);
+ case SEARCH_BOTH:
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->both_btn), TRUE);
+ case SEARCH_HEADERS:
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->label_btn), TRUE);
+ }
+}
+
+static gboolean is_source_widget(GtkWidget* widget) {
+ const gchar* name = gtk_widget_get_name(widget);
+
+ return (name && strcmp("source", name) == 0);
+}
+
+static void foldersel_cb(GtkWidget *widget, gpointer data) {
+ FolderItem *item;
+ gchar *item_id;
+ gint newpos = 0;
+ GtkWidget* entry = GTK_WIDGET(data);
+
+ item = foldersel_folder_sel(NULL, FOLDER_SEL_COPY, NULL, FALSE);
+ if (item && IS_VFOLDER_FOLDER_ITEM(item)) {
+ /* Cannot create virtual folder from virtual folder */
+ alertpanel_error(_("%s: Cannot create virtual folder from virtual folder"), item->name);
+ return;
+ }
+ else {
+ if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
+ gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
+ gtk_editable_insert_text(GTK_EDITABLE(entry),
+ item_id, strlen(item_id), &newpos);
+ g_free(item_id);
+ }
+ debug_print("Source Folder: %s\n", gtk_entry_get_text(GTK_ENTRY(entry)));
+ }
+}
+
+static GtkWidget* vfolder_prop_row(GtkWidget* widget,
+ const gchar* label_markup,
+ gint width, gboolean center) {
+ GtkWidget* row = gtk_hbox_new(FALSE, 5);
+ GtkWidget* label = gtk_label_new(NULL);
+
+ gtk_widget_set_size_request(label, width, -1);
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), label_markup);
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
+ gtk_box_pack_start(GTK_BOX(row), label, FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(row), widget, TRUE, FALSE, 5);
+
+ if (is_source_widget(widget)) {
+ GtkWidget* btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
+ g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(foldersel_cb), widget);
+ gtk_box_pack_start(GTK_BOX(row), btn, FALSE, FALSE, 5);
+ }
+
+ return row;
+}
+
+static gboolean vfolder_set_search_type(VFolderItem* item, GtkWidget* list) {
+ GSList *btn_list, *btns;
+ gboolean active = FALSE;
+ GtkToggleButton* btn = NULL;
+
+ btn_list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(list));
+ for (btns = btn_list; btns && !active; btns = g_slist_next(btns)) {
+ btn = GTK_TOGGLE_BUTTON(btns->data);
+ active = gtk_toggle_button_get_active(btn);
+ }
+ if (active) {
+ const gchar* label = gtk_button_get_label(GTK_BUTTON(btn));
+ if (label) {
+ if (strcmp(BOTH, label) == 0) {
+ if (item->search != SEARCH_BOTH) {
+ item->search = SEARCH_BOTH;
+ return TRUE;
+ }
+ }
+ else if (strcmp(BODY, label) == 0) {
+ if (item->search != SEARCH_BODY) {
+ item->search = SEARCH_BODY;
+ return TRUE;
+ }
+ }
+ else {
+ if (item->search != SEARCH_HEADERS) {
+ item->search = SEARCH_HEADERS;
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+/*
+static void vfolder_copy_msginfo_list(gpointer data, gpointer user_data) {
+ MsgInfo* msg = (MsgInfo *) data;
+ MsgInfo* new_msg;
+ VFolderItem* item = (VFolderItem *) user_data;
+
+ g_return_if_fail(msg != NULL);
+ g_return_if_fail(item != NULL);
+
+ new_msg = procmsg_msginfo_copy(msg);
+ item->msginfos = g_slist_prepend(item->msginfos, new_msg);
+}
+*/
+static gboolean vfolder_search_headers(MsgInfo* msg, GPatternSpec* pattern) {
+ return ((msg->cc && g_pattern_match_string(pattern, msg->cc)) ||
+ (msg->from && g_pattern_match_string(pattern, msg->from)) ||
+ (msg->fromname && g_pattern_match_string(pattern, msg->fromname)) ||
+ (msg->inreplyto && g_pattern_match_string(pattern, msg->inreplyto)) ||
+ (msg->subject && g_pattern_match_string(pattern, msg->subject)) ||
+ (msg->to && g_pattern_match_string(pattern, msg->to)));
+}
+
+static gboolean vfolder_search_body(MsgInfo* msg, GPatternSpec* pattern) {
+ gchar* body;
+ gboolean found = FALSE;
+
+ body = procmsg_get_message_file(msg);
+ if (body) {
+ found = g_pattern_match_string(pattern, body);
+ g_free(body);
+ }
+
+ return found;
+}
+
+static MsgInfoList* vfolder_filter_msgs_list(MsgInfoList* msgs, VFolderItem* item) {
+ MsgInfoList *list = NULL, *tmp;
+ GPatternSpec* pattern;
+ MsgInfo* msg;
+
+ if (!item || item->filter == NULL)
+ return list;
+
+ pattern = g_pattern_spec_new(item->filter);
+
+ for (tmp = msgs; tmp; tmp = g_slist_next(tmp)) {
+ msg = (MsgInfo *) tmp->data;
+ switch (item->search) {
+ case SEARCH_HEADERS:
+ if (vfolder_search_headers(msg, pattern))
+ list = g_slist_prepend(list, msg);
+ break;
+ case SEARCH_BODY:
+ if (vfolder_search_body(msg, pattern))
+ list = g_slist_prepend(list, msg);
+ break;
+ case SEARCH_BOTH:
+ if (vfolder_search_headers(msg, pattern)) {
+ list = g_slist_prepend(list, msg);
+ continue;
+ }
+ if (vfolder_search_body(msg, pattern))
+ list = g_slist_prepend(list, msg);
+ break;
+ }
+ }
+
+ g_pattern_spec_free(pattern);
+
+ return list;
+}
+
+static gboolean vfolder_create_msgs_list(VFolderItem* item, gboolean copy) {
+ MsgInfoList *msgs = NULL, *filtered = NULL;
+ gboolean ok = FALSE;
+ GSList* filelist = NULL;
+
+ if (item->filter && item->msg_filter_func) {
+ item->deep_copy = copy;
+ ok = TRUE;
+ msgs = folder_item_get_msg_list(item->source);
+ filtered = item->msg_filter_func(msgs, item);
+ if (filtered) {
+ filelist = procmsg_get_message_file_list(filtered);
+ if (filelist) {
+ gint n = folder_item_add_msgs(FOLDER_ITEM(item), filelist, FALSE);
+ FOLDER_ITEM(item)->last_num = n;
+ procmsg_message_file_list_free(filelist);
+ }
+ g_slist_free(filtered);
+ }
+ g_slist_free(msgs);
+ }
+ return ok;
+}
+
+void vfolder_set_msgs_filter(VFolderItem* vfolder_item) {
+ g_return_if_fail(vfolder_item != NULL);
+
+ vfolder_item->msg_filter_func = vfolder_filter_msgs_list;
+}
+
+gboolean vfolder_create_item_dialog(FolderItem* folder_item) {
+ gboolean created = FALSE;
+ VFolderItem* item = NULL;
+
+ g_return_val_if_fail(folder_item != NULL, created);
+ g_return_val_if_fail(IS_VFOLDER_FOLDER_ITEM(folder_item), created);
+
+ item = VFOLDER_ITEM(folder_item);
+ item->msg_filter_func = vfolder_filter_msgs_list;
+
+ if (vfolder_edit_item_dialog(item)) {
+ /* save properties */
+ if (FOLDER_ITEM_PROPS_OK != vfolder_folder_item_props_write(item))
+ created = FALSE;
+ else
+ created = TRUE;
+ }
+
+ return created;
+}
+
+gboolean vfolder_edit_item_dialog(VFolderItem* vfolder_item) {
+ gboolean ok = FALSE;
+ PropsDialog* props_dialog;
+ GtkWidget* dialog;
+ GtkWidget* content;
+ GtkWidget* row;
+ GtkWidget* box;
+ gint response;
+ gchar* name;
+ const gchar* str;
+ gboolean frozen, deep_copy;
+ FolderItem* source;
+ gchar* old_filter = NULL;
+
+ g_return_val_if_fail(vfolder_item != NULL, ok);
+
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+ props_dialog = g_new0(PropsDialog, 1);
+ props_dialog->filter = gtk_entry_new();
+ props_dialog->frozen = gtk_check_button_new();
+ props_dialog->deep_copy = gtk_check_button_new();
+ props_dialog->source = gtk_entry_new();
+ props_dialog->label_btn =
+ gtk_radio_button_new_with_mnemonic(NULL, HEADERS);
+ props_dialog->message_btn =
+ gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(props_dialog->label_btn), BODY);
+ props_dialog->both_btn =
+ gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(props_dialog->label_btn), BOTH);
+ gtk_widget_set_name(props_dialog->source, "source");
+ add_current_config(vfolder_item, props_dialog);
+
+ dialog = gtk_dialog_new_with_buttons(
+ N_("Edit VFolder Properties"),
+ GTK_WINDOW(mainwin->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_REJECT);
+ content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+ GtkWidget* vbox = gtk_vbox_new(FALSE, 5);
+
+ row = vfolder_prop_row(props_dialog->source, N_("_Source folder"), 110, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
+
+ GtkWidget* frame1 = gtk_frame_new(_("Message filter"));
+ GtkWidget* vbox1 = gtk_vbox_new(TRUE, 2);
+ gtk_container_add(GTK_CONTAINER(frame1), vbox1);
+
+ row = vfolder_prop_row(props_dialog->filter, N_("_Filter"), 110, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox1), row, FALSE, FALSE, 5);
+
+ box = gtk_hbox_new(TRUE, 2);
+ gtk_box_pack_start(GTK_BOX(box), props_dialog->label_btn, TRUE, TRUE, 2);
+ gtk_box_pack_start(GTK_BOX(box), props_dialog->message_btn, TRUE, TRUE, 2);
+ gtk_box_pack_start(GTK_BOX(box), props_dialog->both_btn, TRUE, TRUE, 2);
+ gtk_box_pack_start(GTK_BOX(vbox1), box, FALSE, FALSE, 5);
+
+ gtk_box_pack_start(GTK_BOX(vbox), frame1, FALSE, FALSE, 5);
+
+ row = vfolder_prop_row(props_dialog->frozen, N_("F_reeze content"), 110, TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
+
+ row = vfolder_prop_row(props_dialog->deep_copy, N_("Co_py messages"), 110, TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
+
+ name = g_strconcat(FOLDER_ITEM(vfolder_item)->name, N_(": settings"), NULL);
+ GtkWidget* frame = gtk_frame_new(name);
+ g_free(name);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+ gtk_widget_show_all(frame);
+
+ gtk_container_add(GTK_CONTAINER(content), frame);
+
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (response == GTK_RESPONSE_ACCEPT) {
+ frozen = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(props_dialog->frozen));
+ deep_copy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(props_dialog->deep_copy));
+
+ str = gtk_entry_get_text(GTK_ENTRY(props_dialog->filter));
+ if (str) {
+ old_filter = g_strdup(vfolder_item->filter);
+ if (strlen(str) == 0) {
+ if (vfolder_item->filter) {
+ g_free(vfolder_item->filter);
+ vfolder_item->filter = NULL;
+ ok = TRUE;
+ }
+ }
+ else {
+ if (!vfolder_item->filter || strcmp(vfolder_item->filter, str) != 0) {
+ g_free(vfolder_item->filter);
+ vfolder_item->filter = g_strdup(str);
+ ok = TRUE;
+ }
+ }
+ }
+ if (vfolder_set_search_type(vfolder_item, props_dialog->label_btn))
+ ok = TRUE;
+
+ str = gtk_entry_get_text(GTK_ENTRY(props_dialog->source));
+ if (str) {
+ source = folder_find_item_from_identifier(str);
+ if (source && (source->stype != F_NORMAL && source->stype != F_INBOX)) {
+ alertpanel_error(_("%s: Not suitable for virtual folders\n"
+ "Use only folder type: Normal or Inbox\n"), str);
+ g_free(vfolder_item->filter);
+ vfolder_item->filter = g_strdup(old_filter);
+ ok = FALSE;
+ goto error;
+ }
+
+ if (strlen(str) == 0) {
+ if (vfolder_item->source) {
+ vfolder_item->source = NULL;
+ folder_item_remove_all_msg(FOLDER_ITEM(vfolder_item));
+ ok = TRUE;
+ }
+ }
+ else {
+ folder_item_remove_all_msg(FOLDER_ITEM(vfolder_item));
+ gchar* id = (vfolder_item->source) ?
+ folder_item_get_identifier(vfolder_item->source) : NULL;
+ if (!id || strcmp(id, str) != 0)
+ vfolder_item->source = source;
+ if (vfolder_item->source) {
+ ok = vfolder_create_msgs_list(vfolder_item, deep_copy);
+ if (ok == FALSE) {
+ g_free(vfolder_item->filter);
+ vfolder_item->filter = g_strdup(old_filter);
+ goto error;
+ }
+ }
+ else {
+ g_free(vfolder_item->filter);
+ vfolder_item->filter = g_strdup(old_filter);
+ ok = FALSE;
+ goto error;
+ }
+ }
+ }
+
+ if (vfolder_item->frozen != frozen) {
+ vfolder_item->frozen = frozen;
+ ok = TRUE;
+ }
+
+ if (vfolder_item->deep_copy != deep_copy) {
+ vfolder_item->deep_copy = deep_copy;
+ ok = TRUE;
+ }
+
+ }
+
+error:
+ gtk_widget_destroy(dialog);
+ g_free(props_dialog);
+ g_free(old_filter);
+
+ return ok;
+}
--- /dev/null
+/*
+ * $Id: $
+ */
+
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Virtual folder plugin for claws-mail
+ * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VFOLDER_PROP_H__
+#define __VFOLDER_PROP_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include "gettext.h"
+#include "folder.h"
+#include "vfolder.h"
+#include <gtk/gtk.h>
+
+gboolean vfolder_create_item_dialog(FolderItem* folder_item);
+gboolean vfolder_edit_item_dialog(VFolderItem* vfolder_item);
+void vfolder_set_msgs_filter(VFolderItem* vfolder_item);
+
+G_END_DECLS
+
+#endif