import working copies of kdepim and kdepimlibs

This commit is contained in:
Ivailo Monev 2015-04-14 21:49:29 +00:00
parent c8a5bdd328
commit df5deda5e5
11354 changed files with 1559333 additions and 1 deletions

View file

@ -29,3 +29,5 @@ macro_optional_add_subdirectory (khelpcenter)
macro_optional_add_subdirectory (kaffeine)
macro_optional_add_subdirectory (kamoso)
macro_optional_add_subdirectory (kcachegrind)
macro_optional_add_subdirectory (kdepimlibs)
macro_optional_add_subdirectory (kdepim)

334
kdepim/CMakeLists.txt Normal file
View file

@ -0,0 +1,334 @@
project(kdepim)
# where to look first for cmake modules. This line must be the first one or cmake will use the system's FindFoo.cmake
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
############### Build Options ###############
option(KDEPIM_BUILD_EXAMPLES "Build the kdepim example applications." FALSE)
option(KDEPIM_BUILD_MOBILE "Build the mobile applications. Note that you have to enable KDEPIM_MOBILE_UI if you want to run these applications on a mobile device." TRUE)
option(KDEPIM_ENTERPRISE_BUILD "Enable features specific to the enterprise branch, which are normally disabled. Also, it disables many components not needed for Kontact such as the Kolab client." FALSE)
option(KDEPIM_MOBILE_UI "Build UI for mobile devices instead of for desktops" FALSE)
option(KDEPIM_ONLY_KLEO "Only build Kleopatra. This option will build only libkleo and kleopatra" FALSE)
option(KDEPIM_BUILD_STATIC "Build KDEPIM static." FALSE)
option(KDEPIM_BUILD_DESKTOP "Build Desktop Applications. Can be deactivated for mobile" TRUE)
option(KDEPIM_NO_WEBKIT "Do not use WebKit in the kdepim applications" FALSE)
if(KDEPIM_BUILD_STATIC)
set(LIBRARY_TYPE STATIC)
else()
set(LIBRARY_TYPE SHARED)
endif()
add_definitions(-DQT_USE_QSTRINGBUILDER)
if(KDEPIM_NO_WEBKIT)
add_definitions(-DKDEPIM_NO_WEBKIT)
endif()
if(KDEPIM_ENTERPRISE_BUILD)
message(STATUS "Enterprise build is enabled.")
endif()
# if KDEPIM_ONLY_KLEO is defined, KDEPIM_BUILD_MOBILE and KDEPIM_MOBILE_UI are disabled.
if(KDEPIM_ONLY_KLEO)
set(KDEPIM_BUILD_MOBILE FALSE)
set(KDEPIM_MOBILE_UI FALSE)
set(KDEPIM_DEFINITIONS "-DHAVE_CONFIG_H=1")
message(STATUS "Only libkleo and Kleopatra will be built.")
endif()
if(KDEPIM_MOBILE_UI)
# Build the mobile applications
set(KDEPIM_BUILD_MOBILE TRUE)
endif()
# config-enterprise.h is needed for both ENTERPRISE_BUILD and BUILD_EVERYTHING
configure_file(config-enterprise.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-enterprise.h )
############### generate kdepim-version.h ###############
# Support for the GIT revision number in kdepim-version.h
if(EXISTS "${kdepim_SOURCE_DIR}/.git")
find_package(Git)
if(GIT_FOUND)
message(STATUS "Found git: ${GIT_EXECUTABLE}")
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY ${kdepim_SOURCE_DIR}
OUTPUT_VARIABLE kdepim_git_revision)
string(REGEX REPLACE "\n" "" kdepim_git_revision "${kdepim_git_revision}")
set(kdepim_git_revision "git-${kdepim_git_revision}")
execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%ci
WORKING_DIRECTORY ${kdepim_SOURCE_DIR}
OUTPUT_VARIABLE kdepim_git_last_change)
string(REGEX REPLACE " [-0-9:+ ]*\n" "" kdepim_git_last_change "${kdepim_git_last_change}")
endif()
endif()
# KDEPIM_VERSION
# Version scheme: "x.y.z build".
#
# x is the version number.
# y is the major release number.
# z is the minor release number.
#
# "x.y.z" follow the kdelibs version kdepim is released with.
#
# If "z" is 0, the version is "x.y"
#
# KDEPIM_DEV_VERSION is empty for final versions.
# For development versions "build" is something like "pre", "alpha1", "alpha2", "beta1", "beta2", "rc1", "rc2".
#
# Examples in chronological order:
# 3.0, 3.0.1, 3.1 alpha1, 3.1 beta1, 3.1 beta2, 3.1 rc1, 3.1, 3.1.1, 3.2 pre, 3.2 alpha1
# Do NOT add quote
set(KDEPIM_DEV_VERSION)
# add an extra space
if(DEFINED KDEPIM_DEV_VERSION)
set(KDEPIM_DEV_VERSION " ${KDEPIM_DEV_VERSION}")
endif()
set(KDEPIM_VERSION "4.14.3${KDEPIM_DEV_VERSION}")
configure_file(kdepim-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdepim-version.h @ONLY)
set(CMAKE_AUTOMOC ON)
############### search packages used by KDE ###############
find_package(KDE4 4.13.0 REQUIRED)
include(KDE4Defaults)
find_package(KdepimLibs 4.14.3)
set_package_properties(KdepimLibs PROPERTIES DESCRIPTION "The KDEPIM libraries" URL "http://www.kde.org" TYPE REQUIRED)
############### Load the CTest options ###############
# CMake is irritating and doesn't allow setting the tests timeout globally.
# Let's work around this. The global timeout is now 2 minutes.
set(_DartConfigFile "${CMAKE_BINARY_DIR}/DartConfiguration.tcl")
if(EXISTS ${_DartConfigFile})
set(DartTestingTimeout "120")
file(READ ${_DartConfigFile} _DartConfigFile_content)
string(REGEX REPLACE "TimeOut: 1500" "TimeOut: ${DartTestingTimeout}" _DartConfigFile_content ${_DartConfigFile_content})
file(WRITE ${_DartConfigFile} ${_DartConfigFile_content})
endif()
# CTestCustom.cmake has to be in the CTEST_BINARY_DIR.
# in the KDE build system, this is the same as CMAKE_BINARY_DIR.
configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_BINARY_DIR}/CTestCustom.cmake)
############### search Boost ###############
find_package(Boost 1.34.0)
set_package_properties(Boost PROPERTIES DESCRIPTION "Boost C++ Libraries" URL "http://www.boost.org" TYPE REQUIRED PURPOSE "Boost is required for building most KDEPIM applications")
# Kleopatra needs to know if the topological.hpp header exists (part of Boost_graph).
find_path(Boost_TOPOLOGICAL_SORT_DIR NAMES boost/graph/topological_sort.hpp PATHS ${Boost_INCLUDE_DIRS})
if(Boost_TOPOLOGICAL_SORT_DIR)
message(STATUS "The Boost Topological_sort header was found. Building Kleopatra")
else()
message(STATUS "The Boost Topological_sort header was NOT found. Kleopatra will not be built")
endif()
############### Windows specific ###############
if(WIN32)
# detect oxygen icon dir at configure time based on KDEDIRS - there may be different package installation locations
execute_process(COMMAND "${KDE4_KDECONFIG_EXECUTABLE}" --path icon OUTPUT_VARIABLE _dir ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
file(TO_CMAKE_PATH "${_dir}" __dir)
find_path(KDE4_ICON_DIR oxygen PATHS
${__dir}
)
message(STATUS "using oxygen application icons from ${KDE4_ICON_DIR}")
else()
set (KDE4_ICON_DIR ${CMAKE_INSTALL_PREFIX}/share/icons)
endif()
############### ONLY_KLEO ###############
# If the KDEPIM_ONLY_KLEO option is true
if(KDEPIM_ONLY_KLEO)
find_package(QGpgme)
set_package_properties(QGpgme PROPERTIES DESCRIPTION "The QGpgME library" URL "http://www.kde.org" TYPE REQUIRED PURPOSE "QGpgME is required to build Kleopatra.")
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} ${KDEPIM_DEFINITIONS})
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${KDEPIMLIBS_INCLUDE_DIRS} ${QT_QTDBUS_INCLUDE_DIR})
include(kleopatra/ConfigureChecks.cmake)
add_subdirectory(libkleo)
if(Boost_TOPOLOGICAL_SORT_DIR)
add_subdirectory(kleopatra)
endif()
else()
# Otherwise...
############### Find the stuff we need ###############
# Akonadi
find_package(Akonadi 1.12.90 QUIET CONFIG)
set_package_properties(Akonadi PROPERTIES DESCRIPTION "Akonadi server libraries" URL "http://pim.kde.org/akonadi" TYPE REQUIRED PURPOSE "Akonadi is required to build KDEPIM")
find_package(ZLIB)
set_package_properties(ZLIB PROPERTIES DESCRIPTION "The Zlib compression library" URL "http://www.zlib.net" TYPE REQUIRED)
find_package(QGpgme)
set_package_properties(QGpgme PROPERTIES DESCRIPTION "The QGpgMe library" URL "http://www.kde.org" TYPE RECOMMENDED PURPOSE "QGpgME is required to build KMail, KOrganizer and Kleopatra")
find_package(Grantlee 0.3.0 QUIET CONFIG)
set_package_properties(Grantlee PROPERTIES DESCRIPTION "The Grantlee Template System" URL "http://www.gitorious.org/grantlee/pages/Home" TYPE REQUIRED PURPOSE "Grantlee is requires for kmail and templating, theming for KJots, KaddressBook, KNotes and MessageViewer(KMail)." )
find_package(Baloo 4.14.0 QUIET CONFIG)
set_package_properties(Baloo PROPERTIES DESCRIPTION "The Baloo libraries" URL "http://www.kde.org" TYPE REQUIRED PURPOSE "Baloo provides search capabilities in KMail and Akonadi")
# Xsltproc
find_package(Xsltproc)
set_package_properties(Xsltproc PROPERTIES DESCRIPTION "XSLT processor from libxslt" TYPE REQUIRED PURPOSE "Required to generate D-Bus interfaces.")
find_package(QJSON)
set_package_properties(QJSON PROPERTIES DESCRIPTION "QJSON" URL "http://qjson.sourceforge.net/" TYPE REQUIRED PURPOSE "Qt library for handling JSON data")
find_package(Prison QUIET CONFIG)
set_package_properties(Prison PROPERTIES DESCRIPTION "The Prison library" URL "http://projects.kde.org/prison" TYPE OPTIONAL PURPOSE "Needed to show mobile barcodes of your contacts")
# Libkgapi2
find_package(LibKGAPI2 2.2.0 QUIET CONFIG)
set_package_properties(LibKGAPI2 PROPERTIES DESCRIPTION "KDE-based library for accessing various Google services" URL "https://projects.kde.org/libkgapi" TYPE OPTIONAL PURPOSE "LibKGAPI is required to build Google Drive Storage Service")
if( LibKGAPI2_FOUND )
add_definitions( -DKDEPIM_STORAGESERVICE_GDRIVE )
endif()
############### Desktop vs. Mobile options ##############
if(KDEPIM_MOBILE_UI)
add_definitions( -DKDEPIM_MOBILE_UI )
if(NOT QT_QTDECLARATIVE_FOUND)
message(FATAL_ERROR "The QtDeclarative (QML) module is required for building the mobile UI")
endif()
else()
if(NOT QT_QTDECLARATIVE_FOUND)
message(STATUS "The Qt Declarative (QML) module was not found. The mobile applications will not be built.")
set(KDEPIM_BUILD_MOBILE FALSE)
endif()
endif()
############### Needed commands before building anything ###############
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS} ${KDEPIM_DEFINITIONS} ${AKONADI_DEFINITIONS})
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDES} ${QT_QTDBUS_INCLUDE_DIR} ${Boost_INCLUDE_DIR})
if(NOT KDEPIMLIBS_KRESOURCES_LIBRARY)
add_definitions( -DKDEPIM_NO_KRESOURCES )
endif()
############### Now, we add the PIM components ###############
include (kleopatra/ConfigureChecks.cmake)
# These targets will always be built before anything else.
add_subdirectory(noteshared)
add_subdirectory(akonadi_next)
add_subdirectory(libkdepim)
add_subdirectory(calendarsupport)
add_subdirectory(calendarviews)
add_subdirectory(incidenceeditor-ng)
add_subdirectory(libkdepimdbusinterfaces)
add_subdirectory(libkleo)
add_subdirectory(libkpgp)
add_subdirectory(libksieve)
add_subdirectory(kdgantt2)
add_subdirectory(icons)
add_subdirectory(composereditor-ng)
add_subdirectory(messagecore)
add_subdirectory(grantleetheme)
add_subdirectory(messagelist)
add_subdirectory(templateparser)
if(QGPGME_FOUND)
if(Boost_TOPOLOGICAL_SORT_DIR)
macro_optional_add_subdirectory(kleopatra)
endif()
endif()
# The following components depend on QGpgME.
add_subdirectory(messageviewer)
macro_optional_add_subdirectory(messagecomposer)
add_subdirectory(pimcommon)
add_subdirectory(mailcommon) # TODO: does this make sense?!?
macro_optional_add_subdirectory(kmail)
macro_optional_add_subdirectory(grantleeeditor)
if(KDEPIM_BUILD_MOBILE)
add_subdirectory(mobile)
endif()
if(KDEPIM_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# If kmail is compiled, KMAIL_SUPPORTED is true (used in several places)
if(BUILD_kmail)
set(KMAIL_SUPPORTED TRUE)
add_definitions(-DKMAIL_SUPPORTED)
endif()
macro_optional_add_subdirectory(korganizer)
macro_optional_add_subdirectory(korgac)
macro_optional_add_subdirectory(sieveeditor)
macro_optional_add_subdirectory(storageservicemanager)
add_subdirectory(kaddressbookgrantlee)
if(KDEPIM_BUILD_DESKTOP)
macro_optional_add_subdirectory(agents)
macro_optional_add_subdirectory(importwizard)
macro_optional_add_subdirectory(kaddressbook)
macro_optional_add_subdirectory(kmailcvt)
macro_optional_add_subdirectory(mboximporter)
macro_optional_add_subdirectory(knotes)
macro_optional_add_subdirectory(ksendemail)
macro_optional_add_subdirectory(ktnef)
macro_optional_add_subdirectory(mailimporter)
macro_optional_add_subdirectory(pimsettingexporter)
macro_optional_add_subdirectory(kalarm)
if (LibKGAPI2_FOUND)
macro_optional_add_subdirectory(blogilo)
endif()
macro_optional_add_subdirectory(kjots)
if(KDEPIMLIBS_KRESOURCES_LIBRARY)
if(QT_QT3SUPPORT_FOUND)
macro_optional_add_subdirectory(knode)
endif()
if(Q_WS_X11)
macro_optional_add_subdirectory(ktimetracker)
endif()
endif()
macro_optional_add_subdirectory(kontact) # must be the last one.
endif()
macro_optional_add_subdirectory(akonadiconsole)
macro_optional_add_subdirectory(console)
# These targets depend on optional applications
if(KDEPIMLIBS_KRESOURCES_LIBRARY)
add_subdirectory(kresources) # Must be after KAddressbook
endif()
add_subdirectory(plugins) # Must be after KMail
endif()
# All done, let's display what we found...
feature_summary(WHAT ALL
INCLUDE_QUIET_PACKAGES
FATAL_ON_MISSING_REQUIRED_PACKAGES
)

346
kdepim/COPYING Normal file
View file

@ -0,0 +1,346 @@
NOTE! The GPL below is copyrighted by the Free Software Foundation, but
the instance of code that it refers to (the kde programs) are copyrighted
by the authors who actually wrote it.
---------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) 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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. 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.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE 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.
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
convey 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) 19yy <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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision 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, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This 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 Library General
Public License instead of this License.

397
kdepim/COPYING.DOC Normal file
View file

@ -0,0 +1,397 @@
GNU Free Documentation License
Version 1.2, November 2002
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of
the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The "Invariant Sections" are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History"
in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation 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. See
http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.

510
kdepim/COPYING.LIB Normal file
View file

@ -0,0 +1,510 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
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 this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms
of the ordinary General Public License).
To apply these terms, attach the following notices to the library.
It is safest to attach them to the start of each source file to most
effectively convey 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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the library,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

13
kdepim/CTestConfig.cmake Normal file
View file

@ -0,0 +1,13 @@
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
## # The following are required to uses Dart and the Cdash dashboard
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "kdepim")
set(CTEST_NIGHTLY_START_TIME "20:00:00 CET")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=kdepim")
set(CTEST_DROP_SITE_CDASH TRUE)

35
kdepim/CTestCustom.cmake Normal file
View file

@ -0,0 +1,35 @@
# This file contains all the specific settings that will be used
# when running 'make Experimental'
# Change the maximum warnings that will be displayed
# on the report page (default 50)
set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 7500)
# Warnings that will be ignored
set(CTEST_CUSTOM_WARNING_EXCEPTION
"groupwise/soap"
"mk4storage"
"kresources"
"'Iterator' is deprecated"
"'ConstIterator' is deprecated"
"'Resource' is deprecated"
"too big, try a different debug format"
"qlist.h.*increases required alignment of target type"
"qmap.h.*increases required alignment of target type"
"qhash.h.*increases required alignment of target type"
".*warning.* is deprecated"
)
# Errors that will be ignored
set(CTEST_CUSTOM_ERROR_EXCEPTION
"ICECC"
"Segmentation fault"
"GConf Error"
"Client failed to connect to the D-BUS daemon"
"Failed to connect to socket"
)
# No coverage for these files
set(CTEST_CUSTOM_COVERAGE_EXCLUDE ".moc$" "moc_" "ui_" "ontologies")

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>LSUIElement</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
</dict>
</plist>

View file

@ -0,0 +1,56 @@
# This is a script for running a Nightly build of kdepim.
# It is ready for testing.
# To adapt it for other projects, basically only the KDE_CTEST_VCS_REPOSITORY variable
# has to be changed.
#
# It uses the file KDECTestNightly.cmake, which is in KDE svn in kdesdk/cmake/modules/.
# You need to have this file on some location on your system and then point the environment variable
# KDECTESTNIGHTLY_DIR to the directory containing this file when running this script.
#
# For more details see the KDELibsNightly.cmake located in KDE/kdelibs/ .
#
# Alex <neundorf AT kde.org>
# The VCS of KDE is "svn", also specify the repository
set(KDE_CTEST_VCS svn)
set(KDE_CTEST_VCS_REPOSITORY https://svn.kde.org/home/kde/trunk/KDE/kdepim)
# for now hardcode the generator to "Unix Makefiles"
set(CTEST_CMAKE_GENERATOR "Unix Makefiles" )
# generic support code, provides the kde_ctest_setup() macro, which sets up everything required:
file(TO_CMAKE_PATH $ENV{KDECTESTNIGHTLY_DIR} KDECTESTNIGHTLY_DIR)
include( "${KDECTESTNIGHTLY_DIR}/KDECTestNightly.cmake" OPTIONAL RESULT_VARIABLE fileIncluded)
if(NOT fileIncluded)
message(FATAL_ERROR "Did not find file ${KDECTESTNIGHTLY_DIR}/KDECTestNightly.cmake . Set the environment variable KDECTESTNIGHTLY_DIR to the directory where this file is located. In KDE svn it is in kdesdk/cmake/modules/ ")
endif(NOT fileIncluded)
# set up binary dir, source dir, etc.
kde_ctest_setup("${CMAKE_CURRENT_LIST_FILE}")
# now actually do the Nightly
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
ctest_start(Nightly)
ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}" )
# read some settings
include("${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake")
include("${CTEST_SOURCE_DIRECTORY}/CTestCustom.cmake" OPTIONAL)
# if CMAKE_INSTALL_PREFIX and BUILD_experimental were defined on the command line, put them
# in the initial cache, so cmake gets them
kde_ctest_write_initial_cache("${CTEST_BINARY_DIRECTORY}" CMAKE_INSTALL_PREFIX)
# configure, build, test, submit
ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" )
ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" )
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" )
ctest_submit()
# optionally install afterwards, so additional nightly builds can use this current install
# (e.g. kdepimlibs could use this kdelibs install)
if(DO_INSTALL)
kde_ctest_install("${CTEST_BINARY_DIRECTORY}" )
endif(DO_INSTALL)

56
kdepim/MAINTAINERS Normal file
View file

@ -0,0 +1,56 @@
Applications:
-------------
akonadiconsole ?
akregator Frank Osterfeld <osterfeld@kde.org>
archivemailagent Laurent Montel <montel@kde.org>
blogilo Laurent Montel <montel@kde.org>
calendarjanitor Sérgio Martins <iamsergio@gmail.com>
calendarsupport Sérgio Martins <iamsergio@gmail.com>
calendarviews Sérgio Martins <iamsergio@gmail.com>
contactthemeeditor Laurent Montel <montel@kde.org>
composereditor-ng Laurent Montel <montel@kde.org>
grantleethemeeditor Laurent Montel <montel@kde.org>
headerthemeeditor Laurent Montel <montel@kde.org>
importwizard Laurent Montel <montel@kde.org>
incidenceeditors-ng Sérgio Martins <iamsergio@gmail.com>
kabcclient Kevin Krammer <kevin.krammer@gmx.at>
kaddressbook Laurent Montel <montel@kde.org>
kaddressbookgrantlee Laurent Montel <montel@kde.org>
kalarm David Jarvie <djarvie@kde.org>
kdgantt2 KDAB
kjots Stephen Kelly <steveire@gmail.com>
kleopatra Marc Mutz <mutz@kde.org>
kmail Laurent Montel <montel@kde.org>
kmailcvt Laurent Montel <montel@kde.org>
knode Olivier Trichet <nive@nivalis.org>
knotes Laurent Montel <montel@kde.org>
konsolekalendar Allen Winter <winter@kde.org>
kontact Laurent Montel <montel@kde.org>
korganizer Allen Winter <winter@kde.org> and Sérgio Martins <iamsergio@gmail.com>
korgac Allen Winter <winter@kde.org>
kresources DEPRECATED
ksendemail ?
ktimetracker Thorsten Staerk <dev@staerk.de>
ktnef Allen Winter <winter@kde.org>
followupreminderagent Laurent Montel <montel@kde.org>
libkdepim Laurent Montel <montel@kde.org>
libkdepimdbusinterfaces ?
libkleo Marc Mutz <mutz@kde.org>
libkpgp DEPRECATED
libksieve Laurent Montel <montel@kde.org>
mailcommon Laurent Montel <montel@kde.org>
mailfilteragent ?
mailcommon Laurent Montel <montel@kde.org>
mboximporter Laurent Montel <montel@kde.org>
notesagent Laurent Montel <montel@kde.org>
pimsettingexporter Laurent Montel <montel@kde.org>
messagecomposer Laurent Montel <montel@kde.org>
messagecore Laurent Montel <montel@kde.org>
messagelist Laurent Montel <montel@kde.org>
messageviewer Laurent Montel <montel@kde.org>
pimcommon Laurent Montel <montel@kde.org>
plugins ?
sendlateragent Laurent Montel <montel@kde.org>
sieveeditor Laurent Montel <montel@kde.org>
storageservicemanager Laurent Montel <montel@kde.org>
templateparser Laurent Montel <montel@kde.org>

89
kdepim/Mainpage.dox Normal file
View file

@ -0,0 +1,89 @@
/**
* @mainpage KDE PIM API Reference
*
*
* \section Overview
*
* This is the online reference for developing KDE-PIM applications.
*
* <table width="100%">
* <tr><th>Applications</th><th>Components</th><th>Libraries</th></tr>
* <tr><td valign="top">
* - <a href="blogilo/html/index.html"><b>blogilo</b></a>
* (<a href="blogilo/html/classes.html">classes</a>)\n
* <i>Blogging client.</i>
* - <a href="kaddressbook/html/index.html"><b>kaddressbook</b></a>
* (<a href="kaddressbook/html/classes.html">classes</a>)\n
* <i>Keeps your addresses on file.</i>
* - <a href="akregator/html/index.html"><b>akregator</b></a>
* (<a href="akregator/html/classes.html">classes</a>)\n
* <i>Feed reader.</i>
* - <a href="kalarm/html/index.html"><b>kalarm</b></a>
* (<a href="kalarm/html/classes.html">classes</a>)\n
* <i>A personal alarm message, command and email scheduler.</i>
* - <a href="kjots/html/index.html"><b>kjots</b></a>
* (<a href="kjots/html/classes.html">classes</a>)\n
* <i>A note taker.</i>
* - <a href="kleopatra/html/index.html"><b>kleopatra</b></a>
* (<a href="kleopatra/html/classes.html">classes</a>)\n
* <i>KDE Key Manager.</i>
* - <a href="kmail/html/index.html"><b>kmail</b></a>
* (<a href="kmail/html/classes.html">classes</a>)\n
* <i>A fully-featured email client.</i>
* - <a href="knode/html/index.html"><b>knode</b></a>
* (<a href="knode/html/classes.html">classes</a>)\n
* <i>The KDE news reader.</i>
* - <a href="knotes/html/index.html"><b>knotes</b></a>
* (<a href="knotes/html/classes.html">classes</a>)\n
* <i>A small tool to scribble down notes.</i>
* - <a href="console/konsolekalendar/html/index.html"><b>konsolekalendar</b></a>
* (<a href="console/konsolekalendar/html/classes.html">classes</a>)\n
* <i>A command line interface to KDE calendars.</i>
* - <a href="kontact/html/index.html"><b>kontact</b></a>
* (<a href="kontact/html/classes.html">classes</a>)\n
* <i>Brings together all the KDE PIM applications under one roof.</i>
* - <a href="korganizer/html/index.html"><b>korganizer</b></a>
* (<a href="korganizer/html/classes.html">classes</a>)\n
* <i>The calendar and scheduling program for KDE.</i>
* - <a href="korgac/html/index.html"><b>korgac</b></a>
* (<a href="korgac/html/classes.html">classes</a>)\n
* <i>A reminder client for KOrganizer.</i>
* - <a href="ktimetracker/html/index.html"><b>ktimetracker</b></a>
* (<a href="ktimetracker/html/classes.html">classes</a>)\n
* <i>A time tracker.</i>
* </td>
*
* <td valign="top">
* - <a href="calendarsupport/html/index.html"><b>calendarsupport</b></a>
* (<a href="calendarsupport/html/classes.html">classes</a>)\n
* <i>Calendar support tools and utilities.</i>
* - <a href="mailcommon/html/index.html"><b>mailcommon</b></a>
* (<a href="mailcommon/html/classes.html">classes</a>)\n
* <i>Mail message filtering, archiving, expiry, annotations, etc.</i>
* - <a href="messageviewer/html/index.html"><b>messageviewer</b></a>
* (<a href="messageviewer/html/classes.html">classes</a>)\n
* <i>A widget that can show a KMime::Message in a nice way.</i>
* - <a href="messagelist/html/index.html"><b>message list</b></a>
* (<a href="messagelist/html/classes.html">classes</a>)\n
* <i>A widget that can show a list of message (KMime::Message, Akonadi::Item).
* </td>
*
* <td valign="top">
* - <a href="libkdepim/html/index.html"><b>libkdepim</b></a>
* (<a href="libkdepim/html/classes.html">classes</a>)\n
* <i>A library of widgets and other goodies for pim.</i>
* - <a href="libkpgp/html/index.html"><b>libkpgp</b></a>
* (<a href="libkpgp/html/classes.html">classes</a>)\n
* <i>Library for kpgp.</i>
* - <a href="libkleo/html/index.html"><b>libkleo</b></a>
* (<a href="libkleo/html/classes.html">classes</a>)\n
* <i>A library for encryption handling.</i>
* - <a href="kdgantt2/html/index.html"><b>kdgantt</b></a>
* (<a href="kdgantt2/html/classes.html">classes</a>)\n
* <i>Klarälvdalens Datakonsult AB's gantt charting engine.</i>
* </td>
* </tr></table>
*
*/
// DOXYGEN_NAME=kdepim
// DOXYGEN_ENABLE=YES

52
kdepim/README Normal file
View file

@ -0,0 +1,52 @@
In this file:
* What you find here
* What it is
* Mailing List, Getting involved
What you find here
------------------
Anything relating to the KDE-PIM project. See also http://pim.kde.org.
The KDE-PIM project aims to bring together those who wish to help design,
implement, test, etc. anything that's to do with personal information
management.
This rather broad scope encompasses mail clients, addressbooks, Usenet news,
scheduling and even sticky notes.
What it is
----------
* akregator: Feed reader
* blogilo: The KDE blogging client
* kaddressbook: The KDE addressbook application.
* kalarm: gui for setting up personal alarm messages, emails and commands
* kjots: manager for several "books" with a subject and notes
* kmail: the KDE mail client
* importwizard: tool for importing mail/filter/settings/bookmarks from other programs
* kmailcvt: tool for importing mail related data from other programs
* knode: Usenet client
* knotes: popup notes application
* konsolekalendar: Command line tool for accessing calendar files.
* kontact: Integrated PIM application
* korgac: a daemon for handling calendar reminders.
* korganizer: a calendar-of-events, todo-list manager, journal
* ksendemail: commandline email tool.
* ktimetracker: Time tracker.
* ktnef: Viewer for mail attachments using TNEF format
* pimsettingexporter: Application to import/export pim config/data
* headerthemeeditor: Application to generate grantlee header mail
* contactthemeeditor: Application to generate grantlee kaddressbook theme
* mboximporter: Application to import mbox directly
* sieveeditor: Application to edit sieve script
* storageservicemanager: Application to manage storage service
Mailing List, getting involved
------------------------------
If you'd like to get involved with the project, subscribe to kde-pim@kde.org
with an email to kde-pim-request@kde.org with the subject line:
subscribe my@email.address
If you have questions relating to development of this module please post them on
the developers mailing list (kde-pim@kde.org). If you have user questions,
please use kdepim-users@kde.org

126
kdepim/README.packagers Normal file
View file

@ -0,0 +1,126 @@
Information for packagers of KDEPIM
=====================================
This document gives some hints to packagers on what is needed to provide
a sane installation and packaging for KDEPIM.
Akonadi is a key component of KDEPIM that is used by almost all applications.
It depends on several components to be properly installed and configured,
which are listed below.
Also, this document discusses other topics which are of importance for
packagers, such as the GPG support.
Baloo
------------------
Akonadi uses Baloo for all kind of searches.
MySQL
-----
Akonadi needs a relational database to keep metadata about the PIM data it
manages. There exists different backends for MySQL, PostgreSQL and SQLite.
While it might be tempting to use the SQLite backend to reduce dependencies,
we highly discourage to use it, because it is not yet finished, can lose
your data, has performance problems and is not automatically tested yet!
The PostgreSQL backend has some more testing, however we discourage the
use of it as well, because it will make the migration path much harder once
we'll switch to Virtuoso as SQL backend in the future. So please make MySQL a
hard (runtime) dependency for Akonadi and compile the Qt library with support
for MySQL (can be done as plugin as well).
Akonadi
-------
Having a working installation of Baloo and MySQL should
normally result in a working installation of Akonadi. Akonadi provides a self
test dialog to make sure it really works. Please make sure all tests in this
self test dialog pass. The test can be found in a control center module that is
started with 'kcmshell4 kcm_akonadi'. The test is in the tab 'Akonadi Server
Configuration' and is started with the 'Test...' button.
KDEPIM-Runtime
--------------
(most of) The kdepim applications can use one or several Akonadi Resources in order
to fetch and store PIM data.
It is usually a good idea to install the kdepim-runtime package when installing
one of the KDEPIM applications. As the module name indicates, it is only needed at
runtime.
The kdepim-runtime module contains applications and plugins, for example
Akonadi resources or KIO slaves, that are needed by all applications making use
of the PIM API in kdepimlibs.
Third-party applications which use the PIM API can be installed without installing
the rest of KDEPIM, only KDEPIM-Runtime (and of course kdepimlibs) is needed.
If you don't install KDEPIM-Runtime for third-party applications which use the PIM
API of kdepimlibs, these applications will fail to work at runtime.
Note that not all parts of kdepimlibs require KDEPIM-Runtime at runtime, only
the parts that access the Akonadi store in some way, like 'kcalcore', 'kabc' or
'akonadi'. Other parts, like 'kmime' or 'gpgme++' are not accessing the Akonadi
store and therefore don't need KDEPIM-Runtime.
Kontact Plugins
---------------
Kontact is a container application which embeds other PIM applications such as
KMail and KOrganizer. For an application to be embedded in Kontact, it needs to
provide a Kontact plugin. These Kontact plugins reside under kontact/plugins,
while the applications itself are in the top-level folder. This is important
when splitting up the KDEPIM module in several packages. The Kontact plugin
should be packaged together with its application. It is an error to install a
Kontact plugin without installing the associated application, this will make
Kontact crash. As an example, assume you want to provide a separate package for
KNode. This package should contain KNode from the knode/ directory, and the
Kontact plugin from the kontact/plugins/knode directory. kontact/plugins/knode
should not be installed when knode/ is not installed.
GPG Support
-----------
Crypto operations are supported in multiple places in KDEPIM: KMail provides
support for dealing with signed and encrypted mails, and Kleopatra is an
application that manages certificates and GPG keys. For this to work, GPG needs
to be installed and configured correctly. An easy way to check if you have a
working GPG installation is to run the self test in Kleopatra, which checks many
aspects of the GPG installation. After starting Kleopatra, the self test can be
found in the menu under 'Settings->Perform Self Test'. Please make sure the self
test passes. Another way to test is sending an encrypted and signed message
with KMail, and later decrypting the received message. Note that saving as draft
is not enough here, you need to actually send the mail.
A common packaging error is that gpg-agent is not running or that it is wrongly
configured. This will result in KMail failing on crypto operations with error
messages that give no indication of the real problem, such as 'bad passphrase'.
Libraries inside KDEPIM
-----------------------
There are several libraries in the KDEPIM module, such as 'libkdepim', 'libkleo'
or 'libksieve'. There is no guarantee for a stable API or ABI in those
libraries. API and ABI stability is only guaranteed for kdepimlibs. The
libraries of the KDEPIM module are generally work in progress and therefore
change a lot, API and ABI breakage can occur at any moment.
Therefore, please make sure to always ship the libraries with the exact same
revision numbers as the applications. This is always the case for the tags
created for KDE SC versions.
As an example, shipping libkdepim from KDE SC 4.4.1 together with KMail from KDE
SC 4.4.2 is an error, and can result in failure at runtime, since this libkdepim
is not binary compatible with that KMail.
Further resources
----------------
Some frequently occurring problems with Akonadi are collected under
http://userbase.kde.org/Akonadi#Some_Technical_Issues.
For further questions feel free to contact the KDE PIM developers on
kde-pim@kde.org or ask on freenode IRC channel #kontact or #akonadi

View file

