]> git.datanom.net - vfolder.git/commitdiff
initial upload
authorMichael Rasmussen <mir@datanom.net>
Mon, 17 Jun 2013 00:53:35 +0000 (02:53 +0200)
committerMichael Rasmussen <mir@datanom.net>
Mon, 17 Jun 2013 00:53:35 +0000 (02:53 +0200)
19 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/gettext.h [new file with mode: 0644]
src/vfolder.c [new file with mode: 0644]
src/vfolder.h [new file with mode: 0644]
src/vfolder_gtk.c [new file with mode: 0644]
src/vfolder_gtk.h [new file with mode: 0644]
src/vfolder_init.c [new file with mode: 0644]
src/vfolder_prop.c [new file with mode: 0644]
src/vfolder_prop.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..bdd3a5f
--- /dev/null
@@ -0,0 +1,59 @@
+/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
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..58936cb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Michael Rasmussen <mir@datanom.net>
+
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    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>.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..8660d23
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,153 @@
+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 .
+
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..80ac3cd
--- /dev/null
@@ -0,0 +1,12 @@
+SUBDIRS = config src
+
+EXTRA_DIST = \
+       config/config.rpath \
+       AUTHORS \
+       COPYING \
+       ChangeLog \
+       INSTALL \
+       NEWS \
+       README \
+       TODO
+
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..9e11bb5
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+No news is good news:-)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..66c2119
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+aclocal \
+  && libtoolize --copy --force \
+  && autoheader \
+  && automake --add-missing --foreign --copy \
+  && autoconf \
+  && ./configure --enable-maintainer-mode $@
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..57c651f
--- /dev/null
@@ -0,0 +1,136 @@
+#                                               -*- 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
+])
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..48a0a3b
--- /dev/null
@@ -0,0 +1,34 @@
+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)"\"
diff --git a/src/gettext.h b/src/gettext.h
new file mode 100644 (file)
index 0000000..c21c25e
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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 */
diff --git a/src/vfolder.c b/src/vfolder.c
new file mode 100644 (file)
index 0000000..1ea7f54
--- /dev/null
@@ -0,0 +1,1046 @@
+/*
+ * $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());
+}
diff --git a/src/vfolder.h b/src/vfolder.h
new file mode 100644 (file)
index 0000000..aa1f750
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * $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
diff --git a/src/vfolder_gtk.c b/src/vfolder_gtk.c
new file mode 100644 (file)
index 0000000..9a8f864
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * $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);
+}
diff --git a/src/vfolder_gtk.h b/src/vfolder_gtk.h
new file mode 100644 (file)
index 0000000..a766aa8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * $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
diff --git a/src/vfolder_init.c b/src/vfolder_init.c
new file mode 100644 (file)
index 0000000..047266e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * $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;
+}
diff --git a/src/vfolder_prop.c b/src/vfolder_prop.c
new file mode 100644 (file)
index 0000000..a7028a2
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * $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;
+}
diff --git a/src/vfolder_prop.h b/src/vfolder_prop.h
new file mode 100644 (file)
index 0000000..086b208
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * $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
This page took 0.198541 seconds and 5 git commands to generate.