@ -0,0 +1,10 @@
add_definitions( -DQT_NO_CAST_FROM_ASCII )
add_definitions( -DQT_NO_CAST_TO_ASCII )
add_definitions( -DQT_NO_CAST_FROM_BYTEARRAY )
add_subdirectory(sendlateragent)
add_subdirectory(archivemailagent)
add_subdirectory(mailfilteragent)
add_subdirectory(notesagent)
add_subdirectory(followupreminderagent)
install(FILES folderarchiveagent.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")

View file

@ -0,0 +1,53 @@
project(archivemailagent)
include_directories(
${CMAKE_SOURCE_DIR}/libkdepim
${CMAKE_SOURCE_DIR}/mailcommon
${CMAKE_SOURCE_DIR}/messagecomposer/
)
set(archivemailagent_SRCS
archivemailkernel.cpp
archivemailagent.cpp
archivemailmanager.cpp
archivemaildialog.cpp
archivemailinfo.cpp
addarchivemaildialog.cpp
archivejob.cpp
archivemailagentutil.cpp
)
kde4_add_kcfg_files(archivemailagent_SRCS
settings/archivemailagentsettings.kcfgc
)
qt4_add_dbus_adaptor(archivemailagent_SRCS org.freedesktop.Akonadi.ArchiveMailAgent.xml archivemailagent.h ArchiveMailAgent)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
kde4_add_ui_files(archivemailagent_SRCS ui/archivemailwidget.ui )
kde4_add_executable(akonadi_archivemail_agent ${archivemailagent_SRCS})
target_link_libraries(akonadi_archivemail_agent
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_KPIMIDENTITIES_LIBS}
${KDEPIMLIBS_KMIME_LIBS}
${KDEPIMLIBS_AKONADI_KMIME_LIBS}
${KDE4_KIO_LIBS}
mailcommon
)
if (Q_WS_MAC)
set_target_properties(akonadi_archivemail_agent PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.template)
set_target_properties(akonadi_archivemail_agent PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Akonadi.archivemail")
set_target_properties(akonadi_archivemail_agent PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Email Archiver")
endif ()
install(TARGETS akonadi_archivemail_agent ${INSTALL_TARGETS_DEFAULT_ARGS} )
install(FILES archivemailagent.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")
install(FILES akonadi_archivemail_agent.notifyrc DESTINATION "${DATA_INSTALL_DIR}/akonadi_archivemail_agent" )
add_subdirectory(tests)

View file

@ -0,0 +1,4 @@
#! /bin/sh
$EXTRACTRC ui/*.ui >> rc.cpp
$XGETTEXT `find . -name '*.h' -o -name '*.cpp' | grep -v '/tests/'` -o $podir/akonadi_archivemail_agent.pot
rm -f rc.cpp

View file

@ -0,0 +1,231 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "addarchivemaildialog.h"
#include "mailcommon/folder/folderrequester.h"
#include <Akonadi/Collection>
#include <KLocale>
#include <KComboBox>
#include <KUrlRequester>
#include <KIntSpinBox>
#include <KSeparator>
#include <QGridLayout>
#include <QLabel>
#include <QCheckBox>
#include <QSpinBox>
AddArchiveMailDialog::AddArchiveMailDialog(ArchiveMailInfo *info,QWidget *parent)
: KDialog(parent),
mInfo(info)
{
if (info)
setCaption( i18n( "Modify Archive Mail" ) );
else
setCaption( i18n( "Add Archive Mail" ) );
setButtons( Ok|Cancel );
setDefaultButton( Ok );
setModal( true );
setWindowIcon( KIcon( QLatin1String("kmail") ) );
QWidget *mainWidget = new QWidget( this );
QGridLayout *mainLayout = new QGridLayout( mainWidget );
mainLayout->setSpacing( KDialog::spacingHint() );
mainLayout->setMargin( KDialog::marginHint() );
setMainWidget( mainWidget );
int row = 0;
QLabel *folderLabel = new QLabel( i18n( "&Folder:" ), mainWidget );
mainLayout->addWidget( folderLabel, row, 0 );
mFolderRequester = new MailCommon::FolderRequester( mainWidget );
mFolderRequester->setMustBeReadWrite( false );
mFolderRequester->setNotAllowToCreateNewFolder( true );
connect( mFolderRequester, SIGNAL(folderChanged(Akonadi::Collection)), SLOT(slotFolderChanged(Akonadi::Collection)) );
if (info) //Don't autorize to modify folder when we just modify item.
mFolderRequester->setEnabled( false );
folderLabel->setBuddy( mFolderRequester );
mainLayout->addWidget( mFolderRequester, row, 1 );
++row;
QLabel *formatLabel = new QLabel( i18n( "F&ormat:" ), mainWidget );
mainLayout->addWidget( formatLabel, row, 0 );
mFormatComboBox = new KComboBox( mainWidget );
formatLabel->setBuddy( mFormatComboBox );
// These combobox values have to stay in sync with the ArchiveType enum from BackupJob!
mFormatComboBox->addItem( i18n( "Compressed Zip Archive (.zip)" ) );
mFormatComboBox->addItem( i18n( "Uncompressed Archive (.tar)" ) );
mFormatComboBox->addItem( i18n( "BZ2-Compressed Tar Archive (.tar.bz2)" ) );
mFormatComboBox->addItem( i18n( "GZ-Compressed Tar Archive (.tar.gz)" ) );
mFormatComboBox->setCurrentIndex( 2 );
mainLayout->addWidget( mFormatComboBox, row, 1 );
++row;
mRecursiveCheckBox = new QCheckBox( i18n( "Archive all subfolders" ), mainWidget );
mainLayout->addWidget( mRecursiveCheckBox, row, 0, 1, 2, Qt::AlignLeft );
mRecursiveCheckBox->setChecked( true );
++row;
QLabel *pathLabel = new QLabel( i18n( "Path:" ), mainWidget );
mainLayout->addWidget( pathLabel, row, 0 );
mPath = new KUrlRequester(mainWidget);
connect(mPath, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateOkButton()));
mPath->setMode(KFile::Directory);
mainLayout->addWidget(mPath);
++row;
QLabel *dateLabel = new QLabel( i18n( "Backup each:" ), mainWidget );
mainLayout->addWidget( dateLabel, row, 0 );
QHBoxLayout * hlayout = new QHBoxLayout;
mDays = new QSpinBox(mainWidget);
mDays->setMinimum(1);
mDays->setMaximum(3600);
hlayout->addWidget(mDays);
mUnits = new KComboBox(mainWidget);
QStringList unitsList;
unitsList<<i18n("Days");
unitsList<<i18n("Weeks");
unitsList<<i18n("Months");
unitsList<<i18n("Years");
mUnits->addItems(unitsList);
hlayout->addWidget(mUnits);
mainLayout->addLayout(hlayout, row, 1);
++row;
QLabel *maxCountlabel = new QLabel( i18n( "Maximum number of archive:" ), mainWidget );
mainLayout->addWidget( maxCountlabel, row, 0 );
mMaximumArchive = new KIntSpinBox( mainWidget );
mMaximumArchive->setMinimum(0);
mMaximumArchive->setMaximum(9999);
mMaximumArchive->setSpecialValueText(i18n("unlimited"));
maxCountlabel->setBuddy( mMaximumArchive );
mainLayout->addWidget( mMaximumArchive, row, 1 );
++row;
mainLayout->addWidget(new KSeparator, row, 0, row, 2);
mainLayout->setColumnStretch( 1, 1 );
mainLayout->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding ), row, 0 );
if (mInfo) {
load(mInfo);
} else {
enableButtonOk(false);
}
// Make it a bit bigger, else the folder requester cuts off the text too early
resize( 500, minimumSize().height() );
}
AddArchiveMailDialog::~AddArchiveMailDialog()
{
}
void AddArchiveMailDialog::load(ArchiveMailInfo *info)
{
mPath->setUrl(info->url());
mRecursiveCheckBox->setChecked(info->saveSubCollection());
mFolderRequester->setCollection(Akonadi::Collection(info->saveCollectionId()));
mFormatComboBox->setCurrentIndex(static_cast<int>(info->archiveType()));
mDays->setValue(info->archiveAge());
mUnits->setCurrentIndex(static_cast<int>(info->archiveUnit()));
mMaximumArchive->setValue(info->maximumArchiveCount());
slotUpdateOkButton();
}
ArchiveMailInfo* AddArchiveMailDialog::info()
{
if (!mInfo) {
mInfo = new ArchiveMailInfo();
}
mInfo->setSaveSubCollection(mRecursiveCheckBox->isChecked());
mInfo->setArchiveType(static_cast<MailCommon::BackupJob::ArchiveType>(mFormatComboBox->currentIndex()));
mInfo->setSaveCollectionId(mFolderRequester->collection().id());
mInfo->setUrl(mPath->url());
mInfo->setArchiveAge(mDays->value());
mInfo->setArchiveUnit(static_cast<ArchiveMailInfo::ArchiveUnit>(mUnits->currentIndex()));
mInfo->setMaximumArchiveCount(mMaximumArchive->value());
return mInfo;
}
void AddArchiveMailDialog::slotUpdateOkButton()
{
const bool valid = (!mPath->url().isEmpty() && mFolderRequester->collection().isValid());
enableButtonOk(valid);
}
void AddArchiveMailDialog::slotFolderChanged(const Akonadi::Collection& collection)
{
Q_UNUSED(collection);
slotUpdateOkButton();
}
void AddArchiveMailDialog::setArchiveType(MailCommon::BackupJob::ArchiveType type)
{
mFormatComboBox->setCurrentIndex((int)type);
}
MailCommon::BackupJob::ArchiveType AddArchiveMailDialog::archiveType() const
{
return static_cast<MailCommon::BackupJob::ArchiveType>(mFormatComboBox->currentIndex());
}
void AddArchiveMailDialog::setRecursive( bool b )
{
mRecursiveCheckBox->setChecked(b);
}
bool AddArchiveMailDialog::recursive() const
{
return mRecursiveCheckBox->isChecked();
}
void AddArchiveMailDialog::setSelectedFolder(const Akonadi::Collection &collection)
{
mFolderRequester->setCollection(collection);
}
Akonadi::Collection AddArchiveMailDialog::selectedFolder() const
{
return mFolderRequester->collection();
}
KUrl AddArchiveMailDialog::path() const
{
return mPath->url();
}
void AddArchiveMailDialog::setPath(const KUrl &url)
{
mPath->setUrl(url);
}
void AddArchiveMailDialog::setMaximumArchiveCount(int max)
{
mMaximumArchive->setValue(max);
}
int AddArchiveMailDialog::maximumArchiveCount() const
{
return mMaximumArchive->value();
}

View file

@ -0,0 +1,80 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ADDARCHIVEMAILDIALOG_H
#define ADDARCHIVEMAILDIALOG_H
#include "mailcommon/job/backupjob.h"
#include "archivemailinfo.h"
#include <kdialog.h>
#include <Akonadi/Collection>
class KComboBox;
class QCheckBox;
class KUrlRequester;
class QSpinBox;
class KIntSpinBox;
namespace MailCommon {
class FolderRequester;
}
class AddArchiveMailDialog : public KDialog
{
Q_OBJECT
public:
explicit AddArchiveMailDialog(ArchiveMailInfo *info, QWidget *parent = 0);
~AddArchiveMailDialog();
void setArchiveType(MailCommon::BackupJob::ArchiveType type);
MailCommon::BackupJob::ArchiveType archiveType() const;
void setRecursive( bool b );
bool recursive() const;
void setSelectedFolder(const Akonadi::Collection &collection);
Akonadi::Collection selectedFolder() const;
KUrl path() const;
void setPath(const KUrl &);
ArchiveMailInfo *info();
void setMaximumArchiveCount(int);
int maximumArchiveCount() const;
private Q_SLOTS:
void slotFolderChanged(const Akonadi::Collection&);
void slotUpdateOkButton();
private:
void load(ArchiveMailInfo *info);
MailCommon::FolderRequester *mFolderRequester;
KComboBox *mFormatComboBox;
KComboBox *mUnits;
QCheckBox *mRecursiveCheckBox;
KUrlRequester *mPath;
QSpinBox *mDays;
KIntSpinBox *mMaximumArchive;
ArchiveMailInfo *mInfo;
};
#endif // ADDARCHIVEMAILDIALOG_H

View file

@ -0,0 +1,255 @@
[Global]
IconName=kmail
Comment=Archive Mail Agent
Comment[bs]=Arhiva poštanskih agenata
Comment[ca]=Agent per arxivar el correu
Comment[ca@valencia]=Agent per arxivar el correu
Comment[cs]=Agent archivace pošty
Comment[da]=Agent til mail-arkivering
Comment[de]=Agent zur E-Mail-Archivierung
Comment[el]=Πράκτορας αρχειοθέτησης αλληλογραφίας
Comment[en_GB]=Archive Mail Agent
Comment[es]=Agente de archivado de correo
Comment[et]=Kirjade arhiveerimise agent
Comment[fi]=Postin arkistointiagentti
Comment[fr]=Agent d'archivage de courriel
Comment[gl]=Axente Arquivar o correo
Comment[hu]=Levélarchiváló ügynök
Comment[ia]=Agente de Archivar posta
Comment[it]=Agente di archiviazione della posta
Comment[kk]=Поштаны архивтеу агенті
Comment[km]=ទុក​ភ្នាក់ងារ​សំបុត្រ​ក្នុង​ប័ណ្ណសារ
Comment[ko]=메일 보관 에이전트
Comment[lt]=Pašto archyvavimo agentas
Comment[mr]=संग्रह मेल प्रतिनिधी
Comment[nb]=Postarkiv-agent
Comment[nds]=Nettpost-Archiveerhölper
Comment[nl]=E-mailagent voor archiveren
Comment[pl]=Agent archiwizacji poczty
Comment[pt]=Agente de Arquivo de E-Mail
Comment[pt_BR]=Agente de Arquivamento de E-mails
Comment[ro]=Agent de arhivare a poștei
Comment[ru]=Агент архивирования почты
Comment[sk]=Archivovať agenta pošty
Comment[sl]=Posrednik za arhiviranje pošte
Comment[sr]=Агент за архивирање поште
Comment[sr@ijekavian]=Агент за архивирање поште
Comment[sr@ijekavianlatin]=Agent za arhiviranje pošte
Comment[sr@latin]=Agent za arhiviranje pošte
Comment[sv]=E-postarkiveringsmodul
Comment[tr]=Arşiv Posta Aracı
Comment[uk]=Агент архівування пошти
Comment[wa]=Adjint d' årtchivaedje d' emiles
Comment[x-test]=xxArchive Mail Agentxx
Comment[zh_CN]=邮件归档代理
Comment[zh_TW]=歸檔郵件代理程式
Name=Archive Mail Agent
Name[bs]=Arhiva poštanskih agenata
Name[ca]=Agent per arxivar el correu
Name[ca@valencia]=Agent per arxivar el correu
Name[cs]=Agent archivace pošty
Name[da]=Agent til mail-arkivering
Name[de]=Agent zur E-Mail-Archivierung
Name[el]=Πράκτορας αρχειοθέτησης αλληλογραφίας
Name[en_GB]=Archive Mail Agent
Name[es]=Agente de archivado de correo
Name[et]=Kirjade arhiveerimise agent
Name[fi]=Postin arkistointiagentti
Name[fr]=Agent d'archivage de courriel
Name[gl]=Axente Arquivar o correo
Name[hu]=Levélarchiváló ügynök
Name[ia]=Agente de Archivar posta
Name[it]=Agente di archiviazione della posta
Name[kk]=Поштаны архивтеу агенті
Name[km]=ទុក​ភ្នាក់ងារ​សំបុត្រ​ក្នុង​ប័ណ្ណសារ
Name[ko]=메일 보관 에이전트
Name[lt]=Pašto archyvavimo agentas
Name[mr]=संग्रह मेल प्रतिनिधी
Name[nb]=Postarkiv-agent
Name[nds]=Nettpost-Archiveerhölper
Name[nl]=E-mailagent voor archiveren
Name[pl]=Agent archiwizacji poczty
Name[pt]=Agente de Arquivo de E-Mail
Name[pt_BR]=Agente de Arquivamento de E-mails
Name[ro]=Agent de arhivare a poștei
Name[ru]=Агент архивирования почты
Name[sk]=Archivovať agenta pošty
Name[sl]=Posrednik za arhiviranje pošte
Name[sr]=Агент за архивирање поште
Name[sr@ijekavian]=Агент за архивирање поште
Name[sr@ijekavianlatin]=Agent za arhiviranje pošte
Name[sr@latin]=Agent za arhiviranje pošte
Name[sv]=E-postarkiveringsmodul
Name[tr]=Posta Arşivleme Aracı
Name[uk]=Агент архівування пошти
Name[wa]=Adjint d' årtchivaedje d' emiles
Name[x-test]=xxArchive Mail Agentxx
Name[zh_CN]=邮件归档代理
Name[zh_TW]=歸檔郵件代理程式
[Event/archivemailfinished]
Name=Archive Mail finished
Name[bs]=Arhiva završene pošte
Name[ca]=Ha finalitzat l'arxivat del correu
Name[ca@valencia]=Ha finalitzat l'arxivat del correu
Name[da]=Mail-arkivering gennemført
Name[de]=E-Mail-Archivierung beendet
Name[el]=Η αρχειοθέτηση της αλληλογραφίας ολοκληρώθηκε
Name[en_GB]=Archive Mail finished
Name[es]=Archivado de correo terminado
Name[et]=Kirjad on arhiveeritud
Name[fi]=Postin arkistointi valmis
Name[fr]=Archivage du courriel terminé
Name[gl]=Rematou Arquivar o correo
Name[hu]=A Levélarchiváló végzett
Name[ia]=Action de archivar posta terminate
Name[it]=Completata archiviazione della posta
Name[kk]=Поштаны архивтеу аяқталды
Name[km]=ទុក​សំបុត្រ​ក្នុង​ប័ណ្ណសារ​បាន​បញ្ចប់
Name[ko]=메일 보관 완료됨
Name[lt]=Pašto archyvavimas baigtas
Name[mr]=संग्रह मेल संपले
Name[nb]=Postarkiv fullført
Name[nds]=Nettpost archiveren afslaten
Name[nl]=E-mail archiveren is gereed
Name[pl]=Ukończono archiwizację poczty
Name[pt]=O Arquivo de E-Mail Terminou
Name[pt_BR]=Arquivamento de e-mails concluído
Name[ro]=Arhivarea poștei s-a încheiat
Name[ru]=Архивирование почты завершено
Name[sk]=Archivovať ukončenú poštu
Name[sl]=Arhiviranje pošte je zaključeno
Name[sr]=Архивирање поште завршено
Name[sr@ijekavian]=Архивирање поште завршено
Name[sr@ijekavianlatin]=Arhiviranje pošte završeno
Name[sr@latin]=Arhiviranje pošte završeno
Name[sv]=Arkivering av e-post klar
Name[tr]=Posta Arşivleme tamamlandı
Name[uk]=Архівування пошти завершено
Name[wa]=Årtchivaedje des emiles tot fwait
Name[x-test]=xxArchive Mail finishedxx
Name[zh_CN]=邮件归档完成
Name[zh_TW]=歸檔郵件已完成
Action=Popup
[Event/archivemailstarted]
Name=Archive Mail started
Name[bs]=Arhiva započete pošte
Name[ca]=S'ha iniciat l'arxivat del correu
Name[ca@valencia]=S'ha iniciat l'arxivat del correu
Name[da]=Mail-arkivering startet
Name[de]=E-Mail-Archivierung gestartet
Name[el]=Η αρχειοθέτηση της αλληλογραφίας ξεκίνησε
Name[en_GB]=Archive Mail started
Name[es]=Archivado de correo iniciado
Name[et]=Kirjade arhiveerimine algas
Name[fi]=Postin arkistointi käynnistetty
Name[fr]=Archivage du courriel démarré
Name[gl]=Iniciouse Arquivar o correo
Name[hu]=A Levélarchiváló elindult
Name[ia]=Action de archivar posta initiate
Name[it]=Iniziata archiviazione della posta
Name[kk]=Поштаны архивтеу басталды
Name[km]=បាន​ចាប់ផ្ដើម​ការ​ទុក​សំបុត្រ​ក្នុង​ប័ណ្ណសារ
Name[ko]=메일 보관 시작됨
Name[lt]=Archyvuoti ir šifruoti aplanką
Name[mr]=संग्रह मेल सुरु झाले
Name[nb]=Postarkiv startet
Name[nds]=Nettpost archiveren anfungen
Name[nl]=E-mail archiveren is gestart
Name[pl]=Rozpoczęto archiwizację poczty
Name[pt]=O Arquivo de E-Mail Iniciou
Name[pt_BR]=Arquivamento de e-mails iniciado
Name[ro]=Arhivarea poștei a început
Name[ru]=Запущено архивирование почты
Name[sk]=Archivovať spustenú poštu
Name[sl]=Arhiviranje pošte se je začelo
Name[sr]=Архивирање поште започето
Name[sr@ijekavian]=Архивирање поште започето
Name[sr@ijekavianlatin]=Arhiviranje pošte započeto
Name[sr@latin]=Arhiviranje pošte započeto
Name[sv]=Arkivering av e-post påbörjad
Name[tr]=Posta Arşivleme başladı
Name[uk]=Розпочато архівування пошти
Name[wa]=Årtchivaedje des emiles ataké
Name[x-test]=xxArchive Mail startedxx
Name[zh_CN]=邮件归档开始
Name[zh_TW]=歸檔郵件已開始
Action=Popup
[Event/archivemailfolderdoesntexist]
Name=Directory does not exist
Name[ca]=El directori no existeix
Name[cs]=Adresář neexistuje
Name[da]=Mappen findes ikke
Name[de]=Der Ordner existiert nicht
Name[en_GB]=Directory does not exist
Name[es]=El directorio no existe
Name[et]=Kataloogi ei ole olemas
Name[fi]=Kansiota ei ole olemassa
Name[fr]=Le répertoire n'existe pas
Name[hu]=A könyvtár nem létezik
Name[it]=La cartella non esiste
Name[nb]=Mappa finnes ikke
Name[nds]=Gifft Orner nich
Name[nl]=Map bestaat niet
Name[pl]=Katalog nie istnieje
Name[pt]=A pasta não existe
Name[pt_BR]=A pasta não existe
Name[ro]=Directorul nu există
Name[sk]=Adresár neexistuje
Name[sr]=Фасцикла не постоји
Name[sr@ijekavian]=Фасцикла не постоји
Name[sr@ijekavianlatin]=Fascikla ne postoji
Name[sr@latin]=Fascikla ne postoji
Name[sv]=Katalogen finns inte
Name[uk]=Каталогу не існує
Name[x-test]=xxDirectory does not existxx
Name[zh_TW]=目錄不存在
Action=Popup
[Event/archivemailerror]
Name=Archive Mail Error
Name[bs]=arhiva pogrešne pošte
Name[ca]=Error en arxivar el correu
Name[ca@valencia]=Error en arxivar el correu
Name[da]=Fejl i mail-arkivering
Name[de]=E-Mail-Archivierungsfehler
Name[el]=Σφάλμα στην αρχειοθέτηση της αλληλογραφίας
Name[en_GB]=Archive Mail Error
Name[es]=Error de archivado de correo
Name[et]=Kirjade arhiveerimise tõrge
Name[fi]=Postin arkistointivirhe
Name[fr]=Erreur d'archivage du courriel
Name[gl]=Erro de Arquivar o correo
Name[hu]=Levélarchiváló hiba
Name[ia]=Error de Archivar posta
Name[it]=Errore nell'archiviazione della posta
Name[kk]=Поштаны архивтеу қатесі
Name[km]=កំហុស​ការ​ទុក​សំបុត្រ​ក្នុង​ប័ណ្ណសារ
Name[ko]=메일 보관 오류
Name[lt]=Archyvuoti ir šifruoti aplanką
Name[mr]=संग्रह मेल त्रुटी
Name[nb]=Postarkiv-feil
Name[nds]=Nettpost-Archiveerfehler
Name[nl]=Fout in e-mail archiveren
Name[pl]=Błąd archiwum poczty
Name[pt]=Erro no Arquivo de E-Mail
Name[pt_BR]=Erro no arquivamento de e-mails
Name[ro]=Eroare la arhivarea poștei
Name[ru]=Ошибка архивирования почты
Name[sk]=Archivovať chybu pošty
Name[sl]=Napaka pri arhiviranju pošte
Name[sr]=Грешка при архивирању поште
Name[sr@ijekavian]=Грешка при архивирању поште
Name[sr@ijekavianlatin]=Greška pri arhiviranju pošte
Name[sr@latin]=Greška pri arhiviranju pošte
Name[sv]=Fel vid brevarkivering
Name[tr]=Posta Arşivleme Hatası
Name[uk]=Помилка під час архівування пошти
Name[wa]=Åk n' a nén stî come dj' årtchivéve les emiles
Name[x-test]=xxArchive Mail Errorxx
Name[zh_CN]=邮件归档发生错误
Name[zh_TW]=歸檔郵件發生錯誤
Action=Popup

View file

@ -0,0 +1,135 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivejob.h"
#include "archivemailinfo.h"
#include "archivemailmanager.h"
#include "mailcommon/util/mailutil.h"
#include <mailcommon/job/backupjob.h>
#include <KNotification>
#include <KLocale>
#include <KGlobal>
#include <KIcon>
#include <KIconLoader>
ArchiveJob::ArchiveJob(ArchiveMailManager *manager, ArchiveMailInfo *info, const Akonadi::Collection &folder, bool immediate )
: MailCommon::ScheduledJob( folder, immediate )
,mInfo(info)
,mManager(manager)
{
mPixmap = KIcon( QLatin1String("kmail") ).pixmap( KIconLoader::SizeSmall, KIconLoader::SizeSmall );
}
ArchiveJob::~ArchiveJob()
{
delete mInfo;
}
void ArchiveJob::execute()
{
if (mInfo) {
Akonadi::Collection collection(mInfo->saveCollectionId());
const QString realPath = MailCommon::Util::fullCollectionPath(collection);
if (realPath.isEmpty()) {
qDebug()<<" We cannot find real path, collection doesn't exist";
mManager->collectionDoesntExist(mInfo);
deleteLater();
return;
}
if (mInfo->url().isEmpty()) {
qDebug()<<" Path is empty";
mManager->collectionDoesntExist(mInfo);
deleteLater();
return;
}
bool dirExit = true;
const KUrl archivePath = mInfo->realUrl(realPath, dirExit);
if (!dirExit) {
mManager->backupDone(mInfo);
KNotification::event( QLatin1String("archivemailfolderdoesntexist"),
i18n("Directory does not exist. Please verify settings. Archive postponed."),
mPixmap,
0,
KNotification::CloseOnTimeout,
KGlobal::mainComponent());
deleteLater();
return;
}
MailCommon::BackupJob *backupJob = new MailCommon::BackupJob();
backupJob->setRootFolder( MailCommon::Util::updatedCollection(collection) );
backupJob->setSaveLocation( archivePath );
backupJob->setArchiveType( mInfo->archiveType() );
backupJob->setDeleteFoldersAfterCompletion( false );
backupJob->setRecursive( mInfo->saveSubCollection() );
backupJob->setDisplayMessageBox(false);
backupJob->setRealPath(realPath);
const QString summary = i18n("Start to archive %1",realPath );
KNotification::event( QLatin1String("archivemailstarted"),
summary,
mPixmap,
0,
KNotification::CloseOnTimeout,
KGlobal::mainComponent());
connect(backupJob, SIGNAL(backupDone(QString)), this, SLOT(slotBackupDone(QString)));
connect(backupJob, SIGNAL(error(QString)), this, SLOT(slotError(QString)));
backupJob->start();
}
}
void ArchiveJob::slotError(const QString &error)
{
KNotification::event( QLatin1String("archivemailerror"),
error,
mPixmap,
0,
KNotification::CloseOnTimeout,
KGlobal::mainComponent());
mManager->backupDone(mInfo);
deleteLater();
}
void ArchiveJob::slotBackupDone(const QString &info)
{
KNotification::event( QLatin1String("archivemailfinished"),
info,
mPixmap,
0,
KNotification::CloseOnTimeout,
KGlobal::mainComponent());
mManager->backupDone(mInfo);
deleteLater();
}
void ArchiveJob::kill()
{
ScheduledJob::kill();
}
MailCommon::ScheduledJob *ScheduledArchiveTask::run()
{
return folder().isValid() ? new ArchiveJob( mManager, mInfo, folder(), isImmediate() ) : 0;
}

View file

@ -0,0 +1,76 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEJOB_H
#define ARCHIVEJOB_H
#include <mailcommon/job/jobscheduler.h>
#include <Akonadi/Collection>
#include <QPixmap>
class ArchiveMailInfo;
class ArchiveMailManager;
class ArchiveJob : public MailCommon::ScheduledJob
{
Q_OBJECT
public:
explicit ArchiveJob(ArchiveMailManager *manager, ArchiveMailInfo *info, const Akonadi::Collection &folder, bool immediate);
~ArchiveJob();
void execute();
void kill();
private Q_SLOTS:
void slotBackupDone(const QString &info);
void slotError(const QString &error);
private:
QPixmap mPixmap;
ArchiveMailInfo *mInfo;
ArchiveMailManager *mManager;
};
/// A scheduled "expire mails in this folder" task.
class ScheduledArchiveTask : public MailCommon::ScheduledTask
{
public:
/// If immediate is set, the job will execute synchronously. This is used when
/// the user requests explicitly that the operation should happen immediately.
ScheduledArchiveTask( ArchiveMailManager *manager, ArchiveMailInfo *info, const Akonadi::Collection &folder, bool immediate )
: MailCommon::ScheduledTask( folder, immediate )
, mInfo(info)
, mManager(manager)
{
}
~ScheduledArchiveTask()
{
}
MailCommon::ScheduledJob *run();
int taskTypeId() const
{
return 2;
}
private:
ArchiveMailInfo *mInfo;
ArchiveMailManager *mManager;
};
#endif // ARCHIVEJOB_H

View file

@ -0,0 +1,169 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailagent.h"
#include "archivemailagentadaptor.h"
#include "archivemaildialog.h"
#include "archivemailmanager.h"
#include "archivemailagentsettings.h"
#include <mailcommon/kernel/mailkernel.h>
#include <akonadi/dbusconnectionpool.h>
#include <Akonadi/Monitor>
#include <Akonadi/Session>
#include <Akonadi/CollectionFetchScope>
#include <KMime/Message>
#include <KWindowSystem>
#include <QTimer>
#include <QPointer>
//#define DEBUG_ARCHIVEMAILAGENT 1
ArchiveMailAgent::ArchiveMailAgent( const QString &id )
: Akonadi::AgentBase( id )
{
mArchiveManager = new ArchiveMailManager(this);
connect(mArchiveManager, SIGNAL(needUpdateConfigDialogBox()), SIGNAL(needUpdateConfigDialogBox()));
KGlobal::locale()->insertCatalog( QLatin1String("akonadi_archivemail_agent") );
KGlobal::locale()->insertCatalog( QLatin1String("libmailcommon") );
Akonadi::Monitor *collectionMonitor = new Akonadi::Monitor( this );
collectionMonitor->fetchCollection( true );
collectionMonitor->ignoreSession( Akonadi::Session::defaultSession() );
collectionMonitor->collectionFetchScope().setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
collectionMonitor->setMimeTypeMonitored( KMime::Message::mimeType() );
new ArchiveMailAgentAdaptor( this );
Akonadi::DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/ArchiveMailAgent" ), this, QDBusConnection::ExportAdaptors );
Akonadi::DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.ArchiveMailAgent" ) );
connect( collectionMonitor, SIGNAL(collectionRemoved(Akonadi::Collection)),
this, SLOT(mailCollectionRemoved(Akonadi::Collection)) );
if (enabledAgent()) {
#ifdef DEBUG_ARCHIVEMAILAGENT
QTimer::singleShot(1000, mArchiveManager, SLOT(load()));
#else
QTimer::singleShot(1000*60*5, mArchiveManager, SLOT(load()));
#endif
}
mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(reload()));
mTimer->start(24*60*60*1000);
}
ArchiveMailAgent::~ArchiveMailAgent()
{
}
void ArchiveMailAgent::setEnableAgent(bool enabled)
{
if (enabled != ArchiveMailAgentSettings::enabled()) {
ArchiveMailAgentSettings::setEnabled(enabled);
ArchiveMailAgentSettings::self()->writeConfig();
if (!enabled) {
mTimer->stop();
pause();
} else {
mTimer->start();
}
}
}
bool ArchiveMailAgent::enabledAgent() const
{
return ArchiveMailAgentSettings::enabled();
}
void ArchiveMailAgent::mailCollectionRemoved(const Akonadi::Collection &collection)
{
mArchiveManager->removeCollection(collection);
}
void ArchiveMailAgent::showConfigureDialog(qlonglong windowId)
{
QPointer<ArchiveMailDialog> dialog = new ArchiveMailDialog();
if (windowId) {
#ifndef Q_WS_WIN
KWindowSystem::setMainWindow( dialog, windowId );
#else
KWindowSystem::setMainWindow( dialog, (HWND)windowId );
#endif
}
connect(dialog, SIGNAL(archiveNow(ArchiveMailInfo*)),mArchiveManager, SLOT(slotArchiveNow(ArchiveMailInfo*)));
connect(this, SIGNAL(needUpdateConfigDialogBox()), dialog, SLOT(slotNeedReloadConfig()));
if (dialog->exec()) {
mArchiveManager->load();
}
delete dialog;
}
void ArchiveMailAgent::doSetOnline(bool online)
{
if (online) {
resume();
} else {
pause();
}
}
void ArchiveMailAgent::reload()
{
if (isOnline() && enabledAgent()) {
mArchiveManager->load();
mTimer->start();
}
}
void ArchiveMailAgent::configure( WId windowId )
{
showConfigureDialog((qulonglong)windowId);
}
void ArchiveMailAgent::pause()
{
if (isOnline() && enabledAgent()) {
mArchiveManager->pause();
}
}
void ArchiveMailAgent::resume()
{
if (isOnline() && enabledAgent()) {
mArchiveManager->resume();
}
}
QString ArchiveMailAgent::printArchiveListInfo()
{
return mArchiveManager->printArchiveListInfo();
}
QString ArchiveMailAgent::printCurrentListInfo()
{
return mArchiveManager->printCurrentListInfo();
}
void ArchiveMailAgent::archiveFolder(const QString &path, Akonadi::Collection::Id collectionId)
{
mArchiveManager->archiveFolder(path, collectionId);
}
AKONADI_AGENT_MAIN( ArchiveMailAgent )

View file

@ -0,0 +1,94 @@
[Desktop Entry]
Name=Archive Mail Agent
Name[bs]=Arhiva poštanskih agenata
Name[ca]=Agent per arxivar el correu
Name[ca@valencia]=Agent per arxivar el correu
Name[cs]=Agent archivace pošty
Name[da]=Agent til mail-arkivering
Name[de]=Agent zur E-Mail-Archivierung
Name[el]=Πράκτορας αρχειοθέτησης αλληλογραφίας
Name[en_GB]=Archive Mail Agent
Name[es]=Agente de archivado de correo
Name[et]=Kirjade arhiveerimise agent
Name[fi]=Postin arkistointiagentti
Name[fr]=Agent d'archivage de courriel
Name[gl]=Axente Arquivar o correo
Name[hu]=Levélarchiváló ügynök
Name[ia]=Agente de Archivar posta
Name[it]=Agente di archiviazione della posta
Name[kk]=Поштаны архивтеу агенті
Name[km]=
Name[ko]=
Name[lt]=Pašto archyvavimo agentas
Name[mr]= िि
Name[nb]=Postarkiv-agent
Name[nds]=Nettpost-Archiveerhölper
Name[nl]=E-mailagent voor archiveren
Name[pl]=Agent archiwizacji poczty
Name[pt]=Agente de Arquivo de E-Mail
Name[pt_BR]=Agente de Arquivamento de E-mails
Name[ro]=Agent de arhivare a poștei
Name[ru]=Агент архивирования почты
Name[sk]=Archivovať agenta pošty
Name[sl]=Posrednik za arhiviranje pošte
Name[sr]=Агент за архивирање поште
Name[sr@ijekavian]=Агент за архивирање поште
Name[sr@ijekavianlatin]=Agent za arhiviranje pošte
Name[sr@latin]=Agent za arhiviranje pošte
Name[sv]=E-postarkiveringsmodul
Name[tr]=Posta Arşivleme Aracı
Name[uk]=Агент архівування пошти
Name[wa]=Adjint d' årtchivaedje d' emiles
Name[x-test]=xxArchive Mail Agentxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Archive Mail Agent
Comment[bs]=Arhiva poštanskih agenata
Comment[ca]=Agent per arxivar el correu
Comment[ca@valencia]=Agent per arxivar el correu
Comment[cs]=Agent archivace pošty
Comment[da]=Agent til mail-arkivering
Comment[de]=Agent zur E-Mail-Archivierung
Comment[el]=Πράκτορας αρχειοθέτησης αλληλογραφίας
Comment[en_GB]=Archive Mail Agent
Comment[es]=Agente de archivado de correo
Comment[et]=Kirjade arhiveerimise agent
Comment[fi]=Postin arkistointiagentti
Comment[fr]=Agent d'archivage de courriel
Comment[gl]=Axente Arquivar o correo
Comment[hu]=Levélarchiváló ügynök
Comment[ia]=Agente de Archivar posta
Comment[it]=Agente di archiviazione della posta
Comment[kk]=Поштаны архивтеу агенті
Comment[km]=
Comment[ko]=
Comment[lt]=Pašto archyvavimo agentas
Comment[mr]= िि
Comment[nb]=Postarkiv-agent
Comment[nds]=Nettpost-Archiveerhölper
Comment[nl]=E-mailagent voor archiveren
Comment[pl]=Agent archiwizacji poczty
Comment[pt]=Agente de Arquivo de E-Mail
Comment[pt_BR]=Agente de Arquivamento de E-mails
Comment[ro]=Agent de arhivare a poștei
Comment[ru]=Агент архивирования почты
Comment[sk]=Archivovať agenta pošty
Comment[sl]=Posrednik za arhiviranje pošte
Comment[sr]=Агент за архивирање поште
Comment[sr@ijekavian]=Агент за архивирање поште
Comment[sr@ijekavianlatin]=Agent za arhiviranje pošte
Comment[sr@latin]=Agent za arhiviranje pošte
Comment[sv]=E-postarkiveringsmodul
Comment[tr]=Arşiv Posta Aracı
Comment[uk]=Агент архівування пошти
Comment[wa]=Adjint d' årtchivaedje d' emiles
Comment[x-test]=xxArchive Mail Agentxx
Comment[zh_CN]=
Comment[zh_TW]=
Type=AkonadiAgent
Exec=akonadi_archivemail_agent
Icon=kmail
X-DocPath=akonadi_archivemail_agent/index.html
X-Akonadi-MimeTypes=message/rfc822
X-Akonadi-Capabilities=Unique,Autostart
X-Akonadi-Identifier=akonadi_archivemail_agent

View file

@ -0,0 +1,69 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILAGENT_H
#define ARCHIVEMAILAGENT_H
#include <akonadi/agentbase.h>
#include <Akonadi/Collection>
class QTimer;
class ArchiveMailManager;
class ArchiveMailInfo;
class ArchiveMailAgent : public Akonadi::AgentBase, public Akonadi::AgentBase::ObserverV3
{
Q_OBJECT
public:
explicit ArchiveMailAgent( const QString &id );
~ArchiveMailAgent();
void showConfigureDialog(qlonglong windowId = 0);
QString printArchiveListInfo();
void setEnableAgent(bool b);
bool enabledAgent() const;
QString printCurrentListInfo();
void archiveFolder(const QString &path, Akonadi::Collection::Id collectionId);
Q_SIGNALS:
void archiveNow(ArchiveMailInfo *info);
void needUpdateConfigDialogBox();
public Q_SLOTS:
void configure( WId windowId );
void reload();
void pause();
void resume();
private Q_SLOTS:
void mailCollectionRemoved( const Akonadi::Collection &collection );
protected:
void doSetOnline(bool online);
private:
QTimer *mTimer;
ArchiveMailManager *mArchiveManager;
};
#endif /* ARCHIVEMAILAGENT_H */

View file

@ -0,0 +1,58 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailagentutil.h"
#include <KDebug>
QDate ArchiveMailAgentUtil::diffDate(ArchiveMailInfo *info)
{
QDate diffDate(info->lastDateSaved());
switch(info->archiveUnit()) {
case ArchiveMailInfo::ArchiveDays:
diffDate = diffDate.addDays(info->archiveAge());
break;
case ArchiveMailInfo::ArchiveWeeks:
diffDate = diffDate.addDays(info->archiveAge()*7);
break;
case ArchiveMailInfo::ArchiveMonths:
diffDate = diffDate.addMonths(info->archiveAge());
break;
case ArchiveMailInfo::ArchiveYears:
diffDate = diffDate.addYears(info->archiveAge());
break;
default:
kDebug()<<"archiveUnit not defined :"<<info->archiveUnit();
break;
}
return diffDate;
}
bool ArchiveMailAgentUtil::needToArchive(ArchiveMailInfo *info)
{
if (!info->isEnabled())
return false;
if (info->url().isEmpty())
return false;
if (!info->lastDateSaved().isValid()) {
return true;
} else {
if (QDate::currentDate() >= diffDate(info)) {
return true;
}
}
return false;
}

View file

@ -0,0 +1,30 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILAGENTUTIL_H
#define ARCHIVEMAILAGENTUTIL_H
#include "archivemailinfo.h"
#include <QDate>
namespace ArchiveMailAgentUtil {
static QString archivePattern = QLatin1String("ArchiveMailCollection %1");
QDate diffDate(ArchiveMailInfo *info);
bool needToArchive(ArchiveMailInfo *info);
}
#endif // ARCHIVEMAILAGENTUTIL_H

View file

@ -0,0 +1,408 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemaildialog.h"
#include "addarchivemaildialog.h"
#include "archivemailagentutil.h"
#include "kdepim-version.h"
#include <mailcommon/util/mailutil.h>
#include <KGlobal>
#include <KLocale>
#include <KMessageBox>
#include <KMenu>
#include <KRun>
#include <KHelpMenu>
#include <KAboutData>
#include <QHBoxLayout>
static QString archiveMailCollectionPattern = QLatin1String( "ArchiveMailCollection \\d+" );
ArchiveMailDialog::ArchiveMailDialog(QWidget *parent)
: KDialog(parent)
{
setCaption( i18n( "Configure Archive Mail Agent" ) );
setWindowIcon( KIcon( QLatin1String("kmail") ) );
setButtons( Help | Ok|Cancel );
setDefaultButton( Ok );
setModal( true );
QWidget *mainWidget = new QWidget( this );
QHBoxLayout *mainLayout = new QHBoxLayout( mainWidget );
mainLayout->setSpacing( KDialog::spacingHint() );
mainLayout->setMargin( KDialog::marginHint() );
mWidget = new ArchiveMailWidget(this);
mWidget->setObjectName(QLatin1String("archivemailwidget"));
connect(mWidget, SIGNAL(archiveNow(ArchiveMailInfo*)), this, SIGNAL(archiveNow(ArchiveMailInfo*)));
mainLayout->addWidget(mWidget);
setMainWidget( mainWidget );
connect(this, SIGNAL(okClicked()), SLOT(slotSave()));
readConfig();
mAboutData = new KAboutData(
QByteArray( "archivemailagent" ),
QByteArray(),
ki18n( "Archive Mail Agent" ),
QByteArray( KDEPIM_VERSION ),
ki18n( "Archive emails automatically." ),
KAboutData::License_GPL_V2,
ki18n( "Copyright (C) 2012, 2013, 2014 Laurent Montel" ) );
mAboutData->addAuthor( ki18n( "Laurent Montel" ),
ki18n( "Maintainer" ), "montel@kde.org" );
mAboutData->setProgramIconName( QLatin1String("kmail") );
mAboutData->setTranslator( ki18nc( "NAME OF TRANSLATORS", "Your names" ),
ki18nc( "EMAIL OF TRANSLATORS", "Your emails" ) );
KHelpMenu *helpMenu = new KHelpMenu(this, mAboutData, true);
//Initialize menu
KMenu *menu = helpMenu->menu();
helpMenu->action(KHelpMenu::menuAboutApp)->setIcon(KIcon(QLatin1String("kmail")));
setButtonMenu( Help, menu );
}
ArchiveMailDialog::~ArchiveMailDialog()
{
writeConfig();
delete mAboutData;
}
void ArchiveMailDialog::slotNeedReloadConfig()
{
mWidget->needReloadConfig();
}
static const char *myConfigGroupName = "ArchiveMailDialog";
void ArchiveMailDialog::readConfig()
{
KConfigGroup group( KGlobal::config(), myConfigGroupName );
const QSize size = group.readEntry( "Size", QSize(500, 300) );
if ( size.isValid() ) {
resize( size );
}
mWidget->restoreTreeWidgetHeader(group.readEntry("HeaderState",QByteArray()));
}
void ArchiveMailDialog::writeConfig()
{
KConfigGroup group( KGlobal::config(), myConfigGroupName );
group.writeEntry( "Size", size() );
mWidget->saveTreeWidgetHeader(group);
group.sync();
}
void ArchiveMailDialog::slotSave()
{
mWidget->save();
}
ArchiveMailItem::ArchiveMailItem(QTreeWidget *parent )
: QTreeWidgetItem(parent),mInfo(0)
{
}
ArchiveMailItem::~ArchiveMailItem()
{
delete mInfo;
}
void ArchiveMailItem::setInfo(ArchiveMailInfo *info)
{
mInfo = info;
}
ArchiveMailInfo* ArchiveMailItem::info() const
{
return mInfo;
}
ArchiveMailWidget::ArchiveMailWidget( QWidget *parent )
: QWidget( parent ),
mChanged(false)
{
mWidget = new Ui::ArchiveMailWidget;
mWidget->setupUi( this );
QStringList headers;
headers<<i18n("Name")<<i18n("Last archive")<<i18n("Next archive in")<<i18n("Storage directory");
mWidget->treeWidget->setHeaderLabels(headers);
mWidget->treeWidget->setObjectName(QLatin1String("treewidget"));
mWidget->treeWidget->setSortingEnabled(true);
mWidget->treeWidget->setRootIsDecorated(false);
mWidget->treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
mWidget->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(mWidget->treeWidget, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(customContextMenuRequested(QPoint)));
load();
connect(mWidget->removeItem, SIGNAL(clicked(bool)), SLOT(slotRemoveItem()));
connect(mWidget->modifyItem, SIGNAL(clicked(bool)), SLOT(slotModifyItem()));
connect(mWidget->addItem, SIGNAL(clicked(bool)), SLOT(slotAddItem()));
connect(mWidget->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), SLOT(slotItemChanged(QTreeWidgetItem*,int)));
connect(mWidget->treeWidget, SIGNAL(itemSelectionChanged()), SLOT(updateButtons()));
connect(mWidget->treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(slotModifyItem()));
updateButtons();
}
ArchiveMailWidget::~ArchiveMailWidget()
{
delete mWidget;
}
void ArchiveMailWidget::customContextMenuRequested(const QPoint &)
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
KMenu menu;
menu.addAction(i18n("Add..."),this,SLOT(slotAddItem()));
if ( !listItems.isEmpty() ) {
if ( listItems.count() == 1) {
menu.addAction(i18n("Open Containing Folder..."), this, SLOT(slotOpenFolder()));
menu.addSeparator();
menu.addAction(i18n("Archive now"), this, SLOT(slotArchiveNow()));
}
menu.addSeparator();
menu.addAction(KIcon(QLatin1String("edit-delete")), i18n("Delete"), this, SLOT(slotRemoveItem()));
}
menu.exec(QCursor::pos());
}
void ArchiveMailWidget::restoreTreeWidgetHeader(const QByteArray &data)
{
mWidget->treeWidget->header()->restoreState(data);
}
void ArchiveMailWidget::saveTreeWidgetHeader(KConfigGroup& group)
{
group.writeEntry( "HeaderState", mWidget->treeWidget->header()->saveState() );
}
void ArchiveMailWidget::updateButtons()
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
if (listItems.isEmpty()) {
mWidget->removeItem->setEnabled(false);
mWidget->modifyItem->setEnabled(false);
} else if (listItems.count() == 1) {
mWidget->removeItem->setEnabled(true);
mWidget->modifyItem->setEnabled(true);
} else {
mWidget->removeItem->setEnabled(true);
mWidget->modifyItem->setEnabled(false);
}
}
void ArchiveMailWidget::needReloadConfig()
{
//TODO add messagebox which informs that we save settings here.
mWidget->treeWidget->clear();
load();
}
void ArchiveMailWidget::load()
{
KSharedConfig::Ptr config = KGlobal::config();
const QStringList collectionList = config->groupList().filter( QRegExp( archiveMailCollectionPattern ) );
const int numberOfCollection = collectionList.count();
for (int i = 0 ; i < numberOfCollection; ++i) {
KConfigGroup group = config->group(collectionList.at(i));
ArchiveMailInfo *info = new ArchiveMailInfo(group);
if (info->isValid()) {
createOrUpdateItem(info);
} else {
delete info;
}
}
}
void ArchiveMailWidget::createOrUpdateItem(ArchiveMailInfo *info, ArchiveMailItem *item)
{
if (!item) {
item = new ArchiveMailItem(mWidget->treeWidget);
}
item->setText(ArchiveMailWidget::Name,i18n("Folder: %1",MailCommon::Util::fullCollectionPath(Akonadi::Collection(info->saveCollectionId()))));
item->setCheckState(ArchiveMailWidget::Name, info->isEnabled() ? Qt::Checked : Qt::Unchecked);
item->setText(ArchiveMailWidget::StorageDirectory, info->url().toLocalFile());
if (info->lastDateSaved().isValid()) {
item->setText(ArchiveMailWidget::LastArchiveDate,KGlobal::locale()->formatDate(info->lastDateSaved()));
updateDiffDate(item, info);
} else {
item->setBackgroundColor(ArchiveMailWidget::NextArchive,Qt::green);
}
item->setInfo(info);
}
void ArchiveMailWidget::updateDiffDate(ArchiveMailItem *item, ArchiveMailInfo *info)
{
const QDate diffDate = ArchiveMailAgentUtil::diffDate(info);
const int diff = QDate::currentDate().daysTo(diffDate);
item->setText(ArchiveMailWidget::NextArchive,i18np("Tomorrow", "%1 days",diff));
if (diff<0) {
if (info->isEnabled())
item->setBackgroundColor(ArchiveMailWidget::NextArchive,Qt::red);
else
item->setBackgroundColor(ArchiveMailWidget::NextArchive,Qt::lightGray);
} else {
item->setToolTip(ArchiveMailWidget::NextArchive,i18n("Archive will be done %1",KGlobal::locale()->formatDate(diffDate)));
}
}
void ArchiveMailWidget::save()
{
if (!mChanged)
return;
KSharedConfig::Ptr config = KGlobal::config();
// first, delete all filter groups:
const QStringList filterGroups =config->groupList().filter( QRegExp( archiveMailCollectionPattern ) );
foreach ( const QString &group, filterGroups ) {
config->deleteGroup( group );
}
const int numberOfItem(mWidget->treeWidget->topLevelItemCount());
for (int i = 0; i < numberOfItem; ++i) {
ArchiveMailItem *mailItem = static_cast<ArchiveMailItem *>(mWidget->treeWidget->topLevelItem(i));
if (mailItem->info()) {
KConfigGroup group = config->group( ArchiveMailAgentUtil::archivePattern.arg(mailItem->info()->saveCollectionId()));
mailItem->info()->writeConfig(group);
}
}
config->sync();
config->reparseConfiguration();
}
void ArchiveMailWidget::slotRemoveItem()
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
if (KMessageBox::warningYesNo(this,i18n("Do you want to delete selected items? Do you want to continue?"),i18n("Remove items"))== KMessageBox::No)
return;
Q_FOREACH(QTreeWidgetItem *item,listItems) {
delete item;
}
mChanged = true;
updateButtons();
}
void ArchiveMailWidget::slotModifyItem()
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
if (listItems.count()==1) {
QTreeWidgetItem *item = listItems.at(0);
if (!item)
return;
ArchiveMailItem *archiveItem = static_cast<ArchiveMailItem*>(item);
QPointer<AddArchiveMailDialog> dialog = new AddArchiveMailDialog(archiveItem->info(), this);
if ( dialog->exec() ) {
ArchiveMailInfo *info = dialog->info();
createOrUpdateItem(info,archiveItem);
mChanged = true;
}
delete dialog;
}
}
void ArchiveMailWidget::slotAddItem()
{
QPointer<AddArchiveMailDialog> dialog = new AddArchiveMailDialog(0,this);
if ( dialog->exec() ) {
ArchiveMailInfo *info = dialog->info();
if (verifyExistingArchive(info)) {
KMessageBox::error(this,i18n("Cannot add a second archive for this folder. Modify the existing one instead."),i18n("Add Archive Mail"));
delete info;
} else {
createOrUpdateItem(info);
updateButtons();
mChanged = true;
}
}
delete dialog;
}
bool ArchiveMailWidget::verifyExistingArchive(ArchiveMailInfo *info) const
{
const int numberOfItem(mWidget->treeWidget->topLevelItemCount());
for (int i = 0; i < numberOfItem; ++i) {
ArchiveMailItem *mailItem = static_cast<ArchiveMailItem *>(mWidget->treeWidget->topLevelItem(i));
ArchiveMailInfo *archiveItemInfo = mailItem->info();
if (archiveItemInfo) {
if (info->saveCollectionId() == archiveItemInfo->saveCollectionId()) {
return true;
}
}
}
return false;
}
void ArchiveMailWidget::slotOpenFolder()
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
if (listItems.count()==1) {
QTreeWidgetItem *item = listItems.first();
if (!item)
return;
ArchiveMailItem *archiveItem = static_cast<ArchiveMailItem*>(item);
ArchiveMailInfo *archiveItemInfo = archiveItem->info();
if (archiveItemInfo) {
const KUrl url = archiveItemInfo->url();
KRun *runner = new KRun( url, this ); // will delete itself
runner->setRunExecutables( false );
}
}
}
void ArchiveMailWidget::slotArchiveNow()
{
const QList<QTreeWidgetItem *> listItems = mWidget->treeWidget->selectedItems();
if (listItems.count()==1) {
QTreeWidgetItem *item = listItems.first();
if (!item)
return;
ArchiveMailItem *archiveItem = static_cast<ArchiveMailItem*>(item);
ArchiveMailInfo *archiveItemInfo = archiveItem->info();
save();
if (archiveItemInfo) {
Q_EMIT archiveNow(archiveItemInfo);
}
}
}
void ArchiveMailWidget::slotItemChanged(QTreeWidgetItem *item,int col)
{
if (item) {
ArchiveMailItem *archiveItem = static_cast<ArchiveMailItem*>(item);
if (archiveItem->info()) {
if (col == ArchiveMailWidget::Name) {
archiveItem->info()->setEnabled(archiveItem->checkState(ArchiveMailWidget::Name) == Qt::Checked);
mChanged = true;
} else if (col == ArchiveMailWidget::NextArchive) {
updateDiffDate(archiveItem, archiveItem->info());
}
}
}
}

View file

@ -0,0 +1,109 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILDIALOG_H
#define ARCHIVEMAILDIALOG_H
#include "ui_archivemailwidget.h"
#include "archivemailinfo.h"
#include <QTreeWidgetItem>
class QTreeWidget;
class KAboutData;
class ArchiveMailItem : public QTreeWidgetItem
{
public:
explicit ArchiveMailItem(QTreeWidget *parent = 0);
~ArchiveMailItem();
void setInfo(ArchiveMailInfo *info);
ArchiveMailInfo *info() const;
private:
ArchiveMailInfo *mInfo;
};
class ArchiveMailWidget : public QWidget
{
Q_OBJECT
public:
explicit ArchiveMailWidget( QWidget *parent = 0 );
~ArchiveMailWidget();
enum ArchiveMailColumn {
Name = 0,
LastArchiveDate,
NextArchive,
StorageDirectory
};
void save();
void saveTreeWidgetHeader(KConfigGroup &group);
void restoreTreeWidgetHeader(const QByteArray &group);
void needReloadConfig();
Q_SIGNALS:
void archiveNow(ArchiveMailInfo *info);
private:
void load();
void createOrUpdateItem(ArchiveMailInfo *info, ArchiveMailItem *item = 0);
bool verifyExistingArchive(ArchiveMailInfo *info) const;
void updateDiffDate(ArchiveMailItem *item, ArchiveMailInfo *info);
private Q_SLOTS:
void slotRemoveItem();
void slotModifyItem();
void slotAddItem();
void updateButtons();
void slotOpenFolder();
void customContextMenuRequested(const QPoint &);
void slotArchiveNow();
void slotItemChanged(QTreeWidgetItem *item, int);
private:
bool mChanged;
Ui::ArchiveMailWidget *mWidget;
};
class ArchiveMailDialog : public KDialog
{
Q_OBJECT
public:
explicit ArchiveMailDialog(QWidget *parent = 0);
~ArchiveMailDialog();
Q_SIGNALS:
void archiveNow(ArchiveMailInfo *info);
public Q_SLOTS:
void slotNeedReloadConfig();
protected Q_SLOTS:
void slotSave();
private:
void writeConfig();
void readConfig();
ArchiveMailWidget *mWidget;
KAboutData *mAboutData;
};
#endif /* ARCHIVEMAILWIDGET_H */

View file

@ -0,0 +1,277 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailinfo.h"
#include <KLocale>
#include <QDir>
ArchiveMailInfo::ArchiveMailInfo()
: mLastDateSaved(QDate())
, mArchiveAge( 1 )
, mArchiveType( MailCommon::BackupJob::Zip )
, mArchiveUnit( ArchiveMailInfo::ArchiveDays )
, mSaveCollectionId(-1)
, mMaximumArchiveCount(0)
, mSaveSubCollection(false)
, mIsEnabled(true)
{
}
ArchiveMailInfo::ArchiveMailInfo(const KConfigGroup &config)
: mLastDateSaved(QDate())
, mArchiveAge( 1 )
, mArchiveType( MailCommon::BackupJob::Zip )
, mArchiveUnit( ArchiveMailInfo::ArchiveDays )
, mSaveCollectionId(-1)
, mMaximumArchiveCount(0)
, mSaveSubCollection(false)
, mIsEnabled(true)
{
readConfig(config);
}
ArchiveMailInfo::ArchiveMailInfo(const ArchiveMailInfo &info)
{
mLastDateSaved = info.lastDateSaved();
mArchiveAge = info.archiveAge();
mArchiveType = info.archiveType();
mArchiveUnit = info.archiveUnit();
mSaveCollectionId = info.saveCollectionId();
mMaximumArchiveCount = info.maximumArchiveCount();
mSaveSubCollection = info.saveSubCollection();
mPath = info.url();
mIsEnabled = info.isEnabled();
}
ArchiveMailInfo::~ArchiveMailInfo()
{
}
ArchiveMailInfo& ArchiveMailInfo::operator=( const ArchiveMailInfo &old )
{
mLastDateSaved = old.lastDateSaved();
mArchiveAge = old.archiveAge();
mArchiveType = old.archiveType();
mArchiveUnit = old.archiveUnit();
mSaveCollectionId = old.saveCollectionId();
mMaximumArchiveCount = old.maximumArchiveCount();
mSaveSubCollection = old.saveSubCollection();
mPath = old.url();
mIsEnabled = old.isEnabled();
return (*this);
}
QString normalizeFolderName(const QString &folderName)
{
QString adaptFolderName(folderName);
adaptFolderName.replace(QLatin1Char('/'),QLatin1Char('_'));
return adaptFolderName;
}
QString ArchiveMailInfo::dirArchive(bool &dirExit) const
{
const QDir dir(url().path());
QString dirPath = url().path();
if (!dir.exists()) {
dirExit = false;
dirPath = QDir::homePath();
kDebug()<<" Path doesn't exist"<<dir.path();
} else {
dirExit = true;
}
return dirPath;
}
KUrl ArchiveMailInfo::realUrl(const QString &folderName, bool &dirExist) const
{
const int numExtensions = 4;
// The extensions here are also sorted, like the enum order of BackupJob::ArchiveType
const char *extensions[numExtensions] = { ".zip", ".tar", ".tar.bz2", ".tar.gz" };
const QString dirPath = dirArchive(dirExist);
const QString path = dirPath + QLatin1Char( '/' ) + i18nc( "Start of the filename for a mail archive file" , "Archive" )
+ QLatin1Char( '_' ) + normalizeFolderName(folderName) + QLatin1Char( '_' )
+ QDate::currentDate().toString( Qt::ISODate ) + QString::fromLatin1(extensions[mArchiveType]);
KUrl real(path);
return real;
}
QStringList ArchiveMailInfo::listOfArchive(const QString &folderName, bool &dirExist) const
{
const int numExtensions = 4;
// The extensions here are also sorted, like the enum order of BackupJob::ArchiveType
const char *extensions[numExtensions] = { ".zip", ".tar", ".tar.bz2", ".tar.gz" };
const QString dirPath = dirArchive(dirExist);
QDir dir(dirPath);
QStringList nameFilters;
nameFilters << i18nc( "Start of the filename for a mail archive file" , "Archive" ) + QLatin1Char( '_' ) +
normalizeFolderName(folderName) + QLatin1Char( '_' ) + QLatin1String("*") + QString::fromLatin1(extensions[mArchiveType]);
const QStringList lst = dir.entryList ( nameFilters, QDir::Files|QDir::NoDotAndDotDot, QDir::Time|QDir::Reversed );
return lst;
}
bool ArchiveMailInfo::isValid() const
{
return (mSaveCollectionId!=-1);
}
void ArchiveMailInfo::setArchiveAge( int age )
{
mArchiveAge = age;
}
int ArchiveMailInfo::archiveAge() const
{
return mArchiveAge;
}
void ArchiveMailInfo::setArchiveUnit( ArchiveMailInfo::ArchiveUnit unit )
{
mArchiveUnit = unit;
}
ArchiveMailInfo::ArchiveUnit ArchiveMailInfo::archiveUnit() const
{
return mArchiveUnit;
}
void ArchiveMailInfo::setArchiveType( MailCommon::BackupJob::ArchiveType type )
{
mArchiveType = type;
}
MailCommon::BackupJob::ArchiveType ArchiveMailInfo::archiveType() const
{
return mArchiveType;
}
void ArchiveMailInfo::setLastDateSaved( const QDate &date )
{
mLastDateSaved = date;
}
QDate ArchiveMailInfo::lastDateSaved() const
{
return mLastDateSaved;
}
void ArchiveMailInfo::readConfig(const KConfigGroup &config)
{
mPath = config.readEntry("storePath", KUrl());
if (config.hasKey(QLatin1String("lastDateSaved"))) {
mLastDateSaved = QDate::fromString(config.readEntry("lastDateSaved"),Qt::ISODate);
}
mSaveSubCollection = config.readEntry("saveSubCollection",false);
mArchiveType = static_cast<MailCommon::BackupJob::ArchiveType>( config.readEntry( "archiveType", ( int )MailCommon::BackupJob::Zip ) );
mArchiveUnit = static_cast<ArchiveUnit>( config.readEntry( "archiveUnit", ( int )ArchiveDays ) );
Akonadi::Collection::Id tId = config.readEntry("saveCollectionId",mSaveCollectionId);
mArchiveAge = config.readEntry("archiveAge",1);
mMaximumArchiveCount = config.readEntry("maximumArchiveCount",0);
if ( tId >= 0 ) {
mSaveCollectionId = tId;
}
mIsEnabled = config.readEntry("enabled", true);
}
void ArchiveMailInfo::writeConfig(KConfigGroup & config )
{
if (!isValid()) {
return;
}
config.writeEntry("storePath",mPath);
if (mLastDateSaved.isValid()) {
config.writeEntry("lastDateSaved", mLastDateSaved.toString(Qt::ISODate) );
}
config.writeEntry("saveSubCollection",mSaveSubCollection);
config.writeEntry("archiveType", ( int )mArchiveType );
config.writeEntry("archiveUnit", ( int )mArchiveUnit );
config.writeEntry("saveCollectionId",mSaveCollectionId);
config.writeEntry("archiveAge",mArchiveAge);
config.writeEntry("maximumArchiveCount",mMaximumArchiveCount);
config.writeEntry("enabled",mIsEnabled);
config.sync();
}
KUrl ArchiveMailInfo::url() const
{
return mPath;
}
void ArchiveMailInfo::setUrl(const KUrl &url)
{
mPath = url;
}
bool ArchiveMailInfo::saveSubCollection() const
{
return mSaveSubCollection;
}
void ArchiveMailInfo::setSaveSubCollection( bool saveSubCol )
{
mSaveSubCollection = saveSubCol;
}
void ArchiveMailInfo::setSaveCollectionId(Akonadi::Collection::Id collectionId)
{
mSaveCollectionId = collectionId;
}
Akonadi::Collection::Id ArchiveMailInfo::saveCollectionId() const
{
return mSaveCollectionId;
}
int ArchiveMailInfo::maximumArchiveCount() const
{
return mMaximumArchiveCount;
}
void ArchiveMailInfo::setMaximumArchiveCount( int max )
{
mMaximumArchiveCount = max;
}
bool ArchiveMailInfo::isEnabled() const
{
return mIsEnabled;
}
void ArchiveMailInfo::setEnabled(bool b)
{
mIsEnabled = b;
}
bool ArchiveMailInfo::operator==( const ArchiveMailInfo& other ) const
{
return saveCollectionId() == other.saveCollectionId() &&
saveSubCollection() == other.saveSubCollection() &&
url() == other.url() &&
archiveType() == other.archiveType() &&
archiveUnit() == other.archiveUnit() &&
archiveAge() == other.archiveAge() &&
lastDateSaved() == other.lastDateSaved() &&
maximumArchiveCount() == other.maximumArchiveCount() &&
isEnabled() == other.isEnabled();
}

View file

@ -0,0 +1,95 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILINFO_H
#define ARCHIVEMAILINFO_H
#include "mailcommon/job/backupjob.h"
#include <KConfigGroup>
#include <Akonadi/Collection>
#include <KUrl>
#include <QDate>
class ArchiveMailInfo
{
public:
explicit ArchiveMailInfo();
explicit ArchiveMailInfo(const KConfigGroup &config);
ArchiveMailInfo(const ArchiveMailInfo &info);
~ArchiveMailInfo();
ArchiveMailInfo& operator=( const ArchiveMailInfo &old );
enum ArchiveUnit {
ArchiveDays = 0,
ArchiveWeeks,
ArchiveMonths,
ArchiveYears
};
KUrl realUrl(const QString &folderName, bool &dirExist) const;
bool isValid() const;
Akonadi::Collection::Id saveCollectionId() const;
void setSaveCollectionId(Akonadi::Collection::Id collectionId);
void setSaveSubCollection(bool b);
bool saveSubCollection() const;
void setUrl(const KUrl& url);
KUrl url() const;
void readConfig(const KConfigGroup &config);
void writeConfig(KConfigGroup &config );
void setArchiveType( MailCommon::BackupJob::ArchiveType type );
MailCommon::BackupJob::ArchiveType archiveType() const;
void setArchiveUnit( ArchiveMailInfo::ArchiveUnit unit );
ArchiveMailInfo::ArchiveUnit archiveUnit() const;
void setArchiveAge( int age );
int archiveAge() const;
void setLastDateSaved( const QDate &date );
QDate lastDateSaved() const;
int maximumArchiveCount() const;
void setMaximumArchiveCount( int max );
QStringList listOfArchive(const QString &foldername, bool &dirExist) const;
bool isEnabled() const;
void setEnabled(bool b);
bool operator ==(const ArchiveMailInfo &other) const;
private:
QString dirArchive(bool &dirExit) const;
QDate mLastDateSaved;
int mArchiveAge;
MailCommon::BackupJob::ArchiveType mArchiveType;
ArchiveUnit mArchiveUnit;
Akonadi::Collection::Id mSaveCollectionId;
KUrl mPath;
int mMaximumArchiveCount;
bool mSaveSubCollection;
bool mIsEnabled;
};
#endif // ARCHIVEMAILINFO_H

View file

@ -0,0 +1,123 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailkernel.h"
#include <kglobal.h>
#include <kpimidentities/identitymanager.h>
#include <mailcommon/folder/foldercollectionmonitor.h>
#include <mailcommon/job/jobscheduler.h>
#include <akonadi/session.h>
#include <akonadi/entitytreemodel.h>
#include <akonadi/entitymimetypefiltermodel.h>
#include <akonadi/changerecorder.h>
ArchiveMailKernel::ArchiveMailKernel( QObject *parent )
: QObject( parent )
{
mIdentityManager = new KPIMIdentities::IdentityManager( false, this );
Akonadi::Session *session = new Akonadi::Session( "Archive Mail Kernel ETM", this );
mFolderCollectionMonitor = new MailCommon::FolderCollectionMonitor( session, this );
mFolderCollectionMonitor->monitor()->setChangeRecordingEnabled(false);
mEntityTreeModel = new Akonadi::EntityTreeModel( folderCollectionMonitor(), this );
mEntityTreeModel->setIncludeUnsubscribed( false );
mEntityTreeModel->setItemPopulationStrategy( Akonadi::EntityTreeModel::LazyPopulation );
mCollectionModel = new Akonadi::EntityMimeTypeFilterModel( this );
mCollectionModel->setSourceModel( mEntityTreeModel );
mCollectionModel->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() );
mCollectionModel->setHeaderGroup( Akonadi::EntityTreeModel::CollectionTreeHeaders );
mCollectionModel->setDynamicSortFilter( true );
mCollectionModel->setSortCaseSensitivity( Qt::CaseInsensitive );
mJobScheduler = new MailCommon::JobScheduler(this);
}
KPIMIdentities::IdentityManager *ArchiveMailKernel::identityManager()
{
return mIdentityManager;
}
MessageComposer::MessageSender *ArchiveMailKernel::msgSender()
{
return 0;
}
Akonadi::EntityMimeTypeFilterModel *ArchiveMailKernel::collectionModel() const
{
return mCollectionModel;
}
KSharedConfig::Ptr ArchiveMailKernel::config()
{
return KGlobal::config();
}
void ArchiveMailKernel::syncConfig()
{
Q_ASSERT( false );
}
MailCommon::JobScheduler* ArchiveMailKernel::jobScheduler() const
{
return mJobScheduler;
}
Akonadi::ChangeRecorder *ArchiveMailKernel::folderCollectionMonitor() const
{
return mFolderCollectionMonitor->monitor();
}
void ArchiveMailKernel::updateSystemTray()
{
Q_ASSERT( false );
}
bool ArchiveMailKernel::showPopupAfterDnD()
{
return false;
}
qreal ArchiveMailKernel::closeToQuotaThreshold()
{
return 80;
}
QStringList ArchiveMailKernel::customTemplates()
{
Q_ASSERT( false );
return QStringList();
}
bool ArchiveMailKernel::excludeImportantMailFromExpiry()
{
Q_ASSERT( false );
return true;
}
Akonadi::Entity::Id ArchiveMailKernel::lastSelectedFolder()
{
return Akonadi::Entity::Id();
}
void ArchiveMailKernel::setLastSelectedFolder(const Akonadi::Entity::Id& col)
{
Q_UNUSED( col );
}

View file

@ -0,0 +1,64 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILKERNEL_H
#define ARCHIVEMAILKERNEL_H
#include <mailcommon/interfaces/mailinterfaces.h>
namespace Akonadi {
class EntityTreeModel;
class EntityMimeTypeFilterModel;
}
namespace MailCommon {
class FolderCollectionMonitor;
class JobScheduler;
}
class ArchiveMailKernel : public QObject, public MailCommon::IKernel, public MailCommon::ISettings
{
public:
explicit ArchiveMailKernel( QObject *parent = 0 );
KPIMIdentities::IdentityManager *identityManager();
MessageComposer::MessageSender *msgSender();
Akonadi::EntityMimeTypeFilterModel *collectionModel() const;
KSharedConfig::Ptr config();
void syncConfig();
MailCommon::JobScheduler* jobScheduler() const;
Akonadi::ChangeRecorder *folderCollectionMonitor() const;
void updateSystemTray();
qreal closeToQuotaThreshold();
bool excludeImportantMailFromExpiry();
QStringList customTemplates();
Akonadi::Entity::Id lastSelectedFolder();
void setLastSelectedFolder(const Akonadi::Entity::Id& col);
bool showPopupAfterDnD();
private:
KPIMIdentities::IdentityManager *mIdentityManager;
MailCommon::FolderCollectionMonitor *mFolderCollectionMonitor;
Akonadi::EntityTreeModel *mEntityTreeModel;
Akonadi::EntityMimeTypeFilterModel *mCollectionModel;
MailCommon::JobScheduler* mJobScheduler;
};
#endif

View file

@ -0,0 +1,209 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailmanager.h"
#include "archivemailinfo.h"
#include "archivejob.h"
#include "archivemailkernel.h"
#include "archivemailagentutil.h"
#include <mailcommon/kernel/mailkernel.h>
#include <mailcommon/util/mailutil.h>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KGlobal>
#include <QDate>
#include <QFile>
#include <QDir>
ArchiveMailManager::ArchiveMailManager(QObject *parent)
: QObject( parent )
{
mArchiveMailKernel = new ArchiveMailKernel( this );
CommonKernel->registerKernelIf( mArchiveMailKernel ); //register KernelIf early, it is used by the Filter classes
CommonKernel->registerSettingsIf( mArchiveMailKernel ); //SettingsIf is used in FolderTreeWidget
mConfig = KGlobal::config();
}
ArchiveMailManager::~ArchiveMailManager()
{
qDeleteAll(mListArchiveInfo);
}
void ArchiveMailManager::slotArchiveNow(ArchiveMailInfo *info)
{
if (!info)
return;
ArchiveMailInfo *stockInfo = new ArchiveMailInfo(*info);
mListArchiveInfo.append(stockInfo);
ScheduledArchiveTask *task = new ScheduledArchiveTask( this, stockInfo,Akonadi::Collection(stockInfo->saveCollectionId()), true /*immediat*/ );
mArchiveMailKernel->jobScheduler()->registerTask( task );
}
void ArchiveMailManager::load()
{
qDeleteAll(mListArchiveInfo);
mListArchiveInfo.clear();
const QStringList collectionList = mConfig->groupList().filter( QRegExp( QLatin1String("ArchiveMailCollection \\d+") ) );
const int numberOfCollection = collectionList.count();
for (int i = 0 ; i < numberOfCollection; ++i) {
KConfigGroup group = mConfig->group(collectionList.at(i));
ArchiveMailInfo *info = new ArchiveMailInfo(group);
if (ArchiveMailAgentUtil::needToArchive(info)) {
Q_FOREACH(ArchiveMailInfo*oldInfo,mListArchiveInfo) {
if (oldInfo->saveCollectionId() == info->saveCollectionId()) {
//already in jobscheduler
delete info;
info = 0;
break;
}
}
if (info) {
//Store task started
mListArchiveInfo.append(info);
ScheduledArchiveTask *task = new ScheduledArchiveTask( this, info,Akonadi::Collection(info->saveCollectionId()), /*immediate*/false );
mArchiveMailKernel->jobScheduler()->registerTask( task );
}
} else {
delete info;
}
}
}
void ArchiveMailManager::removeCollection(const Akonadi::Collection &collection)
{
removeCollectionId(collection.id());
}
void ArchiveMailManager::removeCollectionId(Akonadi::Collection::Id id)
{
const QString groupname = ArchiveMailAgentUtil::archivePattern.arg(id);
if (mConfig->hasGroup(groupname)) {
KConfigGroup group = mConfig->group(groupname);
group.deleteGroup();
mConfig->sync();
mConfig->reparseConfiguration();
Q_FOREACH(ArchiveMailInfo *info, mListArchiveInfo) {
if (info->saveCollectionId() == id) {
mListArchiveInfo.removeAll(info);
}
}
}
}
void ArchiveMailManager::backupDone(ArchiveMailInfo *info)
{
info->setLastDateSaved(QDate::currentDate());
const QString groupname = ArchiveMailAgentUtil::archivePattern.arg(info->saveCollectionId());
//Don't store it if we removed this task
if (mConfig->hasGroup(groupname)) {
KConfigGroup group = mConfig->group(groupname);
info->writeConfig(group);
}
Akonadi::Collection collection(info->saveCollectionId());
const QString realPath = MailCommon::Util::fullCollectionPath(collection);
bool dirExist = true;
const QStringList lst = info->listOfArchive(realPath, dirExist);
if (dirExist) {
if (info->maximumArchiveCount() != 0) {
if (lst.count() > info->maximumArchiveCount()) {
const int diff = (lst.count() - info->maximumArchiveCount());
for (int i = 0; i < diff; ++i) {
const QString fileToRemove(info->url().path() + QDir::separator() + lst.at(i));
kDebug()<<" file to remove "<<fileToRemove;
QFile::remove(fileToRemove);
}
}
}
}
mListArchiveInfo.removeAll(info);
Q_EMIT needUpdateConfigDialogBox();
}
void ArchiveMailManager::collectionDoesntExist(ArchiveMailInfo *info)
{
removeCollectionId(info->saveCollectionId());
mListArchiveInfo.removeAll(info);
Q_EMIT needUpdateConfigDialogBox();
}
void ArchiveMailManager::pause()
{
mArchiveMailKernel->jobScheduler()->pause();
}
void ArchiveMailManager::resume()
{
mArchiveMailKernel->jobScheduler()->resume();
}
QString ArchiveMailManager::printCurrentListInfo()
{
QString infoStr;
if (mListArchiveInfo.isEmpty()) {
infoStr = QLatin1String("No archive in queue");
} else {
Q_FOREACH (ArchiveMailInfo *info, mListArchiveInfo) {
if (!infoStr.isEmpty())
infoStr += QLatin1Char('\n');
infoStr += infoToStr(info);
}
}
return infoStr;
}
QString ArchiveMailManager::infoToStr(ArchiveMailInfo *info) const
{
QString infoStr = QLatin1String("collectionId: ") + QString::number(info->saveCollectionId()) + QLatin1Char('\n');
infoStr += QLatin1String("save sub collection: ") + (info->saveSubCollection() ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char('\n');
infoStr += QLatin1String("last Date Saved: ") + info->lastDateSaved().toString() + QLatin1Char('\n');
infoStr += QLatin1String("maximum achive number: ") + QString::number(info->maximumArchiveCount()) + QLatin1Char('\n');
infoStr += QLatin1String("directory: ") + info->url().pathOrUrl() + QLatin1Char('\n');
infoStr += QLatin1String("Enabled: ") + (info->isEnabled() ? QLatin1String("true") : QLatin1String("false"));
return infoStr;
}
QString ArchiveMailManager::printArchiveListInfo()
{
QString infoStr;
const QStringList collectionList = mConfig->groupList().filter( QRegExp( QLatin1String("ArchiveMailCollection \\d+") ) );
const int numberOfCollection = collectionList.count();
for (int i = 0 ; i < numberOfCollection; ++i) {
KConfigGroup group = mConfig->group(collectionList.at(i));
ArchiveMailInfo info(group);
if (!infoStr.isEmpty())
infoStr += QLatin1Char('\n');
infoStr += infoToStr(&info);
}
return infoStr;
}
void ArchiveMailManager::archiveFolder(const QString &path, Akonadi::Collection::Id collectionId)
{
ArchiveMailInfo *info = new ArchiveMailInfo;
info->setSaveCollectionId(collectionId);
info->setUrl(KUrl(path));
slotArchiveNow(info);
delete info;
}

View file

@ -0,0 +1,64 @@
/*
Copyright (c) 2012-2013 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILMANAGER_H
#define ARCHIVEMAILMANAGER_H
#include <QObject>
#include <KSharedConfig>
#include <Akonadi/Collection>
class ArchiveMailKernel;
class ArchiveMailInfo;
class ArchiveMailManager : public QObject
{
Q_OBJECT
public:
explicit ArchiveMailManager(QObject *parent = 0);
~ArchiveMailManager();
void removeCollection(const Akonadi::Collection &collection);
void backupDone(ArchiveMailInfo *info);
void pause();
void resume();
QString printArchiveListInfo();
void collectionDoesntExist(ArchiveMailInfo *info);
QString printCurrentListInfo();
void archiveFolder(const QString &path, Akonadi::Collection::Id collectionId);
public Q_SLOTS:
void load();
void slotArchiveNow(ArchiveMailInfo *info);
Q_SIGNALS:
void needUpdateConfigDialogBox();
private:
QString infoToStr(ArchiveMailInfo *info) const;
void removeCollectionId(Akonadi::Collection::Id id);
KSharedConfig::Ptr mConfig;
QList<ArchiveMailInfo *> mListArchiveInfo;
ArchiveMailKernel *mArchiveMailKernel;
};
#endif /* ARCHIVEMAILMANAGER_H */

View file

@ -0,0 +1,27 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.Akonadi.ArchiveMailAgent">
<method name="showConfigureDialog" >
<arg direction="in" type="x" name="windowId" />
</method>
<method name="pause"/>
<method name="resume"/>
<method name="printArchiveListInfo">
<arg direction="out" type="s" />
</method>
<method name="printCurrentListInfo">
<arg direction="out" type="s" />
</method>
<method name="setEnableAgent" >
<arg direction="in" type="b" name="enabled" />
</method>
<method name="enabledAgent" >
<arg direction="out" type="b" />
</method>
<method name="archiveFolder" >
<arg direction="in" type="s" name="path" />
<arg direction="in" type="x" name="collectionId" />
</method>
</interface>
</node>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<group name="General">
<entry name="enabled" key="enabled" type="Bool">
<default>true</default>
</entry>
</group>
</kcfg>

View file

@ -0,0 +1,5 @@
# Code generation options for kconfig_compiler
File=archivemailagentsettings.kcfg
ClassName=ArchiveMailAgentSettings
Singleton=true
Mutators=true

View file

@ -0,0 +1,15 @@
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. )
remove_definitions( -DQT_NO_CAST_FROM_BYTEARRAY )
# Convenience macro to add unit tests.
macro( archivemail_agent _source )
set( _test ${_source} ../archivemailinfo.cpp ../archivemaildialog.cpp ../archivemailagentutil.cpp ../addarchivemaildialog.cpp)
kde4_add_ui_files(_test ../ui/archivemailwidget.ui )
get_filename_component( _name ${_source} NAME_WE )
kde4_add_unit_test( ${_name} TESTNAME archivemailagent-${_name} ${_test} )
target_link_libraries( ${_name} ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} mailcommon ${KDEPIMLIBS_AKONADI_LIBS} ${KDE4_KIO_LIBS})
endmacro()
archivemail_agent(archivemailinfotest.cpp)
archivemail_agent(archivemaildialogtest.cpp)

View file

@ -0,0 +1,49 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemaildialogtest.h"
#include "../archivemaildialog.h"
#include <qtest_kde.h>
ArchiveMailDialogTest::ArchiveMailDialogTest(QObject *parent)
: QObject(parent)
{
}
ArchiveMailDialogTest::~ArchiveMailDialogTest()
{
}
void ArchiveMailDialogTest::shouldHaveDefaultValue()
{
ArchiveMailDialog dlg;
ArchiveMailWidget *mailwidget = qFindChild<ArchiveMailWidget *>(&dlg, QLatin1String("archivemailwidget"));
QVERIFY(mailwidget);
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(mailwidget, QLatin1String("treewidget"));
QVERIFY(treeWidget);
QCOMPARE(treeWidget->topLevelItemCount(), 0);
}
QTEST_KDEMAIN(ArchiveMailDialogTest, GUI)

View file

@ -0,0 +1,37 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILDIALOGTEST_H
#define ARCHIVEMAILDIALOGTEST_H
#include <QObject>
class ArchiveMailDialogTest : public QObject
{
Q_OBJECT
public:
explicit ArchiveMailDialogTest(QObject *parent=0);
~ArchiveMailDialogTest();
private Q_SLOTS:
void shouldHaveDefaultValue();
};
#endif // ARCHIVEMAILDIALOGTEST_H

View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archivemailinfotest.h"
#include "../archivemailinfo.h"
#include <Akonadi/Collection>
#include <qtest_kde.h>
#include <KGlobal>
#include <KConfigGroup>
ArchiveMailInfoTest::ArchiveMailInfoTest(QObject *parent)
: QObject(parent)
{
}
ArchiveMailInfoTest::~ArchiveMailInfoTest()
{
}
void ArchiveMailInfoTest::shouldHaveDefaultValue()
{
ArchiveMailInfo info;
QCOMPARE(info.saveCollectionId(), Akonadi::Collection::Id(-1));
QCOMPARE(info.saveSubCollection(), false);
QCOMPARE(info.url(), KUrl());
QCOMPARE(info.archiveType(), MailCommon::BackupJob::Zip);
QCOMPARE(info.archiveUnit(), ArchiveMailInfo::ArchiveDays);
QCOMPARE(info.archiveAge(), 1);
QCOMPARE(info.lastDateSaved(), QDate());
QCOMPARE(info.maximumArchiveCount(), 0);
QCOMPARE(info.isEnabled(), true);
}
void ArchiveMailInfoTest::shouldRestoreFromSettings()
{
ArchiveMailInfo info;
info.setSaveCollectionId(Akonadi::Collection::Id(42));
info.setUrl(KUrl("/foo/foo"));
info.setArchiveType(MailCommon::BackupJob::TarBz2);
info.setArchiveUnit(ArchiveMailInfo::ArchiveMonths);
info.setArchiveAge(5);
info.setLastDateSaved(QDate::currentDate());
info.setMaximumArchiveCount(5);
info.setEnabled(false);
KConfigGroup grp(KGlobal::config(), "testsettings");
info.writeConfig(grp);
ArchiveMailInfo restoreInfo(grp);
QCOMPARE(info, restoreInfo);
}
void ArchiveMailInfoTest::shouldCopyArchiveInfo()
{
ArchiveMailInfo info;
info.setSaveCollectionId(Akonadi::Collection::Id(42));
info.setUrl(KUrl("/foo/foo"));
info.setArchiveType(MailCommon::BackupJob::TarBz2);
info.setArchiveUnit(ArchiveMailInfo::ArchiveMonths);
info.setArchiveAge(5);
info.setLastDateSaved(QDate::currentDate());
info.setMaximumArchiveCount(5);
info.setEnabled(false);
ArchiveMailInfo copyInfo(info);
QCOMPARE(info, copyInfo);
}
QTEST_KDEMAIN(ArchiveMailInfoTest, NoGUI)

View file

@ -0,0 +1,40 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARCHIVEMAILINFOTEST_H
#define ARCHIVEMAILINFOTEST_H
#include <QObject>
class ArchiveMailInfoTest : public QObject
{
Q_OBJECT
public:
explicit ArchiveMailInfoTest(QObject *parent=0);
~ArchiveMailInfoTest();
private Q_SLOTS:
void shouldHaveDefaultValue();
void shouldCopyArchiveInfo();
void shouldRestoreFromSettings();
};
#endif // ARCHIVEMAILINFOTEST_H

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ArchiveMailWidget</class>
<widget class="QWidget" name="ArchiveMailWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<height>634</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="addItem">
<property name="text">
<string>Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="modifyItem">
<property name="text">
<string>Modify...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeItem">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QTreeWidget" name="treeWidget">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,79 @@
[Desktop Entry]
Name=Folder Archive Agent
Name[bs]=Agent foldera arhiva
Name[ca]=Agent per arxivar una carpeta
Name[ca@valencia]=Agent per arxivar una carpeta
Name[da]=Agent til mappe-arkivering
Name[de]=Agent zur Ordner-Archivierung
Name[el]=Πράκτορας φακέλου αρχειοθέτησης
Name[en_GB]=Folder Archive Agent
Name[es]=Agente de archivado de carpeta
Name[et]=Kausta arhiveerimise agent
Name[fi]=Kansioiden arkistointiagentti
Name[fr]=Agent d'archivage de dossiers
Name[gl]=Axente de Arquivo de Cartafoles
Name[hu]=Mappaarchiváló ügynök
Name[ia]=Agente de archivar dossier
Name[it]=Agente di archiviazione per cartelle
Name[kk]=Қапшық архивтеу агенті
Name[nb]=Postarkiv-agent
Name[nds]=Orner-Archiveerhölper
Name[nl]=Agent voor archiveren van map
Name[pl]=Agent archiwizacji katalogu
Name[pt]=Agente de Arquivo de Pastas
Name[pt_BR]=Agente de Arquivamento de Pastas
Name[ro]=Agent de arhivare a dosarelor
Name[ru]=Агент архивирования папок
Name[sk]=Agent archívu priečinka
Name[sr]=Агент за архивирање фасцикли
Name[sr@ijekavian]=Агент за архивирање фасцикли
Name[sr@ijekavianlatin]=Agent za arhiviranje fascikli
Name[sr@latin]=Agent za arhiviranje fascikli
Name[sv]=Korgarkiveringsmodul
Name[tr]=Klasör Arşivleme Aracı
Name[uk]=Агент архівування тек
Name[x-test]=xxFolder Archive Agentxx
Name[zh_TW]=
Comment=Folder Archive Agent allows to store mails in specific archive folder
Comment[bs]=Agent foldera arhiva omogućava pohranu mailova u poseban arhivski folder
Comment[ca]=L'agent per arxivar una carpeta permet emmagatzemar el correu a una carpeta d'arxiu específica
Comment[ca@valencia]=L'agent per arxivar una carpeta permet emmagatzemar el correu a una carpeta d'arxiu específica
Comment[da]=Agent til mappe-arkivering muliggør at gemme e-mails i en specifik arkivmappe
Comment[de]=Der Agent zur Ordner-Archivierung ermöglicht das Speichern von E-Mails in angegebenen Archivordnern
Comment[el]=Ο πράκτορας φακέλου αρχειοθέτησης σας επιτρέπει να αποθηκεύετε μηνύματα ηλ. αλληλογραφίας σε έναν συγκεκριμένο φάκελο αρχειοθέτησης
Comment[en_GB]=Folder Archive Agent allows to store mails in specific archive folder
Comment[es]=El agente de archivado de carpeta permite almacenar correos en una carpeta de archivos específica
Comment[et]=Kausta arhiveerimise agent võimaldab salvestada kirju spetsiaalsesse arhiivikausta
Comment[fi]=Kansioiden arkistointiagentti mahdollistaa postien tallettamisen erityisiin arkistokansioihin
Comment[fr]=L'agent d'archivage de dossiers permet de stocker des courriers électroniques dans un dossier d'archive
Comment[gl]=O Axente de Arquivo de Cartafoles permite almacenar o correo nun cartafol de arquivo específico
Comment[hu]=A mappaarchiváló ügynök lehetővé teszi e-mailek tárolását a megadott archívum mappában
Comment[ia]=Agente de archivar dossier permitte immagasinar messages de e-posta in un specific dossier
Comment[it]=L'agente di archiviazione per cartella permette di memorizzazar i messaggi di posta in specifiche cartelle di archiviazione
Comment[kk]=Қапшық архивтеу агенті тиісті архив қапшықта поштаны сақтап береді
Comment[nb]=Postarkiv-agenten kan lagre e-poster i en bestemt arkivmappe
Comment[nds]=De Orner-Archiveerhölper sekert Nettpost binnen en fastleggt Archievorner
Comment[nl]=Agent voor archiveren van map stelt u in staat om e-mailberichten op te slaan in een archiefmap
Comment[pl]=Agent archiwizacji katalogu pozwala na przechowywanie poczty w określonym katalogu archiwum
Comment[pt]=O Agente de Arquivo de Pastas permite-lhe guardar as mensagens numa pasta de arquivo específica
Comment[pt_BR]=O Agente de Arquivamento de Pastas permite armazenar os e-mails em uma pasta específica
Comment[ru]=Агент архивирования папок позволяет сохранять почту в определённой архивной папке
Comment[sk]=Agent archívu priečinka umožní uložiť maily v určenom priečinku archívu
Comment[sr]=Агент за архивирање фасцикли омогућава складиштење порука у задату архивску фасциклу
Comment[sr@ijekavian]=Агент за архивирање фасцикли омогућава складиштење порука у задату архивску фасциклу
Comment[sr@ijekavianlatin]=Agent za arhiviranje fascikli omogućava skladištenje poruka u zadatu arhivsku fasciklu
Comment[sr@latin]=Agent za arhiviranje fascikli omogućava skladištenje poruka u zadatu arhivsku fasciklu
Comment[sv]=Korgarkiveringsmodulen gör det möjligt att lagra brev i en specifik arkivkorg
Comment[tr]=Klasör Arşivleme Aracı, postaları belirtilen bir arşiv klasörüne depolamayı sağlar
Comment[uk]=Агент архівування тек надає змогу зберігати повідомлення у певній теці архіву
Comment[x-test]=xxFolder Archive Agent allows to store mails in specific archive folderxx
Comment[zh_TW]=
Type=AkonadiAgent
Exec=akonadi_folderarchive_agent
Icon=kmail
# This agent is disabled, do not autostart it.
# KDE5: remove this file
X-Akonadi-MimeTypes=
X-Akonadi-Capabilities=
X-Akonadi-Identifier=akonadi_folderarchive_agent

View file

@ -0,0 +1,67 @@
project(followupreminderagent)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
include_directories(
${CMAKE_SOURCE_DIR}/messagecomposer/
)
set(followupreminderlib_SRCS
followupreminderinfo.cpp
followupreminderutil.cpp
)
kde4_add_kcfg_files(followupreminderlib_SRCS
settings/followupreminderagentsettings.kcfgc
)
kde4_add_library( followupreminder ${LIBRARY_TYPE} ${followupreminderlib_SRCS} )
target_link_libraries( followupreminder ${KDE4_KDEUI_LIBS} )
set_target_properties( followupreminder PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
install( TARGETS followupreminder ${INSTALL_TARGETS_DEFAULT_ARGS} )
set(followupreminderagent_job_SRCS
jobs/followupreminderjob.cpp
jobs/followupreminderfinishtaskjob.cpp
jobs/followupremindershowmessagejob.cpp
)
set(followupreminderagent_SRCS
followupreminderagent.cpp
followupremindermanager.cpp
followupreminderinfodialog.cpp
followupremindernoanswerdialog.cpp
followupreminderinfowidget.cpp
${followupreminderagent_job_SRCS}
)
qt4_add_dbus_adaptor(followupreminderagent_SRCS org.freedesktop.Akonadi.FollowUpReminder.xml followupreminderagent.h FollowUpReminderAgent)
kde4_add_executable(akonadi_followupreminder_agent ${followupreminderagent_SRCS})
target_link_libraries(akonadi_followupreminder_agent
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_AKONADI_KMIME_LIBS}
${KDEPIMLIBS_KMIME_LIBS}
${KDEPIMLIBS_KCALCORE_LIBS}
followupreminder
)
if (Q_WS_MAC)
set_target_properties(akonadi_followupreminder_agent PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.template)
set_target_properties(akonadi_followupreminder_agent PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.akonadi_followupreminder_agent")
set_target_properties(akonadi_followupreminder_agent PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Followup Reminder Agent")
endif ()
install(TARGETS akonadi_followupreminder_agent ${INSTALL_TARGETS_DEFAULT_ARGS} )
install(FILES followupreminder.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")
add_subdirectory(tests)
install(FILES akonadi_followupreminder_agent.notifyrc DESTINATION "${DATA_INSTALL_DIR}/akonadi_followupreminder_agent" )

View file

@ -0,0 +1,2 @@
#! /bin/sh
$XGETTEXT `find . -name '*.h' -o -name '*.cpp' | grep -v '/tests/'` -o $podir/akonadi_followupreminder_agent.pot

View file

@ -0,0 +1,66 @@
[Global]
IconName=kmail
Comment=Followup reminder agent
Comment[bs]=Prateći agent koji Vas podsjeća
Comment[ca]=Agent per a recordatoris de seguiment
Comment[ca@valencia]=Agent per a recordatoris de seguiment
Comment[da]=Agent til opfølgningspåmindelse
Comment[de]=Agent zur Erinnerung an Folgenachrichten
Comment[el]=Πράκτορας υπενθύμισης συνέχισης επικοινωνίας
Comment[en_GB]=Followup reminder agent
Comment[es]=Seguimiento de agente de recordatorio
Comment[et]=Vastamise meeldetuletuse agent
Comment[fi]=Vastaamisesta muistuttaja
Comment[fr]=Agent de rappel des messages suivis
Comment[gl]=Axente de lembranzas de seguimento
Comment[hu]=Nyomkövető emlékeztető ügynök
Comment[ia]=Agente de memorar de continuation (Followup Reminder Agent)
Comment[it]=Agente per gli avvisi delle azioni da seguire
Comment[kk]=Жауап беру туралы ескерту агенті
Comment[nb]=Agent for påminnelse om oppfølging
Comment[nds]=Antwoortnaricht-Anstoothölper
Comment[nl]=Agent voor herinneren aan vervolgactie
Comment[pl]=Agent ponaglającego przypominania
Comment[pt]=Agente de recordação de seguimentos
Comment[pt_BR]=Acompanhamento do agente de lembretes
Comment[ru]=Агент напоминания о продолжении
Comment[sk]=Agent pripomienky sledovania
Comment[sr]=Агент подсетника на одговор
Comment[sr@ijekavian]=Агент подсетника на одговор
Comment[sr@ijekavianlatin]=Agent podsetnika na odgovor
Comment[sr@latin]=Agent podsetnika na odgovor
Comment[sv]=Påminnelseuppföljningsmodul
Comment[tr]=Takip hatırlatma aracı
Comment[uk]=Агент стеження за нагадуваннями
Comment[x-test]=xxFollowup reminder agentxx
Comment[zh_TW]=回覆提醒代理程式
[Event/mailreceived]
Name=Mail Follow Up Received
Name[ca]=S'ha rebut correu de seguiment
Name[da]=Opfølgning på mail modtaget
Name[de]=Folgenachricht erhalten
Name[en_GB]=Mail Follow Up Received
Name[es]=Recibido seguimiento de correo
Name[et]=Saadi vastuskiri
Name[fi]=Vastausposti vastaanotettu
Name[fr]=Un message suivis a été reçu
Name[hu]=Levél nyomkövető érkezett
Name[it]=Ricevuta risposta ad un messaggio seguito
Name[nb]=Oppfølgings-epost mottatt
Name[nds]=Antwoortnaricht kregen
Name[nl]=Ontvangen e-mailbericht van vervolgactie
Name[pl]=Otrzymano powiadamiającą pocztę
Name[pt]=Mensagem de Seguimento Recebida
Name[pt_BR]=Mensagem de acompanhamento recebida
Name[sk]=Prijaté sledovanie mailu
Name[sr]=Примљен одговор на поруку
Name[sr@ijekavian]=Примљен одговор на поруку
Name[sr@ijekavianlatin]=Primljen odgovor na poruku
Name[sr@latin]=Primljen odgovor na poruku
Name[sv]=Uppföljningsbrev mottaget
Name[uk]=Отримано відповідь на повідомлення
Name[x-test]=xxMail Follow Up Receivedxx
Name[zh_TW]=接收到回覆郵件
Action=Popup

View file

@ -0,0 +1,76 @@
[Desktop Entry]
Name=Followup Reminder Agent
Name[bs]=Prateći agent koji Vas podsjeća
Name[ca]=Agent per a recordatoris de seguiment
Name[ca@valencia]=Agent per a recordatoris de seguiment
Name[da]=Agent til opfølgningspåmindelse
Name[de]=Agent zur Erinnerung an Folgenachrichten
Name[el]=Πράκτορας υπενθύμισης συνέχισης επικοινωνίας
Name[en_GB]=Followup Reminder Agent
Name[es]=Seguimiento de agente de recordatorio
Name[et]=Vastamise meeldetuletuse agent
Name[fi]=Vastaamisesta muistuttaja
Name[fr]=Agent de rappel des messages suivis
Name[gl]=Axente de lembranzas de seguimento
Name[hu]=Nyomkövető emlékeztető ügynök
Name[ia]=Followup Reminder Agent
Name[it]=Agente per gli avvisi delle azioni da seguire
Name[kk]=Жауап беру туралы ескерту агенті
Name[nb]=Agent for påminnelse om oppfølging
Name[nds]=Antwoortnaricht-Anstoothölper
Name[nl]=Agent voor herinneren aan vervolgactie
Name[pl]=Agent ponaglającego przypominania
Name[pt]=Agente de Recordação de Seguimentos
Name[pt_BR]=Acompanhamento do Agente de Lembretes
Name[ru]=Агент напоминания о продолжении
Name[sk]=Agent pripomienky spracovania
Name[sr]=Агент подсетника на одговор
Name[sr@ijekavian]=Агент подсетника на одговор
Name[sr@ijekavianlatin]=Agent podsetnika na odgovor
Name[sr@latin]=Agent podsetnika na odgovor
Name[sv]=Påminnelseuppföljningsmodul
Name[tr]=Takip Hatırlatma Aracı
Name[uk]=Агент нагадування про відповіді
Name[x-test]=xxFollowup Reminder Agentxx
Name[zh_TW]=
Comment=Followup Reminder Agent allows to remind you when an email was not answered.
Comment[bs]=Prateći agent koji Vas podsjeća omogućava vam informaciju kada neki email nije odgovoren.
Comment[ca]=L'agent per a recordatoris de seguiment permet recordar quan un correu electrònic no ha estat respost.
Comment[ca@valencia]=L'agent per a recordatoris de seguiment permet recordar quan no s'ha rebut resposta d'un correu electrònic.
Comment[da]=Agent til opfølgningspåmindelse muliggør at minde dig om når e-mail ikke er blevet besvaret.
Comment[de]=Der Agent zur Erinnerung an Folgenachrichten erinnert Sie, wenn eine E-Mail nicht beantwortet wurde.
Comment[el]=Ο πράκτορας υπενθύμισης συνέχισης επικοινωνίας σας υπενθυμίζει πότε ένα μήνυμα ηλ. αλληλογραφίας δεν έχει απαντηθεί.
Comment[en_GB]=Followup Reminder Agent allows to remind you when an email was not answered.
Comment[es]=El seguimiento de agente de recordatorio le permite recordar cuando no se ha respondido a un correo.
Comment[et]=Vastamise meeldetuletuse agent laseb meelde tuletada, kui sa pole kirjale vastust saanud.
Comment[fi]=Vastaamisesta muistuttaja voi muistuttaa sinua, kun sähköpostiin ei ole vastattu.
Comment[fr]=L'agent de rappel des messages suivis permet de se rappeler lorsqu'il n'y a pas eu de réponse à un courriel.
Comment[gl]=O Axente de lembranzas de seguimento permite lembrarlle cando non se respondeu a unha mensaxe de correo.
Comment[hu]=A Nyomkövető emlékeztető ügynök lehetővé teszi, hogy emlékeztesse önt, ha egy levél nem lett megválaszolva.
Comment[ia]=Follorwup Reminder Agent permitte te de memorar te quando un message de e-posta esseva sin responsa.
Comment[it]=L'agente per gli avvisi delle azioni da seguire permette di avvisarti quando un messaggio di posta non ha avuto una risposta.
Comment[kk]=Жауап беру туралы ескерту агенті эл.поштаға жауап берілмегеніңізді ескереді.
Comment[nb]=Agenten for påminnelse om oppfølging kan minne deg om at det ikke er sendt svar på en e-post.
Comment[nds]=De Antwoortnaricht-Anstoothölper stööt Di an, wenn Du op en Nettbreef noch nich antert hest.
Comment[nl]=Agent voor herinneren aan vervolgactie stelt u in staat om u te herinneren aan een nog niet beantwoord e-mailbericht.
Comment[pl]=Agent ponaglającego przypominania przypomina ci gdy nie odpowiedziano na wiadomość.
Comment[pt]=O Agente de Recordação de Seguimentos permite-lhe lembrar que um dado e-mail não foi respondido.
Comment[pt_BR]=O Acompanhamento do Agente de Lembretes permite lembrar-lhe quando um e-mail não foi respondido.
Comment[ru]=Агент напоминания о продолжении будет напоминать вам о письмах, на которые вы не ответили.
Comment[sk]=Agent pripomienky spracovania vám umožní upozorniť vás, keď e-mail nemá odpoveď.
Comment[sr]=Агент подсетника на одговор служи да вас подсети кад нисте одговорили на поруку
Comment[sr@ijekavian]=Агент подсетника на одговор служи да вас подсети кад нисте одговорили на поруку
Comment[sr@ijekavianlatin]=Agent podsetnika na odgovor služi da vas podseti kad niste odgovorili na poruku
Comment[sr@latin]=Agent podsetnika na odgovor služi da vas podseti kad niste odgovorili na poruku
Comment[sv]=Påminnelseuppföljningsmodulen gör det möjligt att få en påminnelse när ett brev inte besvarats.
Comment[tr]=Takip hatırlatma aracı, bir e-posta yanıtlanmadığında hatırlatılmanızı sağlar.
Comment[uk]=Агент нагадування про відповіді нагадуватиме вам про електронні листи, на які ви не дали відповіді.
Comment[x-test]=xxFollowup Reminder Agent allows to remind you when an email was not answered.xx
Comment[zh_TW]=
Type=AkonadiAgent
Exec=akonadi_followupreminder_agent
Icon=kmail
X-Akonadi-MimeTypes=message/rfc822
X-Akonadi-Capabilities=Unique,Autostart
X-Akonadi-Identifier=akonadi_followupreminder_agent
X-DocPath=akonadi_followupreminder_agent/index.html

View file

@ -0,0 +1,38 @@
/*
Copyright (c) 2014 Laurent Montel <montel@kde.org>
This library 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 2 of the License, or (at your
option) any later version.
This library 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 library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef FOLLOWUPREMINDER_EXPORT_H
#define FOLLOWUPREMINDER_EXPORT_H
#include <kdemacros.h>
#ifndef FOLLOWUPREMINDER_EXPORT
# if defined(KDEPIM_STATIC_LIBS)
/* No export/import for static libraries */
# define FOLLOWUPREMINDER_EXPORT
# elif defined(MAKE_FOLLOWUPREMINDER_LIB)
/* We are building this library */
# define FOLLOWUPREMINDER_EXPORT KDE_EXPORT
# else
/* We are using this library */
# define FOLLOWUPREMINDER_EXPORT KDE_IMPORT
# endif
#endif
#endif

View file

@ -0,0 +1,144 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderagent.h"
#include "followupremindermanager.h"
#include "followupreminderutil.h"
#include "followupreminderadaptor.h"
#include "followupreminderinfodialog.h"
#include "followupreminderagentsettings.h"
#include <KWindowSystem>
#include <KLocale>
#include <KMime/Message>
#include <Akonadi/Session>
#include <Akonadi/ChangeRecorder>
#include <Akonadi/ItemFetchScope>
#include <akonadi/dbusconnectionpool.h>
#include <Akonadi/CollectionFetchScope>
#include <QPointer>
#include <QDebug>
#include <QTimer>
FollowUpReminderAgent::FollowUpReminderAgent(const QString &id)
: Akonadi::AgentBase( id )
{
KGlobal::locale()->insertCatalog( QLatin1String("akonadi_followupreminder_agent") );
new FollowUpReminderAgentAdaptor(this);
Akonadi::DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/FollowUpReminder" ), this, QDBusConnection::ExportAdaptors );
Akonadi::DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.FollowUpReminder" ) );
mManager = new FollowUpReminderManager(this);
setNeedsNetwork(true);
changeRecorder()->setMimeTypeMonitored( KMime::Message::mimeType() );
changeRecorder()->itemFetchScope().setCacheOnly( true );
changeRecorder()->itemFetchScope().setFetchModificationTime( false );
changeRecorder()->fetchCollection( true );
changeRecorder()->setChangeRecordingEnabled( false );
changeRecorder()->ignoreSession( Akonadi::Session::defaultSession() );
changeRecorder()->collectionFetchScope().setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
changeRecorder()->setCollectionMonitored(Akonadi::Collection::root(), true);
if (FollowUpReminderAgentSettings::enabled()) {
mManager->load();
}
mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(reload()));
//Reload all each 24hours
mTimer->start(24*60*60*1000);
}
FollowUpReminderAgent::~FollowUpReminderAgent()
{
}
void FollowUpReminderAgent::setEnableAgent(bool enabled)
{
if (FollowUpReminderAgentSettings::self()->enabled() == enabled)
return;
FollowUpReminderAgentSettings::self()->setEnabled(enabled);
FollowUpReminderAgentSettings::self()->writeConfig();
if (enabled) {
mManager->load();
mTimer->start();
} else {
mTimer->stop();
}
}
bool FollowUpReminderAgent::enabledAgent() const
{
return FollowUpReminderAgentSettings::self()->enabled();
}
void FollowUpReminderAgent::showConfigureDialog(qlonglong windowId)
{
QPointer<FollowUpReminderInfoDialog> dialog = new FollowUpReminderInfoDialog();
dialog->load();
if (windowId) {
#ifndef Q_WS_WIN
KWindowSystem::setMainWindow( dialog, windowId );
#else
KWindowSystem::setMainWindow( dialog, (HWND)windowId );
#endif
}
if (dialog->exec()) {
const QList<qint32> lstRemoveItem = dialog->listRemoveId();
if (FollowUpReminder::FollowUpReminderUtil::removeFollowupReminderInfo(FollowUpReminder::FollowUpReminderUtil::defaultConfig(), lstRemoveItem)) {
mManager->load();
}
}
delete dialog;
}
void FollowUpReminderAgent::configure( WId windowId )
{
showConfigureDialog((qulonglong)windowId);
}
void FollowUpReminderAgent::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{
if (!enabledAgent())
return;
if ( item.mimeType() != KMime::Message::mimeType() ) {
kDebug() << "FollowUpReminderAgent::itemAdded called for a non-message item!";
return;
}
mManager->checkFollowUp(item, collection);
}
void FollowUpReminderAgent::reload()
{
if (enabledAgent()) {
mManager->load(true);
mTimer->start();
}
}
QString FollowUpReminderAgent::printDebugInfo()
{
return mManager->printDebugInfo();
}
AKONADI_AGENT_MAIN( FollowUpReminderAgent )

View file

@ -0,0 +1,49 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERAGENT_H
#define FOLLOWUPREMINDERAGENT_H
#include <akonadi/agentbase.h>
class FollowUpReminderManager;
class FollowUpReminderAgent : public Akonadi::AgentBase, public Akonadi::AgentBase::ObserverV3
{
Q_OBJECT
public:
explicit FollowUpReminderAgent(const QString &id);
~FollowUpReminderAgent();
void setEnableAgent(bool b);
bool enabledAgent() const;
void showConfigureDialog(qlonglong windowId = 0);
QString printDebugInfo();
public Q_SLOTS:
void configure( WId windowId );
void reload();
protected:
void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection);
private:
FollowUpReminderManager *mManager;
QTimer *mTimer;
};
#endif // FOLLOWUPREMINDERAGENT_H

View file

@ -0,0 +1,196 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderinfo.h"
#include <KConfigGroup>
using namespace FollowUpReminder;
FollowUpReminderInfo::FollowUpReminderInfo()
: mOriginalMessageItemId(-1),
mAnswerMessageItemId(-1),
mTodoId(-1),
mUniqueIdentifier(-1),
mAnswerWasReceived(false)
{
}
FollowUpReminderInfo::FollowUpReminderInfo(const KConfigGroup &config)
: mOriginalMessageItemId(-1),
mAnswerMessageItemId(-1),
mTodoId(-1),
mUniqueIdentifier(-1),
mAnswerWasReceived(false)
{
readConfig(config);
}
FollowUpReminderInfo::FollowUpReminderInfo(const FollowUpReminderInfo &info)
{
mFollowUpReminderDate = info.followUpReminderDate();
mOriginalMessageItemId = info.originalMessageItemId();
mMessageId = info.messageId();
mTo = info.to();
mSubject = info.subject();
mAnswerWasReceived = info.answerWasReceived();
mAnswerMessageItemId = info.answerMessageItemId();
mUniqueIdentifier = info.uniqueIdentifier();
mTodoId = info.todoId();
}
void FollowUpReminderInfo::readConfig(const KConfigGroup &config)
{
if (config.hasKey(QLatin1String("followUpReminderDate"))) {
mFollowUpReminderDate = QDate::fromString(config.readEntry("followUpReminderDate"), Qt::ISODate);
}
mOriginalMessageItemId = config.readEntry("itemId", -1);
mMessageId = config.readEntry("messageId", QString());
mTo = config.readEntry("to", QString());
mSubject = config.readEntry("subject", QString());
mAnswerWasReceived = config.readEntry("answerWasReceived", false);
mAnswerMessageItemId = config.readEntry("answerMessageItemId", -1);
mTodoId = config.readEntry("todoId", -1);
mUniqueIdentifier = config.readEntry("identifier", -1);
}
qint32 FollowUpReminderInfo::uniqueIdentifier() const
{
return mUniqueIdentifier;
}
void FollowUpReminderInfo::setUniqueIdentifier(const qint32 &uniqueIdentifier)
{
mUniqueIdentifier = uniqueIdentifier;
}
Akonadi::Item::Id FollowUpReminderInfo::answerMessageItemId() const
{
return mAnswerMessageItemId;
}
void FollowUpReminderInfo::setAnswerMessageItemId(const Akonadi::Item::Id &answerMessageId)
{
mAnswerMessageItemId = answerMessageId;
}
bool FollowUpReminderInfo::answerWasReceived() const
{
return mAnswerWasReceived;
}
void FollowUpReminderInfo::setAnswerWasReceived(bool answerWasReceived)
{
mAnswerWasReceived = answerWasReceived;
}
QString FollowUpReminderInfo::subject() const
{
return mSubject;
}
void FollowUpReminderInfo::setSubject(const QString &subject)
{
mSubject = subject;
}
void FollowUpReminderInfo::writeConfig(KConfigGroup &config, qint32 identifier )
{
if (mFollowUpReminderDate.isValid()) {
config.writeEntry("followUpReminderDate", mFollowUpReminderDate.toString(Qt::ISODate) );
}
setUniqueIdentifier(identifier);
config.writeEntry("messageId", mMessageId);
config.writeEntry("itemId", mOriginalMessageItemId);
config.writeEntry("to", mTo);
config.writeEntry("subject", mSubject);
config.writeEntry("answerWasReceived", mAnswerWasReceived);
config.writeEntry("answerMessageItemId", mAnswerMessageItemId);
config.writeEntry("todoId", mTodoId);
config.writeEntry("identifier", identifier);
config.sync();
}
Akonadi::Item::Id FollowUpReminderInfo::originalMessageItemId() const
{
return mOriginalMessageItemId;
}
void FollowUpReminderInfo::setOriginalMessageItemId(Akonadi::Item::Id value)
{
mOriginalMessageItemId = value;
}
Akonadi::Item::Id FollowUpReminderInfo::todoId() const
{
return mTodoId;
}
void FollowUpReminderInfo::setTodoId(Akonadi::Item::Id value)
{
mTodoId = value;
}
bool FollowUpReminderInfo::isValid() const
{
return (!mMessageId.isEmpty() &&
mFollowUpReminderDate.isValid() &&
!mTo.isEmpty());
}
QString FollowUpReminderInfo::messageId() const
{
return mMessageId;
}
void FollowUpReminderInfo::setMessageId(const QString &messageId)
{
mMessageId = messageId;
}
void FollowUpReminderInfo::setTo(const QString &to)
{
mTo = to;
}
QString FollowUpReminderInfo::to() const
{
return mTo;
}
QDate FollowUpReminderInfo::followUpReminderDate() const
{
return mFollowUpReminderDate;
}
void FollowUpReminderInfo::setFollowUpReminderDate(const QDate &followUpReminderDate)
{
mFollowUpReminderDate = followUpReminderDate;
}
bool FollowUpReminderInfo::operator==( const FollowUpReminderInfo& other ) const
{
return mOriginalMessageItemId == other.originalMessageItemId()
&& mMessageId == other.messageId()
&& mTo == other.to()
&& mFollowUpReminderDate == other.followUpReminderDate()
&& mSubject == other.subject()
&& mAnswerWasReceived == other.answerWasReceived()
&& mAnswerMessageItemId == other.answerMessageItemId()
&& mUniqueIdentifier == other.uniqueIdentifier()
&& mTodoId == other.todoId();
}

View file

@ -0,0 +1,83 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERINFO_H
#define FOLLOWUPREMINDERINFO_H
#include <Akonadi/Item>
#include <QDate>
#include "followupreminder_export.h"
class KConfigGroup;
namespace FollowUpReminder {
class FOLLOWUPREMINDER_EXPORT FollowUpReminderInfo
{
public:
FollowUpReminderInfo();
FollowUpReminderInfo(const KConfigGroup &config);
FollowUpReminderInfo(const FollowUpReminderInfo &info);
//Can be invalid.
Akonadi::Item::Id originalMessageItemId() const;
void setOriginalMessageItemId(Akonadi::Item::Id value);
Akonadi::Item::Id todoId() const;
void setTodoId(Akonadi::Item::Id value);
bool isValid() const;
QString messageId() const;
void setMessageId(const QString &messageId);
void setTo(const QString &to);
QString to() const;
QDate followUpReminderDate() const;
void setFollowUpReminderDate(const QDate &followUpReminderDate);
void writeConfig(KConfigGroup &config, qint32 identifier);
QString subject() const;
void setSubject(const QString &subject);
bool operator ==(const FollowUpReminderInfo &other) const;
bool answerWasReceived() const;
void setAnswerWasReceived(bool answerWasReceived);
Akonadi::Item::Id answerMessageItemId() const;
void setAnswerMessageItemId(const Akonadi::Item::Id &answerMessageItemId);
qint32 uniqueIdentifier() const;
void setUniqueIdentifier(const qint32 &uniqueIdentifier);
private:
void readConfig(const KConfigGroup &config);
Akonadi::Item::Id mOriginalMessageItemId;
Akonadi::Item::Id mAnswerMessageItemId;
Akonadi::Item::Id mTodoId;
QString mMessageId;
QDate mFollowUpReminderDate;
QString mTo;
QString mSubject;
qint32 mUniqueIdentifier;
bool mAnswerWasReceived;
};
}
#endif // FOLLOWUPREMINDERINFO_H

View file

@ -0,0 +1,116 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderinfodialog.h"
#include "followupreminderinfowidget.h"
#include "kdepim-version.h"
#include <KLocalizedString>
#include <KAboutData>
#include <KHelpMenu>
#include <KMenu>
#include <QTreeWidget>
#include <QHBoxLayout>
#include <QHeaderView>
FollowUpReminderInfoDialog::FollowUpReminderInfoDialog(QWidget *parent)
: KDialog(parent)
{
setCaption( i18n("Configure") );
setWindowIcon( KIcon( QLatin1String("kmail") ) );
setButtons( Help|Ok|Cancel );
QWidget *mainWidget = new QWidget( this );
setMainWidget(mainWidget);
QHBoxLayout *mainLayout = new QHBoxLayout( mainWidget );
mainLayout->setSpacing( KDialog::spacingHint() );
mainLayout->setMargin( KDialog::marginHint() );
connect(this, SIGNAL(okClicked()), SLOT(slotSave()));
mWidget = new FollowUpReminderInfoWidget;
mWidget->setObjectName(QLatin1String("FollowUpReminderInfoWidget"));
mainLayout->addWidget(mWidget);
readConfig();
mAboutData = new KAboutData(
QByteArray( "followupreminderagent" ),
QByteArray(),
ki18n( "Follow Up Reminder Agent" ),
QByteArray( KDEPIM_VERSION ),
ki18n( "Follow Up Mail." ),
KAboutData::License_GPL_V2,
ki18n( "Copyright (C) 2014 Laurent Montel" ) );
mAboutData->addAuthor( ki18n( "Laurent Montel" ),
ki18n( "Maintainer" ), "montel@kde.org" );
mAboutData->setProgramIconName( QLatin1String("kmail") );
mAboutData->setTranslator( ki18nc( "NAME OF TRANSLATORS", "Your names" ),
ki18nc( "EMAIL OF TRANSLATORS", "Your emails" ) );
KHelpMenu *helpMenu = new KHelpMenu(this, mAboutData, true);
//Initialize menu
KMenu *menu = helpMenu->menu();
helpMenu->action(KHelpMenu::menuAboutApp)->setIcon(KIcon(QLatin1String("kmail")));
setButtonMenu( Help, menu );
}
FollowUpReminderInfoDialog::~FollowUpReminderInfoDialog()
{
writeConfig();
}
void FollowUpReminderInfoDialog::readConfig()
{
KConfigGroup group( KGlobal::config(), "FollowUpReminderInfoDialog" );
const QSize sizeDialog = group.readEntry( "Size", QSize(800,600) );
if ( sizeDialog.isValid() ) {
resize( sizeDialog );
}
mWidget->restoreTreeWidgetHeader(group.readEntry("HeaderState",QByteArray()));
}
void FollowUpReminderInfoDialog::writeConfig()
{
KConfigGroup group( KGlobal::config(), "FollowUpReminderInfoDialog" );
group.writeEntry( "Size", size() );
mWidget->saveTreeWidgetHeader(group);
}
void FollowUpReminderInfoDialog::slotSave()
{
mWidget->save();
}
void FollowUpReminderInfoDialog::load()
{
mWidget->load();
}
void FollowUpReminderInfoDialog::setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &info)
{
mWidget->setInfo(info);
}
QList<qint32> FollowUpReminderInfoDialog::listRemoveId() const
{
return mWidget->listRemoveId();
}

View file

@ -0,0 +1,51 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERINFODIALOG_H
#define FOLLOWUPREMINDERINFODIALOG_H
#include <KDialog>
#include <QList>
class KAboutData;
class QTreeWidget;
class FollowUpReminderInfoWidget;
namespace FollowUpReminder {
class FollowUpReminderInfo;
}
class FollowUpReminderInfoDialog : public KDialog
{
Q_OBJECT
public:
explicit FollowUpReminderInfoDialog(QWidget *parent=0);
~FollowUpReminderInfoDialog();
void load();
void setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &info);
QList<qint32> listRemoveId() const;
private slots:
void slotSave();
private:
void readConfig();
void writeConfig();
FollowUpReminderInfoWidget *mWidget;
KAboutData *mAboutData;
};
#endif // FOLLOWUPREMINDERINFODIALOG_H

View file

@ -0,0 +1,229 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderinfowidget.h"
#include "followupreminderinfo.h"
#include "followupreminderutil.h"
#include "jobs/followupremindershowmessagejob.h"
#include <QTreeWidget>
#include <QHBoxLayout>
#include <QHeaderView>
#include <kicon.h>
#include <KGlobal>
#include <KLocale>
#include <kmenu.h>
#include <KLocalizedString>
// #define DEBUG_MESSAGE_ID
static QString followUpItemPattern = QLatin1String("FollowupReminderItem \\d+");
FollowUpReminderInfoItem::FollowUpReminderInfoItem(QTreeWidget *parent)
: QTreeWidgetItem(parent),
mInfo(0)
{
}
FollowUpReminderInfoItem::~FollowUpReminderInfoItem()
{
delete mInfo;
}
void FollowUpReminderInfoItem::setInfo(FollowUpReminder::FollowUpReminderInfo *info)
{
mInfo = info;
}
FollowUpReminder::FollowUpReminderInfo* FollowUpReminderInfoItem::info() const
{
return mInfo;
}
FollowUpReminderInfoWidget::FollowUpReminderInfoWidget(QWidget *parent)
: QWidget(parent),
mChanged(false)
{
setObjectName(QLatin1String("FollowUpReminderInfoWidget"));
QHBoxLayout *hbox = new QHBoxLayout;
mTreeWidget = new QTreeWidget;
mTreeWidget->setObjectName(QLatin1String("treewidget"));
QStringList headers;
headers << i18n("To")
<< i18n("Subject")
<< i18n("Dead Line")
<< i18n("Answer")
#ifdef DEBUG_MESSAGE_ID
<< QLatin1String("Message Id")
<< QLatin1String("Answer Message Id")
#endif
;
mTreeWidget->setHeaderLabels(headers);
mTreeWidget->setSortingEnabled(true);
mTreeWidget->setRootIsDecorated(false);
mTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
mTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(mTreeWidget, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(customContextMenuRequested(QPoint)));
hbox->addWidget(mTreeWidget);
setLayout(hbox);
}
FollowUpReminderInfoWidget::~FollowUpReminderInfoWidget()
{
}
void FollowUpReminderInfoWidget::setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &infoList)
{
mTreeWidget->clear();
Q_FOREACH(FollowUpReminder::FollowUpReminderInfo *info, infoList) {
if (info->isValid())
createOrUpdateItem(info);
}
}
void FollowUpReminderInfoWidget::load()
{
KSharedConfig::Ptr config = KGlobal::config();
const QStringList filterGroups =config->groupList().filter( QRegExp( followUpItemPattern ) );
const int numberOfItem = filterGroups.count();
for (int i = 0 ; i < numberOfItem; ++i) {
KConfigGroup group = config->group(filterGroups.at(i));
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo(group);
if (info->isValid())
createOrUpdateItem(info);
else
delete info;
}
}
QList<qint32> FollowUpReminderInfoWidget::listRemoveId() const
{
return mListRemoveId;
}
void FollowUpReminderInfoWidget::createOrUpdateItem(FollowUpReminder::FollowUpReminderInfo *info, FollowUpReminderInfoItem *item)
{
if (!item) {
item = new FollowUpReminderInfoItem(mTreeWidget);
}
item->setInfo(info);
item->setText(To, info->to());
item->setText(Subject, info->subject());
const QString date = KGlobal::locale()->formatDate( info->followUpReminderDate(), KLocale::LongDate );
item->setText(DeadLine, date);
const bool answerWasReceived = info->answerWasReceived();
item->setText(AnswerWasReceived, answerWasReceived ? i18n("Received") : i18n("On hold"));
item->setData(0, AnswerItemFound, answerWasReceived);
if (answerWasReceived) {
item->setBackgroundColor(DeadLine, Qt::green);
} else {
if (info->followUpReminderDate() < QDate::currentDate()) {
item->setBackgroundColor(DeadLine, Qt::red);
}
}
#ifdef DEBUG_MESSAGE_ID
item->setText(MessageId, QString::number(info->originalMessageItemId()));
item->setText(AnswerMessageId, QString::number(info->answerMessageItemId()));
#endif
}
void FollowUpReminderInfoWidget::save()
{
if (!mChanged)
return;
KSharedConfig::Ptr config = KGlobal::config();
// first, delete all filter groups:
const QStringList filterGroups =config->groupList().filter( QRegExp( followUpItemPattern ) );
foreach ( const QString &group, filterGroups ) {
config->deleteGroup( group );
}
const int numberOfItem(mTreeWidget->topLevelItemCount());
int i = 0;
for (; i < numberOfItem; ++i) {
FollowUpReminderInfoItem *mailItem = static_cast<FollowUpReminderInfoItem *>(mTreeWidget->topLevelItem(i));
if (mailItem->info()) {
KConfigGroup group = config->group(FollowUpReminder::FollowUpReminderUtil::followUpReminderPattern.arg(i));
mailItem->info()->writeConfig(group, i);
}
}
++i;
KConfigGroup general = config->group(QLatin1String("General"));
general.writeEntry("Number", i);
config->sync();
config->reparseConfiguration();
}
void FollowUpReminderInfoWidget::customContextMenuRequested(const QPoint &pos)
{
Q_UNUSED(pos);
const QList<QTreeWidgetItem *> listItems = mTreeWidget->selectedItems();
if ( !listItems.isEmpty() ) {
FollowUpReminderInfoItem *mailItem = static_cast<FollowUpReminderInfoItem *>(listItems.at(0));
KMenu menu;
QAction *showMessage = 0;
if (mailItem && mailItem->data(0, AnswerItemFound).toBool()) {
showMessage = menu.addAction(i18n("Show Message"));
}
QAction *deleteItem = menu.addAction(KIcon(QLatin1String("edit-delete")), i18n("Delete"));
QAction *result = menu.exec(QCursor::pos());
if (result) {
if (result == showMessage) {
openShowMessage(mailItem->info()->answerMessageItemId());
} else if (result == deleteItem) {
removeItem(mailItem);
}
}
}
}
void FollowUpReminderInfoWidget::openShowMessage(Akonadi::Item::Id id)
{
FollowUpReminderShowMessageJob *job = new FollowUpReminderShowMessageJob(id);
job->start();
}
void FollowUpReminderInfoWidget::removeItem(FollowUpReminderInfoItem *mailItem)
{
if (mailItem) {
mListRemoveId << mailItem->info()->uniqueIdentifier();
delete mailItem;
mChanged = true;
} else {
qDebug() << "Not item selected";
}
}
void FollowUpReminderInfoWidget::restoreTreeWidgetHeader(const QByteArray &data)
{
mTreeWidget->header()->restoreState(data);
}
void FollowUpReminderInfoWidget::saveTreeWidgetHeader(KConfigGroup &group)
{
group.writeEntry( "HeaderState", mTreeWidget->header()->saveState() );
}

View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERINFOWIDGET_H
#define FOLLOWUPREMINDERINFOWIDGET_H
#include <QWidget>
#include <KConfigGroup>
#include <QTreeWidgetItem>
#include <Akonadi/Item>
class QTreeWidget;
namespace FollowUpReminder {
class FollowUpReminderInfo;
}
class FollowUpReminderInfoItem : public QTreeWidgetItem
{
public:
explicit FollowUpReminderInfoItem(QTreeWidget *parent = 0);
~FollowUpReminderInfoItem();
void setInfo(FollowUpReminder::FollowUpReminderInfo *info);
FollowUpReminder::FollowUpReminderInfo *info() const;
private:
FollowUpReminder::FollowUpReminderInfo *mInfo;
};
class FollowUpReminderInfoWidget : public QWidget
{
Q_OBJECT
public:
explicit FollowUpReminderInfoWidget(QWidget *parent=0);
~FollowUpReminderInfoWidget();
void restoreTreeWidgetHeader(const QByteArray &data);
void saveTreeWidgetHeader(KConfigGroup &group);
void setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &infoList);
void save();
void load();
QList<qint32> listRemoveId() const;
private slots:
void customContextMenuRequested(const QPoint &pos);
private:
void createOrUpdateItem(FollowUpReminder::FollowUpReminderInfo *info, FollowUpReminderInfoItem *item = 0);
void removeItem(FollowUpReminderInfoItem *mailItem);
void openShowMessage(Akonadi::Item::Id id);
enum ItemData {
AnswerItemId = Qt::UserRole + 1,
AnswerItemFound = Qt::UserRole + 2
};
enum FollowUpReminderColumn {
To = 0,
Subject,
DeadLine,
AnswerWasReceived,
MessageId,
AnswerMessageId
};
QList<qint32> mListRemoveId;
QTreeWidget *mTreeWidget;
bool mChanged;
};
#endif // FOLLOWUPREMINDERINFOWIDGET_H

View file

@ -0,0 +1,177 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupremindermanager.h"
#include "followupreminderinfo.h"
#include "followupreminderutil.h"
#include "followupremindernoanswerdialog.h"
#include "jobs/followupreminderjob.h"
#include "jobs/followupreminderfinishtaskjob.h"
#include <Akonadi/KMime/SpecialMailCollections>
#include <KGlobal>
#include <KConfigGroup>
#include <KConfig>
#include <knotification.h>
#include <KLocalizedString>
using namespace FollowUpReminder;
FollowUpReminderManager::FollowUpReminderManager(QObject *parent)
: QObject(parent),
mInitialize(false)
{
mConfig = KGlobal::config();
}
FollowUpReminderManager::~FollowUpReminderManager()
{
qDeleteAll(mFollowUpReminderInfoList);
mFollowUpReminderInfoList.clear();
}
void FollowUpReminderManager::load(bool forceReloadConfig)
{
if (forceReloadConfig)
mConfig->reparseConfiguration();
const QStringList itemList = mConfig->groupList().filter( QRegExp( QLatin1String("FollowupReminderItem \\d+") ) );
const int numberOfItems = itemList.count();
QList<FollowUpReminder::FollowUpReminderInfo*> noAnswerList;
for (int i = 0 ; i < numberOfItems; ++i) {
KConfigGroup group = mConfig->group(itemList.at(i));
FollowUpReminderInfo *info = new FollowUpReminderInfo(group);
if (info->isValid()) {
if (!info->answerWasReceived()) {
mFollowUpReminderInfoList.append(info);
if (!mInitialize) {
FollowUpReminderInfo *noAnswerInfo = new FollowUpReminderInfo(*info);
noAnswerList.append(noAnswerInfo);
}
}
} else {
delete info;
}
}
if (!noAnswerList.isEmpty()) {
mInitialize = true;
if (!mNoAnswerDialog.data()) {
mNoAnswerDialog = new FollowUpReminderNoAnswerDialog;
}
mNoAnswerDialog->setInfo(noAnswerList);
mNoAnswerDialog->show();
}
}
void FollowUpReminderManager::checkFollowUp(const Akonadi::Item &item, const Akonadi::Collection &col)
{
if (mFollowUpReminderInfoList.isEmpty()) {
return;
}
//If we move to trash directly => exclude it.
Akonadi::SpecialMailCollections::Type type = Akonadi::SpecialMailCollections::self()->specialCollectionType(col);
if (type == Akonadi::SpecialMailCollections::Trash)
return;
//Exclude outbox too
if (type == Akonadi::SpecialMailCollections::Outbox)
return;
if (type == Akonadi::SpecialMailCollections::Drafts)
return;
if (type == Akonadi::SpecialMailCollections::Templates)
return;
if (type == Akonadi::SpecialMailCollections::SentMail)
return;
FollowUpReminderJob *job = new FollowUpReminderJob(this);
connect(job, SIGNAL(finished(QString,Akonadi::Item::Id)), SLOT(slotCheckFollowUpFinished(QString,Akonadi::Item::Id)));
job->setItem(item);
job->start();
}
void FollowUpReminderManager::slotCheckFollowUpFinished(const QString &messageId,Akonadi::Item::Id id)
{
Q_FOREACH(FollowUpReminderInfo* info, mFollowUpReminderInfoList) {
if (info->messageId() == messageId) {
info->setAnswerMessageItemId(id);
info->setAnswerWasReceived(true);
answerReceived(info->to());
if (info->todoId() != -1) {
FollowUpReminderFinishTaskJob *job = new FollowUpReminderFinishTaskJob(info->todoId(), this);
connect(job, SIGNAL(finishTaskDone()), this, SLOT(slotFinishTaskDone()));
connect(job, SIGNAL(finishTaskFailed()), this, SLOT(slotFinishTaskFailed()));
job->start();
}
//Save item
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(FollowUpReminder::FollowUpReminderUtil::defaultConfig(), info, true);
break;
}
}
}
void FollowUpReminderManager::slotFinishTaskDone()
{
//TODO
}
void FollowUpReminderManager::slotFinishTaskFailed()
{
//TODO
}
void FollowUpReminderManager::answerReceived(const QString &from)
{
const QPixmap pixmap = KIcon( QLatin1String("kmail") ).pixmap( KIconLoader::SizeSmall, KIconLoader::SizeSmall );
KNotification::event( QLatin1String("mailreceived"),
i18n("Answer from %1 received", from),
pixmap,
0,
KNotification::CloseOnTimeout,
KGlobal::mainComponent());
}
QString FollowUpReminderManager::printDebugInfo()
{
QString infoStr;
if (mFollowUpReminderInfoList.isEmpty()) {
infoStr = QLatin1String("No mail");
} else {
Q_FOREACH (FollowUpReminder::FollowUpReminderInfo *info, mFollowUpReminderInfoList) {
if (!infoStr.isEmpty())
infoStr += QLatin1Char('\n');
infoStr += infoToStr(info);
}
}
return infoStr;
}
QString FollowUpReminderManager::infoToStr(FollowUpReminder::FollowUpReminderInfo *info)
{
QString infoStr;
infoStr = QLatin1String("****************************************");
infoStr += QString::fromLatin1("Akonadi Item id :%1\n").arg(info->originalMessageItemId());
infoStr += QString::fromLatin1("MessageId :%1\n").arg(info->messageId());
infoStr += QString::fromLatin1("Subject :%1\n").arg(info->subject());
infoStr += QString::fromLatin1("To :%1\n").arg(info->to());
infoStr += QString::fromLatin1("Dead Line :%1\n").arg(info->followUpReminderDate().toString());
infoStr += QString::fromLatin1("Answer received :%1\n").arg(info->answerWasReceived() ? QLatin1String("true") : QLatin1String("false") );
infoStr += QLatin1String("****************************************\n");
return infoStr;
}

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERMANAGER_H
#define FOLLOWUPREMINDERMANAGER_H
#include <QObject>
#include <KSharedConfig>
#include <Akonadi/Item>
#include <QPointer>
namespace FollowUpReminder {
class FollowUpReminderInfo;
}
class FollowUpReminderNoAnswerDialog;
class FollowUpReminderManager : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderManager(QObject *parent = 0);
~FollowUpReminderManager();
void load(bool forceReloadConfig = false);
void checkFollowUp(const Akonadi::Item &item, const Akonadi::Collection &col);
QString printDebugInfo();
private slots:
void slotCheckFollowUpFinished(const QString &messageId, Akonadi::Item::Id id);
void slotFinishTaskDone();
void slotFinishTaskFailed();
private:
void answerReceived(const QString &from);
QString infoToStr(FollowUpReminder::FollowUpReminderInfo *info);
KSharedConfig::Ptr mConfig;
QList<FollowUpReminder::FollowUpReminderInfo*> mFollowUpReminderInfoList;
QPointer<FollowUpReminderNoAnswerDialog> mNoAnswerDialog;
bool mInitialize;
};
#endif // FOLLOWUPREMINDERMANAGER_H

View file

@ -0,0 +1,76 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupremindernoanswerdialog.h"
#include "followupreminderinfo.h"
#include "followupreminderinfowidget.h"
#include <KLocalizedString>
#include <KMenu>
#include <KSharedConfig>
#include <QHBoxLayout>
#include <QTreeWidget>
#include <QHeaderView>
#include <QLabel>
FollowUpReminderNoAnswerDialog::FollowUpReminderNoAnswerDialog(QWidget *parent)
: KDialog(parent)
{
setCaption( i18n("Follow Up Mail") );
setWindowIcon( KIcon( QLatin1String("kmail") ) );
setButtons( Ok|Cancel );
setAttribute(Qt::WA_DeleteOnClose);
QWidget *w = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout(w);
QLabel *lab = new QLabel(i18n("You still wait an answer about this mail:"));
vbox->addWidget(lab);
mWidget = new FollowUpReminderInfoWidget;
mWidget->setObjectName(QLatin1String("FollowUpReminderInfoWidget"));
vbox->addWidget(mWidget);
setMainWidget(w);
readConfig();
}
FollowUpReminderNoAnswerDialog::~FollowUpReminderNoAnswerDialog()
{
writeConfig();
}
void FollowUpReminderNoAnswerDialog::setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &info)
{
mWidget->setInfo(info);
}
void FollowUpReminderNoAnswerDialog::readConfig()
{
KConfigGroup group( KGlobal::config(), "FollowUpReminderNoAnswerDialog" );
const QSize sizeDialog = group.readEntry( "Size", QSize(800,600) );
if ( sizeDialog.isValid() ) {
resize( sizeDialog );
}
mWidget->restoreTreeWidgetHeader(group.readEntry("HeaderState",QByteArray()));
}
void FollowUpReminderNoAnswerDialog::writeConfig()
{
KConfigGroup group( KGlobal::config(), "FollowUpReminderNoAnswerDialog" );
group.writeEntry( "Size", size() );
mWidget->saveTreeWidgetHeader(group);
}

View file

@ -0,0 +1,41 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERNOANSWERDIALOG_H
#define FOLLOWUPREMINDERNOANSWERDIALOG_H
#include <KDialog>
namespace FollowUpReminder {
class FollowUpReminderInfo;
}
class FollowUpReminderInfoWidget;
class FollowUpReminderNoAnswerDialog : public KDialog
{
Q_OBJECT
public:
explicit FollowUpReminderNoAnswerDialog(QWidget *parent = 0);
~FollowUpReminderNoAnswerDialog();
void setInfo(const QList<FollowUpReminder::FollowUpReminderInfo *> &info);
private:
void readConfig();
void writeConfig();
FollowUpReminderInfoWidget *mWidget;
};
#endif // FOLLOWUPREMINDERNOANSWERDIALOG_H

View file

@ -0,0 +1,117 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderutil.h"
#include "followupreminderinfo.h"
#include <QDBusInterface>
#include "followupreminderagentsettings.h"
bool FollowUpReminder::FollowUpReminderUtil::followupReminderAgentWasRegistered()
{
QDBusInterface interface( QLatin1String("org.freedesktop.Akonadi.Agent.akonadi_followupreminder_agent"), QLatin1String("/FollowUpReminder") );
return interface.isValid();
}
bool FollowUpReminder::FollowUpReminderUtil::followupReminderAgentEnabled()
{
return FollowUpReminderAgentSettings::self()->enabled();
}
void FollowUpReminder::FollowUpReminderUtil::reload()
{
QDBusInterface interface( QLatin1String("org.freedesktop.Akonadi.Agent.akonadi_followupreminder_agent"), QLatin1String("/FollowUpReminder") );
if (interface.isValid()) {
interface.call(QLatin1String("reload"));
}
}
void FollowUpReminder::FollowUpReminderUtil::forceReparseConfiguration()
{
FollowUpReminderAgentSettings::self()->writeConfig();
FollowUpReminderAgentSettings::self()->config()->reparseConfiguration();
}
KSharedConfig::Ptr FollowUpReminder::FollowUpReminderUtil::defaultConfig()
{
return KSharedConfig::openConfig( QLatin1String("akonadi_followupreminder_agentrc") );
}
void FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(KSharedConfig::Ptr config, FollowUpReminder::FollowUpReminderInfo *info, bool forceReload)
{
if (!info || !info->isValid())
return;
KConfigGroup general = config->group(QLatin1String("General"));
int value = general.readEntry("Number", 0);
int identifier = info->uniqueIdentifier();
if (identifier == -1) {
identifier = value;
}
++value;
const QString groupName = FollowUpReminder::FollowUpReminderUtil::followUpReminderPattern.arg(identifier);
// first, delete all filter groups:
const QStringList filterGroups = config->groupList();
foreach ( const QString &group, filterGroups ) {
if (group == groupName) {
config->deleteGroup( group );
}
}
KConfigGroup group = config->group(groupName);
info->writeConfig(group, identifier);
general.writeEntry("Number", value);
config->sync();
config->reparseConfiguration();
if (forceReload)
reload();
}
bool FollowUpReminder::FollowUpReminderUtil::removeFollowupReminderInfo(KSharedConfig::Ptr config, const QList<qint32> &listRemove, bool forceReload)
{
if (listRemove.isEmpty()) {
return false;
}
bool needSaveConfig = false;
KConfigGroup general = config->group(QLatin1String("General"));
int value = general.readEntry("Number", 0);
Q_FOREACH(qint32 identifier, listRemove) {
const QString groupName = FollowUpReminder::FollowUpReminderUtil::followUpReminderPattern.arg(identifier);
const QStringList filterGroups = config->groupList();
foreach ( const QString &group, filterGroups ) {
if (group == groupName) {
config->deleteGroup( group );
--value;
needSaveConfig = true;
}
}
}
if (needSaveConfig) {
general.writeEntry("Number", value);
config->sync();
config->reparseConfiguration();
if (forceReload)
reload();
}
return needSaveConfig;
}

View file

@ -0,0 +1,42 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERUTIL_H
#define FOLLOWUPREMINDERUTIL_H
#include "followupreminder_export.h"
#include <KSharedConfig>
namespace FollowUpReminder {
class FollowUpReminderInfo;
namespace FollowUpReminderUtil {
FOLLOWUPREMINDER_EXPORT bool followupReminderAgentWasRegistered();
FOLLOWUPREMINDER_EXPORT bool followupReminderAgentEnabled();
FOLLOWUPREMINDER_EXPORT void reload();
FOLLOWUPREMINDER_EXPORT void forceReparseConfiguration();
FOLLOWUPREMINDER_EXPORT KSharedConfig::Ptr defaultConfig();
FOLLOWUPREMINDER_EXPORT void writeFollowupReminderInfo(KSharedConfig::Ptr config, FollowUpReminder::FollowUpReminderInfo *info, bool forceReload);
FOLLOWUPREMINDER_EXPORT bool removeFollowupReminderInfo(KSharedConfig::Ptr config, const QList<qint32> &listRemove, bool forceReload = false);
static QString followUpReminderPattern = QLatin1String("FollowupReminderItem %1");
}
}
#endif // FOLLOWUPREMINDERUTIL_H

View file

@ -0,0 +1,99 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderfinishtaskjob.h"
#include "../followupreminderinfo.h"
#include <Akonadi/Item>
#include <Akonadi/ItemFetchJob>
#include <Akonadi/ItemModifyJob>
#include <QDebug>
#include <KCalCore/Todo>
FollowUpReminderFinishTaskJob::FollowUpReminderFinishTaskJob(Akonadi::Item::Id id, QObject *parent)
: QObject(parent),
mTodoId(id)
{
}
FollowUpReminderFinishTaskJob::~FollowUpReminderFinishTaskJob()
{
}
void FollowUpReminderFinishTaskJob::start()
{
if (mTodoId != -1) {
closeTodo();
} else {
Q_EMIT finishTaskFailed();
deleteLater();
}
}
void FollowUpReminderFinishTaskJob::closeTodo()
{
Akonadi::Item item(mTodoId);
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item, this );
connect( job, SIGNAL(result(KJob*)), SLOT(slotItemFetchJobDone(KJob*)) );
}
void FollowUpReminderFinishTaskJob::slotItemFetchJobDone(KJob *job)
{
if ( job->error() ) {
qWarning() << job->errorString();
Q_EMIT finishTaskFailed();
deleteLater();
return;
}
const Akonadi::Item::List lst = qobject_cast<Akonadi::ItemFetchJob*>( job )->items();
if (lst.count() == 1) {
const Akonadi::Item item = lst.first();
if (!item.hasPayload<KCalCore::Todo::Ptr>()) {
qDebug()<<" item is not a todo.";
Q_EMIT finishTaskFailed();
deleteLater();
return;
}
KCalCore::Todo::Ptr todo = item.payload<KCalCore::Todo::Ptr>();
todo->setCompleted(true);
Akonadi::Item updateItem = item;
updateItem.setPayload<KCalCore::Todo::Ptr>( todo );
Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob( updateItem );
connect( job, SIGNAL(result(KJob*)), SLOT(slotItemModifiedResult(KJob*)) );
} else {
qWarning()<<" Found item different from 1: "<<lst.count();
Q_EMIT finishTaskFailed();
deleteLater();
return;
}
}
void FollowUpReminderFinishTaskJob::slotItemModifiedResult(KJob *job)
{
if ( job->error() ) {
qWarning() << job->errorString();
Q_EMIT finishTaskFailed();
} else {
Q_EMIT finishTaskDone();
}
deleteLater();
}

View file

@ -0,0 +1,49 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERFINISHTASKJOB_H
#define FOLLOWUPREMINDERFINISHTASKJOB_H
#include <QObject>
#include <Akonadi/Item>
class KJob;
namespace FollowUpReminder {
class FollowUpReminderInfo;
}
class FollowUpReminderFinishTaskJob : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderFinishTaskJob(Akonadi::Item::Id id, QObject *parent = 0);
~FollowUpReminderFinishTaskJob();
void start();
Q_SIGNALS:
void finishTaskDone();
void finishTaskFailed();
private slots:
void slotItemFetchJobDone(KJob *job);
void slotItemModifiedResult(KJob *job);
private:
void closeTodo();
Akonadi::Item::Id mTodoId;
};
#endif // FOLLOWUPREMINDERFINISHTASKJOB_H

View file

@ -0,0 +1,88 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderjob.h"
#include <Akonadi/ItemFetchJob>
#include <Akonadi/ItemFetchScope>
#include <Akonadi/KMime/MessageParts>
#include <KMime/Message>
#include <KDebug>
FollowUpReminderJob::FollowUpReminderJob(QObject *parent)
: QObject(parent)
{
}
FollowUpReminderJob::~FollowUpReminderJob()
{
}
void FollowUpReminderJob::start()
{
if (!mItem.isValid()) {
qDebug()<<" item is not valid";
deleteLater();
return;
}
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mItem);
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
connect( job, SIGNAL(result(KJob*)), SLOT(slotItemFetchJobDone(KJob*)) );
}
void FollowUpReminderJob::setItem(const Akonadi::Item &item)
{
mItem = item;
}
void FollowUpReminderJob::slotItemFetchJobDone(KJob* job)
{
if ( job->error() ) {
kError() << "Error while fetching item. " << job->error() << job->errorString();
deleteLater();
return;
}
const Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
const Akonadi::Item::List items = fetchJob->items();
if ( items.isEmpty() ) {
kError() << "Error while fetching item: item not found";
deleteLater();
return;
}
const Akonadi::Item item = items.at(0);
if ( !item.hasPayload<KMime::Message::Ptr>() ) {
kError() << "Item has not payload";
deleteLater();
return;
}
const KMime::Message::Ptr msg = item.payload<KMime::Message::Ptr>();
if (msg) {
KMime::Headers::InReplyTo *replyTo = msg->inReplyTo(false);
if (replyTo) {
const QString replyToIdStr = replyTo->asUnicodeString();
Q_EMIT finished(replyToIdStr, item.id());
}
}
deleteLater();
}

View file

@ -0,0 +1,46 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERJOB_H
#define FOLLOWUPREMINDERJOB_H
#include <QObject>
#include <Akonadi/Item>
class FollowUpReminderJob : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderJob(QObject *parent=0);
~FollowUpReminderJob();
void setItem(const Akonadi::Item &item);
void start();
Q_SIGNALS:
void finished(const QString &messageId, Akonadi::Item::Id id);
private slots:
void slotItemFetchJobDone(KJob *job);
private:
Akonadi::Item mItem;
};
#endif // FOLLOWUPREMINDERJOB_H

View file

@ -0,0 +1,56 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupremindershowmessagejob.h"
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusConnectionInterface>
#include <ktoolinvocation.h>
FollowUpReminderShowMessageJob::FollowUpReminderShowMessageJob(Akonadi::Item::Id id, QObject *parent)
: QObject(parent),
mId(id)
{
}
FollowUpReminderShowMessageJob::~FollowUpReminderShowMessageJob()
{
}
void FollowUpReminderShowMessageJob::start()
{
if (mId < 0) {
qDebug()<<" value < 0";
deleteLater();
return;
}
const QString kmailInterface = QLatin1String("org.kde.kmail");
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kmailInterface)) {
// Program is not already running, so start it
QString errmsg;
if (KToolInvocation::startServiceByDesktopName(QLatin1String("kmail2"), QString(), &errmsg)) {
qDebug()<<" Can not start kmail"<<errmsg;
deleteLater();
return;
}
}
QDBusInterface kmail(kmailInterface, QLatin1String("/KMail"), QLatin1String("org.kde.kmail.kmail"));
kmail.call(QLatin1String("showMail"), mId);
deleteLater();
}

View file

@ -0,0 +1,38 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERSHOWMESSAGEJOB_H
#define FOLLOWUPREMINDERSHOWMESSAGEJOB_H
#include <QObject>
#include <Akonadi/Item>
class FollowUpReminderShowMessageJob : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderShowMessageJob(Akonadi::Item::Id id, QObject *parent=0);
~FollowUpReminderShowMessageJob();
void start();
private:
Akonadi::Item::Id mId;
};
#endif // FOLLOWUPREMINDERSHOWMESSAGEJOB_H

View file

@ -0,0 +1,18 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.Akonadi.FollowUpReminderAgent">
<method name="showConfigureDialog" >
<arg direction="in" type="x" name="windowId" />
</method>
<method name="setEnableAgent" >
<arg type="b" direction="in"/>
</method>
<method name="enabledAgent" >
<arg type="b" direction="out"/>
</method>
<method name="printDebugInfo" >
<arg type="s" direction="out"/>
</method>
<method name="reload" />
</interface>
</node>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="akonadi_followupreminder_agentrc" />
<group name="General">
<entry name="enabled" key="enabled" type="Bool">
<default>true</default>
</entry>
</group>
</kcfg>

View file

@ -0,0 +1,8 @@
# Code generation options for kconfig_compiler
File=followupreminderagentsettings.kcfg
ClassName=FollowUpReminderAgentSettings
Singleton=true
Mutators=true
Visibility=FOLLOWUPREMINDER_EXPORT
IncludeFiles=followupreminder_export.h

View file

@ -0,0 +1,18 @@
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
remove_definitions( -DQT_NO_CAST_FROM_BYTEARRAY )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. )
# Convenience macro to add unit tests.
macro( followupreminder_agent _source )
set( _test ${_source} ../followupreminderinfodialog.cpp ../followupreminderinfowidget.cpp ../jobs/followupremindershowmessagejob.cpp ../followupremindernoanswerdialog.cpp)
get_filename_component( _name ${_source} NAME_WE )
kde4_add_unit_test( ${_name} TESTNAME followupreminder-${_name} ${_test} )
target_link_libraries( ${_name} ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} followupreminder)
endmacro()
followupreminder_agent(followupreminderinfotest.cpp)
followupreminder_agent(followupreminderinfodialogtest.cpp)
followupreminder_agent(followupremindernoanswerdialogtest.cpp)
followupreminder_agent(followupreminderconfigtest.cpp)

View file

@ -0,0 +1,244 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderconfigtest.h"
#include "../followupreminderutil.h"
#include "../followupreminderinfo.h"
#include <qtest_kde.h>
#include <KSharedConfig>
FollowUpReminderConfigTest::FollowUpReminderConfigTest(QObject *parent)
: QObject(parent)
{
}
FollowUpReminderConfigTest::~FollowUpReminderConfigTest()
{
}
void FollowUpReminderConfigTest::init()
{
mConfig = KSharedConfig::openConfig(QLatin1String("test-followupreminder.rc"));
mFollowupRegExpFilter = QRegExp( QLatin1String("FollowupReminderItem \\d+") );
cleanup();
}
void FollowUpReminderConfigTest::cleanup()
{
const QStringList filterGroups = mConfig->groupList();
foreach ( const QString &group, filterGroups ) {
mConfig->deleteGroup( group );
}
mConfig->sync();
mConfig->reparseConfiguration();
}
void FollowUpReminderConfigTest::cleanupTestCase()
{
//Make sure to clean config
cleanup();
}
void FollowUpReminderConfigTest::shouldConfigBeEmpty()
{
const QStringList filterGroups = mConfig->groupList();
QCOMPARE(filterGroups.isEmpty(), true);
}
void FollowUpReminderConfigTest::shouldAddAnItem()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
const QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.isEmpty(), false);
QCOMPARE(itemList.count(), 1);
QCOMPARE(mConfig->hasGroup(QLatin1String("General")), true);
}
void FollowUpReminderConfigTest::shouldNotAddAnInvalidItem()
{
FollowUpReminder::FollowUpReminderInfo info;
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
const QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.isEmpty(), true);
}
void FollowUpReminderConfigTest::shouldReplaceItem()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
qint32 uniq = 42;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 1);
info.setTo(QLatin1String("kmail.org"));
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 1);
}
void FollowUpReminderConfigTest::shouldAddSeveralItem()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
qint32 uniq = 42;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 1);
info.setTo(QLatin1String("kmail.org"));
uniq = 43;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 2);
uniq = 44;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 3);
//Replace It
info.setUniqueIdentifier(uniq);
info.setTo(QLatin1String("kontact.org"));
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 3);
// Add item without uniqIdentifier
FollowUpReminder::FollowUpReminderInfo infoNotHaveUniq;
infoNotHaveUniq.setMessageId(QLatin1String("foo"));
infoNotHaveUniq.setFollowUpReminderDate(QDate(date));
infoNotHaveUniq.setTo(to);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &infoNotHaveUniq, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 4);
QCOMPARE(infoNotHaveUniq.uniqueIdentifier(), 4);
}
void FollowUpReminderConfigTest::shouldRemoveItems()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
qint32 uniq = 42;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 1);
info.setTo(QLatin1String("kmail.org"));
uniq = 43;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
uniq = 44;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
// Add item without uniqIdentifier
FollowUpReminder::FollowUpReminderInfo infoNotHaveUniq;
infoNotHaveUniq.setMessageId(QLatin1String("foo"));
infoNotHaveUniq.setFollowUpReminderDate(QDate(date));
infoNotHaveUniq.setTo(to);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &infoNotHaveUniq, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 4);
QCOMPARE(infoNotHaveUniq.uniqueIdentifier(), 3);
QList<qint32> listRemove;
listRemove<<43<<42;
const bool elementRemoved = FollowUpReminder::FollowUpReminderUtil::removeFollowupReminderInfo(mConfig, listRemove);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
QCOMPARE(itemList.count(), 2);
QVERIFY(elementRemoved);
}
void FollowUpReminderConfigTest::shouldNotRemoveItemWhenListIsEmpty()
{
QList<qint32> listRemove;
const bool elementRemoved = FollowUpReminder::FollowUpReminderUtil::removeFollowupReminderInfo(mConfig, listRemove);
QVERIFY(!elementRemoved);
}
void FollowUpReminderConfigTest::shouldNotRemoveItemWhenItemDoesntExist()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
qint32 uniq = 42;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
QStringList itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
info.setTo(QLatin1String("kmail.org"));
uniq = 43;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
itemList = mConfig->groupList().filter( mFollowupRegExpFilter );
uniq = 44;
info.setUniqueIdentifier(uniq);
FollowUpReminder::FollowUpReminderUtil::writeFollowupReminderInfo(mConfig, &info, false);
QList<qint32> listRemove;
listRemove << 55 << 75;
const bool elementRemoved = FollowUpReminder::FollowUpReminderUtil::removeFollowupReminderInfo(mConfig, listRemove);
QVERIFY(!elementRemoved);
}
QTEST_KDEMAIN(FollowUpReminderConfigTest, NoGUI)

View file

@ -0,0 +1,54 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERCONFIGTEST_H
#define FOLLOWUPREMINDERCONFIGTEST_H
#include <QObject>
#include <QRegExp>
#include <KSharedConfig>
class FollowUpReminderConfigTest : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderConfigTest(QObject *parent=0);
~FollowUpReminderConfigTest();
private Q_SLOTS:
void init();
void cleanup();
void cleanupTestCase();
void shouldConfigBeEmpty();
void shouldAddAnItem();
void shouldNotAddAnInvalidItem();
void shouldReplaceItem();
void shouldAddSeveralItem();
void shouldRemoveItems();
void shouldNotRemoveItemWhenListIsEmpty();
void shouldNotRemoveItemWhenItemDoesntExist();
private:
KSharedConfig::Ptr mConfig;
QRegExp mFollowupRegExpFilter;
};
#endif // FOLLOWUPREMINDERCONFIGTEST_H

View file

@ -0,0 +1,101 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderinfodialogtest.h"
#include "../followupreminderinfodialog.h"
#include "../followupreminderinfowidget.h"
#include "../followupreminderinfo.h"
#include <qtest_kde.h>
FollowupReminderInfoDialogTest::FollowupReminderInfoDialogTest(QObject *parent)
: QObject(parent)
{
}
FollowupReminderInfoDialogTest::~FollowupReminderInfoDialogTest()
{
}
void FollowupReminderInfoDialogTest::shouldHaveDefaultValues()
{
FollowUpReminderInfoDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QVERIFY(infowidget);
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QVERIFY(treeWidget);
QCOMPARE(treeWidget->topLevelItemCount(), 0);
}
void FollowupReminderInfoDialogTest::shouldAddItemInTreeList()
{
FollowUpReminderInfoDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QList<FollowUpReminder::FollowUpReminderInfo *> lstInfo;
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
//We load invalid infos.
QCOMPARE(treeWidget->topLevelItemCount(), 0);
//Load valid infos
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
info->setOriginalMessageItemId(42);
info->setMessageId(QLatin1String("foo"));
info->setFollowUpReminderDate(QDate::currentDate());
info->setTo(QLatin1String("To"));
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
QCOMPARE(treeWidget->topLevelItemCount(), 10);
}
void FollowupReminderInfoDialogTest::shouldItemHaveInfo()
{
FollowUpReminderInfoDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QList<FollowUpReminder::FollowUpReminderInfo *> lstInfo;
//Load valid infos
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
info->setOriginalMessageItemId(42);
info->setMessageId(QLatin1String("foo"));
info->setFollowUpReminderDate(QDate::currentDate());
info->setTo(QLatin1String("To"));
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
FollowUpReminderInfoItem *item = static_cast<FollowUpReminderInfoItem *>(treeWidget->topLevelItem(i));
QVERIFY(item->info());
QVERIFY(item->info()->isValid());
}
}
QTEST_KDEMAIN(FollowupReminderInfoDialogTest, GUI)

View file

@ -0,0 +1,40 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERINFODIALOGTEST_H
#define FOLLOWUPREMINDERINFODIALOGTEST_H
#include <QObject>
class FollowupReminderInfoDialogTest : public QObject
{
Q_OBJECT
public:
explicit FollowupReminderInfoDialogTest(QObject *parent = 0);
~FollowupReminderInfoDialogTest();
private Q_SLOTS:
void shouldHaveDefaultValues();
void shouldAddItemInTreeList();
void shouldItemHaveInfo();
};
#endif // FOLLOWUPREMINDERINFODIALOGTEST_H

View file

@ -0,0 +1,110 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupreminderinfotest.h"
#include "../followupreminderinfo.h"
#include <KConfigGroup>
#include <qtest_kde.h>
FollowUpReminderInfoTest::FollowUpReminderInfoTest(QObject *parent)
: QObject(parent)
{
}
void FollowUpReminderInfoTest::shouldHaveDefaultValue()
{
FollowUpReminder::FollowUpReminderInfo info;
QCOMPARE(info.originalMessageItemId(), Akonadi::Item::Id(-1));
QCOMPARE(info.messageId(), QString());
QCOMPARE(info.isValid(), false);
QCOMPARE(info.to(), QString());
QCOMPARE(info.subject(), QString());
QCOMPARE(info.uniqueIdentifier(), -1);
}
void FollowUpReminderInfoTest::shoudBeNotValid()
{
FollowUpReminder::FollowUpReminderInfo info;
//We need a messageId not empty and a valid date and a "To" not empty
info.setMessageId(QLatin1String("foo"));
QCOMPARE(info.isValid(), false);
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
QCOMPARE(info.isValid(), false);
const QString to = QLatin1String("kde.org");
info.setTo(to);
QCOMPARE(info.isValid(), true);
info.setOriginalMessageItemId(Akonadi::Item::Id(42));
QCOMPARE(info.isValid(), true);
}
void FollowUpReminderInfoTest::shoudBeValidEvenIfSubjectIsEmpty()
{
FollowUpReminder::FollowUpReminderInfo info;
//We need a Akonadi::Id valid and a messageId not empty and a valid date and a "To" not empty
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
info.setOriginalMessageItemId(Akonadi::Item::Id(42));
QCOMPARE(info.isValid(), true);
}
void FollowUpReminderInfoTest::shouldRestoreFromSettings()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
info.setOriginalMessageItemId(Akonadi::Item::Id(42));
info.setSubject(QLatin1String("Subject"));
info.setUniqueIdentifier(42);
info.setTodoId(52);
KConfigGroup grp(KGlobal::config(), "testsettings");
info.writeConfig(grp, info.uniqueIdentifier());
FollowUpReminder::FollowUpReminderInfo restoreInfo(grp);
QCOMPARE(info, restoreInfo);
}
void FollowUpReminderInfoTest::shouldCopyReminderInfo()
{
FollowUpReminder::FollowUpReminderInfo info;
info.setMessageId(QLatin1String("foo"));
const QDate date(2014,1,1);
info.setFollowUpReminderDate(QDate(date));
const QString to = QLatin1String("kde.org");
info.setTo(to);
info.setOriginalMessageItemId(Akonadi::Item::Id(42));
info.setSubject(QLatin1String("Subject"));
info.setUniqueIdentifier(42);
info.setTodoId(52);
FollowUpReminder::FollowUpReminderInfo copyInfo(info);
QCOMPARE(info, copyInfo);
}
QTEST_KDEMAIN(FollowUpReminderInfoTest, NoGUI)

View file

@ -0,0 +1,37 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERINFOTEST_H
#define FOLLOWUPREMINDERINFOTEST_H
#include <QObject>
class FollowUpReminderInfoTest : public QObject
{
Q_OBJECT
public:
explicit FollowUpReminderInfoTest(QObject *parent=0);
private Q_SLOTS:
void shouldHaveDefaultValue();
void shoudBeNotValid();
void shoudBeValidEvenIfSubjectIsEmpty();
void shouldRestoreFromSettings();
void shouldCopyReminderInfo();
};
#endif // FOLLOWUPREMINDERINFOTEST_H

View file

@ -0,0 +1,102 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "followupremindernoanswerdialogtest.h"
#include "../followupremindernoanswerdialog.h"
#include "../followupreminderinfowidget.h"
#include "../followupreminderinfo.h"
#include <QTreeWidget>
#include <qtest_kde.h>
FollowupReminderNoAnswerDialogTest::FollowupReminderNoAnswerDialogTest(QObject *parent)
: QObject(parent)
{
}
FollowupReminderNoAnswerDialogTest::~FollowupReminderNoAnswerDialogTest()
{
}
void FollowupReminderNoAnswerDialogTest::shouldHaveDefaultValues()
{
FollowUpReminderNoAnswerDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QVERIFY(infowidget);
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QVERIFY(treeWidget);
QCOMPARE(treeWidget->topLevelItemCount(), 0);
}
void FollowupReminderNoAnswerDialogTest::shouldAddItemInTreeList()
{
FollowUpReminderNoAnswerDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QList<FollowUpReminder::FollowUpReminderInfo *> lstInfo;
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
//We load invalid infos.
QCOMPARE(treeWidget->topLevelItemCount(), 0);
//Load valid infos
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
info->setOriginalMessageItemId(42);
info->setMessageId(QLatin1String("foo"));
info->setFollowUpReminderDate(QDate::currentDate());
info->setTo(QLatin1String("To"));
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
QCOMPARE(treeWidget->topLevelItemCount(), 10);
}
void FollowupReminderNoAnswerDialogTest::shouldItemHaveInfo()
{
FollowUpReminderNoAnswerDialog dlg;
FollowUpReminderInfoWidget *infowidget = qFindChild<FollowUpReminderInfoWidget *>(&dlg, QLatin1String("FollowUpReminderInfoWidget"));
QTreeWidget *treeWidget = qFindChild<QTreeWidget *>(infowidget, QLatin1String("treewidget"));
QList<FollowUpReminder::FollowUpReminderInfo *> lstInfo;
//Load valid infos
for (int i = 0; i<10; ++i) {
FollowUpReminder::FollowUpReminderInfo *info = new FollowUpReminder::FollowUpReminderInfo();
info->setOriginalMessageItemId(42);
info->setMessageId(QLatin1String("foo"));
info->setFollowUpReminderDate(QDate::currentDate());
info->setTo(QLatin1String("To"));
lstInfo.append(info);
}
dlg.setInfo(lstInfo);
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
FollowUpReminderInfoItem *item = static_cast<FollowUpReminderInfoItem *>(treeWidget->topLevelItem(i));
QVERIFY(item->info());
QVERIFY(item->info()->isValid());
}
}
QTEST_KDEMAIN(FollowupReminderNoAnswerDialogTest, GUI)

View file

@ -0,0 +1,39 @@
/*
Copyright (c) 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FOLLOWUPREMINDERNOANSWERDIALOGTEST_H
#define FOLLOWUPREMINDERNOANSWERDIALOGTEST_H
#include <QObject>
class FollowupReminderNoAnswerDialogTest : public QObject
{
Q_OBJECT
public:
explicit FollowupReminderNoAnswerDialogTest(QObject *parent=0);
~FollowupReminderNoAnswerDialogTest();
private slots:
void shouldHaveDefaultValues();
void shouldAddItemInTreeList();
void shouldItemHaveInfo();
};
#endif // FOLLOWUPREMINDERNOANSWERDIALOGTEST_H

View file

@ -0,0 +1,54 @@
project(akonadi_mailfilter_agent)
add_subdirectory( kconf_update )
include_directories(
${Boost_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/mailcommon
${CMAKE_SOURCE_DIR}/messagecomposer
${CMAKE_SOURCE_DIR}/pimcommon
)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
set(akonadi_mailfilter_agent_SRCS
dummykernel.cpp
filterlogdialog.cpp
filtermanager.cpp
mailfilteragent.cpp
pop3resourceattribute.cpp
)
qt4_add_dbus_adaptor(akonadi_mailfilter_agent_SRCS org.freedesktop.Akonadi.MailFilterAgent.xml mailfilteragent.h MailFilterAgent)
#kde4_add_kcfg_files(akonadi_mailfilter_agent_SRCS settings.kcfgc)
#kde4_add_ui_files(akonadi_mailfilter_agent_SRCS configdialog.ui)
kde4_add_executable(akonadi_mailfilter_agent ${akonadi_mailfilter_agent_SRCS})
if (Q_WS_MAC)
set_target_properties(akonadi_mailfilter_agent PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.template)
set_target_properties(akonadi_mailfilter_agent PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Akonadi.mailfilter")
set_target_properties(akonadi_mailfilter_agent PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Email Filter")
endif ()
target_link_libraries(akonadi_mailfilter_agent
mailcommon
messagecore
messagecomposer
pimcommon
${KDE4_KDEUI_LIBRARY}
${KDE4_KDECORE_LIBS}
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_AKONADI_KMIME_LIBS}
${QT_QTSCRIPT_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTDBUS_LIBRARY}
${KDEPIMLIBS_KMIME_LIBS}
${KDEPIMLIBS_KPIMIDENTITIES_LIBS}
)
install(TARGETS akonadi_mailfilter_agent ${INSTALL_TARGETS_DEFAULT_ARGS})
install(FILES mailfilteragent.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")
install(FILES akonadi_mailfilter_agent.notifyrc DESTINATION "${DATA_INSTALL_DIR}/akonadi_mailfilter_agent" )

View file

@ -0,0 +1,2 @@
#! /bin/sh
$XGETTEXT *.cpp -o $podir/akonadi_mailfilter_agent.pot

View file

@ -0,0 +1,135 @@
[Global]
IconName=view-filter
Comment=Mail Filter Agent
Comment[bs]=Agent poštanskog filtera
Comment[ca]=Agent per filtrar el correu
Comment[ca@valencia]=Agent per filtrar el correu
Comment[cs]=Agent filtrování pošty
Comment[da]=Mailfilteragent
Comment[de]=Agent zur E-Mail-Filterung
Comment[el]=Πράκτορας φιλτραρίσματος αλληλογραφίας
Comment[en_GB]=Mail Filter Agent
Comment[es]=Agente de filtro de correo
Comment[et]=Kirjade filtreerimise agent
Comment[fi]=Sähköpostisuodatin
Comment[fr]=Agent de filtrage de messages
Comment[gl]=Axente de filtrado do correo
Comment[hu]=Levélszűrő ügynök
Comment[ia]=Agente de filtro de posta
Comment[it]=Agente per il filtraggio della posta
Comment[kk]=Пошта сүзгіш агенті
Comment[km]=ភ្នាក់ងារ​តម្រង​សំបុត្រ
Comment[lt]=El. pašto filtravimo agentas
Comment[mr]=मेल गाळणी प्रतिनिधी
Comment[nb]=E-post filteragent
Comment[nds]=Nettpostfilter-Hölper
Comment[nl]=E-mail filteragent
Comment[pl]=Agent filtrowania poczty
Comment[pt]=Agente de Filtragem de E-mail
Comment[pt_BR]=Agente de filtros de e-mail
Comment[ro]=Agent de filtrare a mesajelor
Comment[ru]=Агент почтовых фильтров
Comment[sk]=Agent filtrovania pošty
Comment[sl]=Posrednik za filtriranje pošte
Comment[sr]=Агент филтрирања поште
Comment[sr@ijekavian]=Агент филтрирања поште
Comment[sr@ijekavianlatin]=Agent filtriranja pošte
Comment[sr@latin]=Agent filtriranja pošte
Comment[sv]=Postfiltreringsmodul
Comment[tr]=Posta Filtre Aracı
Comment[uk]=Агент фільтрування пошти
Comment[wa]=Adjint passete d' emile
Comment[x-test]=xxMail Filter Agentxx
Comment[zh_CN]=邮件过滤代理
Comment[zh_TW]=郵件過濾代理程式
Name=Mail Filter Agent
Name[bs]=Agent poštanskog filtera
Name[ca]=Agent per filtrar el correu
Name[ca@valencia]=Agent per filtrar el correu
Name[cs]=Agent filtrování pošty
Name[da]=Mailfilteragent
Name[de]=Agent zur E-Mail-Filterung
Name[el]=Πράκτορας φιλτραρίσματος αλληλογραφίας
Name[en_GB]=Mail Filter Agent
Name[es]=Agente de filtro de correo
Name[et]=Kirjade filtreerimise agent
Name[fi]=Sähköpostisuodatin
Name[fr]=Agent de filtrage de messages
Name[gl]=Axente de filtrado de correo
Name[hu]=Levélszűrő ügynök
Name[ia]=Agente de filtro de posta
Name[it]=Agente per il filtraggio della posta
Name[kk]=Пошта сүзгіш агенті
Name[km]=ភ្នាក់ងារ​ត្រង​សំបុត្រ
Name[lt]=El. pašto filtravimo agentas
Name[mr]=मेल गाळणी प्रतिनिधी
Name[nb]=E-post filteragent
Name[nds]=Nettpostfilter-Hölper
Name[nl]=E-mail filteragent
Name[pl]=Agent filtrowania poczty
Name[pt]=Agente de Filtragem de E-mail
Name[pt_BR]=Agente de filtros de e-mail
Name[ro]=Agent de filtrare a mesajelor
Name[ru]=Агент почтовых фильтров
Name[sk]=Agent filtrovania pošty
Name[sl]=Posrednik za filtriranje pošte
Name[sr]=Агент филтрирања поште
Name[sr@ijekavian]=Агент филтрирања поште
Name[sr@ijekavianlatin]=Agent filtriranja pošte
Name[sr@latin]=Agent filtriranja pošte
Name[sv]=Postfiltreringsmodul
Name[tr]=Posta Filtre Aracı
Name[uk]=Агент фільтрування пошти
Name[wa]=Adjint passete d' emile
Name[x-test]=xxMail Filter Agentxx
Name[zh_CN]=邮件过滤代理
Name[zh_TW]=郵件過濾代理程式
[Event/mailfilterlogenabled]
Name=Mail filter log enabled
Name[bs]=Poštanski filter omogućen
Name[ca]=Activat el registre pel filtratge de correu
Name[ca@valencia]=Activat el registre pel filtratge de correu
Name[cs]=Záznam filtrování pošty povolen
Name[da]=Mailfilterlog aktiveret
Name[de]=E-Mail-Filterprotokoll aktiviert
Name[el]=Η καταγραφή φιλτραρίσματος μηνυμάτων ενεργοποιήθηκε
Name[en_GB]=Mail filter log enabled
Name[es]=Registro de filtro de correo activado
Name[et]=Kirjade filtreerimise logi on lubatud
Name[fi]=Sähköpostisuodatinloki käytössä
Name[fr]=Journal de l'agent de filtrage activé
Name[gl]=Activouse o rexistro do filtrado do correo
Name[hu]=Levélszűrő napló engedélyezve
Name[ia]=Registro de filtro de posta habilitate
Name[it]=Log dei filtri di posta abilitato
Name[kk]=Пошта сүзгіш агенті
Name[km]=បាន​បើក​កំណត់ហេតុ​តម្រង​សំបុត្រ
Name[lt]=El. pašto filtravimo agentas
Name[mr]=मेल गाळणी नोंद कार्यान्वित
Name[nb]=E-post filterlogg slått på
Name[nds]=Nettpost-Filterlogbook anmaakt
Name[nl]=E-mail filterlog ingeschakeld
Name[pl]=Dziennik filtrowania poczty jest włączony
Name[pt]=Registo de filtragem de e-mail activado
Name[pt_BR]=Registro de filtragem de e-mail ativado
Name[ro]=Jurnalul de filtrare a mesajelor e activat
Name[ru]=Журнал фильтрации почты включён
Name[sk]=Záznam filtra mailu povolený
Name[sl]=Dnevnik filtriranja pošte je omogočen
Name[sr]=Дневник филтрирања поште укључен
Name[sr@ijekavian]=Дневник филтрирања поште укључен
Name[sr@ijekavianlatin]=Dnevnik filtriranja pošte uključen
Name[sr@latin]=Dnevnik filtriranja pošte uključen
Name[sv]=Postfiltreringslogg aktiverad
Name[tr]=Posta filtre günlüğü etkin
Name[uk]=Увімкнено журнал фільтрування пошти
Name[wa]=Djournålijhaedje del passete d' emile
Name[x-test]=xxMail filter log enabledxx
Name[zh_CN]=邮件过滤器日志已启用
Name[zh_TW]=郵件過濾紀錄已開啟
Action=Popup
[Event/mailfilterjoberror]
Name=An error occurred during filtering
Action=None

View file

@ -0,0 +1,109 @@
#include "dummykernel.h"
#include <kglobal.h>
#include <kpimidentities/identitymanager.h>
#include <messagecomposer/sender/akonadisender.h>
#include <mailcommon/folder/foldercollectionmonitor.h>
#include <akonadi/session.h>
#include <akonadi/entitytreemodel.h>
#include <akonadi/entitymimetypefiltermodel.h>
#include <akonadi/changerecorder.h>
DummyKernel::DummyKernel( QObject *parent )
: QObject( parent )
{
mMessageSender = new MessageComposer::AkonadiSender( this );
mIdentityManager = new KPIMIdentities::IdentityManager( false, this );
Akonadi::Session *session = new Akonadi::Session( "MailFilter Kernel ETM", this );
mFolderCollectionMonitor = new MailCommon::FolderCollectionMonitor( session, this );
mEntityTreeModel = new Akonadi::EntityTreeModel( folderCollectionMonitor(), this );
mEntityTreeModel->setIncludeUnsubscribed( false );
mEntityTreeModel->setItemPopulationStrategy( Akonadi::EntityTreeModel::LazyPopulation );
mCollectionModel = new Akonadi::EntityMimeTypeFilterModel( this );
mCollectionModel->setSourceModel( mEntityTreeModel );
mCollectionModel->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() );
mCollectionModel->setHeaderGroup( Akonadi::EntityTreeModel::CollectionTreeHeaders );
mCollectionModel->setDynamicSortFilter( true );
mCollectionModel->setSortCaseSensitivity( Qt::CaseInsensitive );
}
KPIMIdentities::IdentityManager *DummyKernel::identityManager()
{
return mIdentityManager;
}
MessageComposer::MessageSender *DummyKernel::msgSender()
{
return mMessageSender;
}
Akonadi::EntityMimeTypeFilterModel *DummyKernel::collectionModel() const
{
return mCollectionModel;
}
KSharedConfig::Ptr DummyKernel::config()
{
return KGlobal::config();
}
void DummyKernel::syncConfig()
{
Q_ASSERT( false );
}
MailCommon::JobScheduler* DummyKernel::jobScheduler() const
{
Q_ASSERT( false );
return 0;
}
Akonadi::ChangeRecorder *DummyKernel::folderCollectionMonitor() const
{
return mFolderCollectionMonitor->monitor();
}
void DummyKernel::updateSystemTray()
{
Q_ASSERT( false );
}
bool DummyKernel::showPopupAfterDnD()
{
return false;
}
qreal DummyKernel::closeToQuotaThreshold()
{
return 80;
}
QStringList DummyKernel::customTemplates()
{
Q_ASSERT( false );
return QStringList();
}
bool DummyKernel::excludeImportantMailFromExpiry()
{
Q_ASSERT( false );
return true;
}
Akonadi::Entity::Id DummyKernel::lastSelectedFolder()
{
Q_ASSERT( false );
return Akonadi::Entity::Id();
}
void DummyKernel::setLastSelectedFolder(const Akonadi::Entity::Id& col)
{
Q_UNUSED(col);
}

View file

@ -0,0 +1,46 @@
#ifndef DUMMYKERNEL_H
#define DUMMYKERNEL_H
#include <mailcommon/interfaces/mailinterfaces.h>
namespace Akonadi {
class EntityTreeModel;
class EntityMimeTypeFilterModel;
}
namespace MailCommon {
class FolderCollectionMonitor;
}
class DummyKernel : public QObject, public MailCommon::IKernel, public MailCommon::ISettings
{
public:
explicit DummyKernel( QObject *parent = 0 );
virtual KPIMIdentities::IdentityManager *identityManager();
virtual MessageComposer::MessageSender *msgSender();
virtual Akonadi::EntityMimeTypeFilterModel *collectionModel() const;
virtual KSharedConfig::Ptr config();
virtual void syncConfig();
virtual MailCommon::JobScheduler* jobScheduler() const;
virtual Akonadi::ChangeRecorder *folderCollectionMonitor() const;
virtual void updateSystemTray();
virtual qreal closeToQuotaThreshold();
virtual bool excludeImportantMailFromExpiry();
virtual QStringList customTemplates();
virtual Akonadi::Entity::Id lastSelectedFolder();
virtual void setLastSelectedFolder(const Akonadi::Entity::Id& col);
virtual bool showPopupAfterDnD();
private:
KPIMIdentities::IdentityManager *mIdentityManager;
MessageComposer::MessageSender *mMessageSender;
MailCommon::FolderCollectionMonitor *mFolderCollectionMonitor;
Akonadi::EntityTreeModel *mEntityTreeModel;
Akonadi::EntityMimeTypeFilterModel *mCollectionModel;
};
#endif

View file

@ -0,0 +1,347 @@
/*
Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
Copyright (c) 2012 Laurent Montel <montel@kde.org>
KMail is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
KMail 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "filterlogdialog.h"
#include <mailcommon/filter/filterlog.h>
#include <messageviewer/utils/autoqpointer.h>
#include "pimcommon/texteditor/plaintexteditor/plaintexteditorwidget.h"
#include "pimcommon/texteditor/plaintexteditor/plaintexteditor.h"
#include <kdebug.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kvbox.h>
#include <QCheckBox>
#include <QLabel>
#include <QSpinBox>
#include <QStringList>
#include <QGroupBox>
#include <QVBoxLayout>
#include <errno.h>
using namespace MailCommon;
FilterLogDialog::FilterLogDialog( QWidget * parent )
: KDialog( parent ), mIsInitialized( false )
{
KGlobal::locale()->insertCatalog(QLatin1String("akonadi_mailfilter_agent"));
KGlobal::locale()->insertCatalog(QLatin1String("libpimcommon"));
setCaption( i18n( "Filter Log Viewer" ) );
setButtons( User1|User2|Close );
setWindowIcon( KIcon( QLatin1String("view-filter") ) );
setModal( false );
setDefaultButton( Close );
setButtonGuiItem( User1, KStandardGuiItem::clear() );
setButtonGuiItem( User2, KStandardGuiItem::saveAs() );
QFrame *page = new KVBox( this );
setMainWidget( page );
mTextEdit = new PimCommon::PlainTextEditorWidget( page );
mTextEdit->setReadOnly( true );
mTextEdit->editor()->setWordWrapMode(QTextOption::NoWrap);
const QStringList logEntries = FilterLog::instance()->logEntries();
QStringList::ConstIterator end( logEntries.constEnd() );
for ( QStringList::ConstIterator it = logEntries.constBegin();
it != end; ++it ) {
mTextEdit->editor()->appendHtml(*it);
}
mLogActiveBox = new QCheckBox( i18n("&Log filter activities"), page );
mLogActiveBox->setChecked( FilterLog::instance()->isLogging() );
connect( mLogActiveBox, SIGNAL(clicked()),
this, SLOT(slotSwitchLogState()) );
mLogActiveBox->setWhatsThis(
i18n( "You can turn logging of filter activities on and off here. "
"Of course, log data is collected and shown only when logging "
"is turned on. " ) );
mLogDetailsBox = new QGroupBox(i18n( "Logging Details" ), page );
QVBoxLayout *layout = new QVBoxLayout;
mLogDetailsBox->setLayout( layout );
mLogDetailsBox->setEnabled( mLogActiveBox->isChecked() );
connect( mLogActiveBox, SIGNAL(toggled(bool)),
mLogDetailsBox, SLOT(setEnabled(bool)) );
mLogPatternDescBox = new QCheckBox( i18n("Log pattern description") );
layout->addWidget( mLogPatternDescBox );
mLogPatternDescBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternDescription ) );
connect( mLogPatternDescBox, SIGNAL(clicked()),
this, SLOT(slotChangeLogDetail()) );
// TODO
//QWhatsThis::add( mLogPatternDescBox,
// i18n( "" ) );
mLogRuleEvaluationBox = new QCheckBox( i18n("Log filter &rule evaluation") );
layout->addWidget( mLogRuleEvaluationBox );
mLogRuleEvaluationBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::RuleResult ) );
connect( mLogRuleEvaluationBox, SIGNAL(clicked()),
this, SLOT(slotChangeLogDetail()) );
mLogRuleEvaluationBox->setWhatsThis(
i18n( "You can control the feedback in the log concerning the "
"evaluation of the filter rules of applied filters: "
"having this option checked will give detailed feedback "
"for each single filter rule; alternatively, only "
"feedback about the result of the evaluation of all rules "
"of a single filter will be given." ) );
mLogPatternResultBox = new QCheckBox( i18n("Log filter pattern evaluation") );
layout->addWidget( mLogPatternResultBox );
mLogPatternResultBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternResult ) );
connect( mLogPatternResultBox, SIGNAL(clicked()),
this, SLOT(slotChangeLogDetail()) );
// TODO
//QWhatsThis::add( mLogPatternResultBox,
// i18n( "" ) );
mLogFilterActionBox = new QCheckBox( i18n("Log filter actions") );
layout->addWidget( mLogFilterActionBox );
mLogFilterActionBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::AppliedAction ) );
connect( mLogFilterActionBox, SIGNAL(clicked()),
this, SLOT(slotChangeLogDetail()) );
// TODO
//QWhatsThis::add( mLogFilterActionBox,
// i18n( "" ) );
KHBox * hbox = new KHBox( page );
new QLabel( i18n("Log size limit:"), hbox );
mLogMemLimitSpin = new QSpinBox( hbox );
mLogMemLimitSpin->setMinimum( 1 );
mLogMemLimitSpin->setMaximum( 1024 * 256 ); // 256 MB
// value in the QSpinBox is in KB while it's in Byte in the FilterLog
mLogMemLimitSpin->setValue( FilterLog::instance()->maxLogSize() / 1024 );
mLogMemLimitSpin->setSuffix( i18n(" KB") );
mLogMemLimitSpin->setSpecialValueText(
i18nc("@label:spinbox Set the size of the logfile to unlimited.", "unlimited") );
connect( mLogMemLimitSpin, SIGNAL(valueChanged(int)),
this, SLOT(slotChangeLogMemLimit(int)) );
mLogMemLimitSpin->setWhatsThis(
i18n( "Collecting log data uses memory to temporarily store the "
"log data; here you can limit the maximum amount of memory "
"to be used: if the size of the collected log data exceeds "
"this limit then the oldest data will be discarded until "
"the limit is no longer exceeded. " ) );
connect(FilterLog::instance(), SIGNAL(logEntryAdded(QString)),
this, SLOT(slotLogEntryAdded(QString)));
connect(FilterLog::instance(), SIGNAL(logShrinked()),
this, SLOT(slotLogShrinked()));
connect(FilterLog::instance(), SIGNAL(logStateChanged()),
this, SLOT(slotLogStateChanged()));
setInitialSize( QSize( 500, 500 ) );
connect( this, SIGNAL(user1Clicked()), SLOT(slotUser1()) );
connect( this, SIGNAL(user2Clicked()), SLOT(slotUser2()) );
connect(mTextEdit->editor(), SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
slotTextChanged();
readConfig();
mIsInitialized = true;
}
void FilterLogDialog::slotTextChanged()
{
const bool hasText = !mTextEdit->toPlainText().isEmpty();
enableButton(User2, hasText);
enableButton(User1, hasText);
}
void FilterLogDialog::readConfig()
{
KSharedConfig::Ptr config = KGlobal::config();
KConfigGroup group( config, "FilterLog" );
const bool isEnabled = group.readEntry( "Enabled", false );
const bool isLogPatternDescription = group.readEntry( "LogPatternDescription", false );
const bool isLogRuleResult = group.readEntry( "LogRuleResult", false );
const bool isLogPatternResult = group.readEntry( "LogPatternResult", false );
const bool isLogAppliedAction = group.readEntry( "LogAppliedAction", false );
const int maxLogSize = group.readEntry( "maxLogSize", -1 );
if ( isEnabled !=FilterLog::instance()->isLogging() )
FilterLog::instance()->setLogging( isEnabled );
if ( isLogPatternDescription != FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternDescription ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::PatternDescription, isLogPatternDescription );
if ( isLogRuleResult!= FilterLog::instance()->isContentTypeEnabled( FilterLog::RuleResult ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::RuleResult, isLogRuleResult);
if ( isLogPatternResult != FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternResult ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::PatternResult,isLogPatternResult );
if ( isLogAppliedAction != FilterLog::instance()->isContentTypeEnabled( FilterLog::AppliedAction ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::AppliedAction,isLogAppliedAction );
if ( FilterLog::instance()->maxLogSize() != maxLogSize )
FilterLog::instance()->setMaxLogSize( maxLogSize );
KConfigGroup geometryGroup( config, "Geometry" );
const QSize size = geometryGroup.readEntry( "filterLogSize", QSize() );
if ( size != QSize() ) {
resize( size );
} else {
adjustSize();
}
}
FilterLogDialog::~FilterLogDialog()
{
KConfigGroup myGroup( KGlobal::config(), "Geometry" );
myGroup.writeEntry( "filterLogSize", size() );
myGroup.sync();
}
void FilterLogDialog::writeConfig()
{
if ( !mIsInitialized )
return;
KSharedConfig::Ptr config = KGlobal::config();
KConfigGroup group( config, "FilterLog" );
group.writeEntry( "Enabled", FilterLog::instance()->isLogging() );
group.writeEntry( "LogPatternDescription", FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternDescription ) );
group.writeEntry( "LogRuleResult", FilterLog::instance()->isContentTypeEnabled( FilterLog::RuleResult ) );
group.writeEntry( "LogPatternResult", FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternResult ) );
group.writeEntry( "LogAppliedAction", FilterLog::instance()->isContentTypeEnabled( FilterLog::AppliedAction ) );
group.writeEntry( "maxLogSize", ( int )( FilterLog::instance()->maxLogSize() ) );
group.sync();
}
void FilterLogDialog::slotLogEntryAdded(const QString& logEntry )
{
mTextEdit->editor()->appendHtml( logEntry );
}
void FilterLogDialog::slotLogShrinked()
{
// limit the size of the shown log lines as soon as
// the log has reached it's memory limit
if ( mTextEdit->editor()->document()->maximumBlockCount () <= 0 ) {
mTextEdit->editor()->document()->setMaximumBlockCount( mTextEdit->editor()->document()->blockCount() );
}
}
void FilterLogDialog::slotLogStateChanged()
{
mLogActiveBox->setChecked( FilterLog::instance()->isLogging() );
mLogPatternDescBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternDescription ) );
mLogRuleEvaluationBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::RuleResult ) );
mLogPatternResultBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternResult ) );
mLogFilterActionBox->setChecked(
FilterLog::instance()->isContentTypeEnabled( FilterLog::AppliedAction ) );
// value in the QSpinBox is in KB while it's in Byte in the FilterLog
int newLogSize = FilterLog::instance()->maxLogSize() / 1024;
if ( mLogMemLimitSpin->value() != newLogSize ) {
if(newLogSize <= 0)
mLogMemLimitSpin->setValue( 1 );
else
mLogMemLimitSpin->setValue( newLogSize );
}
writeConfig();
}
void FilterLogDialog::slotChangeLogDetail()
{
if ( mLogPatternDescBox->isChecked() !=
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternDescription ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::PatternDescription,
mLogPatternDescBox->isChecked() );
if ( mLogRuleEvaluationBox->isChecked() !=
FilterLog::instance()->isContentTypeEnabled( FilterLog::RuleResult ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::RuleResult,
mLogRuleEvaluationBox->isChecked() );
if ( mLogPatternResultBox->isChecked() !=
FilterLog::instance()->isContentTypeEnabled( FilterLog::PatternResult ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::PatternResult,
mLogPatternResultBox->isChecked() );
if ( mLogFilterActionBox->isChecked() !=
FilterLog::instance()->isContentTypeEnabled( FilterLog::AppliedAction ) )
FilterLog::instance()->setContentTypeEnabled( FilterLog::AppliedAction,
mLogFilterActionBox->isChecked() );
}
void FilterLogDialog::slotSwitchLogState()
{
FilterLog::instance()->setLogging( mLogActiveBox->isChecked() );
}
void FilterLogDialog::slotChangeLogMemLimit( int value )
{
mTextEdit->editor()->document()->setMaximumBlockCount( 0 ); //Reset value
if(value == 1) //unilimited
FilterLog::instance()->setMaxLogSize(-1);
else
FilterLog::instance()->setMaxLogSize( value * 1024 );
}
void FilterLogDialog::slotUser1()
{
FilterLog::instance()->clear();
mTextEdit->editor()->clear();
}
void FilterLogDialog::slotUser2()
{
KUrl url;
MessageViewer::AutoQPointer<KFileDialog> fdlg( new KFileDialog( url, QString(), this) );
fdlg->setMode( KFile::File );
fdlg->setSelection( QLatin1String("kmail-filter.html") );
fdlg->setOperationMode( KFileDialog::Saving );
fdlg->setConfirmOverwrite(true);
if ( fdlg->exec() == QDialog::Accepted && fdlg )
{
const QString fileName = fdlg->selectedFile();
if ( !fileName.isEmpty() && !FilterLog::instance()->saveToFile( fileName ) )
{
KMessageBox::error( this,
i18n( "Could not write the file %1:\n"
"\"%2\" is the detailed error description.",
fileName,
QString::fromLocal8Bit( strerror( errno ) ) ),
i18n( "KMail Error" ) );
}
}
}

View file

@ -0,0 +1,83 @@
/*
Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
Copyright (c) 2012-2013 Laurent Montel <montel@kde.org>
KMail is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
KMail 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef FILTERLOGDIALOG_H
#define FILTERLOGDIALOG_H
#include <kdialog.h>
class QCheckBox;
class QSpinBox;
class QGroupBox;
/**
@short KMail Filter Log Collector.
@author Andreas Gungl <a.gungl@gmx.de>
The filter log dialog allows a continued observation of the
filter log of MailFilterAgent.
*/
namespace PimCommon {
class PlainTextEditorWidget;
}
class FilterLogDialog : public KDialog
{
Q_OBJECT
public:
/** constructor */
explicit FilterLogDialog( QWidget * parent );
~FilterLogDialog();
protected slots:
void slotLogEntryAdded( const QString& logEntry );
void slotLogShrinked();
void slotLogStateChanged();
void slotChangeLogDetail();
void slotSwitchLogState();
void slotChangeLogMemLimit( int value );
void slotUser1();
void slotUser2();
private:
void readConfig();
void writeConfig();
protected:
PimCommon::PlainTextEditorWidget * mTextEdit;
QCheckBox * mLogActiveBox;
QGroupBox * mLogDetailsBox;
QCheckBox * mLogPatternDescBox;
QCheckBox * mLogRuleEvaluationBox;
QCheckBox * mLogPatternResultBox;
QCheckBox * mLogFilterActionBox;
QSpinBox * mLogMemLimitSpin;
bool mIsInitialized;
private slots:
void slotTextChanged();
};
#endif

View file

@ -0,0 +1,622 @@
// -*- mode: C++; c-file-style: "gnu" -*-
/* Copyright: before 2012: missing, see KMail copyrights
* Copyright (C) 2012 Andras Mantia <amantia@kde.org> *
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "filtermanager.h"
#include <akonadi/agentmanager.h>
#include <akonadi/changerecorder.h>
#include <akonadi/collectionfetchjob.h>
#include <akonadi/collectionfetchscope.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/itemmodifyjob.h>
#include <akonadi/itemmovejob.h>
#include <akonadi/itemdeletejob.h>
#include <akonadi/kmime/messageparts.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <KNotification>
#include <KIcon>
#include <KIconLoader>
#include <kmime/kmime_message.h>
#include <mailcommon/filter/filterimporterexporter.h>
#include <mailcommon/filter/filterlog.h>
#include <mailcommon/filter/mailfilter.h>
#include <mailcommon/util/mailutil.h>
#include <QtCore/QTimer>
#include <QApplication>
// other headers
#include <algorithm>
#include <assert.h>
#include <boost/bind.hpp>
#include <errno.h>
using namespace MailCommon;
class FilterManager::Private
{
public:
Private( FilterManager *qq )
: q( qq ),
mRequiredPartsBasedOnAll( SearchRule::Envelope ),
mInboundFiltersExist( false ),
mTotalProgressCount( 0 ),
mCurrentProgressCount( 0 )
{
pixmapNotification = KIcon( QLatin1String("view-filter") ).pixmap( KIconLoader::SizeSmall, KIconLoader::SizeSmall );
}
void itemsFetchJobForFilterDone( KJob *job );
void itemFetchJobForFilterDone( KJob *job );
void moveJobResult( KJob* );
void modifyJobResult( KJob* );
void deleteJobResult( KJob* );
void slotItemsFetchedForFilter( const Akonadi::Item::List &items );
void showNotification(const QString &errorMsg, const QString &jobErrorString);
bool isMatching( const Akonadi::Item &item, const MailCommon::MailFilter *filter );
void beginFiltering( const Akonadi::Item &item ) const;
void endFiltering( const Akonadi::Item &item ) const;
bool atLeastOneFilterAppliesTo( const QString &accountId ) const;
bool atLeastOneIncomingFilterAppliesTo( const QString &accountId ) const;
FilterManager *q;
QList<MailCommon::MailFilter *> mFilters;
QMap<QString, SearchRule::RequiredPart> mRequiredParts;
SearchRule::RequiredPart mRequiredPartsBasedOnAll;
QPixmap pixmapNotification;
bool mInboundFiltersExist;
int mTotalProgressCount;
int mCurrentProgressCount;
};
void FilterManager::Private::slotItemsFetchedForFilter( const Akonadi::Item::List &items )
{
FilterManager::FilterSet filterSet = FilterManager::Inbound;
if ( q->sender()->property( "filterSet" ).isValid() ) {
filterSet = static_cast<FilterManager::FilterSet>(q->sender()->property( "filterSet" ).toInt());
}
QList<MailFilter *> listMailFilters;
if ( q->sender()->property( "listFilters" ).isValid() ) {
const QStringList listFilters = q->sender()->property( "listFilters" ).toStringList();
//TODO improve it
foreach( const QString &filterId, listFilters) {
foreach ( MailCommon::MailFilter *filter, mFilters ) {
if ( filter->identifier() == filterId ) {
listMailFilters << filter;
break;
}
}
}
}
if(listMailFilters.isEmpty())
listMailFilters = mFilters;
bool needsFullPayload = q->sender()->property( "needsFullPayload" ).toBool();
foreach ( const Akonadi::Item &item, items ) {
++mCurrentProgressCount;
if ((mTotalProgressCount > 0) && (mCurrentProgressCount != mTotalProgressCount)) {
const QString statusMsg =
i18n( "Filtering message %1 of %2", mCurrentProgressCount, mTotalProgressCount );
emit q->progressMessage(statusMsg);
emit q->percent(mCurrentProgressCount * 100 / mTotalProgressCount);
} else {
emit q->percent(0);
}
const bool filterResult = q->process( listMailFilters, item, needsFullPayload, filterSet );
if (mCurrentProgressCount == mTotalProgressCount) {
mTotalProgressCount = 0;
mCurrentProgressCount = 0;
}
if ( !filterResult ) {
emit q->filteringFailed( item );
// something went horribly wrong (out of space?)
//CommonKernel->emergencyExit( i18n( "Unable to process messages: " ) + QString::fromLocal8Bit( strerror( errno ) ) );
}
}
}
void FilterManager::Private::itemsFetchJobForFilterDone( KJob *job )
{
if ( job->error() ) {
kError() << "Error while fetching items. " << job->error() << job->errorString();
}
}
void FilterManager::Private::itemFetchJobForFilterDone( KJob *job )
{
if ( job->error() ) {
kError() << "Error while fetching item. " << job->error() << job->errorString();
return;
}
const Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
const Akonadi::Item::List items = fetchJob->items();
if ( items.isEmpty() ) {
kError() << "Error while fetching item: item not found";
return;
}
const QString resourceId = fetchJob->property( "resourceId" ).toString();
bool needsFullPayload = q->requiredPart( resourceId ) != SearchRule::Envelope;
if ( job->property( "filterId" ).isValid() ) {
const QString filterId = job->property( "filterId" ).toString();
// find correct filter object
MailCommon::MailFilter *wantedFilter = 0;
foreach ( MailCommon::MailFilter *filter, mFilters ) {
if ( filter->identifier() == filterId ) {
wantedFilter = filter;
break;
}
}
if ( !wantedFilter ) {
kError() << "Cannot find filter object with id" << filterId;
return;
}
if ( !q->process( items.first(), needsFullPayload, wantedFilter )) {
emit q->filteringFailed( items.first() );
}
} else {
const FilterManager::FilterSet set = static_cast<FilterManager::FilterSet>( job->property( "filterSet" ).toInt() );
if ( !q->process( items.first(), needsFullPayload, set, !resourceId.isEmpty(), resourceId )) {
emit q->filteringFailed( items.first() );
}
}
}
void FilterManager::Private::moveJobResult( KJob *job )
{
if ( job->error() ) {
const Akonadi::ItemMoveJob *movejob = qobject_cast<Akonadi::ItemMoveJob*>( job );
if( movejob ) {
kError() << "Error while moving items. "<< job->error() << job->errorString()
<< " to destinationCollection.id() :" << movejob->destinationCollection().id();
} else {
kError() << "Error while moving items. " << job->error() << job->errorString();
}
//Laurent: not real info and when we have 200 errors it's very long to click all the time on ok.
showNotification(i18n("Error applying mail filter move"), job->errorString());
}
}
void FilterManager::Private::deleteJobResult( KJob *job )
{
if ( job->error() ) {
kError() << "Error while delete items. " << job->error() << job->errorString();
showNotification(i18n("Error applying mail filter delete"), job->errorString());
}
}
void FilterManager::Private::modifyJobResult( KJob *job )
{
if ( job->error() ) {
kError() << "Error while modifying items. " << job->error() << job->errorString();
showNotification(i18n("Error applying mail filter modifications"), job->errorString());
}
}
void FilterManager::Private::showNotification(const QString &errorMsg, const QString &jobErrorString)
{
KNotification *notify = new KNotification( QLatin1String("mailfilterjoberror") );
notify->setComponentData( KComponentData("akonadi_mailfilter_agent") );
notify->setPixmap( pixmapNotification );
notify->setText( errorMsg + QLatin1Char('\n') + jobErrorString );
notify->sendEvent();
}
bool FilterManager::Private::isMatching( const Akonadi::Item &item, const MailCommon::MailFilter *filter )
{
bool result = false;
if ( FilterLog::instance()->isLogging() ) {
QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
logText.append( filter->pattern()->asString() );
FilterLog::instance()->add( logText, FilterLog::PatternDescription );
}
if ( filter->pattern()->matches( item ) ) {
if ( FilterLog::instance()->isLogging() ) {
FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
FilterLog::PatternResult );
}
result = true;
}
return result;
}
void FilterManager::Private::beginFiltering( const Akonadi::Item &item ) const
{
if ( FilterLog::instance()->isLogging() ) {
FilterLog::instance()->addSeparator();
KMime::Message::Ptr msg = item.payload<KMime::Message::Ptr>();
const QString subject = msg->subject()->asUnicodeString();
const QString from = msg->from()->asUnicodeString();
const KDateTime dateTime = msg->date()->dateTime();
const QString date = KGlobal::locale()->formatDateTime( dateTime, KLocale::LongDate );
const QString logText( i18n( "<b>Begin filtering on message \"%1\" from \"%2\" at \"%3\" :</b>",
subject, from, date ) );
FilterLog::instance()->add( logText, FilterLog::PatternDescription );
}
}
void FilterManager::Private::endFiltering( const Akonadi::Item &/*item*/ ) const
{
}
bool FilterManager::Private::atLeastOneFilterAppliesTo( const QString &accountId ) const
{
foreach ( const MailCommon::MailFilter *filter, mFilters ) {
if ( filter->applyOnAccount( accountId ) ) {
return true;
}
}
return false;
}
bool FilterManager::Private::atLeastOneIncomingFilterAppliesTo( const QString &accountId ) const
{
foreach ( const MailCommon::MailFilter *filter, mFilters ) {
if ( filter->applyOnInbound() && filter->applyOnAccount( accountId ) ) {
return true;
}
}
return false;
}
FilterManager::FilterManager( QObject *parent )
: QObject( parent ), d( new Private( this ) )
{
readConfig();
}
FilterManager::~FilterManager()
{
clear();
delete d;
}
void FilterManager::clear()
{
qDeleteAll( d->mFilters );
d->mFilters.clear();
}
void FilterManager::readConfig()
{
KSharedConfig::Ptr config = KGlobal::config(); // use akonadi_mailfilter_agentrc
config->reparseConfiguration();
clear();
QStringList emptyFilters;
d->mFilters = FilterImporterExporter::readFiltersFromConfig( config, emptyFilters );
d->mRequiredParts.clear();
d->mRequiredPartsBasedOnAll = SearchRule::Envelope;
if (!d->mFilters.isEmpty()){
Akonadi::AgentInstance::List agents = Akonadi::AgentManager::self()->instances();
foreach( const Akonadi::AgentInstance &agent, agents) {
const QString id = agent.identifier();
QList<MailFilter*>::const_iterator it = std::max_element(d->mFilters.constBegin(), d->mFilters.constEnd(),
boost::bind(&MailCommon::MailFilter::requiredPart, _1, id)
< boost::bind(&MailCommon::MailFilter::requiredPart, _2, id));
d->mRequiredParts[id] = (*it)->requiredPart(id);
d->mRequiredPartsBasedOnAll = qMax( d->mRequiredPartsBasedOnAll, d->mRequiredParts[id] );
}
}
// check if at least one filter is to be applied on inbound mail
d->mInboundFiltersExist = std::find_if( d->mFilters.constBegin(), d->mFilters.constEnd(),
boost::bind( &MailCommon::MailFilter::applyOnInbound, _1 ) ) != d->mFilters.constEnd();
emit filterListUpdated();
}
void FilterManager::mailCollectionRemoved( const Akonadi::Collection& collection )
{
QList<MailCommon::MailFilter*>::const_iterator end( d->mFilters.constEnd() );
for ( QList<MailCommon::MailFilter*>::const_iterator it = d->mFilters.constBegin();
it != end ; ++it ) {
(*it)->folderRemoved( collection, Akonadi::Collection() );
}
}
void FilterManager::filter( const Akonadi::Item& item, FilterManager::FilterSet set, const QString& resourceId )
{
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item, this );
job->setProperty( "filterSet", static_cast<int>(set) );
job->setProperty( "resourceId", resourceId );
SearchRule::RequiredPart requestedPart = requiredPart(resourceId);
if ( requestedPart == SearchRule::CompleteMessage )
job->fetchScope().fetchFullPayload( true );
else if ( requestedPart == SearchRule::Header )
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header, true );
else
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
connect( job, SIGNAL(result(KJob*)), SLOT(itemFetchJobForFilterDone(KJob*)) );
}
void FilterManager::filter(const Akonadi::Item& item, const QString& filterId, const QString& resourceId)
{
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item, this );
job->setProperty( "filterId", filterId );
SearchRule::RequiredPart requestedPart = requiredPart(resourceId);
if ( requestedPart == SearchRule::CompleteMessage )
job->fetchScope().fetchFullPayload( true );
else if ( requestedPart == SearchRule::Header )
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header, true );
else
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
connect( job, SIGNAL(result(KJob*)), SLOT(itemFetchJobForFilterDone(KJob*)) );
}
bool FilterManager::process( const Akonadi::Item& item, bool needsFullPayload, const MailFilter* filter )
{
if ( !filter ) {
return false;
}
if ( !filter->isEnabled() ) {
return true;
}
if ( !item.hasPayload<KMime::Message::Ptr>() ) {
kError() << "Filter is null or item doesn't have correct payload.";
return false;
}
bool stopIt = false;
bool applyOnOutbound = false;
if ( d->isMatching( item, filter ) ) {
// do the actual filtering stuff
d->beginFiltering( item );
ItemContext context( item, needsFullPayload );
if ( filter->execActions( context, stopIt, applyOnOutbound ) == MailCommon::MailFilter::CriticalError ) {
return false;
}
d->endFiltering( item );
if( !processContextItem( context ))
return false;
}
return true;
}
bool FilterManager::processContextItem( ItemContext context )
{
const KMime::Message::Ptr msg = context.item().payload<KMime::Message::Ptr>();
msg->assemble();
const bool itemCanDelete = (MailCommon::Util::updatedCollection(context.item().parentCollection()).rights() & Akonadi::Collection::CanDeleteItem);
if ( context.deleteItem() ) {
if ( itemCanDelete ){
Akonadi::ItemDeleteJob *deleteJob = new Akonadi::ItemDeleteJob( context.item(), this );
connect( deleteJob, SIGNAL(result(KJob*)), SLOT(deleteJobResult(KJob*)));
} else {
return false;
}
} else {
if ( context.moveTargetCollection().isValid() && context.item().storageCollectionId() != context.moveTargetCollection().id() ) {
if ( itemCanDelete ) {
Akonadi::ItemMoveJob *moveJob = new Akonadi::ItemMoveJob( context.item(), context.moveTargetCollection(), this );
connect( moveJob, SIGNAL(result(KJob*)), SLOT(moveJobResult(KJob*)) );
} else {
return false;
}
}
if ( context.needsPayloadStore() || context.needsFlagStore() ) {
Akonadi::Item item = context.item();
//the item might be in a new collection with a different remote id, so don't try to force on it
//the previous remote id. Example: move to another collection on another resource => new remoteId, but our context.item()
//remoteid still holds the old one. Without clearing it, we try to enforce that on the new location, which is
//anything but good (and the server replies with "NO Only resources can modify remote identifiers"
item.setRemoteId(QString());
Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob( item, this );
modifyJob->disableRevisionCheck(); //no conflict handling for mails as no other process could change the mail body and we don't care about flag conflicts
//The below is a safety check to ignore modifying payloads if it was not requested,
//as in that case we might change the payload to an invalid one
modifyJob->setIgnorePayload( !context.needsFullPayload() );
connect( modifyJob, SIGNAL(result(KJob*)), SLOT(modifyJobResult(KJob*)));
}
}
return true;
}
bool FilterManager::process(const QList< MailFilter* >& mailFilters, const Akonadi::Item& item, bool needsFullPayload, FilterManager::FilterSet set, bool account, const QString& accountId )
{
if ( set == NoSet ) {
kDebug() << "FilterManager: process() called with not filter set selected";
return false;
}
if ( !item.hasPayload<KMime::Message::Ptr>() ) {
kError() << "Filter is null or item doesn't have correct payload.";
return false;
}
bool stopIt = false;
d->beginFiltering( item );
ItemContext context( item, needsFullPayload );
QList<MailCommon::MailFilter*>::const_iterator end( mailFilters.constEnd() );
const bool applyOnOutbound = ((set & Outbound) || (set & BeforeOutbound));
for ( QList<MailCommon::MailFilter*>::const_iterator it = mailFilters.constBegin();
!stopIt && it != end ; ++it ) {
if ( ( *it )->isEnabled() ) {
const bool inboundOk = ((set & Inbound) && (*it)->applyOnInbound());
const bool outboundOk = ((set & Outbound) && (*it)->applyOnOutbound());
const bool beforeOutboundOk = ((set & BeforeOutbound) && (*it)->applyBeforeOutbound());
const bool explicitOk = ((set & Explicit) && (*it)->applyOnExplicit());
const bool accountOk = (!account || (account && (*it)->applyOnAccount( accountId )));
if ( (inboundOk && accountOk) || outboundOk || beforeOutboundOk || explicitOk ) {
// filter is applicable
if ( d->isMatching( context.item(), *it ) ) {
// execute actions:
if ( (*it)->execActions( context, stopIt, applyOnOutbound ) == MailCommon::MailFilter::CriticalError ) {
return false;
}
}
}
}
}
d->endFiltering( item );
if( !processContextItem( context ) )
return false;
return true;
}
bool FilterManager::process( const Akonadi::Item &item, bool needsFullPayload,
FilterSet set, bool account, const QString &accountId )
{
return process( d->mFilters, item, needsFullPayload, set, account, accountId );
}
QString FilterManager::createUniqueName( const QString &name ) const
{
QString uniqueName = name;
int counter = 0;
bool found = true;
while ( found ) {
found = false;
foreach ( const MailCommon::MailFilter *filter, d->mFilters ) {
if ( !filter->name().compare( uniqueName ) ) {
found = true;
++counter;
uniqueName = name;
uniqueName += QString::fromLatin1( " (" ) + QString::number( counter )
+ QString::fromLatin1( ")" );
break;
}
}
}
return uniqueName;
}
MailCommon::SearchRule::RequiredPart FilterManager::requiredPart(const QString& id) const
{
if (id.isEmpty())
return d->mRequiredPartsBasedOnAll;
return d->mRequiredParts.contains(id) ? d->mRequiredParts[id] : SearchRule::Envelope ;
}
#ifndef NDEBUG
void FilterManager::dump() const
{
foreach ( const MailCommon::MailFilter *filter, d->mFilters ) {
kDebug() << filter->asString();
}
}
#endif
void FilterManager::applySpecificFilters(const QList< Akonadi::Item >& selectedMessages, SearchRule::RequiredPart requiredPart, const QStringList& listFilters )
{
emit progressMessage( i18n( "Filtering messages" ) );
d->mTotalProgressCount = selectedMessages.size();
d->mCurrentProgressCount = 0;
Akonadi::ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob( selectedMessages, this );
if( requiredPart == SearchRule::CompleteMessage ) {
itemFetchJob->fetchScope().fetchFullPayload( true );
} else if( requiredPart == SearchRule::Header ) {
itemFetchJob->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header, true );
} else {
itemFetchJob->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
}
itemFetchJob->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
itemFetchJob->setProperty( "listFilters", QVariant::fromValue( listFilters ) );
itemFetchJob->setProperty( "needsFullPayload", requiredPart != SearchRule::Envelope );
connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)),
this, SLOT(slotItemsFetchedForFilter(Akonadi::Item::List)) );
connect( itemFetchJob, SIGNAL(result(KJob*)),
SLOT(itemsFetchJobForFilterDone(KJob*)) );
}
void FilterManager::applyFilters( const QList<Akonadi::Item> &selectedMessages, FilterSet filterSet )
{
emit progressMessage( i18n( "Filtering messages" ) );
d->mTotalProgressCount = selectedMessages.size();
d->mCurrentProgressCount = 0;
Akonadi::ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob( selectedMessages, this );
SearchRule::RequiredPart requiredParts = requiredPart(QString());
if ( requiredParts == SearchRule::CompleteMessage )
itemFetchJob->fetchScope().fetchFullPayload( true );
else if ( requiredParts == SearchRule::Header )
itemFetchJob->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header, true );
else
itemFetchJob->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
itemFetchJob->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
itemFetchJob->setProperty( "filterSet", QVariant::fromValue( static_cast<int>( filterSet ) ) );
itemFetchJob->setProperty( "needsFullPayload", requiredParts != SearchRule::Envelope );
connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)),
this, SLOT(slotItemsFetchedForFilter(Akonadi::Item::List)) );
connect( itemFetchJob, SIGNAL(result(KJob*)),
SLOT(itemsFetchJobForFilterDone(KJob*)) );
}
#include "moc_filtermanager.cpp"

View file

@ -0,0 +1,169 @@
/*
* kmail: KDE mail client
* Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef FILTERMANAGER_H
#define FILTERMANAGER_H
#include <akonadi/collection.h>
#include <akonadi/item.h>
#include "mailcommon/search/searchpattern.h"
namespace MailCommon {
class MailFilter;
class ItemContext;
}
class FilterManager: public QObject
{
Q_OBJECT
public:
/**
* Describes the list of filters.
*/
enum FilterSet
{
NoSet = 0x0,
Inbound = 0x1,
Outbound = 0x2,
Explicit = 0x4,
BeforeOutbound = 0x8,
All = Inbound|BeforeOutbound|Outbound|Explicit
};
enum FilterRequires
{
Unknown = 0,
HeaderMessage = 1,
FullMessage = 2
};
/**
* Creates a new filter manager.
*
* @param parent The parent object.
*/
explicit FilterManager( QObject *parent = 0 );
/**
* Destroys the filter manager.
*/
virtual ~FilterManager();
/**
* Clears the list of filters and deletes them.
*/
void clear();
/**
* Reloads the filter rules from config file.
*/
void readConfig();
/**
* Checks for existing filters with the @p name and extend the
* "name" to "name (i)" until no match is found for i=1..n
*/
QString createUniqueName( const QString &name ) const;
/**
* Process given message item by applying the filter rules one by
* one. You can select which set of filters (incoming or outgoing)
* should be used.
*
* @param item The message item to process.
* @param set Select the filter set to use.
* @param account @c true if an account id is specified else @c false
* @param accountId The id of the KMAccount that the message was retrieved from
*
* @return true if the filtering was successful, false in case of any error
*/
bool process( const Akonadi::Item &item, bool needsFullPayload,
FilterSet set = Inbound,
bool account = false, const QString &accountId = QString() );
bool process( const QList<MailCommon::MailFilter*>& mailFilters, const Akonadi::Item &item,
bool needsFullPayload, FilterSet set = Inbound,
bool account = false, const QString &accountId = QString() );
/**
* For ad-hoc filters.
*
* Applies @p filter to message @p item.
* Return codes are as with the above method.
*/
bool process( const Akonadi::Item &item, bool needsFullPayload, const MailCommon::MailFilter *filter );
void filter( const Akonadi::Item& item, FilterManager::FilterSet set, const QString& resourceId );
void filter( const Akonadi::Item &item, const QString& filterId, const QString& resourceId );
void applySpecificFilters(const QList<Akonadi::Item> &selectedMessages, MailCommon::SearchRule::RequiredPart requiredPart, const QStringList& listFilters );
/**
* Applies the filters on the given @p messages.
*/
void applyFilters( const QList<Akonadi::Item> &messages, FilterSet set = Explicit );
/**
* Returns whether the configured filters need the full mail content.
*/
MailCommon::SearchRule::RequiredPart requiredPart(const QString& id) const;
void mailCollectionRemoved( const Akonadi::Collection& collection );
#ifndef NDEBUG
/**
* Outputs all filter rules to console. Used for debugging.
*/
void dump() const;
#endif
protected:
bool processContextItem(MailCommon::ItemContext context );
Q_SIGNALS:
/**
* This signal is emitted whenever the filter list has been updated.
*/
void filterListUpdated();
/**
* This signal is emitted to notify that @p item has not been moved.
*/
void filteringFailed( const Akonadi::Item &item );
void percent(int progress);
void progressMessage(const QString& message);
private:
//@cond PRIVATE
class Private;
Private* d;
Q_PRIVATE_SLOT( d, void itemsFetchJobForFilterDone( KJob* ) )
Q_PRIVATE_SLOT( d, void itemFetchJobForFilterDone( KJob* ) )
Q_PRIVATE_SLOT( d, void moveJobResult( KJob* ) )
Q_PRIVATE_SLOT( d, void modifyJobResult( KJob* ) )
Q_PRIVATE_SLOT( d, void deleteJobResult( KJob* ) )
Q_PRIVATE_SLOT( d, void slotItemsFetchedForFilter( const Akonadi::Item::List& ) )
//@endcond
};
#endif

View file

@ -0,0 +1,2 @@
install(FILES mailfilteragent.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR})
install(PROGRAMS migrate-kmail-filters.pl DESTINATION ${KCONF_UPDATE_INSTALL_DIR})

View file

@ -0,0 +1,4 @@
# Migrate kmail's filters setting to Akonadi mail filter agent
Id=initial-mailfilteragent-migration
File=kmail2rc,akonadi_mailfilter_agentrc
Script=migrate-kmail-filters.pl,perl

View file

@ -0,0 +1,44 @@
#!/usr/bin/perl
#
# Copyright (c) 2011 Tobias Koenig <tokoe@kde.org>
# based on migrate-kmail-filters.pl by Volker Krause <vkrause@kde.org>
#
# 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 2 of the License, or
# (at your option) any later version.
# You should have received a copy of the GNU 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, US
#
$currentGroup = "";
while (<STDIN>) {
next if /^$/;
# recognize groups:
if ( /^\[(.+)\]$/ ) {
$currentGroup = $1;
if ( $currentGroup =~ /^Filter/ ) {
print "# DELETEGROUP [$currentGroup]\n";
print "[$currentGroup]\n";
}
next;
};
($key,$value) = split /=/;
chomp $value;
# Move over keys from the transport groups
if ( $currentGroup =~ /^Filter/ ) {
print "$key=$value\n";
}
# Move over the key for the default transport
elsif ( $currentGroup eq 'General' ) {
if ( $key eq 'filters' ) {
print "[General]\n$key=$value\n";
print "# DELETE [$currentGroup]$key\n";
}
}
}

View file

@ -0,0 +1,334 @@
/*
Copyright (c) 2011 Tobias Koenig <tokoe@kde.org>
This library 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 2 of the License, or (at your
option) any later version.
This library 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 library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "mailfilteragent.h"
#include "mailcommon/dbusoperators.h"
#include "dummykernel.h"
#include "filterlogdialog.h"
#include "filtermanager.h"
#include "mailfilteragentadaptor.h"
#include "pop3resourceattribute.h"
#include <akonadi/changerecorder.h>
#include <akonadi/collectionfetchjob.h>
#include <akonadi/collectionfetchscope.h>
#include <akonadi/dbusconnectionpool.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/kmime/messageparts.h>
#include <akonadi/kmime/messagestatus.h>
#include <akonadi/session.h>
#include <mailcommon/kernel/mailkernel.h>
#include <KLocalizedString>
#include <KMime/Message>
#include <KNotification>
#include <KWindowSystem>
#include <Akonadi/AgentManager>
#include <Akonadi/ItemFetchJob>
#include <Akonadi/AttributeFactory>
#include <QtCore/QVector>
#include <QtCore/QTimer>
static bool isFilterableCollection( const Akonadi::Collection &collection )
{
return MailCommon::Kernel::folderIsInbox( collection );
//TODO: check got filter attribute here
}
MailFilterAgent::MailFilterAgent( const QString &id )
: Akonadi::AgentBase( id ),
m_filterLogDialog( 0 )
{
KGlobal::locale()->insertCatalog(QLatin1String("libmailcommon"));
Akonadi::AttributeFactory::registerAttribute<Pop3ResourceAttribute>();
DummyKernel *kernel = new DummyKernel( this );
CommonKernel->registerKernelIf( kernel ); //register KernelIf early, it is used by the Filter classes
CommonKernel->registerSettingsIf( kernel ); //SettingsIf is used in FolderTreeWidget
m_filterManager = new FilterManager( this );
connect(m_filterManager, SIGNAL(percent(int)), this, SLOT(emitProgress(int)));
connect(m_filterManager, SIGNAL(progressMessage(QString)), this, SLOT(emitProgressMessage(QString)));
Akonadi::Monitor *collectionMonitor = new Akonadi::Monitor( this );
collectionMonitor->fetchCollection( true );
collectionMonitor->ignoreSession( Akonadi::Session::defaultSession() );
collectionMonitor->collectionFetchScope().setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
collectionMonitor->setMimeTypeMonitored( KMime::Message::mimeType() );
connect( collectionMonitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)),
this, SLOT(mailCollectionAdded(Akonadi::Collection,Akonadi::Collection)) );
connect( collectionMonitor, SIGNAL(collectionChanged(Akonadi::Collection)),
this, SLOT(mailCollectionChanged(Akonadi::Collection)) );
connect( collectionMonitor, SIGNAL(collectionRemoved(Akonadi::Collection)),
this, SLOT(mailCollectionRemoved(Akonadi::Collection)) );
QTimer::singleShot( 0, this, SLOT(initializeCollections()) );
qDBusRegisterMetaType<QList<qint64> >();
new MailFilterAgentAdaptor( this );
Akonadi::DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/MailFilterAgent" ), this, QDBusConnection::ExportAdaptors );
Akonadi::DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.MailFilterAgent" ) );
//Enabled or not filterlogdialog
KSharedConfig::Ptr config = KGlobal::config();
if ( config->hasGroup( "FilterLog" ) ) {
KConfigGroup group( config, "FilterLog" );
if ( group.hasKey( "Enabled" ) ) {
if ( group.readEntry( "Enabled", false ) ) {
m_filterLogDialog = new FilterLogDialog( 0 );
const QPixmap pixmap = KIcon( QLatin1String("view-filter") ).pixmap( KIconLoader::SizeSmall, KIconLoader::SizeSmall );
KNotification *notify = new KNotification( QLatin1String("mailfilterlogenabled") );
notify->setComponentData( componentData() );
notify->setPixmap( pixmap );
notify->setText( i18nc("Notification when the filter log was enabled", "Mail Filter Log Enabled" ) );
notify->sendEvent();
}
}
}
changeRecorder()->itemFetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
changeRecorder()->itemFetchScope().setCacheOnly(true);
changeRecorder()->fetchCollection( true );
changeRecorder()->setChangeRecordingEnabled( false );
mProgressCounter = 0;
mProgressTimer = new QTimer( this );
connect(mProgressTimer, SIGNAL(timeout()), this, SLOT(emitProgress()));
}
MailFilterAgent::~MailFilterAgent()
{
delete m_filterLogDialog;
}
void MailFilterAgent::initializeCollections()
{
m_filterManager->readConfig();
Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob( Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive, this );
job->fetchScope().setContentMimeTypes( QStringList() << KMime::Message::mimeType() );
connect( job, SIGNAL(result(KJob*)), this, SLOT(initialCollectionFetchingDone(KJob*)) );
}
void MailFilterAgent::initialCollectionFetchingDone( KJob *job )
{
if ( job->error() ) {
qWarning() << job->errorString();
return; //TODO: proper error handling
}
Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob*>( job );
foreach ( const Akonadi::Collection &collection, fetchJob->collections() ) {
if ( isFilterableCollection( collection ) )
changeRecorder()->setCollectionMonitored( collection, true );
}
emit status(AgentBase::Idle, i18n("Ready") );
emit percent(100);
QTimer::singleShot( 2000, this, SLOT(clearMessage()) );
}
void MailFilterAgent::clearMessage()
{
emit status(AgentBase::Idle, QString() );
}
void MailFilterAgent::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{
/* The monitor mimetype filter would override the collection filter, therefor we have to check
* for the mimetype of the item here.
*/
if ( item.mimeType() != KMime::Message::mimeType() ) {
kDebug() << "MailFilterAgent::itemAdded called for a non-message item!";
return;
}
MailCommon::SearchRule::RequiredPart requiredPart = m_filterManager->requiredPart(collection.resource());
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(item);
connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)),
this, SLOT(itemsReceiviedForFiltering(Akonadi::Item::List)) );
if (requiredPart == MailCommon::SearchRule::CompleteMessage) {
job->fetchScope().fetchFullPayload();
} else if (requiredPart == MailCommon::SearchRule::Header) {
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header, true );
} else {
job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Envelope, true );
}
job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
job->fetchScope().fetchAttribute<Pop3ResourceAttribute>();
job->setProperty( "resource", collection.resource() );
//TODO: Error handling?
}
void MailFilterAgent::itemsReceiviedForFiltering (const Akonadi::Item::List& items)
{
if (items.isEmpty()) {
kDebug() << "MailFilterAgent::itemsReceiviedForFiltering items is empty!";
return;
}
Akonadi::Item item = items.first();
/*
* happens when item no longer exists etc, and queue compression didn't happen yet
*/
if ( !item.hasPayload() ) {
kDebug() << "MailFilterAgent::itemsReceiviedForFiltering item has no payload!";
return;
}
Akonadi::MessageStatus status;
status.setStatusFromFlags( item.flags() );
if ( status.isRead() || status.isSpam() || status.isIgnored() ) {
return;
}
QString resource = sender()->property("resource").toString();
const Pop3ResourceAttribute *pop3ResourceAttribute = item.attribute<Pop3ResourceAttribute>();
if ( pop3ResourceAttribute ) {
resource = pop3ResourceAttribute->pop3AccountName();
}
emitProgressMessage(i18n("Filtering in %1",Akonadi::AgentManager::self()->instance(resource).name()) );
m_filterManager->process( item, m_filterManager->requiredPart(resource), FilterManager::Inbound, true, resource );
emitProgress( ++mProgressCounter );
mProgressTimer->start(1000);
}
void MailFilterAgent::mailCollectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection& )
{
if ( isFilterableCollection( collection ) )
changeRecorder()->setCollectionMonitored( collection, true );
}
void MailFilterAgent::mailCollectionChanged( const Akonadi::Collection &collection )
{
changeRecorder()->setCollectionMonitored( collection, isFilterableCollection( collection ) );
}
void MailFilterAgent::mailCollectionRemoved( const Akonadi::Collection& collection )
{
changeRecorder()->setCollectionMonitored( collection, false );
m_filterManager->mailCollectionRemoved(collection);
}
QString MailFilterAgent::createUniqueName( const QString &nameTemplate )
{
return m_filterManager->createUniqueName( nameTemplate );
}
void MailFilterAgent::filterItems( const QList< qint64 >& itemIds, int filterSet )
{
QList<Akonadi::Item> items;
foreach ( qint64 id, itemIds ) {
items << Akonadi::Item( id );
}
m_filterManager->applyFilters( items, static_cast<FilterManager::FilterSet>(filterSet) );
}
void MailFilterAgent::applySpecificFilters( const QList< qint64 >& itemIds, int requires, const QStringList& listFilters )
{
QList<Akonadi::Item> items;
foreach ( qint64 id, itemIds ) {
items << Akonadi::Item( id );
}
m_filterManager->applySpecificFilters( items, static_cast<MailCommon::SearchRule::RequiredPart>(requires),listFilters );
}
void MailFilterAgent::filterItem( qint64 item, int filterSet, const QString& resourceId )
{
m_filterManager->filter( Akonadi::Item( item ), static_cast<FilterManager::FilterSet>( filterSet ), resourceId );
}
void MailFilterAgent::filter(qint64 item, const QString& filterIdentifier, const QString& resourceId)
{
m_filterManager->filter( Akonadi::Item( item ), filterIdentifier, resourceId );
}
void MailFilterAgent::reload()
{
Akonadi::Collection::List collections = changeRecorder()->collectionsMonitored();
foreach( const Akonadi::Collection &collection, collections) {
changeRecorder()->setCollectionMonitored( collection, false );
}
initializeCollections();
}
void MailFilterAgent::showFilterLogDialog(qlonglong windowId)
{
if ( !m_filterLogDialog ) {
m_filterLogDialog = new FilterLogDialog( 0 );
}
#ifndef Q_WS_WIN
KWindowSystem::setMainWindow(m_filterLogDialog,windowId);
#else
KWindowSystem::setMainWindow(m_filterLogDialog,(HWND)windowId);
#endif
m_filterLogDialog->show();
m_filterLogDialog->raise();
m_filterLogDialog->activateWindow();
m_filterLogDialog->setModal(false);
}
void MailFilterAgent::emitProgress(int p)
{
if ( p == 0 ) {
mProgressTimer->stop();
emit status(AgentBase::Idle, QString() );
}
mProgressCounter = p;
emit percent(p);
}
void MailFilterAgent::emitProgressMessage (const QString& message)
{
emit status(AgentBase::Running, message);
}
QString MailFilterAgent::printCollectionMonitored()
{
QString printDebugCollection;
Akonadi::Collection::List collections = changeRecorder()->collectionsMonitored();
if (collections.isEmpty()) {
printDebugCollection = QLatin1String("No collection is monitored!");
} else {
foreach( const Akonadi::Collection &collection, collections) {
if (!printDebugCollection.isEmpty()) {
printDebugCollection += QLatin1Char('\n');
}
printDebugCollection += QString::fromLatin1("Collection name: %1\n").arg(collection.name());
printDebugCollection += QString::fromLatin1("Collection id: %1\n").arg(collection.id());
}
}
return printDebugCollection;
}
AKONADI_AGENT_MAIN( MailFilterAgent )

View file

@ -0,0 +1,91 @@
[Desktop Entry]
Name=Mail Filter Agent
Name[bs]=Agent poštanskog filtera
Name[ca]=Agent per filtrar el correu
Name[ca@valencia]=Agent per filtrar el correu
Name[cs]=Agent filtrování pošty
Name[da]=Mailfilteragent
Name[de]=Agent zur E-Mail-Filterung
Name[el]=Πράκτορας φιλτραρίσματος αλληλογραφίας
Name[en_GB]=Mail Filter Agent
Name[es]=Agente de filtro de correo
Name[et]=Kirjade filtreerimise agent
Name[fi]=Sähköpostisuodatin
Name[fr]=Agent de filtrage de messages
Name[gl]=Axente de filtrado de correo
Name[hu]=Levélszűrő ügynök
Name[ia]=Agente de filtro de posta
Name[it]=Agente per il filtraggio della posta
Name[kk]=Пошта сүзгіш агенті
Name[km]=
Name[lt]=El. pašto filtravimo agentas
Name[mr]= िि
Name[nb]=E-post filteragent
Name[nds]=Nettpostfilter-Hölper
Name[nl]=E-mail filteragent
Name[pl]=Agent filtrowania poczty
Name[pt]=Agente de Filtragem de E-mail
Name[pt_BR]=Agente de filtros de e-mail
Name[ro]=Agent de filtrare a mesajelor
Name[ru]=Агент почтовых фильтров
Name[sk]=Agent filtrovania pošty
Name[sl]=Posrednik za filtriranje pošte
Name[sr]=Агент филтрирања поште
Name[sr@ijekavian]=Агент филтрирања поште
Name[sr@ijekavianlatin]=Agent filtriranja pošte
Name[sr@latin]=Agent filtriranja pošte
Name[sv]=Postfiltreringsmodul
Name[tr]=Posta Filtre Aracı
Name[uk]=Агент фільтрування пошти
Name[wa]=Adjint passete d' emile
Name[x-test]=xxMail Filter Agentxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Extension to filter emails
Comment[bs]=Proširenje za filtriranje elektronske pošte
Comment[ca]=Extensió per a filtrar correus
Comment[ca@valencia]=Extensió per a filtrar correus
Comment[da]=Udvidelse til at filtrere e-mails
Comment[de]=Erweiterung zur Filterung von E-Mails
Comment[el]=Επέκταση φιλτραρίσματος αλληλογραφίας
Comment[en_GB]=Extension to filter emails
Comment[es]=Extensión para filtrar correos
Comment[et]=Laiendus e-kirjade filtreerimiseks
Comment[fi]=Sähköpostien suodatuslaajennus
Comment[fr]=Extension pour filtrer les courriels
Comment[gl]=Extensión para filtrar correos
Comment[hu]=Kiegészítő e-mailek szűrésére
Comment[ia]=Extension per filtrar messages de e-posta
Comment[it]=Estensione per filtrare i messaggi di posta elettronica
Comment[kk]=Эл.поштаны сузгілеу модулі
Comment[km]=
Comment[lt]=Įskiepis el. laiškų filtravimui
Comment[mr]= ि ि
Comment[nb]=Utvidelse som filtrerer e-poster
Comment[nds]=Verwiedern för't Filtern vun Nettbreven
Comment[nl]=Uitbreiding om e-mails te filteren
Comment[pl]=Rozszerzenie do filtrowania poczty
Comment[pt]=Extensão para filtrar as mensagens de e-mail
Comment[pt_BR]=Extensão para filtros de e-mails
Comment[ro]=Extensie de filtrat scrisori
Comment[ru]=Расширение для фильтрации писем
Comment[sk]=Rozšírenie pre filtrovanie e-mailov
Comment[sl]=Razširitev za filtriranje sporočil
Comment[sr]=Проширење за филтрирање епоште
Comment[sr@ijekavian]=Проширење за филтрирање епоште
Comment[sr@ijekavianlatin]=Proširenje za filtriranje epošte
Comment[sr@latin]=Proširenje za filtriranje epošte
Comment[sv]=Utökning för att filtrera e-post
Comment[tr]=E-postaları filtrelemek için uzantı
Comment[uk]=Додаток для фільтрування поштових повідомлень
Comment[wa]=Stindaedje po passer les emiles al passete
Comment[x-test]=xxExtension to filter emailsxx
Comment[zh_CN]=
Comment[zh_TW]=
Type=AkonadiAgent
Exec=akonadi_mailfilter_agent
Icon=view-filter
X-Akonadi-MimeTypes=message/rfc822
X-Akonadi-Capabilities=Unique,Autostart,NoConfig
X-Akonadi-Identifier=akonadi_mailfilter_agent

View file

@ -0,0 +1,75 @@
/*
Copyright (c) 2011 Tobias Koenig <tokoe@kde.org>
This library 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 2 of the License, or (at your
option) any later version.
This library 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 library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef MAILFILTERAGENT_H
#define MAILFILTERAGENT_H
#include <akonadi/agentbase.h>
#include "mailcommon/search/searchpattern.h"
#include <Akonadi/Collection>
#include <akonadi/item.h>
class FilterLogDialog;
class FilterManager;
class KJob;
class MailFilterAgent : public Akonadi::AgentBase, public Akonadi::AgentBase::ObserverV2
{
Q_OBJECT
public:
explicit MailFilterAgent( const QString &id );
~MailFilterAgent();
void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
QString createUniqueName( const QString &nameTemplate );
void filterItems( const QList< qint64 >& itemIds, int filterSet );
void filterItem( qint64 item, int filterSet, const QString &resourceId );
void filter( qint64 item, const QString &filterIdentifier, const QString &resourceId );
void applySpecificFilters( const QList< qint64 >& itemIds, int requires, const QStringList& listFilters );
void reload();
void showFilterLogDialog(qlonglong windowId = 0);
QString printCollectionMonitored();
private Q_SLOTS:
void initializeCollections();
void initialCollectionFetchingDone( KJob* );
void mailCollectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent );
void mailCollectionChanged( const Akonadi::Collection &collection );
void mailCollectionRemoved( const Akonadi::Collection& collection );
void emitProgress(int percent = 0);
void emitProgressMessage(const QString &message);
void itemsReceiviedForFiltering( const Akonadi::Item::List &items );
void clearMessage();
private:
FilterManager *m_filterManager;
FilterLogDialog *m_filterLogDialog;
QTimer *mProgressTimer;
int mProgressCounter;
};
#endif

View file

@ -0,0 +1,38 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.Akonadi.MailFilterAgent">
<method name="createUniqueName">
<arg name="nameTemplate" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="filter">
<arg name="item" type="x" direction="in"/>
<arg name="filterIdentifier" type="s" direction="in"/>
<arg name="resourceId" type="s" direction="in"/>
</method>
<method name="filterItem">
<arg name="item" type="x" direction="in"/>
<arg name="filterSet" type="i" direction="in"/>
<arg name="resourceId" type="s" direction="in"/>
</method>
<method name="applySpecificFilters">
<arg name="items" type="ax" direction="in"/>
<arg name="FilterRequires" type="i" direction="in"/>
<arg name="listFilters" type="as" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="const QList&lt;qint64&gt; &amp;"/>
</method>
<method name="filterItems">
<arg name="items" type="ax" direction="in"/>
<arg name="filterSet" type="i" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="const QList&lt;qint64&gt; &amp;"/>
</method>
<method name="reload"/>
<method name="showFilterLogDialog">
<arg direction="in" type="x" name="windowId" />
</method>
<method name="printCollectionMonitored">
<arg direction="out" type="s"/>
</method>
<signal name="filtersChanged"/>
</interface>
</node>

View file

@ -0,0 +1,82 @@
/*
Copyright (c) 2013, 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "pop3resourceattribute.h"
#include <QByteArray>
#include <QIODevice>
#include <QDataStream>
class Pop3ResourceAttributePrivate
{
public:
Pop3ResourceAttributePrivate()
{
}
QString accountName;
};
Pop3ResourceAttribute::Pop3ResourceAttribute()
: d(new Pop3ResourceAttributePrivate)
{
}
Pop3ResourceAttribute::~Pop3ResourceAttribute()
{
delete d;
}
Pop3ResourceAttribute *Pop3ResourceAttribute::clone() const
{
Pop3ResourceAttribute *attr = new Pop3ResourceAttribute();
attr->setPop3AccountName(pop3AccountName());
return attr;
}
QByteArray Pop3ResourceAttribute::type() const
{
static const QByteArray sType( "pop3resourceattribute" );
return sType;
}
QByteArray Pop3ResourceAttribute::serialized() const
{
QByteArray result;
QDataStream s( &result, QIODevice::WriteOnly );
s << pop3AccountName();
return result;
}
void Pop3ResourceAttribute::deserialize( const QByteArray &data )
{
QDataStream s( data );
QString value;
s >> value;
d->accountName = value;
}
QString Pop3ResourceAttribute::pop3AccountName() const
{
return d->accountName;
}
void Pop3ResourceAttribute::setPop3AccountName(const QString &accountName)
{
d->accountName = accountName;
}

View file

@ -0,0 +1,45 @@
/*
Copyright (c) 2013, 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef POP3RESOURCEATTRIBUTE_H
#define POP3RESOURCEATTRIBUTE_H
#include <akonadi/attribute.h>
class Pop3ResourceAttributePrivate;
class Pop3ResourceAttribute : public Akonadi::Attribute
{
public:
Pop3ResourceAttribute();
~Pop3ResourceAttribute();
/* reimpl */
Pop3ResourceAttribute *clone() const;
QByteArray type() const;
QByteArray serialized() const;
void deserialize( const QByteArray &data );
QString pop3AccountName() const;
void setPop3AccountName(const QString &accountName);
private:
friend class Pop3ResourceAttributePrivate;
Pop3ResourceAttributePrivate * const d;
};
#endif // POP3RESOURCEATTRIBUTE_H

View file

@ -0,0 +1,51 @@
project(notesagent)
include_directories(
${CMAKE_SOURCE_DIR}/noteshared
${CMAKE_BINARY_DIR}/noteshared
${CMAKE_SOURCE_DIR}/pimcommon
)
set(notesagent_SRCS
notesagent.cpp
notesmanager.cpp
notesagentsettingsdialog.cpp
notesagentalarmdialog.cpp
notesagentnotedialog.cpp
)
kde4_add_kcfg_files(notesagent_SRCS
settings/notesagentsettings.kcfgc
)
qt4_add_dbus_adaptor(notesagent_SRCS org.freedesktop.Akonadi.NotesAgent.xml notesagent.h NotesAgent)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
kde4_add_executable(akonadi_notes_agent ${notesagent_SRCS})
target_link_libraries(akonadi_notes_agent
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_KPIMIDENTITIES_LIBS}
${KDEPIMLIBS_KMIME_LIBS}
${KDEPIMLIBS_AKONADI_KMIME_LIBS}
${KDE4_KIO_LIBS}
${KDE4_KNOTIFYCONFIG_LIBS}
noteshared
pimcommon
)
if (Q_WS_MAC)
set_target_properties(akonadi_notes_agent PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.template)
set_target_properties(akonadi_notes_agent PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Akonadi.archivemail")
set_target_properties(akonadi_notes_agent PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Notes")
endif ()
install(TARGETS akonadi_notes_agent ${INSTALL_TARGETS_DEFAULT_ARGS} )
install(FILES notesagent.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")
install(FILES akonadi_notes_agent.notifyrc DESTINATION "${DATA_INSTALL_DIR}/akonadi_notes_agent" )
add_subdirectory(kconf_update)

Some files were not shown because too many files have changed in this diff Show more