[Commits] [SCM] claws branch, master, updated. 3.11.1-91-gf35429a

ticho at claws-mail.org ticho at claws-mail.org
Sat Apr 25 13:31:19 CEST 2015


The branch, master has been updated
       via  f35429aec1f56ec8bfbba16f6ff736c5f20f19fd (commit)
       via  952c6d7e35c3f6733d5fb7b4edcdc9c9b2e52a27 (commit)
       via  9b928dfc0e70dfd7010becf1801ccbcfd4ab7bfa (commit)
       via  b0978b8f43fa2da616a3171001ba75e7c89f9c34 (commit)
      from  56422f5638fedb2bb8e0e3312403d0bce577161e (commit)

Summary of changes:
 AUTHORS                                            |    1 +
 README                                             |    3 +
 configure.ac                                       |   15 +
 doc/src/readme.txt                                 |    1 +
 doc/src/rfc5804.txt                                | 2747 ++++++++++++++++++++
 src/common/session.c                               |   15 +-
 src/common/session.h                               |    2 +
 src/message_search.c                               |   75 +-
 src/message_search.h                               |   11 +
 src/plugins/Makefile.am                            |    1 +
 .../{libravatar => managesieve}/Makefile.am        |   23 +-
 src/plugins/{libravatar => managesieve}/claws.def  |    2 +-
 src/plugins/managesieve/managesieve.c              | 1031 ++++++++
 src/plugins/managesieve/managesieve.h              |  193 ++
 src/plugins/{libravatar => managesieve}/plugin.def |    0
 src/plugins/managesieve/sieve_editor.c             |  675 +++++
 src/plugins/managesieve/sieve_editor.h             |   50 +
 src/plugins/managesieve/sieve_manager.c            |  803 ++++++
 .../managesieve/sieve_manager.h}                   |   40 +-
 src/plugins/managesieve/sieve_plugin.c             |  154 ++
 src/plugins/managesieve/sieve_prefs.c              |  520 ++++
 src/plugins/managesieve/sieve_prefs.h              |   51 +
 src/plugins/{tnef_parse => managesieve}/version.rc |    4 +-
 23 files changed, 6338 insertions(+), 79 deletions(-)
 create mode 100644 doc/src/rfc5804.txt
 copy src/plugins/{libravatar => managesieve}/Makefile.am (76%)
 copy src/plugins/{libravatar => managesieve}/claws.def (97%)
 create mode 100644 src/plugins/managesieve/managesieve.c
 create mode 100644 src/plugins/managesieve/managesieve.h
 copy src/plugins/{libravatar => managesieve}/plugin.def (100%)
 create mode 100644 src/plugins/managesieve/sieve_editor.c
 create mode 100644 src/plugins/managesieve/sieve_editor.h
 create mode 100644 src/plugins/managesieve/sieve_manager.c
 copy src/{viewtypes.h => plugins/managesieve/sieve_manager.h} (58%)
 create mode 100644 src/plugins/managesieve/sieve_plugin.c
 create mode 100644 src/plugins/managesieve/sieve_prefs.c
 create mode 100644 src/plugins/managesieve/sieve_prefs.h
 copy src/plugins/{tnef_parse => managesieve}/version.rc (83%)


- Log -----------------------------------------------------------------
commit f35429aec1f56ec8bfbba16f6ff736c5f20f19fd
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Apr 25 13:29:51 2015 +0200

    Update AUTHORS and README regarding the Managesieve plugin.

diff --git a/AUTHORS b/AUTHORS
index 2f1d7f5..4b83479 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -312,3 +312,4 @@ contributors (in addition to the above; based on Changelog)
 	Anton Butanaev
 	Daniel Zaoui
 	Johan Vromans
+	Charles Lehner
diff --git a/README b/README
index 4646af4..0ed6b9a 100644
--- a/README
+++ b/README
@@ -147,6 +147,9 @@ All plugin preferences can be found under
     files can be added to the folder tree and used like regular mailboxes.
     LibEtPan! is available from http://www.etpan.org/.
 
+  o Managesieve
+    Manage sieve filters on a server using the ManageSieve protocol.
+
   o Newmail
     Writes a header summary to a log file for each mail received after 
     sorting. The file for the summary is ~/Mail/NewLog.

commit 952c6d7e35c3f6733d5fb7b4edcdc9c9b2e52a27
Author: Charles Lehner <cel at celehner.com>
Date:   Sat Nov 22 22:32:35 2014 -0500

    Add ManageSieve plugin

diff --git a/configure.ac b/configure.ac
index 9439980..60cca19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -973,6 +973,10 @@ AC_ARG_ENABLE(mailmbox-plugin,
 		[  --disable-mailmbox-plugin       Do not build mailmbox plugin],
 		[enable_mailmbox_plugin=$enableval], [enable_mailmbox_plugin=auto])
 
+AC_ARG_ENABLE(managesieve-plugin,
+		[  --disable-managesieve-plugin       Do not build managesieve plugin],
+		[enable_managesieve_plugin=$enableval], [enable_managesieve_plugin=auto])
+
 AC_ARG_ENABLE(newmail-plugin,
 		[  --disable-newmail-plugin        Do not build newmail plugin],
 		[enable_newmail_plugin=$enableval], [enable_newmail_plugin=auto])
@@ -1517,6 +1521,15 @@ else
 	AC_MSG_RESULT(no)
 fi
 
+AC_MSG_CHECKING([whether to build managesieve plugin])
+if test x"$enable_managesieve_plugin" != xno; then
+	PLUGINS="$PLUGINS managesieve"
+	AC_MSG_RESULT(yes)
+else
+	DISABLED_PLUGINS="$DISABLED_PLUGINS managesieve"
+	AC_MSG_RESULT(no)
+fi
+
 AC_MSG_CHECKING([whether to build newmail plugin])
 if test x"$enable_newmail_plugin" != xno; then
 	PLUGINS="$PLUGINS newmail"
@@ -1870,6 +1883,7 @@ AM_CONDITIONAL(BUILD_GDATA_PLUGIN,		test x"$enable_gdata_plugin" != xno)
 AM_CONDITIONAL(BUILD_GEOLOCATION_PLUGIN,	test x"$enable_geolocation_plugin" != xno)
 AM_CONDITIONAL(BUILD_LIBRAVATAR_PLUGIN,		test x"$enable_libravatar_plugin" != xno)
 AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN,		test x"$enable_mailmbox_plugin" != xno)
+AM_CONDITIONAL(BUILD_MANAGESIEVE_PLUGIN,		test x"$enable_managesieve_plugin" != xno)
 AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN,		test x"$enable_newmail_plugin" != xno)
 AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN,	test x"$enable_notification_plugin" != xno)
 AM_CONDITIONAL(BUILD_HOTKEYS,			test x"$enable_notification_plugin" != xno -a x"$HAVE_HOTKEYS" = xyes)
@@ -1918,6 +1932,7 @@ src/plugins/gdata/Makefile
 src/plugins/geolocation/Makefile
 src/plugins/libravatar/Makefile
 src/plugins/mailmbox/Makefile
+src/plugins/managesieve/Makefile
 src/plugins/newmail/Makefile
 src/plugins/notification/Makefile
 src/plugins/notification/gtkhotkey/Makefile
diff --git a/doc/src/readme.txt b/doc/src/readme.txt
index a2c8694..9e2e1b7 100644
--- a/doc/src/readme.txt
+++ b/doc/src/readme.txt
@@ -16,3 +16,4 @@ rfc2822.txt	Internet Message Format
 rfc2980.txt	Common NNTP Extensions
 rfc3156.txt	MIME Security with OpenPGP
 rfc3501.txt	INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
+rfc5804.txt	A Protocol for Remotely Managing Sieve Scripts
diff --git a/doc/src/rfc5804.txt b/doc/src/rfc5804.txt
new file mode 100644
index 0000000..d6deaa8
--- /dev/null
+++ b/doc/src/rfc5804.txt
@@ -0,0 +1,2747 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF)                  A. Melnikov, Ed.
+Request for Comments: 5804                                 Isode Limited
+Category: Standards Track                                      T. Martin
+ISSN: 2070-1721                                    BeThereBeSquare, Inc.
+                                                               July 2010
+
+
+              A Protocol for Remotely Managing Sieve Scripts
+
+Abstract
+
+   Sieve scripts allow users to filter incoming email.  Message stores
+   are commonly sealed servers so users cannot log into them, yet users
+   must be able to update their scripts on them.  This document
+   describes a protocol "ManageSieve" for securely managing Sieve
+   scripts on a remote server.  This protocol allows a user to have
+   multiple scripts, and also alerts a user to syntactically flawed
+   scripts.
+
+Status of This Memo
+
+   This is an Internet Standards Track document.
+
+   This document is a product of the Internet Engineering Task Force
+   (IETF).  It represents the consensus of the IETF community.  It has
+   received public review and has been approved for publication by the
+   Internet Engineering Steering Group (IESG).  Further information on
+   Internet Standards is available in Section 2 of RFC 5741.
+
+   Information about the current status of this document, any errata,
+   and how to provide feedback on it may be obtained at
+   http://www.rfc-editor.org/info/rfc5804.
+
+Copyright Notice
+
+   Copyright (c) 2010 IETF Trust and the persons identified as the
+   document authors.  All rights reserved.
+
+   This document is subject to BCP 78 and the IETF Trust's Legal
+   Provisions Relating to IETF Documents
+   (http://trustee.ietf.org/license-info) in effect on the date of
+   publication of this document.  Please review these documents
+   carefully, as they describe your rights and restrictions with respect
+   to this document.  Code Components extracted from this document must
+   include Simplified BSD License text as described in Section 4.e of
+   the Trust Legal Provisions and are provided without warranty as
+   described in the Simplified BSD License.
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 1]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+Table of Contents
+
+   1. Introduction ....................................................3
+      1.1. Commands and Responses .....................................3
+      1.2. Syntax .....................................................3
+      1.3. Response Codes .............................................3
+      1.4. Active Script ..............................................6
+      1.5. Quotas .....................................................6
+      1.6. Script Names ...............................................6
+      1.7. Capabilities ...............................................7
+      1.8. Transport ..................................................9
+      1.9. Conventions Used in This Document .........................10
+   2. Commands .......................................................10
+      2.1. AUTHENTICATE Command ......................................11
+           2.1.1. Use of SASL PLAIN Mechanism over TLS ...............16
+      2.2. STARTTLS Command ..........................................16
+           2.2.1. Server Identity Check ..............................17
+      2.3. LOGOUT Command ............................................20
+      2.4. CAPABILITY Command ........................................20
+      2.5. HAVESPACE Command .........................................20
+      2.6. PUTSCRIPT Command .........................................21
+      2.7. LISTSCRIPTS Command .......................................23
+      2.8. SETACTIVE Command .........................................24
+      2.9. GETSCRIPT Command .........................................25
+      2.10. DELETESCRIPT Command .....................................25
+      2.11. RENAMESCRIPT Command .....................................26
+      2.12. CHECKSCRIPT Command ......................................27
+      2.13. NOOP Command .............................................28
+      2.14. Recommended Extensions ...................................28
+           2.14.1. UNAUTHENTICATE Command ............................28
+   3. Sieve URL Scheme ...............................................29
+   4. Formal Syntax ..................................................31
+   5. Security Considerations ........................................37
+   6. IANA Considerations ............................................38
+      6.1. ManageSieve Capability Registration Template ..............39
+      6.2. Registration of Initial ManageSieve Capabilities ..........39
+      6.3. ManageSieve Response Code Registration Template ...........41
+      6.4. Registration of Initial ManageSieve Response Codes ........41
+   7. Internationalization Considerations ............................46
+   8. Acknowledgements ...............................................46
+   9. References .....................................................47
+      9.1. Normative References ......................................47
+      9.2. Informative References ....................................48
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 2]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+1.  Introduction
+
+1.1.  Commands and Responses
+
+   A ManageSieve connection consists of the establishment of a client/
+   server network connection, an initial greeting from the server, and
+   client/server interactions.  These client/server interactions consist
+   of a client command, server data, and a server completion result
+   response.
+
+   All interactions transmitted by client and server are in the form of
+   lines, that is, strings that end with a CRLF.  The protocol receiver
+   of a ManageSieve client or server is either reading a line or reading
+   a sequence of octets with a known count followed by a line.
+
+1.2.  Syntax
+
+   ManageSieve is a line-oriented protocol much like [IMAP] or [ACAP],
+   which runs over TCP.  There are three data types: atoms, numbers and
+   strings.  Strings may be quoted or literal.  See [ACAP] for detailed
+   descriptions of these types.
+
+   Each command consists of an atom (the command name) followed by zero
+   or more strings and numbers terminated by CRLF.
+
+   All client queries are replied to with either an OK, NO, or BYE
+   response.  Each response may be followed by a response code (see
+   Section 1.3) and by a string consisting of human-readable text in the
+   local language (as returned by the LANGUAGE capability; see
+   Section 1.7), encoded in UTF-8 [UTF-8].  The contents of the string
+   SHOULD be shown to the user ,and implementations MUST NOT attempt to
+   parse the message for meaning.
+
+   The BYE response SHOULD be used if the server wishes to close the
+   connection.  A server may wish to do this because the client was idle
+   for too long or there were too many failed authentication attempts.
+   This response can be issued at any time and should be immediately
+   followed by a server hang-up of the connection.  If a server has an
+   inactivity timeout resulting in client autologout, it MUST be no less
+   than 30 minutes after successful authentication.  The inactivity
+   timeout MAY be less before authentication.
+
+1.3.  Response Codes
+
+   An OK, NO, or BYE response from the server MAY contain a response
+   code to describe the event in a more detailed machine-parsable
+   fashion.  A response code consists of data inside parentheses in the
+   form of an atom, possibly followed by a space and arguments.
+
+
+
+Melnikov & Martin            Standards Track                    [Page 3]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Response codes are defined when there is a specific action that a
+   client can take based upon the additional information.  In order to
+   support future extension, the response code is represented as a
+   slash-separated (Solidus, %x2F) hierarchy with each level of
+   hierarchy representing increasing detail about the error.  Response
+   codes MUST NOT start with the Solidus character.  Clients MUST
+   tolerate additional hierarchical response code detail that they don't
+   understand.  For example, if the client supports the "QUOTA" response
+   code, but doesn't understand the "QUOTA/MAXSCRIPTS" response code, it
+   should treat "QUOTA/MAXSCRIPTS" as "QUOTA".
+
+   Client implementations MUST tolerate (ignore) response codes that
+   they do not recognize.
+
+   The currently defined response codes are the following:
+
+   AUTH-TOO-WEAK
+
+   This response code is returned in the NO or BYE response from an
+   AUTHENTICATE command.  It indicates that site security policy forbids
+   the use of the requested mechanism for the specified authentication
+   identity.
+
+   ENCRYPT-NEEDED
+
+   This response code is returned in the NO or BYE response from an
+   AUTHENTICATE command.  It indicates that site security policy
+   requires the use of a strong encryption mechanism for the specified
+   authentication identity and mechanism.
+
+   QUOTA
+
+   If this response code is returned in the NO/BYE response, it means
+   that the command would have placed the user above the site-defined
+   quota constraints.  If this response code is returned in the OK
+   response, it can mean that the user's storage is near its quota, or
+   it can mean that the account exceeded its quota but that the
+   condition is being allowed by the server (the server supports
+   so-called soft quotas).  The QUOTA response code has two more
+   detailed variants: "QUOTA/MAXSCRIPTS" (the maximum number of per-user
+   scripts) and "QUOTA/MAXSIZE" (the maximum script size).
+
+   REFERRAL
+
+   This response code may be returned with a BYE result from any
+   command, and includes a mandatory parameter that indicates what
+   server to access to manage this user's Sieve scripts.  The server
+   will be specified by a Sieve URL (see Section 3).  The scriptname
+
+
+
+Melnikov & Martin            Standards Track                    [Page 4]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   portion of the URL MUST NOT be specified.  The client should
+   authenticate to the specified server and use it for all further
+   commands in the current session.
+
+   SASL
+
+   This response code can occur in the OK response to a successful
+   AUTHENTICATE command and includes the optional final server response
+   data from the server as specified by [SASL].
+
+   TRANSITION-NEEDED
+
+   This response code occurs in a NO response of an AUTHENTICATE
+   command.  It indicates that the user name is valid, but the entry in
+   the authentication database needs to be updated in order to permit
+   authentication with the specified mechanism.  This is typically done
+   by establishing a secure channel using TLS, verifying server identity
+   as specified in Section 2.2.1, and finally authenticating once using
+   the [PLAIN] authentication mechanism.  The selected mechanism SHOULD
+   then work for authentications in subsequent sessions.
+
+   This condition can happen if a user has an entry in a system
+   authentication database such as Unix /etc/passwd, but does not have
+   credentials suitable for use by the specified mechanism.
+
+   TRYLATER
+
+   A command failed due to a temporary server failure.  The client MAY
+   continue using local information and try the command later.  This
+   response code only makes sense when returned in a NO/BYE response.
+
+   ACTIVE
+
+   A command failed because it is not allowed on the active script, for
+   example, DELETESCRIPT on the active script.  This response code only
+   makes sense when returned in a NO/BYE response.
+
+   NONEXISTENT
+
+   A command failed because the referenced script name doesn't exist.
+   This response code only makes sense when returned in a NO/BYE
+   response.
+
+   ALREADYEXISTS
+
+   A command failed because the referenced script name already exists.
+   This response code only makes sense when returned in a NO/BYE
+   response.
+
+
+
+Melnikov & Martin            Standards Track                    [Page 5]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   TAG
+
+   This response code name is followed by a string specified in the
+   command.  See Section 2.13 for a possible use case.
+
+   WARNINGS
+
+   This response code MAY be returned by the server in the OK response
+   (but it might be returned with the NO/BYE response as well) and
+   signals the client that even though the script is syntactically
+   valid, it might contain errors not intended by the script writer.
+   This response code is typically returned in response to PUTSCRIPT
+   and/or CHECKSCRIPT commands.  A client seeing such response code
+   SHOULD present the returned warning text to the user.
+
+1.4.  Active Script
+
+   A user may have multiple Sieve scripts on the server, yet only one
+   script may be used for filtering of incoming messages.  This is the
+   active script.  Users may have zero or one active script and MUST use
+   the SETACTIVE command described below for changing the active script
+   or disabling Sieve processing.  For example, users may have an
+   everyday script they normally use and a special script they use when
+   they go on vacation.  Users can change which script is being used
+   without having to download and upload a script stored somewhere else.
+
+1.5.  Quotas
+
+   Servers SHOULD impose quotas to prevent malicious users from
+   overflowing available storage.  If a command would place a user over
+   a quota setting, servers that impose such quotas MUST reply with a NO
+   response containing the QUOTA response code.  Client implementations
+   MUST be able to handle commands failing because of quota
+   restrictions.
+
+1.6.  Script Names
+
+   A Sieve script name is a sequence of Unicode characters encoded in
+   UTF-8 [UTF-8].  A script name MUST comply with Net-Unicode Definition
+   (Section 2 of [NET-UNICODE]), with the additional restriction of
+   prohibiting the following Unicode characters:
+
+   o  0000-001F; [CONTROL CHARACTERS]
+
+   o  007F; DELETE
+
+   o  0080-009F; [CONTROL CHARACTERS]
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 6]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   o  2028; LINE SEPARATOR
+
+   o  2029; PARAGRAPH SEPARATOR
+
+   Sieve script names MUST be at least one octet (and hence Unicode
+   character) long.  Zero octets script name has a special meaning (see
+   Section 2.8).  Servers MUST allow names of up to 128 Unicode
+   characters in length (which can take up to 512 bytes when encoded in
+   UTF-8, not counting the terminating NUL), and MAY allow longer names.
+   A server that receives a script name longer than its internal limit
+   MUST reject the corresponding operation, in particular it MUST NOT
+   truncate the script name.
+
+1.7.  Capabilities
+
+   Server capabilities are sent automatically by the server upon a
+   client connection, or after successful STARTTLS and AUTHENTICATE
+   (which establishes a Simple Authentication and Security Layer (SASL))
+   commands.  Capabilities may change immediately after a successfully
+   completed STARTTLS command, and/or immediately after a successfully
+   completed AUTHENTICATE command, and/or after a successfully completed
+   UNAUTHENTICATE command (see Section 2.14.1).  Capabilities MUST
+   remain static at all other times.
+
+   Clients MAY request the capabilities at a later time by issuing the
+   CAPABILITY command described later.  The capabilities consist of a
+   series of lines each with one or two strings.  The first string is
+   the name of the capability, which is case-insensitive.  The second
+   optional string is the value associated with that capability.  Order
+   of capabilities is arbitrary, but each capability name can appear at
+   most once.
+
+   The following capabilities are defined in this document:
+
+   IMPLEMENTATION - Name of implementation and version.  This capability
+   MUST always be returned by the server.
+
+   SASL - List of SASL mechanisms supported by the server, each
+   separated by a space.  This list can be empty if and only if STARTTLS
+   is also advertised.  This means that the client must negotiate TLS
+   encryption with STARTTLS first, at which point the SASL capability
+   will list a non-empty list of SASL mechanisms.
+
+   SIEVE - List of space-separated Sieve extensions (as listed in Sieve
+   "require" action [SIEVE]) supported by the Sieve engine.  This
+   capability MUST always be returned by the server.
+
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 7]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   STARTTLS - If TLS [TLS] is supported by this implementation.  Before
+   advertising this capability a server MUST verify to the best of its
+   ability that TLS can be successfully negotiated by a client with
+   common cipher suites.  Specifically, a server should verify that a
+   server certificate has been installed and that the TLS subsystem has
+   successfully initialized.  This capability SHOULD NOT be advertised
+   once STARTTLS or AUTHENTICATE command completes successfully.  Client
+   and server implementations MUST implement the STARTTLS extension.
+
+   MAXREDIRECTS - Specifies the limit on the number of Sieve "redirect"
+   actions a script can perform during a single evaluation.  Note that
+   this is different from the total number of "redirect" actions a
+   script can contain.  The value is a non-negative number represented
+   as a ManageSieve string.
+
+   NOTIFY - A space-separated list of URI schema parts for supported
+   notification methods.  This capability MUST be specified if the Sieve
+   implementation supports the "enotify" extension [NOTIFY].
+
+   LANGUAGE - The language (<Language-Tag> from [RFC5646]) currently
+   used for human-readable error messages.  If this capability is not
+   returned, the "i-default" [RFC2277] language is assumed.  Note that
+   the current language MAY be per-user configurable (i.e., it MAY
+   change after authentication).
+
+   OWNER - The canonical name of the logged-in user (SASL "authorization
+   identity") encoded in UTF-8.  This capability MUST NOT be returned in
+   unauthenticated state and SHOULD be returned once the AUTHENTICATE
+   command succeeds.
+
+   VERSION - This capability MUST be returned by servers compliant with
+   this document or its successor.  For servers compliant with this
+   document, the capability value is the string "1.0".  Lack of this
+   capability means that the server predates this specification and thus
+   doesn't support the following commands: RENAMESCRIPT, CHECKSCRIPT,
+   and NOOP.
+
+   Section 2.14 defines some additional ManageSieve extensions and their
+   respective capabilities.
+
+   A server implementation MUST return SIEVE, IMPLEMENTATION, and
+   VERSION capabilities.
+
+   A client implementation MUST ignore any listed capabilities that it
+   does not understand.
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 8]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+       Example:
+
+       S: "IMPlemENTATION" "Example1 ManageSieved v001"
+       S: "SASl" "DIGEST-MD5 GSSAPI"
+       S: "SIeVE" "fileinto vacation"
+       S: "StaRTTLS"
+       S: "NOTIFY" "xmpp mailto"
+       S: "MAXREdIRECTS" "5"
+       S: "VERSION" "1.0"
+       S: OK
+
+   After successful authentication, this might look like this:
+
+       Example:
+
+       S: "IMPlemENTATION" "Example1 ManageSieved v001"
+       S: "SASl" "DIGEST-MD5 GSSAPI"
+       S: "SIeVE" "fileinto vacation"
+       S: "NOTIFY" "xmpp mailto"
+       S: "OWNER" "alexey at example.com"
+       S: "MAXREdIRECTS" "5"
+       S: "VERSION" "1.0"
+       S: OK
+
+1.8.  Transport
+
+   The ManageSieve protocol assumes a reliable data stream such as that
+   provided by TCP.  When TCP is used, a ManageSieve server typically
+   listens on port 4190.
+
+   Before opening the TCP connection, the ManageSieve client first MUST
+   resolve the Domain Name System (DNS) hostname associated with the
+   receiving entity and determine the appropriate TCP port for
+   communication with the receiving entity.  The process is as follows:
+
+   1.  Attempt to resolve the hostname using a [DNS-SRV] Service of
+       "sieve" and a Proto of "tcp" for the target domain (e.g.,
+       "example.net"), resulting in resource records such as
+       "_sieve._tcp.example.net.".  The result of the SRV lookup, if
+       successful, will be one or more combinations of a port and
+       hostname; the ManageSieve client MUST resolve the returned
+       hostnames to IPv4/IPv6 addresses according to returned SRV record
+       weight.  IP addresses from the first successfully resolved
+       hostname (with the corresponding port number returned by SRV
+       lookup) are used to connect to the server.  If connection using
+       one of the IP addresses fails, the next resolved IP address is
+
+
+
+
+
+Melnikov & Martin            Standards Track                    [Page 9]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+       used to connect.  If connection to all resolved IP addresses
+       fails, then the resolution/connect is repeated for the next
+       hostname returned by SRV lookup.
+
+   2.  If the SRV lookup fails, the fallback SHOULD be a normal IPv4 or
+       IPv6 address record resolution to determine the IP address, where
+       the port used is the default ManageSieve port of 4190.
+
+1.9.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [KEYWORDS].
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.  Line breaks that do not start a new "C:" or
+   "S:" exist for editorial reasons.
+
+   Examples of authentication in this document are using DIGEST-MD5
+   [DIGEST-MD5] and GSSAPI [GSSAPI] SASL mechanisms.
+
+2.  Commands
+
+   This section and its subsections describe valid ManageSieve commands.
+   Upon initial connection to the server, the client's session is in
+   non-authenticated state.  Prior to successful authentication, only
+   the AUTHENTICATE, CAPABILITY, STARTTLS, LOGOUT, and NOOP (see Section
+   2.13) commands are valid.  ManageSieve extensions MAY define other
+   commands that are valid in non-authenticated state.  Servers MUST
+   reject all other commands with a NO response.  Clients may pipeline
+   commands (send more than one command at a time without waiting for
+   completion of the first command).  However, a group of commands sent
+   together MUST NOT have an AUTHENTICATE (*), a STARTTLS, or a
+   HAVESPACE command anywhere but the last command in the list.
+
+   (*) - The only exception to this rule is when the AUTHENTICATE
+   command contains an initial response for a SASL mechanism that allows
+   clients to send data first, the mechanism is known to complete in one
+   round trip, and the mechanism doesn't negotiate a SASL security
+   layer.  Two examples of such SASL mechanisms are PLAIN [PLAIN] and
+   EXTERNAL [SASL].
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 10]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.1.  AUTHENTICATE Command
+
+   Arguments:  String - mechanism
+               String - initial data (optional)
+
+   The AUTHENTICATE command indicates a SASL [SASL] authentication
+   mechanism to the server.  If the server supports the requested
+   authentication mechanism, it performs an authentication protocol
+   exchange to identify and authenticate the user.  Optionally, it also
+   negotiates a security layer for subsequent protocol interactions.  If
+   the requested authentication mechanism is not supported, the server
+   rejects the AUTHENTICATE command by sending the NO response.
+
+   The authentication protocol exchange consists of a series of server
+   challenges and client responses that are specific to the selected
+   authentication mechanism.  A server challenge consists of a string
+   (quoted or literal) followed by a CRLF.  The contents of the string
+   is a base-64 encoding [BASE64] of the SASL data.  A client response
+   consists of a string (quoted or literal) with the base-64 encoding of
+   the SASL data followed by a CRLF.  If the client wishes to cancel the
+   authentication exchange, it issues a string containing a single "*".
+   If the server receives such a response, it MUST reject the
+   AUTHENTICATE command by sending a NO reply.
+
+   Note that an empty challenge/response is sent as an empty string.  If
+   the mechanism dictates that the final response is sent by the server,
+   this data MAY be placed within the data portion of the SASL response
+   code to save a round trip.
+
+   The optional initial-response argument to the AUTHENTICATE command is
+   used to save a round trip when using authentication mechanisms that
+   are defined to send no data in the initial challenge.  When the
+   initial-response argument is used with such a mechanism, the initial
+   empty challenge is not sent to the client and the server uses the
+   data in the initial-response argument as if it were sent in response
+   to the empty challenge.  If the initial-response argument to the
+   AUTHENTICATE command is used with a mechanism that sends data in the
+   initial challenge, the server MUST reject the AUTHENTICATE command by
+   sending the NO response.
+
+   The service name specified by this protocol's profile of SASL is
+   "sieve".
+
+   Reauthentication is not supported by ManageSieve protocol's profile
+   of SASL.  That is, after a successfully completed AUTHENTICATE
+   command, no more AUTHENTICATE commands may be issued in the same
+   session.  After a successful AUTHENTICATE command completes, a server
+   MUST reject any further AUTHENTICATE commands with a NO reply.
+
+
+
+Melnikov & Martin            Standards Track                   [Page 11]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   However, note that a server may implement the UNAUTHENTICATE
+   extension described in Section 2.14.1.
+
+   If a security layer is negotiated through the SASL authentication
+   exchange, it takes effect immediately following the CRLF that
+   concludes the successful authentication exchange for the client, and
+   the CRLF of the OK response for the server.
+
+   When a security layer takes effect, the ManageSieve protocol is reset
+   to the initial state (the state in ManageSieve after a client has
+   connected to the server).  The server MUST discard any knowledge
+   obtained from the client that was not obtained from the SASL (or TLS)
+   negotiation itself.  Likewise, the client MUST discard any knowledge
+   obtained from the server, such as the list of ManageSieve extensions,
+   that was not obtained from the SASL (and/or TLS) negotiation itself.
+   (Note that a client MAY compare the advertised SASL mechanisms before
+   and after authentication in order to detect an active down-
+   negotiation attack.  See below.)
+
+   Once a SASL security layer is established, the server MUST re-issue
+   the capability results, followed by an OK response.  This is
+   necessary to protect against man-in-the-middle attacks that alter the
+   capabilities list prior to SASL negotiation.  The capability results
+   MUST include all SASL mechanisms the server was capable of
+   negotiating with that client.  This is done in order to allow the
+   client to detect an active down-negotiation attack.  If a user-
+   oriented client detects such a down-negotiation attack, it SHOULD
+   either notify the user (it MAY give the user the opportunity to
+   continue with the ManageSieve session in this case) or close the
+   transport connection and indicate that a down-negotiation attack
+   might be in progress.  If an automated client detects a down-
+   negotiation attack, it SHOULD return or log an error indicating that
+   a possible attack might be in progress and/or SHOULD close the
+   transport connection.
+
+   When both [TLS] and SASL security layers are in effect, the TLS
+   encoding MUST be applied (when sending data) after the SASL encoding.
+
+   Server implementations SHOULD support SASL proxy authentication so
+   that an administrator can administer a user's scripts.  Proxy
+   authentication is when a user authenticates as herself/himself but
+   requests the server to act (authorize) as another user.
+
+   The authorization identity generated by this [SASL] exchange is a
+   "simple username" (in the sense defined in [SASLprep]), and both
+   client and server MUST use the [SASLprep] profile of the [StringPrep]
+   algorithm to prepare these names for transmission or comparison.  If
+   preparation of the authorization identity fails or results in an
+
+
+
+Melnikov & Martin            Standards Track                   [Page 12]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   empty string (unless it was transmitted as the empty string), the
+   server MUST fail the authentication.
+
+   If an AUTHENTICATE command fails with a NO response, the client MAY
+   try another authentication mechanism by issuing another AUTHENTICATE
+   command.  In other words, the client may request authentication types
+   in decreasing order of preference.
+
+   Note that a failed (NO) response to the AUTHENTICATE command may
+   contain one of the following response codes: AUTH-TOO-WEAK, ENCRYPT-
+   NEEDED, or TRANSITION-NEEDED.  See Section 1.3 for detailed
+   description of the relevant conditions.
+
+   To ensure interoperability, both client and server implementations of
+   the ManageSieve protocol MUST implement the SCRAM-SHA-1 [SCRAM] SASL
+   mechanism, as well as [PLAIN] over [TLS].
+
+   Note: use of PLAIN over TLS reflects current use of PLAIN over TLS in
+   other email-related protocols; however, a longer-term goal is to
+   migrate email-related protocols from using PLAIN over TLS to SCRAM-
+   SHA-1 mechanism.
+
+   Examples (Note that long lines are folded for readability and are not
+   part of protocol exchange):
+
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "SASL" "DIGEST-MD5 GSSAPI"
+       S: "SIEVE" "fileinto vacation"
+       S: "STARTTLS"
+       S: "VERSION" "1.0"
+       S: OK
+       C: Authenticate "DIGEST-MD5"
+       S: "cmVhbG09ImVsd29vZC5pbm5vc29mdC5leGFtcGxlLmNvbSIsbm9uY2U9Ik
+          9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGFsZ29yaXRobT1tZDUtc2Vz
+          cyxjaGFyc2V0PXV0Zi04"
+       C: "Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iY2hyaXMiLHJlYWxtPSJlbHdvb2
+          QuaW5ub3NvZnQuZXhhbXBsZS5jb20iLG5vbmNlPSJPQTZNRzl0RVFHbTJo
+          aCIsbmM9MDAwMDAwMDEsY25vbmNlPSJPQTZNSFhoNlZxVHJSayIsZGlnZX
+          N0LXVyaT0ic2lldmUvZWx3b29kLmlubm9zb2Z0LmV4YW1wbGUuY29tIixy
+          ZXNwb25zZT1kMzg4ZGFkOTBkNGJiZDc2MGExNTIzMjFmMjE0M2FmNyxxb3
+          A9YXV0aA=="
+       S: OK (SASL "cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZ
+          mZmZA==")
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 13]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   A slightly different variant of the same authentication exchange is:
+
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "SASL" "DIGEST-MD5 GSSAPI"
+       S: "SIEVE" "fileinto vacation"
+       S: "VERSION" "1.0"
+       S: "STARTTLS"
+       S: OK
+       C: Authenticate "DIGEST-MD5"
+       S: {136}
+       S: cmVhbG09ImVsd29vZC5pbm5vc29mdC5leGFtcGxlLmNvbSIsbm9uY2U9Ik
+          9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGFsZ29yaXRobT1tZDUtc2Vz
+          cyxjaGFyc2V0PXV0Zi04
+       C: {300+}
+       C: Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iY2hyaXMiLHJlYWxtPSJlbHdvb2
+          QuaW5ub3NvZnQuZXhhbXBsZS5jb20iLG5vbmNlPSJPQTZNRzl0RVFHbTJo
+          aCIsbmM9MDAwMDAwMDEsY25vbmNlPSJPQTZNSFhoNlZxVHJSayIsZGlnZX
+          N0LXVyaT0ic2lldmUvZWx3b29kLmlubm9zb2Z0LmV4YW1wbGUuY29tIixy
+          ZXNwb25zZT1kMzg4ZGFkOTBkNGJiZDc2MGExNTIzMjFmMjE0M2FmNyxxb3
+          A9YXV0aA==
+       S: {56}
+       S: cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
+       C: ""
+       S: OK
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 14]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Another example demonstrating use of SASL PLAIN mechanism under TLS
+   follows.  This example also demonstrate use of SASL "initial
+   response" (the second parameter to the Authenticate command):
+
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "VERSION" "1.0"
+       S: "SASL" ""
+       S: "SIEVE" "fileinto vacation"
+       S: "STARTTLS"
+       S: OK
+       C: STARTTLS
+       S: OK
+       <TLS negotiation, further commands are under TLS layer>
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "VERSION" "1.0"
+       S: "SASL" "PLAIN"
+       S: "SIEVE" "fileinto vacation"
+       S: OK
+       C: Authenticate "PLAIN" "QJIrweAPyo6Q1T9xu"
+       S: NO
+       C: Authenticate "PLAIN" "QJIrweAPyo6Q1T9xz"
+       S: NO
+       C: Authenticate "PLAIN" "QJIrweAPyo6Q1T9xy"
+       S: BYE "Too many failed authentication attempts"
+       <Server closes connection>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 15]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   The following example demonstrates use of SASL "initial response".
+   It also demonstrates that an empty response can be sent as a literal
+   and that negotiating a SASL security layer results in the server
+   re-issuing server capabilities:
+
+       C: AUTHENTICATE "GSSAPI" {1488+}
+       C: YIIE[...1480 octets here ...]dA==
+       S: {208}
+       S: YIGZBgkqhkiG9xIBAgICAG+BiTCBhqADAgEFoQMCAQ+iejB4oAMCARKic
+          [...114 octets here ...]
+          /yzpAy9p+Y0LanLskOTvMc0MnjgAa4YEr3eJ6
+       C: {0+}
+       C:
+       S: {44}
+       S: BQQF/wAMAAwAAAAAYRGFAo6W0vIHti8i1UXODgEAEAA=
+       C: {44+}
+       C: BQQE/wAMAAwAAAAAIsT1iv9UkZApw471iXt6cwEAAAE=
+       S: OK
+       <Further commands/responses are under SASL security layer>
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "VERSION" "1.0"
+       S: "SASL" "PLAIN DIGEST-MD5 GSSAPI"
+       S: "SIEVE" "fileinto vacation"
+       S: "LANGUAGE" "ru"
+       S: "MAXREDIRECTS" "3"
+       S: ok
+
+2.1.1.  Use of SASL PLAIN Mechanism over TLS
+
+   This section is normative for ManageSieve client implementations that
+   support SASL [PLAIN] over [TLS].
+
+   If a ManageSieve client is willing to use SASL PLAIN over TLS to
+   authenticate to the ManageSieve server, the client MUST verify the
+   server identity (see Section 2.2.1).  If the server identity can't be
+   verified (e.g., the server has not provided any certificate, or if
+   the certificate verification fails), the client MUST NOT attempt to
+   authenticate using the SASL PLAIN mechanism.
+
+2.2.  STARTTLS Command
+
+   Support for STARTTLS command in servers is optional.  Its
+   availability is advertised with "STARTTLS" capability as described in
+   Section 1.7.
+
+   The STARTTLS command requests commencement of a TLS [TLS]
+   negotiation.  The negotiation begins immediately after the CRLF in
+   the OK response.  After a client issues a STARTTLS command, it MUST
+
+
+
+Melnikov & Martin            Standards Track                   [Page 16]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   NOT issue further commands until a server response is seen and the
+   TLS negotiation is complete.
+
+   The STARTTLS command is only valid in non-authenticated state.  The
+   server remains in non-authenticated state, even if client credentials
+   are supplied during the TLS negotiation.  The SASL [SASL] EXTERNAL
+   mechanism MAY be used to authenticate once TLS client credentials are
+   successfully exchanged, but servers supporting the STARTTLS command
+   are not required to support the EXTERNAL mechanism.
+
+   After the TLS layer is established, the server MUST re-issue the
+   capability results, followed by an OK response.  This is necessary to
+   protect against man-in-the-middle attacks that alter the capabilities
+   list prior to STARTTLS.  This capability result MUST NOT include the
+   STARTTLS capability.
+
+   The client MUST discard cached capability information and replace it
+   with the new information.  The server MAY advertise different
+   capabilities after STARTTLS.
+
+       Example:
+
+       C: StartTls
+       S: oK
+       <TLS negotiation, further commands are under TLS layer>
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "SASL" "PLAIN DIGEST-MD5 GSSAPI"
+       S: "SIEVE" "fileinto vacation"
+       S: "VERSION" "1.0"
+       S: "LANGUAGE" "fr"
+       S: ok
+
+2.2.1.  Server Identity Check
+
+   During the TLS negotiation, the ManageSieve client MUST check its
+   understanding of the server hostname/IP address against the server's
+   identity as presented in the server Certificate message, in order to
+   prevent man-in-the-middle attacks.  In this section, the client's
+   understanding of the server's identity is called the "reference
+   identity".
+
+   Checking is performed according to the following rules:
+
+   o  If the reference identity is a hostname:
+
+      1.  If a subjectAltName extension of the SRVName [X509-SRV],
+          dNSName [X509] (in that order of preference) type is present
+          in the server's certificate, then it SHOULD be used as the
+
+
+
+Melnikov & Martin            Standards Track                   [Page 17]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+          source of the server's identity.  Matching is performed as
+          described in Section 2.2.1.1, with the exception that no
+          wildcard matching is allowed for SRVName type.  If the
+          certificate contains multiple names (e.g., more than one
+          dNSName field), then a match with any one of the fields is
+          considered acceptable.
+
+      2.  The client MAY use other types of subjectAltName for
+          performing comparison.
+
+      3.  The server's identity MAY also be verified by comparing the
+          reference identity to the Common Name (CN) [RFC4519] value in
+          the leaf Relative Distinguished Name (RDN) of the subjectName
+          field of the server's certificate.  This comparison is
+          performed using the rules for comparison of DNS names in
+          Section 2.2.1.1, below.  Although the use of the Common Name
+          value is existing practice, it is deprecated, and
+          Certification Authorities are encouraged to provide
+          subjectAltName values instead.  Note that the TLS
+          implementation may represent DNs in certificates according to
+          X.500 or other conventions.  For example, some X.500
+          implementations order the RDNs in a DN using a left-to-right
+          (most significant to least significant) convention instead of
+          LDAP's right-to-left convention.
+
+   o  When the reference identity is an IP address, the iPAddress
+      subjectAltName SHOULD be used by the client for comparison.  The
+      comparison is performed as described in Section 2.2.1.2.
+
+   If the server identity check fails, user-oriented clients SHOULD
+   either notify the user (clients MAY give the user the opportunity to
+   continue with the ManageSieve session in this case) or close the
+   transport connection and indicate that the server's identity is
+   suspect.  Automated clients SHOULD return or log an error indicating
+   that the server's identity is suspect and/or SHOULD close the
+   transport connection.  Automated clients MAY provide a configuration
+   setting that disables this check, but MUST provide a setting that
+   enables it.
+
+   Beyond the server identity check described in this section, clients
+   should be prepared to do further checking to ensure that the server
+   is authorized to provide the service it is requested to provide.  The
+   client may need to make use of local policy information in making
+   this determination.
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 18]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.2.1.1.  Comparison of DNS Names
+
+   If the reference identity is an internationalized domain name,
+   conforming implementations MUST convert it to the ASCII Compatible
+   Encoding (ACE) format as specified in Section 4 of RFC 3490 [RFC3490]
+   before comparison with subjectAltName values of type dNSName.
+   Specifically, conforming implementations MUST perform the conversion
+   operation specified in Section 4 of [RFC3490] as follows:
+
+   o  in step 1, the domain name SHALL be considered a "stored string";
+
+   o  in step 3, set the flag called "UseSTD3ASCIIRules";
+
+   o  in step 4, process each label with the "ToASCII" operation; and
+
+   o  in step 5, change all label separators to U+002E (full stop).
+
+   After performing the "to-ASCII" conversion, the DNS labels and names
+   MUST be compared for equality according to the rules specified in
+   Section 3 of [RFC3490]; i.e., once all label separators are replaced
+   with U+002E (dot) they are compared in the case-insensitive manner.
+
+   The '*' (ASCII 42) wildcard character is allowed in subjectAltName
+   values of type dNSName, and then only as the left-most (least
+   significant) DNS label in that value.  This wildcard matches any
+   left-most DNS label in the server name.  That is, the subject
+   *.example.com matches the server names a.example.com and
+   b.example.com, but does not match example.com or a.b.example.com.
+
+2.2.1.2.  Comparison of IP Addresses
+
+   When the reference identity is an IP address, the identity MUST be
+   converted to the "network byte order" octet string representation
+   [RFC791][RFC2460].  For IP Version 4, as specified in RFC 791, the
+   octet string will contain exactly four octets.  For IP Version 6, as
+   specified in RFC 2460, the octet string will contain exactly sixteen
+   octets.  This octet string is then compared against subjectAltName
+   values of type iPAddress.  A match occurs if the reference identity
+   octet string and value octet strings are identical.
+
+2.2.1.3.  Comparison of Other subjectName Types
+
+   Client implementations MAY support matching against subjectAltName
+   values of other types as described in other documents.
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 19]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.3.  LOGOUT Command
+
+   The client sends the LOGOUT command when it is finished with a
+   connection and wishes to terminate it.  The server MUST reply with an
+   OK response.  The server MUST ignore commands issued by the client
+   after the LOGOUT command.
+
+   The client SHOULD wait for the OK response before closing the
+   connection.  This avoids the TCP connection going into the TIME_WAIT
+   state on the server.  In order to avoid going into the TIME_WAIT TCP
+   state, the server MAY wait for a short while for the client to close
+   the TCP connection first.  Whether or not the server waits for the
+   client to close the connection, it MUST then close the connection
+   itself.
+
+       Example:
+
+       C: Logout
+       S: Ok
+       <connection is terminated>
+
+2.4.  CAPABILITY Command
+
+   The CAPABILITY command requests the server capabilities as described
+   earlier in this document.  It has no parameters.
+
+       Example:
+
+       C: CAPABILITY
+       S: "IMPLEMENTATION" "Example1 ManageSieved v001"
+       S: "VERSION" "1.0"
+       S: "SASL" "PLAIN SCRAM-SHA-1 GSSAPI"
+       S: "SIEVE" "fileinto vacation"
+       S: "STARTTLS"
+       S: OK
+
+2.5.  HAVESPACE Command
+
+   Arguments:  String - name
+               Number - script size
+
+   The HAVESPACE command is used to query the server for available
+   space.  Clients specify the name they wish to save the script as and
+   its size in octets.  Both parameters can be used by the server to see
+   if the script with the specified name and size is within a user's
+   quota(s).  For example, the server MAY use the script name to check
+   if a script would be replaced or a new one would be created.  Servers
+   respond with a NO if storing a script with that name and size would
+
+
+
+Melnikov & Martin            Standards Track                   [Page 20]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   fail or OK otherwise.  Clients SHOULD issue this command before
+   attempting to place a script on the server.
+
+   Note that the OK response from the HAVESPACE command does not
+   constitute a guarantee of success as server disk space conditions
+   could change between the client issuing the HAVESPACE and the client
+   issuing the PUTSCRIPT commands.  A QUOTA response code (see
+   Section 1.3) remains a possible (albeit unlikely) response to a
+   subsequent PUTSCRIPT with the same name and size.
+
+       Example:
+
+       C: HAVESPACE "myscript" 999999
+       S: NO (QUOTA/MAXSIZE) "Quota exceeded"
+
+       C: HAVESPACE "foobar" 435
+       S: OK
+
+2.6.  PUTSCRIPT Command
+
+   Arguments:  String - Script name
+               String - Script content
+
+   The PUTSCRIPT command is used by the client to submit a Sieve script
+   to the server.
+
+   If the script already exists, upon success the old script will be
+   overwritten.  The old script MUST NOT be overwritten if PUTSCRIPT
+   fails in any way.  A script of zero length SHOULD be disallowed.
+
+   This command places the script on the server.  It does not affect
+   whether the script is processed on incoming mail, unless it replaces
+   the script that is already active.  The SETACTIVE command is used to
+   mark a script as active.
+
+   When submitting large scripts, clients SHOULD use the HAVESPACE
+   command beforehand to query if the server is willing to accept a
+   script of that size.
+
+   The server MUST check the submitted script for validity, which
+   includes checking that the script complies with the Sieve grammar
+   [SIEVE] and that all Sieve extensions mentioned in the script's
+   "require" statement(s) are supported by the Sieve interpreter.  (Note
+   that if the Sieve interpreter supports the Sieve "ihave" extension
+   [I-HAVE], any unrecognized/unsupported extension mentioned in the
+   "ihave" test MUST NOT cause the validation failure.)  Other checks
+   such as validating the supplied command arguments for each command
+   MAY be performed.  Essentially, the performed validation SHOULD be
+
+
+
+Melnikov & Martin            Standards Track                   [Page 21]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   the same as performed when compiling the script for execution.
+   Implementations that use a binary representation to store compiled
+   scripts can extend the validation to a full compilation, in order to
+   avoid validating uploaded scripts multiple times.
+
+   If the script fails the validation, the server MUST reply with a NO
+   response.  Any script that fails the validity test MUST NOT be stored
+   on the server.  The message given with a NO response MUST be human
+   readable and SHOULD contain a specific error message giving the line
+   number of the first error.  Implementors should strive to produce
+   helpful error messages similar to those given by programming language
+   compilers.  Client implementations should note that this may be a
+   multiline literal string with more than one error message separated
+   by CRLFs.  The human-readable message is in the language returned in
+   the latest LANGUAGE capability (or in "i-default"; see Section 1.7),
+   encoded in UTF-8 [UTF-8].
+
+   An OK response MAY contain the WARNINGS response code.  In such a
+   case the human-readable message that follows the OK response SHOULD
+   contain a specific warning message (or messages) giving the line
+   number(s) in the script that might contain errors not intended by the
+   script writer.  The human-readable message is in the language
+   returned in the latest LANGUAGE capability (or in "i-default"; see
+   Section 1.7), encoded in UTF-8 [UTF-8].  A client seeing such a
+   response code SHOULD present the message to the user.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 22]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+       Examples:
+
+       C: Putscript "foo" {31+}
+       C: #comment
+       C: InvalidSieveCommand
+       C:
+       S: NO "line 2: Syntax error"
+
+       C: Putscript "mysievescript" {110+}
+       C: require ["fileinto"];
+       C:
+       C: if envelope :contains "to" "tmartin+sent" {
+       C:   fileinto "INBOX.sent";
+       C: }
+       S: OK
+
+       C: Putscript "myforwards" {190+}
+       C: redirect "111 at example.net";
+       C:
+       C: if size :under 10k {
+       C:     redirect "mobile at cell.example.com";
+       C: }
+       C:
+       C: if envelope :contains "to" "tmartin+lists" {
+       C:     redirect "lists at groups.example.com";
+       C: }
+       S: OK (WARNINGS) "line 8: server redirect action
+               limit is 2, this redirect might be ignored"
+
+2.7.  LISTSCRIPTS Command
+
+   This command lists the scripts the user has on the server.  Upon
+   success, a list of CRLF-separated script names (each represented as a
+   quoted or literal string) is returned followed by an OK response.  If
+   there exists an active script, the atom ACTIVE is appended to the
+   corresponding script name.  The atom ACTIVE MUST NOT appear on more
+   than one response line.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 23]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+       Example:
+
+       C: Listscripts
+       S: "summer_script"
+       S: "vacation_script"
+       S: {13}
+       S: clever"script
+       S: "main_script" ACTIVE
+       S: OK
+
+       C: listscripts
+       S: "summer_script"
+       S: "main_script" active
+       S: OK
+
+2.8.  SETACTIVE Command
+
+   Arguments:  String - script name
+
+   This command sets a script active.  If the script name is the empty
+   string (i.e., ""), then any active script is disabled.  Disabling an
+   active script when there is no script active is not an error and MUST
+   result in an OK reply.
+
+   If the script does not exist on the server, then the server MUST
+   reply with a NO response.  Such a reply SHOULD contain the
+   NONEXISTENT response code.
+
+       Examples:
+
+       C: Setactive "vacationscript"
+       S: Ok
+
+       C: Setactive ""
+       S: Ok
+
+       C: Setactive "baz"
+       S: No (NONEXISTENT) "There is no script by that name"
+
+       C: Setactive "baz"
+       S: No (NONEXISTENT) {31}
+       S: There is no script by that name
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 24]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.9.  GETSCRIPT Command
+
+   Arguments:  String - script name
+
+   This command gets the contents of the specified script.  If the
+   script does not exist, the server MUST reply with a NO response.
+   Such a reply SHOULD contain the NONEXISTENT response code.
+
+   Upon success, a string with the contents of the script is returned
+   followed by an OK response.
+
+       Example:
+
+       C: Getscript "myscript"
+       S: {54}
+       S: #this is my wonderful script
+       S: reject "I reject all";
+       S:
+       S: OK
+
+2.10.  DELETESCRIPT Command
+
+   Arguments:  String - script name
+
+   This command is used to delete a user's Sieve script.  Servers MUST
+   reply with a NO response if the script does not exist.  Such
+   responses SHOULD include the NONEXISTENT response code.
+
+   The server MUST NOT allow the client to delete an active script, so
+   the server MUST reply with a NO response if attempted.  Such a
+   response SHOULD contain the ACTIVE response code.  If a client wishes
+   to delete an active script, it should use the SETACTIVE command to
+   disable the script first.
+
+       Example:
+
+       C: Deletescript "foo"
+       S: Ok
+
+       C: Deletescript "baz"
+       S: No (ACTIVE) "You may not delete an active script"
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 25]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.11.  RENAMESCRIPT Command
+
+   Arguments:  String - Old Script name
+               String - New Script name
+
+   This command is used to rename a user's Sieve script.  Servers MUST
+   reply with a NO response if the old script does not exist (in which
+   case the NONEXISTENT response code SHOULD be included), or a script
+   with the new name already exists (in which case the ALREADYEXISTS
+   response code SHOULD be included).  Renaming the active script is
+   allowed; the renamed script remains active.
+
+       Example:
+
+       C: Renamescript "foo" "bar"
+       S: Ok
+
+       C: Renamescript "baz" "bar"
+       S: No "bar already exists"
+
+   If the server doesn't support the RENAMESCRIPT command, the client
+   can emulate it by performing the following steps:
+
+   1.  List available scripts with LISTSCRIPTS.  If the script with the
+       new script name exists, then the client should ask the user
+       whether to abort the operation, to replace the script (by issuing
+       the DELETESCRIPT <newname> after that), or to choose a different
+       name.
+
+   2.  Download the old script with GETSCRIPT <oldname>.
+
+   3.  Upload the old script with the new name: PUTSCRIPT <newname>.
+
+   4.  If the old script was active (as reported by LISTSCRIPTS in step
+       1), then make the new script active: SETACTIVE <newname>.
+
+   5.  Delete the old script: DELETESCRIPT <oldname>.
+
+   Note that these steps don't describe how to handle various other
+   error conditions (for example, NO response containing QUOTA response
+   code in step 3).  Error handling is left as an exercise for the
+   reader.
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 26]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.12.  CHECKSCRIPT Command
+
+   Arguments:  String - Script content
+
+   The CHECKSCRIPT command is used by the client to verify Sieve script
+   validity without storing the script on the server.
+
+   The server MUST check the submitted script for syntactic validity,
+   which includes checking that all Sieve extensions mentioned in Sieve
+   script "require" statement(s) are supported by the Sieve interpreter.
+   (Note that if the Sieve interpreter supports the Sieve "ihave"
+   extension [I-HAVE], any unrecognized/unsupported extension mentioned
+   in the "ihave" test MUST NOT cause the syntactic validation failure.)
+   If the script fails this test, the server MUST reply with a NO
+   response.  The message given with a NO response MUST be human
+   readable and SHOULD contain a specific error message giving the line
+   number of the first error.  Implementors should strive to produce
+   helpful error messages similar to those given by programming language
+   compilers.  Client implementations should note that this may be a
+   multiline literal string with more than one error message separated
+   by CRLFs.  The human-readable message is in the language returned in
+   the latest LANGUAGE capability (or in "i-default"; see Section 1.7),
+   encoded in UTF-8 [UTF-8].
+
+       Examples:
+
+       C: CheckScript {31+}
+       C: #comment
+       C: InvalidSieveCommand
+       C:
+       S: NO "line 2: Syntax error"
+
+   A ManageSieve server supporting this command MUST NOT check if the
+   script will put the current user over its quota limit.
+
+   An OK response MAY contain the WARNINGS response code.  In such a
+   case, the human-readable message that follows the OK response SHOULD
+   contain a specific warning message (or messages) giving the line
+   number(s) in the script that might contain errors not intended by the
+   script writer.  The human-readable message is in the language
+   returned in the latest LANGUAGE capability (or in "i-default"; see
+   Section 1.7), encoded in UTF-8 [UTF-8].  A client seeing such a
+   response code SHOULD present the message to the user.
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 27]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+2.13.  NOOP Command
+
+   Arguments:  String - tag to echo back (optional)
+
+   The NOOP command does nothing, beyond returning a response to the
+   client.  It may be used by clients for protocol re-synchronization or
+   to reset any inactivity auto-logout timer on the server.
+
+   The response to the NOOP command is always OK, followed by the TAG
+   response code together with the supplied string.  If no string was
+   supplied in the NOOP command, the TAG response code MUST NOT be
+   included.
+
+       Examples:
+
+       C: NOOP
+       S: OK "NOOP completed"
+
+       C: NOOP "STARTTLS-SYNC-42"
+       S: OK (TAG {16}
+       S: STARTTLS-SYNC-42) "Done"
+
+2.14.  Recommended Extensions
+
+   The UNAUTHENTICATE extension (advertised as the "UNAUTHENTICATE"
+   capability with no parameters) defines a new UNAUTHENTICATE command,
+   which allows a client to return the server to non-authenticated
+   state.  Support for this extension is RECOMMENDED.
+
+2.14.1.  UNAUTHENTICATE Command
+
+   The UNAUTHENTICATE command returns the server to the
+   non-authenticated state.  It doesn't affect any previously
+   established TLS [TLS] or SASL (Section 2.1) security layer.
+
+   The UNAUTHENTICATE command is only valid in authenticated state.  If
+   issued in a wrong state, the server MUST reject it with a NO
+   response.
+
+   The UNAUTHENTICATE command has no parameters.
+
+   When issued in the authenticated state, the UNAUTHENTICATE command
+   MUST NOT fail (i.e., it must never return anything other than OK or
+   BYE).
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 28]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+3.  Sieve URL Scheme
+
+   URI scheme name: sieve
+
+   Status: permanent
+
+   URI scheme syntax: Described using ABNF [ABNF].  Some ABNF
+   productions not defined below are from [URI-GEN].
+
+         sieveurl = sieveurl-server / sieveurl-list-scripts /
+                    sieveurl-script
+
+         sieveurl-server = "sieve://" authority
+
+         sieveurl-list-scripts = "sieve://" authority ["/"]
+
+         sieveurl-script = "sieve://" authority "/"
+                           [owner "/"] scriptname
+
+         authority = <defined in [URI-GEN]>
+
+         owner         = *ochar
+                         ;; %-encoded version of [SASL] authorization
+                         ;; identity (script owner) or "userid".
+                         ;;
+                         ;; Empty owner is used to reference
+                         ;; global scripts.
+                         ;;
+                         ;; Note that ASCII characters such as " ", ";",
+                         ;; "&", "=", "/" and "?" must be %-encoded
+                         ;; as per rule specified in [URI-GEN].
+
+         scriptname    = 1*ochar
+                         ;; %-encoded version of UTF-8 representation
+                         ;; of the script name.
+                         ;; Note that ASCII characters such as " ", ";",
+                         ;; "&", "=", "/" and "?" must be %-encoded
+                         ;; as per rule specified in [URI-GEN].
+
+         ochar         = unreserved / pct-encoded / sub-delims-sh /
+                         ":" / "@"
+                         ;; Same as [URI-GEN] 'pchar',
+                         ;; but without ";", "&" and "=".
+
+         unreserved = <defined in [URI-GEN]>
+
+         pct-encoded = <defined in [URI-GEN]>
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 29]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+         sub-delims-sh = "!" / "$" / "'" / "(" / ")" /
+                         "*" / "+" / ","
+                         ;; Same as [URI-GEN] sub-delims,
+                         ;; but without ";", "&" and "=".
+
+   URI scheme semantics:
+
+      A Sieve URL identifies a Sieve server or a Sieve script on a Sieve
+      server.  The latter form is associated with the application/sieve
+      MIME type defined in [SIEVE].  There is no MIME type associated
+      with the former form of Sieve URI.
+
+      The server form is used in the REFERRAL response code (see Section
+      1.3) in order to designate another server where the client should
+      perform its operations.
+
+      The script form allows to retrieve (GETSCRIPT), update
+      (PUTSCRIPT), delete (DELETESCRIPT), or activate (SETACTIVE) the
+      named script; however, the most typical action would be to
+      retrieve the script.  If the script name is empty (omitted), the
+      URI requests that the client lists available scripts using the
+      LISTSCRIPTS command.
+
+   Encoding considerations:
+
+      The script name and/or the owner, if present, is in UTF-8.  Non--
+      US-ASCII UTF-8 octets MUST be percent-encoded as described in
+      [URI-GEN].  US-ASCII characters such as " " (space), ";", "&",
+      "=", "/" and "?"  MUST be %-encoded as described in [URI-GEN].
+      Note that "&" and "?" are in this list in order to allow for
+      future extensions.
+
+      Note that the empty owner (e.g., sieve://example.com//script) is
+      different from the missing owner (e.g.,
+      sieve://example.com/script) and is reserved for referencing global
+      scripts.
+
+      The user name (in the "authority" part), if present, is in UTF-8.
+      Non-US-ASCII UTF-8 octets MUST be percent-encoded as described in
+      [URI-GEN].
+
+   Applications/protocols that use this URI scheme name:
+   ManageSieve [RFC5804] clients and servers.  Clients that can store
+   user preferences in protocols such as [LDAP] or [ACAP].
+
+   Interoperability considerations: None.
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 30]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Security considerations:
+   The <scriptname> part of a ManageSieve URL might potentially disclose
+   some confidential information about the author of the script or,
+   depending on a ManageSieve implementation, about configuration of the
+   mail system.  The latter might be used to prepare for a more complex
+   attack on the mail system.
+
+   Clients resolving ManageSieve URLs that wish to achieve data
+   confidentiality and/or integrity SHOULD use the STARTTLS command (if
+   supported by the server) before starting authentication, or use a
+   SASL mechanism, such as GSSAPI, that provides a confidentiality
+   security layer.
+
+   Contact: Alexey Melnikov <alexey.melnikov at isode.com>
+
+   Author/Change controller: IESG.
+
+   References: This document and RFC 5228 [SIEVE].
+
+4.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (BNF) notation as specified in [ABNF].  This uses the ABNF core
+   rules as specified in Appendix A of the ABNF specification [ABNF].
+   "UTF8-2", "UTF8-3", and "UTF8-4" non-terminal are defined in [UTF-8].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper- or lowercase characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+    SAFE-CHAR             = %x01-09 / %x0B-0C / %x0E-21 / %x23-5B /
+                            %x5D-7F
+                            ;; any TEXT-CHAR except QUOTED-SPECIALS
+
+    QUOTED-CHAR           = SAFE-UTF8-CHAR / "\" QUOTED-SPECIALS
+
+    QUOTED-SPECIALS       = DQUOTE / "\"
+
+    SAFE-UTF8-CHAR        = SAFE-CHAR / UTF8-2 / UTF8-3 / UTF8-4
+                            ;; <UTF8-2>, <UTF8-3>, and <UTF8-4>
+                            ;; are defined in [UTF-8].
+
+    ATOM-CHAR             = "!" / %x23-27 / %x2A-5B / %x5D-7A / %x7C-7E
+                            ;; Any CHAR except ATOM-SPECIALS
+
+    ATOM-SPECIALS         = "(" / ")" / "{" / SP / CTL / QUOTED-SPECIALS
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 31]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+    NZDIGIT               = %x31-39
+                            ;; 1-9
+
+    atom                  = 1*1024ATOM-CHAR
+
+    iana-token            = atom
+                            ;; MUST be registered with IANA
+
+    auth-type             = DQUOTE auth-type-name DQUOTE
+
+    auth-type-name        = iana-token
+                            ;; as defined in SASL [SASL]
+
+    command               = (command-any / command-auth /
+                             command-nonauth) CRLF
+                            ;; Modal based on state
+
+    command-any           = command-capability / command-logout /
+                            command-noop
+                            ;; Valid in all states
+
+    command-auth          = command-getscript / command-setactive /
+                            command-listscripts / command-deletescript /
+                            command-putscript / command-checkscript /
+                            command-havespace /
+                            command-renamescript /
+                            command-unauthenticate
+                            ;; Valid only in Authenticated state
+
+    command-nonauth       = command-authenticate / command-starttls
+                            ;; Valid only when in Non-Authenticated
+                            ;; state
+
+    command-authenticate  = "AUTHENTICATE" SP auth-type [SP string]
+                            *(CRLF string)
+
+    command-capability    = "CAPABILITY"
+
+    command-deletescript  = "DELETESCRIPT" SP sieve-name
+
+    command-getscript     = "GETSCRIPT" SP sieve-name
+
+    command-havespace     = "HAVESPACE" SP sieve-name SP number
+
+    command-listscripts   = "LISTSCRIPTS"
+
+    command-noop          = "NOOP" [SP string]
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 32]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+    command-logout        = "LOGOUT"
+
+    command-putscript     = "PUTSCRIPT" SP sieve-name SP sieve-script
+
+    command-checkscript   = "CHECKSCRIPT" SP sieve-script
+
+    sieve-script          = string
+
+    command-renamescript  = "RENAMESCRIPT" SP old-sieve-name SP
+                            new-sieve-name
+
+    old-sieve-name        = sieve-name
+
+    new-sieve-name        = sieve-name
+
+    command-setactive     = "SETACTIVE" SP active-sieve-name
+
+    command-starttls      = "STARTTLS"
+
+    command-unauthenticate= "UNAUTHENTICATE"
+
+    extend-token          = atom
+                            ;; MUST be defined by a Standards Track or
+                            ;; IESG-approved experimental protocol
+                            ;; extension
+
+    extension-data        = extension-item *(SP extension-item)
+
+    extension-item        = extend-token / string / number /
+                            "(" [extension-data] ")"
+
+    literal-c2s           = "{" number "+}" CRLF *OCTET
+                            ;; The number represents the number of
+                            ;; octets.
+                            ;; This type of literal can only be sent
+                            ;; from the client to the server.
+
+    literal-s2c           = "{" number "}" CRLF *OCTET
+                            ;; Almost identical to literal-c2s,
+                            ;; but with no '+' character.
+                            ;; The number represents the number of
+                            ;; octets.
+                            ;; This type of literal can only be sent
+                            ;; from the server to the client.
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 33]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+    number                = (NZDIGIT *DIGIT) / "0"
+                            ;; A 32-bit unsigned number
+                            ;; with no extra leading zeros.
+                            ;; (0 <= n < 4,294,967,296)
+
+    number-str            = string
+                            ;; <number> encoded as a <string>.
+
+    quoted                = DQUOTE *1024QUOTED-CHAR DQUOTE
+                            ;; limited to 1024 octets between the <">s
+
+    resp-code             = "AUTH-TOO-WEAK" / "ENCRYPT-NEEDED" / "QUOTA"
+                            ["/" ("MAXSCRIPTS" / "MAXSIZE")] /
+                            resp-code-sasl /
+                            resp-code-referral /
+                            "TRANSITION-NEEDED" / "TRYLATER" /
+                            "ACTIVE" / "NONEXISTENT" /
+                            "ALREADYEXISTS" / "WARNINGS" /
+                            "TAG" SP string /
+                            resp-code-ext
+
+    resp-code-referral    = "REFERRAL" SP sieveurl
+
+    resp-code-sasl        = "SASL" SP string
+
+    resp-code-name        = iana-token
+                            ;; The response code name is hierarchical,
+                            ;; separated by '/'.
+                            ;; The response code name MUST NOT start
+                            ;; with '/'.
+
+    resp-code-ext         = resp-code-name [SP extension-data]
+                            ;; unknown response codes MUST be tolerated
+                            ;; by the client.
+
+    response              = response-authenticate /
+                            response-logout /
+                            response-getscript /
+                            response-setactive /
+                            response-listscripts /
+                            response-deletescript /
+                            response-putscript /
+                            response-checkscript /
+                            response-capability /
+                            response-havespace /
+                            response-starttls /
+                            response-renamescript /
+                            response-noop /
+
+
+
+Melnikov & Martin            Standards Track                   [Page 34]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+                            response-unauthenticate
+
+    response-authenticate = *(string CRLF)
+                            ((response-ok [response-capability]) /
+                             response-nobye)
+                            ;; <response-capability> is REQUIRED if a
+                            ;; SASL security layer was negotiated and
+                            ;; MUST be omitted otherwise.
+
+    response-capability   = *(single-capability) response-oknobye
+
+    single-capability     = capability-name [SP string] CRLF
+
+    capability-name       = string
+
+                            ;; Note that literal-s2c is allowed.
+
+    initial-capabilities  = DQUOTE "IMPLEMENTATION" DQUOTE SP string /
+                            DQUOTE "SASL" DQUOTE SP sasl-mechs /
+                            DQUOTE "SIEVE" DQUOTE SP sieve-extensions /
+                            DQUOTE "MAXREDIRECTS" DQUOTE SP number-str /
+                            DQUOTE "NOTIFY" DQUOTE SP notify-mechs /
+                            DQUOTE "STARTTLS" DQUOTE /
+                            DQUOTE "LANGUAGE" DQUOTE SP language /
+                            DQUOTE "VERSION" DQUOTE SP version /
+                            DQUOTE "OWNER" DQUOTE SP string
+                            ;; Each capability conforms to
+                            ;; the syntax for single-capability.
+                            ;; Also, note that the capability name
+                            ;; can be returned as either literal-s2c
+                            ;; or quoted, even though only "quoted"
+                            ;; string is shown above.
+
+    version = ( DQUOTE "1.0" DQUOTE ) / version-ext
+
+    version-ext = DQUOTE ver-major "." ver-minor DQUOTE
+                 ; Future versions specified in updates
+                 ; to this document.  An increment to
+                 ; the ver-major means a backward-incompatible
+                 ; change to the protocol, e.g., "3.5" (ver-major "3")
+                 ; is not backward-compatible with any "2.X" version.
+                 ; Any version "Z.W" MUST be backward compatible
+                 ; with any version "Z.Q", where Q < W.
+                 ; For example, version "2.4" is backward compatible
+                 ; with version "2.0", "2.1", "2.2", and "2.3".
+
+    ver-major = number
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 35]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+    ver-minor = number
+
+    sasl-mechs = string
+                 ; Space-separated list of SASL mechanisms,
+                 ; each SASL mechanism name complies with rules
+                 ; specified in [SASL].
+                 ; Can be empty.
+
+    sieve-extensions = string
+                 ; Space-separated list of supported SIEVE extensions.
+                 ; Can be empty.
+
+    language     = string
+                 ; Contains <Language-Tag> from [RFC5646].
+
+
+    notify-mechs = string
+                 ; Space-separated list of URI schema parts
+                 ; for supported notification [NOTIFY] methods.
+                 ; MUST NOT be empty.
+
+    response-deletescript = response-oknobye
+
+    response-getscript    = (sieve-script CRLF response-ok) /
+                            response-nobye
+
+    response-havespace    = response-oknobye
+
+    response-listscripts  = *(sieve-name [SP "ACTIVE"] CRLF)
+                            response-oknobye
+                            ;; ACTIVE may only occur with one sieve-name
+
+    response-logout       = response-oknobye
+
+    response-unauthenticate= response-oknobye
+                             ;; "NO" response can only be returned when
+                             ;; the command is issued in a wrong state
+                             ;; or has a wrong number of parameters
+
+    response-ok           = "OK" [SP "(" resp-code ")"]
+                            [SP string] CRLF
+                            ;; The string contains human-readable text
+                            ;; encoded as UTF-8.
+
+    response-nobye        = ("NO" / "BYE") [SP "(" resp-code ")"]
+                            [SP string] CRLF
+                            ;; The string contains human-readable text
+                            ;; encoded as UTF-8.
+
+
+
+Melnikov & Martin            Standards Track                   [Page 36]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+    response-oknobye      = response-ok / response-nobye
+
+    response-noop         = response-ok
+
+    response-putscript    = response-oknobye
+
+    response-checkscript  = response-oknobye
+
+    response-renamescript = response-oknobye
+
+    response-setactive    = response-oknobye
+
+    response-starttls     = (response-ok response-capability) /
+                            response-nobye
+
+    sieve-name            = string
+                            ;; See Section 1.6 for the full list of
+                            ;; prohibited characters.
+                            ;; Empty string is not allowed.
+
+    active-sieve-name     = string
+                            ;; See Section 1.6 for the full list of
+                            ;; prohibited characters.
+                            ;; This is similar to <sieve-name>, but
+                            ;; empty string is allowed and has a special
+                            ;; meaning.
+
+    string                = quoted / literal-c2s / literal-s2c
+                            ;; literal-c2s is only allowed when sent
+                            ;; from the client to the server.
+                            ;; literal-s2c is only allowed when sent
+                            ;; from the server to the client.
+                            ;; quoted is allowed in either direction.
+
+5.  Security Considerations
+
+   The AUTHENTICATE command uses SASL [SASL] to provide authentication
+   and authorization services.  Integrity and privacy services can be
+   provided by [SASL] and/or [TLS].  When a SASL mechanism is used, the
+   security considerations for that mechanism apply.
+
+   This protocol's transactions are susceptible to passive observers or
+   man-in-the-middle attacks that alter the data, unless the optional
+   encryption and integrity services of the SASL (via the AUTHENTICATE
+   command) and/or [TLS] (via the STARTTLS command) are enabled, or an
+   external security mechanism is used for protection.  It may be useful
+   to allow configuration of both clients and servers to refuse to
+   transfer sensitive information in the absence of strong encryption.
+
+
+
+Melnikov & Martin            Standards Track                   [Page 37]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   If an implementation supports SASL mechanisms that are vulnerable to
+   passive eavesdropping attacks (such as [PLAIN]), then the
+   implementation MUST support at least one configuration where these
+   SASL mechanisms are not advertised or used without the presence of an
+   external security layer such as [TLS].
+
+   Some response codes returned on failed AUTHENTICATE command may
+   disclose whether or not the username is valid (e.g., TRANSITION-
+   NEEDED), so server implementations SHOULD provide the ability to
+   disable these features (or make them not conditional on a per-user
+   basis) for sites concerned about such disclosure.  In the case of
+   ENCRYPT-NEEDED, if it is applied to all identities then no extra
+   information is disclosed, but if it is applied on a per-user basis it
+   can disclose information.
+
+   A compromised or malicious server can use the TRANSITION-NEEDED
+   response code to force the client that is configured to use a
+   mechanism that does not disclose the user's password to the server
+   (e.g., Kerberos), to send the bare password to the server.  Clients
+   SHOULD have the ability to disable the password transition feature,
+   or disclose that risk to the user and offer the user an option of how
+   to proceed.
+
+6.  IANA Considerations
+
+   IANA has reserved TCP port number 4190 for use with the ManageSieve
+   protocol described in this document.
+
+   IANA has registered the "sieve" URI scheme defined in Section 3 of
+   this document.
+
+   IANA has registered "sieve" in the "GSSAPI/Kerberos/SASL Service
+   Names" registry.
+
+   IANA has created a new registry for ManageSieve capabilities.  The
+   registration template for ManageSieve capabilities is specified in
+   Section 6.1.  ManageSieve protocol capabilities MUST be specified in
+   a Standards-Track or IESG-approved Experimental RFC.
+
+   IANA has created a new registry for ManageSieve response codes.  The
+   registration template for ManageSieve response codes is specified in
+   Section 6.3.  ManageSieve protocol response codes MUST be specified
+   in a Standards-Track or IESG-approved Experimental RFC.
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 38]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+6.1.  ManageSieve Capability Registration Template
+
+   To: iana at iana.org
+   Subject: ManageSieve Capability Registration
+
+   Please register the following ManageSieve capability:
+
+   Capability name:
+   Description:
+   Relevant publications:
+   Person & email address to contact for further information:
+   Author/Change controller:
+
+6.2.  Registration of Initial ManageSieve Capabilities
+
+   To: iana at iana.org
+   Subject: ManageSieve Capability Registration
+
+   Please register the following ManageSieve capabilities:
+
+   Capability name:  IMPLEMENTATION
+   Description:   Its value contains the name of the server
+                  implementation and its version.
+   Relevant publications:  this RFC, Section 1.7.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  SASL
+   Description:   Its value contains a space-separated list of SASL
+                  mechanisms supported by the server.
+   Relevant publications:  this RFC, Sections 1.7 and 2.1.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  SIEVE
+   Description:   Its value contains a space-separated list of supported
+                  SIEVE extensions.
+   Relevant publications:  this RFC, Section 1.7.  Also [SIEVE].
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 39]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Capability name:  STARTTLS
+   Description:   This capability is returned if the server supports TLS
+                  (STARTTLS command).
+   Relevant publications:  this RFC, Sections 1.7 and 2.2.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  NOTIFY
+   Description:   This capability is returned if the server supports the
+                  'enotify' [NOTIFY] Sieve extension.
+   Relevant publications:  this RFC, Section 1.7.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  MAXREDIRECTS
+   Description:   This capability returns the limit on the number of
+                  Sieve "redirect" actions a script can perform during a
+                  single evaluation.  The value is a non-negative number
+                  represented as a ManageSieve string.
+   Relevant publications:  this RFC, Section 1.7.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  LANGUAGE
+   Description:   The language (<Language-Tag> from [RFC5646]) currently
+                  used for human-readable error messages.
+   Relevant publications:  this RFC, Section 1.7.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Capability name:  OWNER
+   Description:   Its value contains the UTF-8-encoded name of the
+                  currently logged-in user ("authorization identity"
+                  according to RFC 4422).
+   Relevant publications:  this RFC, Section 1.7.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 40]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Capability name:  VERSION
+   Description:   This capability is returned if the server is compliant
+                  with RFC 5804; i.e., that it supports RENAMESCRIPT,
+                  CHECKSCRIPT, and NOOP commands.
+   Relevant publications:  this RFC, Sections 2.11, 2.12, and 2.13.
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+6.3.  ManageSieve Response Code Registration Template
+
+   To: iana at iana.org
+   Subject: ManageSieve Response Code Registration
+
+   Please register the following ManageSieve response code:
+
+      Response Code:
+      Arguments (use ABNF to specify syntax, or the word NONE if none
+      can be specified):
+      Purpose:
+      Published Specification(s):
+      Person & email address to contact for further information:
+      Author/Change controller:
+
+6.4.  Registration of Initial ManageSieve Response Codes
+
+   To: iana at iana.org
+   Subject: ManageSieve Response Code Registration
+
+   Please register the following ManageSieve response codes:
+
+   Response Code: AUTH-TOO-WEAK
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       This response code is returned in the NO response from
+                  an AUTHENTICATE command.  It indicates that site
+                  security policy forbids the use of the requested
+                  mechanism for the specified authentication identity.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 41]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Response Code: ENCRYPT-NEEDED
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       This response code is returned in the NO response from
+                  an AUTHENTICATE command.  It indicates that site
+                  security policy requires the use of a strong
+                  encryption mechanism for the specified authentication
+                  identity and mechanism.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: QUOTA
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       If this response code is returned in the NO/BYE
+                  response, it means that the command would have placed
+                  the user above the site-defined quota constraints.  If
+                  this response code is returned in the OK response, it
+                  can mean that the user is near its quota or that the
+                  user exceeded its quota, but the server supports soft
+                  quotas.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: QUOTA/MAXSCRIPTS
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       If this response code is returned in the NO/BYE
+                  response, it means that the command would have placed
+                  the user above the site-defined limit on the number of
+                  Sieve scripts.  If this response code is returned in
+                  the OK response, it can mean that the user is near its
+                  quota or that the user exceeded its quota, but the
+                  server supports soft quotas.  This response code is a
+                  more specific version of the QUOTA response code.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 42]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Response Code: QUOTA/MAXSIZE
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       If this response code is returned in the NO/BYE
+                  response, it means that the command would have placed
+                  the user above the site-defined maximum script size.
+                  If this response code is returned in the OK response,
+                  it can mean that the user is near its quota or that
+                  the user exceeded its quota, but the server supports
+                  soft quotas.  This response code is a more specific
+                  version of the QUOTA response code.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: REFERRAL
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  <sieveurl>
+   Purpose:       This response code may be returned with a BYE result
+                  from any command, and includes a mandatory parameter
+                  that indicates what server to access to manage this
+                  user's Sieve scripts.  The server will be specified by
+                  a Sieve URL (see Section 3).  The scriptname portion
+                  of the URL MUST NOT be specified.  The client should
+                  authenticate to the specified server and use it for
+                  all further commands in the current session.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: SASL
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  <string>
+   Purpose:       This response code can occur in the OK response to a
+                  successful AUTHENTICATE command and includes the
+                  optional final server response data from the server as
+                  specified by [SASL].
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 43]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Response Code: TRANSITION-NEEDED
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       This response code occurs in a NO response of an
+                  AUTHENTICATE command.  It indicates that the user name
+                  is valid, but the entry in the authentication database
+                  needs to be updated in order to permit authentication
+                  with the specified mechanism.  This is typically done
+                  by establishing a secure channel using TLS, followed
+                  by authenticating once using the [PLAIN]
+                  authentication mechanism.  The selected mechanism
+                  SHOULD then work for authentications in subsequent
+                  sessions.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: TRYLATER
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       A command failed due to a temporary server failure.
+                  The client MAY continue using local information and
+                  try the command later.  This response code only make
+                  sense when returned in a NO/BYE response.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: ACTIVE
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       A command failed because it is not allowed on the
+                  active script, for example, DELETESCRIPT on the active
+                  script.  This response code only makes sense when
+                  returned in a NO/BYE response.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 44]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   Response Code: NONEXISTENT
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       A command failed because the referenced script name
+                  doesn't exist.  This response code only makes sense
+                  when returned in a NO/BYE response.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: ALREADYEXISTS
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       A command failed because the referenced script name
+                  already exists.  This response code only makes sense
+                  when returned in a NO/BYE response.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: WARNINGS
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  NONE
+   Purpose:       This response code MAY be returned by the server in
+                  the OK response (but it might be returned with the NO/
+                  BYE response as well) and signals the client that even
+                  though the script is syntactically valid, it might
+                  contain errors not intended by the script writer.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+   Response Code: TAG
+   Arguments (use ABNF to specify syntax, or the word NONE if none can
+   be specified):  string
+   Purpose:       This response code name is followed by a string
+                  specified in the command that caused this response.
+                  It is typically used for client state synchronization.
+   Published Specification(s):  [RFC5804]
+   Person & email address to contact for further information:
+                  Alexey Melnikov <alexey.melnikov at isode.com>
+   Author/Change controller:  IESG.
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 45]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+7.  Internationalization Considerations
+
+   The LANGUAGE capability (see Section 1.7) allows a client to discover
+   the current language used in all human-readable responses that might
+   be returned at the end of any OK/NO/BYE response.  Human-readable
+   text in OK responses typically doesn't need to be shown to the user,
+   unless it is returned in response to a PUTSCRIPT or CHECKSCRIPT
+   command that also contains the WARNINGS response code (Section 1.3).
+   Human-readable text from NO/BYE responses is intended be shown to the
+   user, unless the client can automatically handle failure of the
+   command that caused such a response.  Clients SHOULD use response
+   codes (Section 1.3) for automatic error handling.  Response codes MAY
+   also be used by the client to present error messages in a language
+   understood by the user, for example, if the LANGUAGE capability
+   doesn't return a language understood by the user.
+
+   Note that the human-readable text from OK (WARNINGS) or NO/BYE
+   responses for PUTSCRIPT/CHECKSCRIPT commands is intended for advanced
+   users that understand Sieve language.  Such advanced users are often
+   sophisticated enough to be able to handle whatever language the
+   server is using, even if it is not their preferred language, and will
+   want to see error/warning text no matter what language the server
+   puts it in.
+
+   A client that generates Sieve script automatically, for example, if
+   the script is generated without user intervention or from a UI that
+   presents an abstract list of conditions and corresponding actions,
+   SHOULD NOT present warning/error messages to the user, because the
+   user might not even be aware that the client is using Sieve
+   underneath.  However, if the client has a debugging mode, such
+   warnings/errors SHOULD be available in the debugging mode.
+
+   Note that this document doesn't provide a way to modify the currently
+   used language.  It is expected that a future extension will address
+   that.
+
+8.  Acknowledgements
+
+   Thanks to Simon Josefsson, Larry Greenfield, Allen Johnson, Chris
+   Newman, Lyndon Nerenberg, Tim Showalter, Sarah Robeson, Walter Wong,
+   Barry Leiba, Arnt Gulbrandsen, Stephan Bosch, Ken Murchison, Phil
+   Pennock, Ned Freed, Jeffrey Hutzelman, Mark E. Mallett, Dilyan
+   Palauzov, Dave Cridland, Aaron Stone, Robert Burrell Donkin, Patrick
+   Ben Koetter, Bjoern Hoehrmann, Martin Duerst, Pasi Eronen, Magnus
+   Westerlund, Tim Polk, and Julien Coloos for help with this document.
+   Special thank you to Phil Pennock for providing text for the NOOP
+   command, as well as finding various bugs in the document.
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 46]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+9.  References
+
+9.1.  Normative References
+
+   [ABNF]         Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                  Specifications: ABNF", STD 68, RFC 5234, January 2008.
+
+   [ACAP]         Newman, C. and J. Myers, "ACAP -- Application
+                  Configuration Access Protocol", RFC 2244, November
+                  1997.
+
+   [BASE64]       Josefsson, S., "The Base16, Base32, and Base64 Data
+                  Encodings", RFC 4648, October 2006.
+
+   [DNS-SRV]      Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR
+                  for specifying the location of services (DNS SRV)",
+                  RFC 2782, February 2000.
+
+   [KEYWORDS]     Bradner, S., "Key words for use in RFCs to Indicate
+                  Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [NET-UNICODE]  Klensin, J. and M. Padlipsky, "Unicode Format for
+                  Network Interchange", RFC 5198, March 2008.
+
+   [NOTIFY]       Melnikov, A., Leiba, B., Segmuller, W., and T. Martin,
+                  "Sieve Email Filtering: Extension for Notifications",
+                  RFC 5435, January 2009.
+
+   [RFC2277]      Alvestrand, H., "IETF Policy on Character Sets and
+                  Languages", BCP 18, RFC 2277, January 1998.
+
+   [RFC2460]      Deering, S. and R. Hinden, "Internet Protocol, Version
+                  6 (IPv6) Specification", RFC 2460, December 1998.
+
+   [RFC3490]      Faltstrom, P., Hoffman, P., and A. Costello,
+                  "Internationalizing Domain Names in Applications
+                  (IDNA)", RFC 3490, March 2003.
+
+   [RFC4519]      Sciberras, A., "Lightweight Directory Access Protocol
+                  (LDAP): Schema for User Applications", RFC 4519, June
+                  2006.
+
+   [RFC5646]      Phillips, A. and M. Davis, "Tags for Identifying
+                  Languages", BCP 47, RFC 5646, September 2009.
+
+   [RFC791]       Postel, J., "Internet Protocol", STD 5, RFC 791,
+                  September 1981.
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 47]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   [SASL]         Melnikov, A. and K. Zeilenga, "Simple Authentication
+                  and Security Layer (SASL)", RFC 4422, June 2006.
+
+   [SASLprep]     Zeilenga, K., "SASLprep: Stringprep Profile for User
+                  Names and Passwords", RFC 4013, February 2005.
+
+   [SCRAM]        Menon-Sen, A., Melnikov, A., Newman, C., and N.
+                  Williams, "Salted Challenge Response Authentication
+                  Mechanism (SCRAM) SASL and GSS-API Mechanisms", RFC
+                  5802, July 2010.
+
+   [SIEVE]        Guenther, P. and T. Showalter, "Sieve: An Email
+                  Filtering Language", RFC 5228, January 2008.
+
+   [StringPrep]   Hoffman, P. and M. Blanchet, "Preparation of
+                  Internationalized Strings ("stringprep")", RFC 3454,
+                  December 2002.
+
+   [TLS]          Dierks, T. and E. Rescorla, "The Transport Layer
+                  Security (TLS) Protocol Version 1.2", RFC 5246, August
+                  2008.
+
+   [URI-GEN]      Berners-Lee, T., Fielding, R., and L. Masinter,
+                  "Uniform Resource Identifier (URI): Generic Syntax",
+                  STD 66, RFC 3986, January 2005.
+
+   [UTF-8]        Yergeau, F., "UTF-8, a transformation format of ISO
+                  10646", STD 63, RFC 3629, November 2003.
+
+   [X509]         Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
+                  Housley, R., and W. Polk, "Internet X.509 Public Key
+                  Infrastructure Certificate and Certificate Revocation
+                  List (CRL) Profile", RFC 5280, May 2008.
+
+   [X509-SRV]     Santesson, S., "Internet X.509 Public Key
+                  Infrastructure Subject Alternative Name for Expression
+                  of Service Name", RFC 4985, August 2007.
+
+9.2.  Informative References
+
+   [DIGEST-MD5]   Leach, P. and C. Newman, "Using Digest Authentication
+                  as a SASL Mechanism", RFC 2831, May 2000.
+
+   [GSSAPI]       Melnikov, A., "The Kerberos V5 ("GSSAPI") Simple
+                  Authentication and Security Layer (SASL) Mechanism",
+                  RFC 4752, November 2006.
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 48]
+

+RFC 5804                       ManageSieve                     July 2010
+
+
+   [I-HAVE]       Freed, N., "Sieve Email Filtering: Ihave Extension",
+                  RFC 5463, March 2009.
+
+   [IMAP]         Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
+                  VERSION 4rev1", RFC 3501, March 2003.
+
+   [LDAP]         Zeilenga, K., "Lightweight Directory Access Protocol
+                  (LDAP): Technical Specification Road Map", RFC 4510,
+                  June 2006.
+
+   [PLAIN]        Zeilenga, K., "The PLAIN Simple Authentication and
+                  Security Layer (SASL) Mechanism", RFC 4616, August
+                  2006.
+
+Authors' Addresses
+
+   Alexey Melnikov (editor)
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov at isode.com
+
+
+   Tim Martin
+   BeThereBeSquare, Inc.
+   672 Haight st.
+   San Francisco, CA  94117
+   USA
+
+   Phone: +1 510 260-4175
+   EMail: timmartin at alumni.cmu.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Martin            Standards Track                   [Page 49]
+

diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index e87e4bd..53abd25 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -19,6 +19,7 @@ SUBDIRS = \
 	geolocation \
 	libravatar \
 	mailmbox \
+	managesieve \
 	newmail \
 	notification \
 	pdf_viewer \
diff --git a/src/plugins/managesieve/Makefile.am b/src/plugins/managesieve/Makefile.am
new file mode 100644
index 0000000..5758aaf
--- /dev/null
+++ b/src/plugins/managesieve/Makefile.am
@@ -0,0 +1,84 @@
+# Copyright 1999-2014 the Claws Mail team.
+# This file is part of Claws Mail package, and distributed under the
+# terms of the General Public License version 3 (or later).
+# See COPYING file for license details.
+
+EXTRA_DIST = claws.def plugin.def version.rc
+
+IFLAGS = \
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/src/common \
+	-I$(top_builddir)/src/common \
+	-I$(top_srcdir)/src/gtk
+
+if OS_WIN32
+
+LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RC) \
+     `echo $(DEFS) $(DEFAULT_INCLUDES) $(IFLAGS) | \
+     sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
+
+%.lo : %.rc
+	$(LTRCCOMPILE) -i $< -o $@
+
+plugin_res = version.lo
+plugin_res_ldflag = -Wl,.libs/version.o
+
+export_symbols = -export-symbols $(srcdir)/plugin.def
+
+plugin_deps = libclaws.a $(plugin_res) plugin.def
+
+libclaws.a: claws.def
+	$(DLLTOOL) --output-lib $@ --def $<
+
+plugin_ldadd = -L. -lclaws
+
+else
+plugin_res =
+plugin_res_ldflag =
+export_symbols =
+plugin_deps =
+plugin_ldadd =
+endif
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+else
+no_undefined =
+endif
+
+if CYGWIN
+cygwin_export_lib = -L$(top_builddir)/src -lclaws-mail
+else
+cygwin_export_lib =
+endif
+
+plugindir = $(pkglibdir)/plugins
+
+if BUILD_MANAGESIEVE_PLUGIN
+plugin_LTLIBRARIES = managesieve.la
+endif
+
+managesieve_la_LDFLAGS = \
+	$(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
+	-avoid-version -module \
+	$(GTK_LIBS) \
+	$(CURL_LIBS)
+
+managesieve_la_DEPENDENCIES = $(plugin_deps)
+
+managesieve_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
+	$(GTK_LIBS)
+
+managesieve_la_CPPFLAGS = \
+	$(IFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(GTK_CFLAGS) \
+	$(CURL_CFLAGS)
+
+managesieve_la_SOURCES = \
+	managesieve.c managesieve.h \
+	sieve_plugin.c sieve_plugin.h \
+	sieve_prefs.c sieve_prefs.h \
+	sieve_manager.c sieve_manager.h \
+	sieve_editor.c sieve_editor.h
+
diff --git a/src/plugins/managesieve/claws.def b/src/plugins/managesieve/claws.def
new file mode 100644
index 0000000..cd46de6
--- /dev/null
+++ b/src/plugins/managesieve/claws.def
@@ -0,0 +1,33 @@
+LIBRARY CLAWS-MAIL.EXE
+EXPORTS
+auto_configure_service_sync
+extract_address
+get_locale_dir
+check_plugin_version
+conv_codeset_strdup
+conv_get_locale_charset_str_no_utf8
+debug_print_real
+debug_srcname
+file_exist
+get_rc_dir
+hooks_register_hook
+hooks_unregister_hook
+is_dir_exist
+line_has_quote_char
+make_dir
+pref_get_escaped_pref
+pref_get_unescaped_pref
+prefs_common
+prefs_file_close
+prefs_file_close_revert
+prefs_gtk_register_page
+prefs_gtk_unregister_page
+prefs_read_config
+prefs_set_block_label
+prefs_set_default
+prefs_write_open
+prefs_write_param
+prefs_common_get_prefs
+procmsg_msginfo_add_avatar
+procmsg_msginfo_get_avatar
+md5_hex_digest
diff --git a/src/plugins/managesieve/managesieve.c b/src/plugins/managesieve/managesieve.c
new file mode 100644
index 0000000..7dc23b1
--- /dev/null
+++ b/src/plugins/managesieve/managesieve.c
@@ -0,0 +1,1031 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2015 the Claws Mail Team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "claws.h"
+#include "account.h"
+#include "gtk/inputdialog.h"
+#include "md5.h"
+#include "utils.h"
+#include "log.h"
+#include "session.h"
+
+#include "managesieve.h"
+#include "sieve_editor.h"
+#include "sieve_prefs.h"
+
+GSList *sessions = NULL;
+
+static void sieve_session_destroy(Session *session);
+static gint sieve_pop_send_queue(SieveSession *session);
+static void sieve_session_reset(SieveSession *session);
+
+void sieve_sessions_close()
+{
+	if (sessions) {
+		g_slist_free_full(sessions, (GDestroyNotify)session_destroy);
+		sessions = NULL;
+	}
+}
+
+void noop_data_cb_fn(SieveSession *session, gpointer cb_data,
+		gpointer user_data)
+{
+	/* noop */
+}
+
+/* remove all command callbacks with a given data pointer */
+void sieve_sessions_discard_callbacks(gpointer user_data)
+{
+	GSList *item;
+	GSList *queue;
+	SieveSession *session;
+	SieveCommand *cmd;
+
+	for (item = sessions; item; item = item->next) {
+		session = (SieveSession *)item->data;
+		cmd = session->current_cmd;
+		if (cmd && cmd->data == user_data)
+			cmd->cb = noop_data_cb_fn;
+		for (queue = session->send_queue; queue; queue = queue->next) {
+			cmd = (SieveCommand *)item->data;
+			if (cmd && cmd->data == user_data)
+				cmd->cb = noop_data_cb_fn;
+		}
+	}
+}
+
+void command_free(SieveCommand *cmd) {
+	g_free(cmd->msg);
+	g_free(cmd);
+}
+
+void sieve_session_handle_status(SieveSession *session,
+		sieve_session_error_cb_fn on_error,
+		sieve_session_connected_cb_fn on_connected,
+		gpointer data)
+{
+	session->on_error = on_error;
+	session->on_connected = on_connected;
+	session->cb_data = data;
+}
+
+static void sieve_error(SieveSession *session, const gchar *msg)
+{
+	if (session->on_error)
+		session->on_error(session, msg, session->cb_data);
+}
+
+static void sieve_connected(SieveSession *session, gboolean connected)
+{
+	if (session->on_connected)
+		session->on_connected(session, connected, session->cb_data);
+}
+
+static gint sieve_auth_recv(SieveSession *session, const gchar *msg)
+{
+	gchar buf[MESSAGEBUFSIZE], *tmp;
+
+	switch (session->auth_type) {
+	case SIEVEAUTH_LOGIN:
+		session->state = SIEVE_AUTH_LOGIN_USER;
+
+		if (strstr(msg, "VXNlcm5hbWU6")) {
+			tmp = g_base64_encode(session->user, strlen(session->user));
+			g_snprintf(buf, sizeof(buf), "\"%s\"", tmp);
+
+			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) {
+				g_free(tmp);
+				return SE_ERROR;
+			}
+			g_free(tmp);
+			log_print(LOG_PROTOCOL, "Sieve> [USERID]\n");
+		} else {
+			/* Server rejects AUTH */
+			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+					 "\"*\"") < 0)
+				return SE_ERROR;
+			log_print(LOG_PROTOCOL, "Sieve> *\n");
+		}
+		break;
+	case SIEVEAUTH_CRAM_MD5:
+		session->state = SIEVE_AUTH_CRAM_MD5;
+
+		if (msg[0] == '"') {
+			gchar *response;
+			gchar *response64;
+			gchar *challenge, *tmp;
+			gsize challengelen;
+			guchar hexdigest[33];
+
+			tmp = g_base64_decode(msg + 1, &challengelen);
+			challenge = g_strndup(tmp, challengelen);
+			g_free(tmp);
+			log_print(LOG_PROTOCOL, "Sieve< [Decoded: %s]\n", challenge);
+
+			g_snprintf(buf, sizeof(buf), "%s", session->pass);
+			md5_hex_hmac(hexdigest, challenge, challengelen,
+				     buf, strlen(session->pass));
+			g_free(challenge);
+
+			response = g_strdup_printf
+				("%s %s", session->user, hexdigest);
+			log_print(LOG_PROTOCOL, "Sieve> [Encoded: %s]\n", response);
+
+			response64 = g_base64_encode(response, strlen(response));
+			g_free(response);
+
+			response = g_strdup_printf("\"%s\"", response64);
+			g_free(response64);
+
+			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+					 response) < 0) {
+				g_free(response);
+				return SE_ERROR;
+			}
+			log_print(LOG_PROTOCOL, "Sieve> %s\n", response);
+			g_free(response);
+		} else {
+			/* Server rejects AUTH */
+			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+					 "\"*\"") < 0)
+				return SE_ERROR;
+			log_print(LOG_PROTOCOL, "Sieve> *\n");
+		}
+		break;
+	default:
+		/* stop sieve_auth when no correct authtype */
+		if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0)
+			return SE_ERROR;
+		log_print(LOG_PROTOCOL, "Sieve> *\n");
+		break;
+	}
+
+	return SE_OK;
+}
+
+static gint sieve_auth_login_user_recv(SieveSession *session, const gchar *msg)
+{
+	gchar *tmp, *tmp2;
+
+	session->state = SIEVE_AUTH_LOGIN_PASS;
+	
+	if (strstr(msg, "UGFzc3dvcmQ6")) {
+		tmp2 = g_base64_encode(session->pass, strlen(session->pass));
+		tmp = g_strdup_printf("\"%s\"", tmp2);
+		g_free(tmp2);
+	} else {
+		/* Server rejects AUTH */
+		tmp = g_strdup("\"*\"");
+	}
+
+	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) {
+		g_free(tmp);
+		return SE_ERROR;
+	}
+	g_free(tmp);
+
+	log_print(LOG_PROTOCOL, "Sieve> [PASSWORD]\n");
+
+	return SE_OK;
+}
+
+
+static gint sieve_auth_cram_md5(SieveSession *session)
+{
+	session->state = SIEVE_AUTH;
+	session->auth_type = SIEVEAUTH_CRAM_MD5;
+
+	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+				"Authenticate \"CRAM-MD5\"") < 0)
+		return SE_ERROR;
+	log_print(LOG_PROTOCOL, "Sieve> Authenticate CRAM-MD5\n");
+
+	return SE_OK;
+}
+
+static gint sieve_auth_plain(SieveSession *session)
+{
+	gchar buf[MESSAGEBUFSIZE], *b64buf, *out;
+	gint len;
+
+	session->state = SIEVE_AUTH_PLAIN;
+	session->auth_type = SIEVEAUTH_PLAIN;
+
+	memset(buf, 0, sizeof buf);
+
+	/* "\0user\0password" */
+	len = sprintf(buf, "%c%s%c%s", '\0', session->user, '\0', session->pass);
+	b64buf = g_base64_encode(buf, len);
+	out = g_strconcat("Authenticate \"PLAIN\" \"", b64buf, "\"", NULL);
+	g_free(b64buf);
+
+	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, out) < 0) {
+		g_free(out);
+		return SE_ERROR;
+	}
+
+	g_free(out);
+
+	log_print(LOG_PROTOCOL, "Sieve> [Authenticate PLAIN]\n");
+
+	return SE_OK;
+}
+
+static gint sieve_auth_login(SieveSession *session)
+{
+	session->state = SIEVE_AUTH;
+	session->auth_type = SIEVEAUTH_LOGIN;
+
+	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+				"Authenticate \"LOGIN\"") < 0)
+		return SE_ERROR;
+	log_print(LOG_PROTOCOL, "Sieve> Authenticate LOGIN\n");
+
+	return SE_OK;
+}
+
+static gint sieve_auth(SieveSession *session)
+{
+	SieveAuthType forced_auth_type = session->forced_auth_type;
+
+	if (!session->use_auth) {
+		session->state = SIEVE_READY;
+		sieve_connected(session, TRUE);
+		return sieve_pop_send_queue(session);
+	}
+
+	session->state = SIEVE_AUTH;
+	sieve_error(session, _("Authenticating..."));
+
+	if ((forced_auth_type == SIEVEAUTH_CRAM_MD5 || forced_auth_type == 0) &&
+	     (session->avail_auth_type & SIEVEAUTH_CRAM_MD5) != 0)
+		return sieve_auth_cram_md5(session);
+	else if ((forced_auth_type == SIEVEAUTH_LOGIN || forced_auth_type == 0) &&
+		  (session->avail_auth_type & SIEVEAUTH_LOGIN) != 0)
+		return sieve_auth_login(session);
+	else if ((forced_auth_type == SIEVEAUTH_PLAIN || forced_auth_type == 0) &&
+		  (session->avail_auth_type & SIEVEAUTH_PLAIN) != 0)
+		return sieve_auth_plain(session);
+	else if (forced_auth_type == 0) {
+		log_warning(LOG_PROTOCOL, _("No Sieve auth method available\n"));
+		session->state = SIEVE_RETRY_AUTH;
+		return SE_AUTHFAIL;
+	} else {
+		log_warning(LOG_PROTOCOL, _("Selected Sieve auth method not available\n"));
+		session->state = SIEVE_RETRY_AUTH;
+		return SE_AUTHFAIL;
+	}
+
+	return SE_OK;
+}
+
+void sieve_session_putscript_cb(SieveSession *session, SieveResult *result)
+{
+	/* Remove script name from the beginning the response,
+	 * which are added by Dovecot/Pigeonhole */
+	gchar *start, *desc = result->description;
+	if (desc) {
+		if (g_str_has_prefix(desc, "NULL_") && (start = strchr(desc+5, ':'))) {
+			desc = start+1;
+			while (*desc == ' ')
+				desc++;
+		/* TODO: match against known script name, in case it contains
+		 * weird text like ": line " */
+		} else if ((start = strstr(desc, ": line ")) ||
+				(start = strstr(desc, ": error"))) {
+			desc = start+2;
+		}
+		result->description = desc;
+	}
+	/* pass along the callback */
+	session->current_cmd->cb(session, result, session->current_cmd->data);
+}
+
+inline gboolean response_is_ok(const char *msg)
+{
+	return !strncmp(msg, "OK", 2) && (!msg[2] || msg[2] == ' ');
+}
+
+inline gboolean response_is_no(const char *msg)
+{
+	return !strncmp(msg, "NO", 2) && (!msg[2] || msg[2] == ' ');
+}
+
+inline gboolean response_is_bye(const char *msg)
+{
+	return !strncmp(msg, "BYE", 3) && (!msg[3] || msg[3] == ' ');
+}
+
+void sieve_got_capability(SieveSession *session, gchar *cap_name,
+		gchar *cap_value)
+{
+	if (strcmp(cap_name, "SASL") == 0) {
+		SieveAuthType auth_type = 0;
+		gchar *auth, *end;
+		for (auth = cap_value; auth && auth[0]; auth = end) {
+			if ((end = strchr(auth, ' ')))
+				*end++ = '\0';
+			if (strcmp(auth, "PLAIN") == 0) {
+				auth_type |= SIEVEAUTH_PLAIN;
+			} else if (strcmp(auth, "CRAM-MD5") == 0) {
+				auth_type |= SIEVEAUTH_CRAM_MD5;
+			} else if (strcmp(auth, "LOGIN") == 0) {
+				auth_type |= SIEVEAUTH_LOGIN;
+			}
+		}
+		session->avail_auth_type = auth_type;
+
+	} else if (strcmp(cap_name, "STARTTLS") == 0) {
+		session->capability.starttls = TRUE;
+	}
+}
+
+static void log_send(SieveSession *session, SieveCommand *cmd)
+{
+	gchar *end, *msg = cmd->msg;
+	if (cmd->next_state == SIEVE_PUTSCRIPT && (end = strchr(msg, '\n'))) {
+		/* Don't log the script data */
+		msg = g_strndup(msg, end - msg);
+		log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
+		g_free(msg);
+		msg = "[Data]";
+	}
+	log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
+}
+
+static gint sieve_pop_send_queue(SieveSession *session)
+{
+	SieveCommand *cmd;
+	GSList *send_queue = session->send_queue;
+
+	if (!send_queue)
+		return SE_OK;
+
+	cmd = (SieveCommand *)send_queue->data;
+	session->send_queue = g_slist_next(send_queue);
+	g_slist_free_1(send_queue);
+
+	log_send(session, cmd);
+	session->state = cmd->next_state;
+	if (session->current_cmd)
+		command_free(session->current_cmd);
+	session->current_cmd = cmd;
+	if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0)
+		return SE_ERROR;
+
+	return SE_OK;
+}
+
+static void parse_split(gchar *line, gchar **first_word, gchar **second_word)
+{
+	gchar *first = line;
+	gchar *second;
+	gchar *end;
+
+	/* get first */
+	if (line[0] == '"' && ((second = strchr(line + 1, '"')))) {
+		*second++ = '\0';
+		first++;
+		if (second[0] == ' ')
+			second++;
+	} else if ((second = strchr(line, ' '))) {
+		*second++ = '\0';
+	}
+
+	/* unquote second */
+	if (second && second[0] == '"' &&
+			((end = strchr(second + 1, '"')))) {
+		second++;
+		*end = '\0';
+	}
+
+	*first_word = first;
+	*second_word = second;
+}
+
+static void unquote_inplace(gchar *str)
+{
+	gchar *src, *dest;
+	if (*str != '"')
+		return;
+	for (src = str+1, dest = str; src && *src && *src != '"'; src++) {
+		if (*src == '\\') {
+			src++;
+		}
+		*dest++ = *src;
+	}
+	*dest = '\0';
+}
+
+static void parse_response(gchar *msg, SieveResult *result)
+{
+	/* response status */
+	gchar *end = strchr(msg, ' ');
+	if (end)
+		*end++ = '\0';
+	result->success = strcmp(msg, "OK") == 0;
+	result->has_status = TRUE;
+	if (!end) {
+		result->code = SIEVE_CODE_NONE;
+		result->description = NULL;
+		result->has_octets = FALSE;
+		result->octets = 0;
+		return;
+	}
+	while (*end == ' ')
+		end++;
+	msg = end;
+
+	/* response code */
+	if (msg[0] == '(' && (end = strchr(msg, ')'))) {
+		msg++;
+		*end++ = '\0';
+		result->code =
+			strcmp(msg, "WARNINGS") == 0 ? SIEVE_CODE_WARNINGS :
+			strcmp(msg, "TRYLATER") == 0 ? SIEVE_CODE_TRYLATER :
+			SIEVE_CODE_UNKNOWN;
+		while (*end == ' ')
+			end++;
+		msg = end;
+	} else {
+		result->code = SIEVE_CODE_NONE;
+	}
+
+	/* s2c octets */
+	if (msg[0] == '{' && (end = strchr(msg, '}'))) {
+		msg++;
+		*end++ = '\0';
+		if (msg[0] == '0' && msg+1 == end) {
+			result->has_octets = TRUE;
+			result->octets = 0;
+		} else {
+			result->has_octets =
+				(result->octets = g_ascii_strtoll(msg, NULL, 10)) != 0;
+		}
+		while (*end == ' ')
+			end++;
+		msg = end;
+	} else {
+		result->has_octets = FALSE;
+		result->octets = 0;
+	}
+
+	/* text */
+	if (*msg) {
+		unquote_inplace(msg);
+		result->description = msg;
+	} else {
+		result->description = NULL;
+	}
+}
+
+static gint sieve_session_recv_msg(Session *session, const gchar *msg)
+{
+	SieveSession *sieve_session = SIEVE_SESSION(session);
+	SieveResult result;
+	gint ret = 0;
+
+	switch (sieve_session->state) {
+	case SIEVE_GETSCRIPT_DATA:
+		log_print(LOG_PROTOCOL, "Sieve< [GETSCRIPT data]\n");
+		break;
+	default:
+		log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
+		if (response_is_bye(msg)) {
+			gchar *status;
+			parse_response((gchar *)msg, &result);
+			if (!result.description)
+				status = g_strdup(_("Disconnected"));
+			else if (g_str_has_prefix(result.description, "Disconnected"))
+				status = g_strdup(result.description);
+			else
+				status = g_strdup_printf(_("Disconnected: %s"), result.description);
+			sieve_session->error = SE_ERROR;
+			sieve_error(sieve_session, status);
+			sieve_session->state = SIEVE_DISCONNECTED;
+			g_free(status);
+			return -1;
+		}
+	}
+
+	switch (sieve_session->state) {
+	case SIEVE_CAPABILITIES:
+		if (response_is_ok(msg)) {
+			/* capabilities list done */
+
+#ifdef USE_GNUTLS
+			if (sieve_session->tls_init_done == FALSE &&
+					sieve_session->config->tls_type != SIEVE_TLS_NO) {
+				if (sieve_session->capability.starttls) {
+					log_print(LOG_PROTOCOL, "Sieve> STARTTLS\n");
+					session_send_msg(session, SESSION_SEND, "STARTTLS");
+					sieve_session->state = SIEVE_STARTTLS;
+				} else if (sieve_session->config->tls_type == SIEVE_TLS_YES) {
+					log_warning(LOG_PROTOCOL, "Sieve: does not support STARTTLS\n");
+					sieve_session->state = SIEVE_ERROR;
+				} else {
+					log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n");
+					sieve_session->state = SIEVE_CAPABILITIES;
+				}
+				break;
+			}
+#endif
+			/* authenticate after getting capabilities */
+			if (!sieve_session->authenticated) {
+				ret = sieve_auth(sieve_session);
+			} else {
+				sieve_session->state = SIEVE_READY;
+				sieve_connected(sieve_session, TRUE);
+				ret = sieve_pop_send_queue(sieve_session);
+			}
+		} else {
+			/* got a capability */
+			gchar *cap_name, *cap_value;
+			parse_split((gchar *)msg, &cap_name, &cap_value);
+			sieve_got_capability(sieve_session, cap_name, cap_value);
+		}
+		break;
+	case SIEVE_READY:
+		log_warning(LOG_PROTOCOL,
+				_("unhandled message on Sieve session: %s\n"), msg);
+		break;
+	case SIEVE_STARTTLS:
+#ifdef USE_GNUTLS
+		if (session_start_tls(session) < 0) {
+			sieve_session->state = SIEVE_ERROR;
+			sieve_session->error = SE_ERROR;
+			sieve_error(sieve_session, _("TLS failed"));
+			return -1;
+		}
+		sieve_session->tls_init_done = TRUE;
+		sieve_session->state = SIEVE_CAPABILITIES;
+		ret = SE_OK;
+#endif
+		break;
+	case SIEVE_AUTH:
+		ret = sieve_auth_recv(sieve_session, msg);
+		break;
+	case SIEVE_AUTH_LOGIN_USER:
+		ret = sieve_auth_login_user_recv(sieve_session, msg);
+		break;
+	case SIEVE_AUTH_PLAIN:
+	case SIEVE_AUTH_LOGIN_PASS:
+	case SIEVE_AUTH_CRAM_MD5:
+		if (response_is_no(msg)) {
+			log_print(LOG_PROTOCOL, "Sieve auth failed\n");
+			session->state = SIEVE_RETRY_AUTH;
+			ret = SE_AUTHFAIL;
+		} else if (response_is_ok(msg)) {
+			log_print(LOG_PROTOCOL, "Sieve auth completed\n");
+			sieve_error(sieve_session, _(""));
+			sieve_session->authenticated = TRUE;
+			sieve_session->state = SIEVE_READY;
+			sieve_connected(sieve_session, TRUE);
+			ret = sieve_pop_send_queue(sieve_session);
+		}
+		break;
+	case SIEVE_NOOP:
+		if (!response_is_ok(msg)) {
+			sieve_session->state = SIEVE_ERROR;
+		}
+		sieve_session->state = SIEVE_READY;
+		break;
+	case SIEVE_LISTSCRIPTS:
+		if (response_is_no(msg)) {
+			/* got an error. probably not authenticated. */
+			sieve_session->current_cmd->cb(sieve_session, NULL,
+					sieve_session->current_cmd->data);
+			sieve_session->state = SIEVE_READY;
+			ret = sieve_pop_send_queue(sieve_session);
+		} else if (response_is_ok(msg)) {
+			/* end of list */
+			sieve_session->state = SIEVE_READY;
+			sieve_session->error = SE_OK;
+			sieve_session->current_cmd->cb(sieve_session,
+					(gpointer)&(SieveScript){0},
+					sieve_session->current_cmd->data);
+			ret = sieve_pop_send_queue(sieve_session);
+		} else {
+			/* got a script name */
+			SieveScript script;
+			gchar *script_status;
+
+			parse_split((gchar *)msg, &script.name, &script_status);
+			script.active = (script_status &&
+					strcasecmp(script_status, "active") == 0);
+
+			sieve_session->current_cmd->cb(sieve_session, (gpointer)&script,
+					sieve_session->current_cmd->data);
+			ret = SE_OK;
+		}
+		break;
+	case SIEVE_RENAMESCRIPT:
+		if (response_is_no(msg)) {
+			/* error */
+			sieve_session->current_cmd->cb(sieve_session, NULL,
+					sieve_session->current_cmd->data);
+		} else if (response_is_ok(msg)) {
+			sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
+					sieve_session->current_cmd->data);
+		} else {
+			log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
+		}
+		sieve_session->state = SIEVE_READY;
+		break;
+	case SIEVE_SETACTIVE:
+		if (response_is_no(msg)) {
+			/* error */
+			sieve_session->current_cmd->cb(sieve_session, NULL,
+					sieve_session->current_cmd->data);
+		} else if (response_is_ok(msg)) {
+			sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
+					sieve_session->current_cmd->data);
+		} else {
+			log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
+		}
+		sieve_session->state = SIEVE_READY;
+		break;
+	case SIEVE_GETSCRIPT:
+		if (response_is_no(msg)) {
+			sieve_session->current_cmd->cb(sieve_session, (void *)-1,
+					sieve_session->current_cmd->data);
+			sieve_session->state = SIEVE_READY;
+		} else {
+			parse_response((gchar *)msg, &result);
+			sieve_session->state = SIEVE_GETSCRIPT_DATA;
+		}
+		ret = SE_OK;
+		break;
+	case SIEVE_GETSCRIPT_DATA:
+		if (response_is_ok(msg)) {
+			sieve_session->state = SIEVE_READY;
+			sieve_session->current_cmd->cb(sieve_session, NULL,
+					sieve_session->current_cmd->data);
+		} else {
+			sieve_session->current_cmd->cb(sieve_session, (gchar *)msg,
+					sieve_session->current_cmd->data);
+		}
+		ret = SE_OK;
+		break;
+	case SIEVE_PUTSCRIPT:
+		parse_response((gchar *)msg, &result);
+		if (result.has_octets) {
+			sieve_session->state = SIEVE_PUTSCRIPT_DATA;
+		} else {
+			sieve_session->state = SIEVE_READY;
+		}
+		sieve_session_putscript_cb(sieve_session, &result);
+		ret = SE_OK;
+		break;
+	case SIEVE_PUTSCRIPT_DATA:
+		if (!msg[0]) {
+			sieve_session->state = SIEVE_READY;
+		} else {
+			result.has_status = FALSE;
+			result.has_octets = FALSE;
+			result.success = -1;
+			result.code = SIEVE_CODE_NONE;
+			result.description = (gchar *)msg;
+			sieve_session_putscript_cb(sieve_session, &result);
+		}
+		ret = SE_OK;
+		break;
+	case SIEVE_DELETESCRIPT:
+		parse_response((gchar *)msg, &result);
+		if (!result.success) {
+			sieve_session->current_cmd->cb(sieve_session, result.description,
+					sieve_session->current_cmd->data);
+		} else {
+			sieve_session->current_cmd->cb(sieve_session, NULL,
+					sieve_session->current_cmd->data);
+		}
+		sieve_session->state = SIEVE_READY;
+		break;
+	case SIEVE_ERROR:
+		log_warning(LOG_PROTOCOL, _("error occurred on Sieve session. data: %s\n"), msg);
+		sieve_session->error = SE_ERROR;
+		break;
+	case SIEVE_RETRY_AUTH:
+		log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"),
+					msg);
+		ret = sieve_auth(sieve_session);
+		break;
+	default:
+		log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %d\n"),
+					sieve_session->state);
+		sieve_session->error = SE_ERROR;
+		return -1;
+	}
+
+	if (ret == SE_OK)
+		return session_recv_msg(session);
+	else if (ret == SE_AUTHFAIL) {
+		sieve_error(sieve_session, _("Auth failed"));
+		sieve_session->state = SIEVE_ERROR;
+		sieve_session->error = SE_ERROR;
+	}
+
+	return 0;
+}
+
+static gint sieve_recv_message(Session *session, const gchar *msg,
+		gpointer user_data)
+{
+	return 0;
+}
+
+static gint sieve_cmd_noop(SieveSession *session)
+{
+	log_print(LOG_PROTOCOL, "Sieve> NOOP\n");
+	session->state = SIEVE_NOOP;
+	if (session_send_msg(SESSION(session), SESSION_SEND, "NOOP") < 0) {
+		session->state = SIEVE_ERROR;
+		session->error = SE_ERROR;
+		return 1;
+	}
+	return 0;
+}
+
+static gboolean sieve_ping(gpointer data)
+{
+	Session *session = SESSION(data);
+	SieveSession *sieve_session = SIEVE_SESSION(session);
+
+	if (sieve_session->state == SIEVE_ERROR || session->state == SESSION_ERROR)
+		return FALSE;
+	if (sieve_session->state != SIEVE_READY)
+		return TRUE;
+
+	return sieve_cmd_noop(sieve_session) == 0;
+}
+
+static void sieve_session_destroy(Session *session)
+{
+	SieveSession *sieve_session = SIEVE_SESSION(session);
+	g_free(sieve_session->pass);
+	if (sieve_session->current_cmd)
+		command_free(sieve_session->current_cmd);
+	sessions = g_slist_remove(sessions, (gconstpointer)session);
+}
+
+static void sieve_connect_finished(Session *session, gboolean success)
+{
+	if (!success) {
+		sieve_connected(SIEVE_SESSION(session), FALSE);
+	}
+}
+
+static gint sieve_session_connect(SieveSession *session)
+{
+	session->state = SIEVE_CAPABILITIES;
+	session->authenticated = FALSE;
+	session->tls_init_done = FALSE;
+	return session_connect(SESSION(session), session->host,
+			session->port);
+}
+
+static SieveSession *sieve_session_new(PrefsAccount *account)
+{
+	SieveSession *session;
+	session = g_new0(SieveSession, 1);
+	session_init(SESSION(session), account, FALSE);
+
+	session->account = account;
+
+	SESSION(session)->recv_msg = sieve_session_recv_msg;
+	SESSION(session)->destroy = sieve_session_destroy;
+	SESSION(session)->connect_finished = sieve_connect_finished;
+	session_set_recv_message_notify(SESSION(session), sieve_recv_message, NULL);
+
+	sieve_session_reset(session);
+	return session;
+}
+
+static void sieve_session_reset(SieveSession *session)
+{
+	PrefsAccount *account = session->account;
+	SieveAccountConfig *config = sieve_prefs_account_get_config(account);
+	gboolean reuse_auth = (config->auth == SIEVEAUTH_REUSE);
+
+	g_slist_free_full(session->send_queue, (GDestroyNotify)command_free);
+
+	session_disconnect(SESSION(session));
+
+	SESSION(session)->ssl_cert_auto_accept = account->ssl_certs_auto_accept;
+	SESSION(session)->nonblocking = account->use_nonblocking_ssl;
+	session->authenticated = FALSE;
+	session->current_cmd = NULL;
+	session->send_queue = NULL;
+	session->state = SIEVE_CAPABILITIES;
+	session->tls_init_done = FALSE;
+	session->avail_auth_type = 0;
+	session->auth_type = 0;
+	session->config = config;
+	session->host = config->use_host ? config->host : account->recv_server;
+	session->port = config->use_port ? config->port : SIEVE_PORT;
+	session->user = reuse_auth ? account->userid : session->config->userid;
+	session->forced_auth_type = config->auth_type;
+	session_register_ping(SESSION(session), sieve_ping);
+
+	if (session->pass)
+		g_free(session->pass);
+	if (config->auth == SIEVEAUTH_NONE) {
+		session->pass = NULL;
+	} else if (reuse_auth && account->passwd) {
+		session->pass = g_strdup(account->passwd);
+	} else if (config->passwd && config->passwd[0]) {
+		session->pass = g_strdup(config->passwd);
+	} else if (password_get(session->user, session->host, "sieve",
+				session->port, &session->pass)) {
+	} else {
+		session->pass = input_dialog_query_password_keep(session->host,
+				session->user, &(session->pass));
+	}
+	if (!session->pass) {
+		session->pass = g_strdup("");
+		session->use_auth = FALSE;
+	} else {
+		session->use_auth = TRUE;
+	}
+
+#ifdef USE_GNUTLS
+	SESSION(session)->ssl_type =
+		(config->tls_type == SIEVE_TLS_NO) ? SSL_NONE : SSL_STARTTLS;
+#endif
+}
+
+/* When an account config is changed, reset associated sessions. */
+void sieve_account_prefs_updated(PrefsAccount *account)
+{
+	GSList *item;
+	SieveSession *session;
+
+	for (item = sessions; item; item = item->next) {
+		session = (SieveSession *)item->data;
+		if (session->account == account) {
+			log_print(LOG_PROTOCOL, "Sieve: resetting session\n");
+			sieve_session_reset(session);
+		}
+	}
+}
+
+SieveSession *sieve_session_get_for_account(PrefsAccount *account)
+{
+	SieveSession *session;
+	GSList *item;
+
+	/* find existing */
+	for (item = sessions; item; item = item->next) {
+		session = (SieveSession *)item->data;
+		if (session->account == account) {
+			return session;
+		}
+	}
+
+	/* create new */
+	session = sieve_session_new(account);
+	sessions = g_slist_prepend(sessions, session);
+
+	return session;
+}
+
+static void sieve_queue_send(SieveSession *session, SieveState next_state,
+		gchar *msg, sieve_session_data_cb_fn cb, gpointer data)
+{
+	gboolean queue = FALSE;
+	SieveCommand *cmd = g_new0(SieveCommand, 1);
+	cmd->next_state = next_state;
+	cmd->msg = msg;
+	cmd->data = data;
+	cmd->cb = cb;
+
+	if (!session_is_connected(SESSION(session))) {
+		log_print(LOG_PROTOCOL, "Sieve: connecting to %s:%hu\n",
+				session->host, session->port);
+		if (sieve_session_connect(session) < 0) {
+			sieve_connect_finished(SESSION(session), FALSE);
+		}
+		queue = TRUE;
+	} else if (session->state == SIEVE_RETRY_AUTH) {
+		log_print(LOG_PROTOCOL, _("Sieve: retrying auth\n"));
+		if (sieve_auth(session) == SE_AUTHFAIL)
+			sieve_error(session, _("Auth method not available"));
+		queue = TRUE;
+	} else if (session->state != SIEVE_READY) {
+		log_print(LOG_PROTOCOL, "Sieve: in state %d\n", session->state);
+		queue = TRUE;
+	}
+
+	if (queue) {
+		session->send_queue = g_slist_prepend(session->send_queue, cmd);
+	} else {
+		if (session->current_cmd)
+			command_free(session->current_cmd);
+		session->current_cmd = cmd;
+		session->state = next_state;
+		log_send(session, cmd);
+		if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0) {
+			/* error */
+		}
+	}
+}
+
+void sieve_session_list_scripts(SieveSession *session,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup("LISTSCRIPTS");
+	sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
+}
+
+void sieve_session_add_script(SieveSession *session, const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+/*
+	gchar *msg = g_strdup("LISTSCRIPTS");
+	sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
+*/
+}
+
+void sieve_session_set_active_script(SieveSession *session,
+		const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup_printf("SETACTIVE \"%s\"",
+			filter_name ? filter_name : "");
+	if (!msg) {
+		cb(session, (void*)FALSE, data);
+		return;
+	}
+
+	sieve_queue_send(session, SIEVE_SETACTIVE, msg, cb, data);
+}
+
+void sieve_session_rename_script(SieveSession *session,
+		const gchar *name_old, const char *name_new,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup_printf("RENAMESCRIPT \"%s\" \"%s\"",
+			name_old, name_new);
+
+	sieve_queue_send(session, SIEVE_RENAMESCRIPT, msg, cb, data);
+}
+
+void sieve_session_get_script(SieveSession *session, const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup_printf("GETSCRIPT \"%s\"",
+			filter_name);
+
+	sieve_queue_send(session, SIEVE_GETSCRIPT, msg, cb, data);
+}
+
+void sieve_session_put_script(SieveSession *session, const gchar *filter_name,
+		gint len, const gchar *script_contents,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	/* TODO: refactor so don't have to copy the whole script here */
+	gchar *msg = g_strdup_printf("PUTSCRIPT \"%s\" {%u+}\r\n%s",
+			filter_name, len, script_contents);
+
+	sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
+}
+
+void sieve_session_check_script(SieveSession *session,
+		gint len, const gchar *script_contents,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup_printf("CHECKSCRIPT {%u+}\r\n%s",
+			len, script_contents);
+
+	sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
+}
+
+void sieve_session_delete_script(SieveSession *session,
+		const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data)
+{
+	gchar *msg = g_strdup_printf("DELETESCRIPT \"%s\"",
+			filter_name);
+
+	sieve_queue_send(session, SIEVE_DELETESCRIPT, msg, cb, data);
+}
diff --git a/src/plugins/managesieve/managesieve.h b/src/plugins/managesieve/managesieve.h
new file mode 100644
index 0000000..b775f90
--- /dev/null
+++ b/src/plugins/managesieve/managesieve.h
@@ -0,0 +1,193 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef MANAGESIEVE_H
+#define MANAGESIEVE_H
+
+#include "prefs_account.h"
+#include "socket.h"
+#include "session.h"
+
+#define SIEVE_SESSION(obj)	((SieveSession *)obj)
+#define SIEVE_PORT 4190
+
+typedef struct SieveSession SieveSession;
+typedef struct SieveCommand SieveCommand;
+typedef struct SieveScript SieveScript;
+typedef struct SieveResult SieveResult;
+
+typedef enum
+{
+	SE_OK			= 0,
+	SE_ERROR			= 128,
+	SE_UNRECOVERABLE	= 129,
+	SE_AUTHFAIL		= 130
+} SieveErrorValue;
+
+typedef enum
+{
+	SIEVEAUTH_NONE		= 0,
+	SIEVEAUTH_REUSE		= 1,
+	SIEVEAUTH_CUSTOM	= 2
+} SieveAuth;
+
+typedef enum
+{
+	SIEVEAUTH_AUTO			= 0,
+	SIEVEAUTH_PLAIN			= 1 << 0,
+	SIEVEAUTH_LOGIN			= 1 << 1,
+	SIEVEAUTH_CRAM_MD5		= 1 << 2,
+} SieveAuthType;
+
+typedef enum
+{
+	SIEVE_CAPABILITIES,
+	SIEVE_READY,
+	SIEVE_LISTSCRIPTS,
+	SIEVE_STARTTLS,
+	SIEVE_NOOP,
+	SIEVE_RETRY_AUTH,
+	SIEVE_AUTH,
+	SIEVE_AUTH_PLAIN,
+	SIEVE_AUTH_LOGIN_USER,
+	SIEVE_AUTH_LOGIN_PASS,
+	SIEVE_AUTH_CRAM_MD5,
+	SIEVE_RENAMESCRIPT,
+	SIEVE_SETACTIVE,
+	SIEVE_GETSCRIPT,
+	SIEVE_GETSCRIPT_DATA,
+	SIEVE_PUTSCRIPT,
+	SIEVE_PUTSCRIPT_DATA,
+	SIEVE_DELETESCRIPT,
+	SIEVE_ERROR,
+	SIEVE_DISCONNECTED,
+
+	N_SIEVE_PHASE
+} SieveState;
+
+typedef enum
+{
+	SIEVE_CODE_NONE,
+	SIEVE_CODE_WARNINGS,
+	SIEVE_CODE_TRYLATER,
+	SIEVE_CODE_UNKNOWN
+} SieveResponseCode;
+
+typedef enum {
+	SIEVE_TLS_NO,
+	SIEVE_TLS_MAYBE,
+	SIEVE_TLS_YES
+} SieveTLSType;
+
+typedef void (*sieve_session_cb_fn) (SieveSession *session, gpointer data);
+typedef void (*sieve_session_data_cb_fn) (SieveSession *session,
+		gpointer cb_data, gpointer user_data);
+typedef void (*sieve_session_error_cb_fn) (SieveSession *session,
+		const gchar *msg, gpointer user_data);
+typedef void (*sieve_session_connected_cb_fn) (SieveSession *session,
+		gboolean connected, gpointer user_data);
+
+struct SieveSession
+{
+	Session session;
+	PrefsAccount *account;
+	struct SieveAccountConfig *config;
+	SieveState state;
+	gboolean authenticated;
+	GSList *send_queue;
+	SieveErrorValue error;
+	SieveCommand *current_cmd;
+
+	gboolean use_auth;
+	SieveAuthType avail_auth_type;
+	SieveAuthType forced_auth_type;
+	SieveAuthType auth_type;
+
+	gchar *host;
+	gushort port;
+	gchar *user;
+	gchar *pass;
+
+#ifdef USE_GNUTLS
+	gboolean tls_init_done;
+#endif
+
+	struct {
+		gboolean starttls;
+	} capability;
+
+	sieve_session_error_cb_fn on_error;
+	sieve_session_connected_cb_fn on_connected;
+	gpointer cb_data;
+};
+
+struct SieveCommand {
+	SieveState next_state;
+	gchar *msg;
+	sieve_session_data_cb_fn cb;
+	gpointer data;
+};
+
+struct SieveScript {
+	gchar *name;
+	gboolean active;
+};
+
+struct SieveResult {
+	gboolean has_status;
+	gboolean success;
+	SieveResponseCode code;
+	gchar *description;
+	gboolean has_octets;
+	guint octets;
+};
+
+void sieve_sessions_close();
+
+void sieve_account_prefs_updated(PrefsAccount *account);
+SieveSession *sieve_session_get_for_account(PrefsAccount *account);
+void sieve_sessions_discard_callbacks(gpointer user_data);
+void sieve_session_handle_status(SieveSession *session,
+		sieve_session_error_cb_fn on_error,
+		sieve_session_connected_cb_fn on_connected,
+		gpointer data);
+void sieve_session_list_scripts(SieveSession *session,
+		sieve_session_data_cb_fn got_script_name_cb, gpointer data);
+void sieve_session_add_script(SieveSession *session, const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_set_active_script(SieveSession *session,
+		const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_rename_script(SieveSession *session,
+		const gchar *name_old, const char *name_new,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_get_script(SieveSession *session, const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_put_script(SieveSession *session, const gchar *filter_name,
+		gint len, const gchar *script_contents,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_check_script(SieveSession *session,
+		gint len, const gchar *script_contents,
+		sieve_session_data_cb_fn cb, gpointer data);
+void sieve_session_delete_script(SieveSession *session,
+		const gchar *filter_name,
+		sieve_session_data_cb_fn cb, gpointer data);
+
+#endif /* MANAGESIEVE_H */
diff --git a/src/plugins/managesieve/plugin.def b/src/plugins/managesieve/plugin.def
new file mode 100644
index 0000000..8471df1
--- /dev/null
+++ b/src/plugins/managesieve/plugin.def
@@ -0,0 +1,10 @@
+EXPORTS
+	plugin_desc
+	plugin_done
+	plugin_init
+	plugin_licence
+	plugin_name
+	plugin_type
+	plugin_provides
+	plugin_version
+
diff --git a/src/plugins/managesieve/sieve_editor.c b/src/plugins/managesieve/sieve_editor.c
new file mode 100644
index 0000000..28f75f5
--- /dev/null
+++ b/src/plugins/managesieve/sieve_editor.c
@@ -0,0 +1,675 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "defs.h"
+#include "gtk/gtkutils.h"
+#include "gtk/combobox.h"
+#include "gtk/manage_window.h"
+#include "alertpanel.h"
+#include "undo.h"
+#include "menu.h"
+#include "utils.h"
+#include "prefs.h"
+#include "prefs_common.h"
+#include "account.h"
+#include "mainwindow.h"
+#include "message_search.h"
+#include "managesieve.h"
+#include "sieve_editor.h"
+
+GSList *editors = NULL;
+
+static void sieve_editor_destroy(SieveEditorPage *page);
+
+void sieve_editor_set_position(void *obj, gint pos);
+gboolean sieve_editor_search_string(void *obj,
+	const gchar *str, gboolean case_sens);
+gboolean sieve_editor_search_string_backward(void *obj,
+	const gchar *str, gboolean case_sens);
+static void sieve_editor_save_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_check_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_revert_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_close_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_undo_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_redo_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_cut_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_copy_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_paste_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_allsel_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_find_cb(GtkAction *action, SieveEditorPage *page);
+static void sieve_editor_set_modified(SieveEditorPage *page,
+		gboolean modified);
+
+static SearchInterface search_interface = {
+	.set_position = sieve_editor_set_position,
+	.search_string_backward = sieve_editor_search_string_backward,
+	.search_string = sieve_editor_search_string,
+};
+
+static GtkActionEntry sieve_editor_entries[] =
+{
+	{"Menu",				NULL, "Menu" },
+/* menus */
+	{"Filter",			NULL, N_("_Filter") },
+	{"Edit",			NULL, N_("_Edit") },
+/* Filter menu */
+
+	{"Filter/Save",		NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(sieve_editor_save_cb) },
+	{"Filter/CheckSyntax",		NULL, N_("Chec_k Syntax"), "<control>K", NULL, G_CALLBACK(sieve_editor_check_cb) },
+	{"Filter/Revert",		NULL, N_("Re_vert"), NULL, NULL, G_CALLBACK(sieve_editor_revert_cb) },
+	{"Filter/Close",		NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(sieve_editor_close_cb) },
+
+/* Edit menu */
+	{"Edit/Undo",			NULL, N_("_Undo"), "<control>Z", NULL, G_CALLBACK(sieve_editor_undo_cb) },
+	{"Edit/Redo",			NULL, N_("_Redo"), "<control>Y", NULL, G_CALLBACK(sieve_editor_redo_cb) },
+	/* {"Edit/---",			NULL, "---" }, */
+
+	{"Edit/Cut",			NULL, N_("Cu_t"), "<control>X", NULL, G_CALLBACK(sieve_editor_cut_cb) },
+	{"Edit/Copy",			NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(sieve_editor_copy_cb) },
+	{"Edit/Paste",			NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(sieve_editor_paste_cb) },
+
+	{"Edit/SelectAll",		NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(sieve_editor_allsel_cb) },
+
+	{"Edit/---",			NULL, "---" },
+	{"Edit/Find",		NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(sieve_editor_find_cb) },
+};
+
+
+void sieve_editors_close()
+{
+	if (editors) {
+		g_slist_free_full(editors, (GDestroyNotify)sieve_editor_close);
+		editors = NULL;
+	}
+}
+
+void sieve_editor_append_text(SieveEditorPage *page, gchar *text, gint len)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter iter;
+	gboolean was_modified = page->modified;
+
+	undo_block(page->undostruct);
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	gtk_text_buffer_get_end_iter(buffer, &iter);
+	gtk_text_buffer_insert(buffer, &iter, text, len);
+	undo_unblock(page->undostruct);
+	sieve_editor_set_modified(page, was_modified);
+}
+
+static gint sieve_editor_get_text(SieveEditorPage *page, gchar **text)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	gtk_text_buffer_get_start_iter(buffer, &start);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	*text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+	return gtk_text_iter_get_offset(&end) - gtk_text_iter_get_offset(&start);
+}
+
+static void sieve_editor_set_status(SieveEditorPage *page, const gchar *status)
+{
+	gtk_label_set_text(GTK_LABEL(page->status_text), status);
+}
+
+static void sieve_editor_set_status_icon(SieveEditorPage *page, const gchar *img_id)
+{
+	GtkImage *img = GTK_IMAGE(page->status_icon);
+	if (img_id)
+		gtk_image_set_from_stock(img, img_id, GTK_ICON_SIZE_BUTTON);
+	else
+		gtk_image_clear(img);
+}
+
+static void sieve_editor_append_status(SieveEditorPage *page,
+		const gchar *status)
+{
+	GtkLabel *label = GTK_LABEL(page->status_text);
+	const gchar *prev_status = gtk_label_get_text(label);
+	const gchar *sep = prev_status && prev_status[0] ? "\n" : "";
+	gtk_label_set_text(label, g_strconcat(prev_status, sep, status, NULL));
+}
+
+/* Update the status icon and text from a response. */
+static void sieve_editor_update_status(SieveEditorPage *page,
+		SieveResult *result)
+{
+	if (result->has_status) {
+		/* set status icon */
+		sieve_editor_set_status_icon(page,
+			result->success ? GTK_STOCK_DIALOG_INFO : GTK_STOCK_DIALOG_ERROR);
+		/* clear status text */
+		sieve_editor_set_status(page, "");
+	}
+	if (result->description) {
+		/* append to status */
+		sieve_editor_append_status(page, result->description);
+	}
+}
+
+/* Edit Menu */
+
+static void sieve_editor_undo_cb(GtkAction *action, SieveEditorPage *page)
+{
+	undo_undo(page->undostruct);
+}
+
+static void sieve_editor_redo_cb(GtkAction *action, SieveEditorPage *page)
+{
+	undo_redo(page->undostruct);
+}
+
+static void sieve_editor_cut_cb(GtkAction *action, SieveEditorPage *page)
+{
+	GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+	gtk_text_buffer_cut_clipboard(buf, clipboard, TRUE);
+}
+
+static void sieve_editor_copy_cb(GtkAction *action, SieveEditorPage *page)
+{
+	GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+	gtk_text_buffer_copy_clipboard(buf, clipboard);
+}
+
+static void sieve_editor_paste_cb(GtkAction *action, SieveEditorPage *page)
+{
+	if (!gtk_widget_has_focus(page->text))
+		return;
+
+	GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+	gchar *contents = gtk_clipboard_wait_for_text(clipboard);
+	GtkTextMark *start_mark = gtk_text_buffer_get_insert(buf);
+	GtkTextIter start_iter;
+
+	undo_paste_clipboard(GTK_TEXT_VIEW(page->text), page->undostruct);
+	gtk_text_buffer_delete_selection(buf, FALSE, TRUE);
+
+	gtk_text_buffer_get_iter_at_mark(buf, &start_iter, start_mark);
+	gtk_text_buffer_insert(buf, &start_iter, contents, strlen(contents));
+}
+
+
+static void sieve_editor_allsel_cb(GtkAction *action, SieveEditorPage *page)
+{
+	GtkTextIter start, end;
+	GtkTextBuffer *buffer;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+	gtk_text_buffer_get_start_iter(buffer, &start);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_select_range(buffer, &start, &end);
+}
+
+/* Search */
+
+void sieve_editor_set_position(void *obj, gint pos)
+{
+	SieveEditorPage *page = (SieveEditorPage *)obj;
+	GtkTextView *text = GTK_TEXT_VIEW(page->text);
+
+	gtkut_text_view_set_position(text, pos);
+}
+
+gboolean sieve_editor_search_string(void *obj,
+	const gchar *str, gboolean case_sens)
+{
+	SieveEditorPage *page = (SieveEditorPage *)obj;
+	GtkTextView *text = GTK_TEXT_VIEW(page->text);
+
+	return gtkut_text_view_search_string(text, str, case_sens);
+}
+
+gboolean sieve_editor_search_string_backward(void *obj,
+	const gchar *str, gboolean case_sens)
+{
+	SieveEditorPage *page = (SieveEditorPage *)obj;
+	GtkTextView *text = GTK_TEXT_VIEW(page->text);
+
+	return gtkut_text_view_search_string_backward(text, str, case_sens);
+}
+
+static void sieve_editor_search(SieveEditorPage *page)
+{
+	message_search_other(&search_interface, page);
+}
+
+/* Actions */
+
+static void got_data_reverting(SieveSession *session, gchar *contents,
+		SieveEditorPage *page)
+{
+	if (contents == NULL) {
+		/* end of data */
+		undo_unblock(page->undostruct);
+		gtk_widget_set_sensitive(page->text, TRUE);
+		sieve_editor_set_status(page, "");
+		sieve_editor_set_modified(page, FALSE);
+		return;
+	}
+	if (contents == (void *)-1) {
+		/* error */
+		sieve_editor_set_status(page, _("Unable to get script contents"));
+		sieve_editor_set_status_icon(page, GTK_STOCK_DIALOG_ERROR);
+		return;
+	}
+
+	if (page->first_line) {
+		GtkTextIter start, end;
+		GtkTextBuffer *buffer;
+
+		page->first_line = FALSE;
+
+		/* delete previous data */
+		buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
+		gtk_text_buffer_get_start_iter(buffer, &start);
+		gtk_text_buffer_get_end_iter(buffer, &end);
+		gtk_text_buffer_delete(buffer, &start, &end);
+
+		/* append data */
+		gtk_text_buffer_insert(buffer, &end, contents, strlen(contents));
+	} else {
+		sieve_editor_append_text(page, "\n", 1);
+		sieve_editor_append_text(page, contents, strlen(contents));
+	}
+}
+
+static void sieve_editor_revert(SieveEditorPage *page)
+{
+	undo_block(page->undostruct);
+	page->first_line = TRUE;
+	gtk_widget_set_sensitive(page->text, FALSE);
+	sieve_editor_set_status(page, _("Reverting..."));
+	sieve_editor_set_status_icon(page, NULL);
+	sieve_session_get_script(page->session, page->script_name,
+			(sieve_session_data_cb_fn)got_data_reverting, page);
+}
+
+static void sieve_editor_revert_cb(GtkAction *action, SieveEditorPage *page)
+{
+	if (!page->modified ||
+			alertpanel(_("Revert script"),
+				_("This script has been modified. Revert the unsaved changes?"),
+				_("_Revert"), NULL, GTK_STOCK_CANCEL) == G_ALERTDEFAULT)
+		sieve_editor_revert(page);
+}
+
+static void got_data_saved(SieveSession *session, SieveResult *result,
+		SieveEditorPage *page)
+{
+	if (result->has_status && result->success) {
+		sieve_editor_set_modified(page, FALSE);
+		if (page->closing) {
+			sieve_editor_close(page);
+			return;
+		}
+		/* use nice status message if there are no warnings */
+		if (result->code == SIEVE_CODE_NONE) {
+			result->description = _("Script saved successfully.");
+		}
+	}
+	sieve_editor_update_status(page, result);
+}
+
+static void sieve_editor_save(SieveEditorPage *page)
+{
+	gchar *text;
+	gint len = sieve_editor_get_text(page, &text);
+	sieve_editor_set_status(page, _("Saving..."));
+	sieve_editor_set_status_icon(page, NULL);
+	sieve_session_put_script(page->session, page->script_name, len, text,
+			(sieve_session_data_cb_fn)got_data_saved, page);
+	g_free(text);
+}
+
+static void sieve_editor_save_cb(GtkAction *action, SieveEditorPage *page)
+{
+	sieve_editor_save(page);
+}
+
+static void sieve_editor_find_cb(GtkAction *action, SieveEditorPage *page)
+{
+	sieve_editor_search(page);
+}
+
+static void got_data_checked(SieveSession *session, SieveResult *result,
+		SieveEditorPage *page)
+{
+	sieve_editor_update_status(page, result);
+}
+
+static void sieve_editor_check_cb(GtkAction *action, SieveEditorPage *page)
+{
+	gchar *text;
+	gint len = sieve_editor_get_text(page, &text);
+	sieve_editor_set_status(page, _("Checking syntax..."));
+	sieve_editor_set_status_icon(page, NULL);
+	sieve_session_check_script(page->session, len, text,
+			(sieve_session_data_cb_fn)got_data_checked, page);
+	g_free(text);
+}
+
+static void sieve_editor_changed_cb(GtkTextBuffer *textbuf,
+		SieveEditorPage *page)
+{
+	if (!page->modified) {
+		sieve_editor_set_modified(page, TRUE);
+	}
+}
+
+static void sieve_editor_destroy(SieveEditorPage *page)
+{
+	gtk_widget_destroy(page->window);
+	undo_destroy(page->undostruct);
+	g_free(page);
+}
+
+void sieve_editor_close(SieveEditorPage *page)
+{
+	editors = g_slist_remove(editors, (gconstpointer)page);
+	sieve_editor_destroy(page);
+	sieve_sessions_discard_callbacks(page);
+}
+
+static gboolean sieve_editor_confirm_close(SieveEditorPage *page)
+{
+	if (page->modified) {
+		switch (alertpanel(_("Save changes"),
+				_("This script has been modified. Save the latest changes?"),
+				_("_Discard"), _("+_Save"), GTK_STOCK_CANCEL)) {
+			case G_ALERTDEFAULT:
+				return TRUE;
+			case G_ALERTALTERNATE:
+				page->closing = TRUE;
+				sieve_editor_save(page);
+				return FALSE;
+			default:
+				return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static void sieve_editor_close_cb(GtkAction *action, SieveEditorPage *page)
+{
+	if (sieve_editor_confirm_close(page)) {
+		sieve_editor_close(page);
+	}
+}
+
+static gint sieve_editor_delete_cb(GtkWidget *widget, GdkEventAny *event,
+		SieveEditorPage *page)
+{
+	sieve_editor_close_cb(NULL, page);
+	return TRUE;
+}
+
+/**
+ * sieve_editor_undo_state_changed:
+ *
+ * Change the sensivity of the menuentries undo and redo
+ **/
+static void sieve_editor_undo_state_changed(UndoMain *undostruct,
+		gint undo_state, gint redo_state, gpointer data)
+{
+	SieveEditorPage *page = (SieveEditorPage *)data;
+
+	switch (undo_state) {
+	case UNDO_STATE_TRUE:
+		if (!undostruct->undo_state) {
+			undostruct->undo_state = TRUE;
+			cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", TRUE);
+		}
+		break;
+	case UNDO_STATE_FALSE:
+		if (undostruct->undo_state) {
+			undostruct->undo_state = FALSE;
+			cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", FALSE);
+		}
+		break;
+	case UNDO_STATE_UNCHANGED:
+		break;
+	case UNDO_STATE_REFRESH:
+		cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", undostruct->undo_state);
+		break;
+	default:
+		g_warning("Undo state not recognized");
+		break;
+	}
+
+	switch (redo_state) {
+	case UNDO_STATE_TRUE:
+		if (!undostruct->redo_state) {
+			undostruct->redo_state = TRUE;
+			cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", TRUE);
+		}
+		break;
+	case UNDO_STATE_FALSE:
+		if (undostruct->redo_state) {
+			undostruct->redo_state = FALSE;
+			cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", FALSE);
+		}
+		break;
+	case UNDO_STATE_UNCHANGED:
+		break;
+	case UNDO_STATE_REFRESH:
+		cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", undostruct->redo_state);
+		break;
+	default:
+		g_warning("Redo state not recognized");
+		break;
+	}
+}
+
+
+SieveEditorPage *sieve_editor_new(SieveSession *session, gchar *script_name)
+{
+	SieveEditorPage *page;
+	GtkUIManager *ui_manager;
+	UndoMain *undostruct;
+	GtkWidget *window;
+	GtkWidget *menubar;
+	GtkWidget *vbox, *hbox, *hbox1;
+	GtkWidget *scrolledwin;
+	GtkWidget *text;
+	GtkTextBuffer *buffer;
+	GtkWidget *check_btn, *save_btn, *close_btn;
+	GtkWidget *status_text;
+	GtkWidget *status_icon;
+
+	page = g_new0(SieveEditorPage, 1);
+
+	/* window */
+	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sieveeditor");
+	gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
+	MANAGE_WINDOW_SIGNALS_CONNECT (window);
+	g_signal_connect(G_OBJECT(window), "delete_event",
+			 G_CALLBACK(sieve_editor_delete_cb), page);
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(window), vbox);
+
+	ui_manager = gtk_ui_manager_new();
+	cm_menu_create_action_group_full(ui_manager,
+			"Menu", sieve_editor_entries, G_N_ELEMENTS(sieve_editor_entries),
+			page);
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Filter", "Filter", GTK_UI_MANAGER_MENU)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
+
+/* Filter menu */
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Save", "Filter/Save", GTK_UI_MANAGER_MENUITEM)
+MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "CheckSyntax", "Filter/CheckSyntax", GTK_UI_MANAGER_MENUITEM)
+MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Revert", "Filter/Revert", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Close", "Filter/Close", GTK_UI_MANAGER_MENUITEM)
+
+/* Edit menu */
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Undo", "Edit/Undo", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Redo", "Edit/Redo", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Edit/---", GTK_UI_MANAGER_SEPARATOR)
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Edit/Cut", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Edit/Copy", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Edit/Paste", GTK_UI_MANAGER_MENUITEM)
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Edit/SelectAll", GTK_UI_MANAGER_MENUITEM)
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Edit/---", GTK_UI_MANAGER_SEPARATOR)
+
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Find", "Edit/Find", GTK_UI_MANAGER_MENUITEM)
+
+	menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
+
+	gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
+	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
+
+	cm_menu_set_sensitive_full(ui_manager, "Menu/Edit/Undo", FALSE);
+	cm_menu_set_sensitive_full(ui_manager, "Menu/Edit/Redo", FALSE);
+
+	/* text */
+	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+	gtk_widget_set_size_request (scrolledwin, 660, 408);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+				       GTK_POLICY_AUTOMATIC,
+				       GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
+					    GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
+
+	text = gtk_text_view_new();
+	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD_CHAR);
+	gtk_text_view_set_editable(GTK_TEXT_VIEW(text), TRUE);
+	gtk_container_add(GTK_CONTAINER(scrolledwin), text);
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
+	g_signal_connect(G_OBJECT(buffer), "changed",
+			 G_CALLBACK(sieve_editor_changed_cb), page);
+
+	/* set text font */
+	if (prefs_common.textfont) {
+		PangoFontDescription *font_desc;
+
+		font_desc = pango_font_description_from_string
+			(prefs_common.textfont);
+		if (font_desc) {
+			gtk_widget_modify_font(text, font_desc);
+			pango_font_description_free(font_desc);
+		}
+	}
+
+	hbox = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
+
+	/* status */
+	status_icon = gtk_image_new ();
+	gtk_box_pack_start (GTK_BOX (hbox), status_icon, FALSE, FALSE, 0);
+	status_text = gtk_label_new ("");
+	gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
+
+	/* buttons */
+	gtkut_stock_with_text_button_set_create(&hbox1,
+			&close_btn, GTK_STOCK_CANCEL, _("_Close"),
+			&check_btn, GTK_STOCK_OK, _("Chec_k Syntax"),
+			&save_btn, GTK_STOCK_SAVE, _("_Save"));
+	gtk_box_pack_end (GTK_BOX (hbox), hbox1, FALSE, FALSE, 0);
+	gtk_widget_grab_default (save_btn);
+	g_signal_connect (G_OBJECT (close_btn), "clicked",
+			  G_CALLBACK (sieve_editor_close_cb), page);
+	g_signal_connect (G_OBJECT (check_btn), "clicked",
+			  G_CALLBACK (sieve_editor_check_cb), page);
+	g_signal_connect (G_OBJECT (save_btn), "clicked",
+			  G_CALLBACK (sieve_editor_save_cb), page);
+
+	undostruct = undo_init(text);
+	undo_set_change_state_func(undostruct, &sieve_editor_undo_state_changed,
+			page);
+
+	gtk_widget_show_all(window);
+
+	page->window = window;
+	page->ui_manager = ui_manager;
+	page->text = text;
+	page->undostruct = undostruct;
+	page->session = session;
+	page->script_name = script_name;
+	page->status_text = status_text;
+	page->status_icon = status_icon;
+
+	editors = g_slist_prepend(editors, page);
+
+	sieve_editor_set_modified(page, FALSE);
+
+	return page;
+}
+
+SieveEditorPage *sieve_editor_get(SieveSession *session, gchar *script_name)
+{
+	GSList *item;
+	SieveEditorPage *page;
+	for (item = editors; item; item = item->next) {
+		page = (SieveEditorPage *)item->data;
+		if (page->session == session &&
+				strcmp(script_name, page->script_name) == 0)
+			return page;
+	}
+	return NULL;
+}
+
+void sieve_editor_present(SieveEditorPage *page)
+{
+	gtk_window_present(GTK_WINDOW(page->window));
+}
+
+static void sieve_editor_set_modified(SieveEditorPage *page,
+		gboolean modified)
+{
+	gchar *title;
+
+	page->modified = modified;
+	cm_menu_set_sensitive_full(page->ui_manager, "Menu/Filter/Revert",
+			modified);
+
+	title = g_strdup_printf(_("%s - Sieve Filter%s"), page->script_name,
+			modified ? " [Edited]" : "");
+	gtk_window_set_title (GTK_WINDOW (page->window), title);
+	g_free(title);
+
+	if (modified) {
+		sieve_editor_set_status(page, "");
+		sieve_editor_set_status_icon(page, NULL);
+	}
+}
diff --git a/src/plugins/managesieve/sieve_editor.h b/src/plugins/managesieve/sieve_editor.h
new file mode 100644
index 0000000..4925a54
--- /dev/null
+++ b/src/plugins/managesieve/sieve_editor.h
@@ -0,0 +1,50 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef SIEVE_EDITOR_H
+#define SIEVE_EDITOR_H
+
+#include "undo.h"
+
+typedef struct SieveEditorPage SieveEditorPage;
+
+struct SieveEditorPage
+{
+	GtkWidget*	window;
+	GtkWidget*	status_text;
+	GtkWidget*	status_icon;
+	GtkWidget*	text;
+	GtkUIManager *ui_manager;
+	UndoMain	*undostruct;
+	struct SieveSession *session;
+	gchar *script_name;
+	gboolean	first_line;
+	gboolean	modified;
+	gboolean	closing;
+};
+
+SieveEditorPage *sieve_editor_new(SieveSession *session, gchar *script_name);
+SieveEditorPage *sieve_editor_get(SieveSession *session, gchar *script_name);
+void sieve_editor_append_text(SieveEditorPage *page, gchar *text, gint len);
+void sieve_editor_close(SieveEditorPage *page);
+void sieve_editor_present(SieveEditorPage *page);
+
+#endif /* SIEVE_EDITOR_H */
+
diff --git a/src/plugins/managesieve/sieve_manager.c b/src/plugins/managesieve/sieve_manager.c
new file mode 100644
index 0000000..212c30a
--- /dev/null
+++ b/src/plugins/managesieve/sieve_manager.c
@@ -0,0 +1,803 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "defs.h"
+#include "gtk/gtkutils.h"
+#include "gtk/combobox.h"
+#include "gtk/inputdialog.h"
+#include "gtk/manage_window.h"
+#include "alertpanel.h"
+#include "utils.h"
+#include "prefs.h"
+#include "account.h"
+#include "mainwindow.h"
+#include "managesieve.h"
+#include "sieve_editor.h"
+#include "sieve_prefs.h"
+#include "sieve_manager.h"
+
+enum {
+	FILTER_NAME,
+	FILTER_ACTIVE,
+	N_FILTER_COLUMNS
+};
+
+typedef struct {
+	SieveManagerPage *page;
+	gchar *name_old;
+	gchar *name_new;
+} CommandDataRename;
+
+typedef struct {
+	SieveManagerPage *page;
+	gchar *filter_name;
+} CommandDataName;
+
+typedef struct {
+	SieveManagerPage *page;
+	gchar *filter_name;
+	SieveEditorPage *editor_page;
+	gboolean first_line;
+} CommandDataGetScript;
+
+static void account_changed(GtkWidget *widget, SieveManagerPage *page);
+static void filter_activate(GtkWidget *widget, SieveManagerPage *page);
+void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page);
+static void filter_set_active(SieveManagerPage *page, gchar *filter_name);
+gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
+		gchar *filter_name);
+static void got_session_error(SieveSession *session, const gchar *msg,
+		SieveManagerPage *page);
+
+static GSList *manager_pages = NULL;
+
+/*
+ * Perform a command on all manager pages for a given session
+ */
+#define manager_sessions_foreach(cur, session, page) \
+	for(cur = manager_pages; cur != NULL; cur = cur->next) \
+		if ((page = (SieveManagerPage *)cur->data) && \
+			page->active_session == session)
+
+static void filters_list_clear(SieveManagerPage *page)
+{
+	GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
+	gtk_list_store_clear(list_store);
+	page->got_list = FALSE;
+}
+
+static void filters_list_delete_filter(SieveManagerPage *page, gchar *name)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
+
+	if (!filter_find_by_name(model, &iter, name))
+		return;
+
+	gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+}
+
+
+static void filters_list_rename_filter(SieveManagerPage *page,
+		gchar *name_old, char *name_new)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
+
+	if (!filter_find_by_name(model, &iter, name_old))
+		return;
+
+	gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+			FILTER_NAME, name_new,
+			-1);
+}
+
+static void filters_list_insert_filter(SieveManagerPage *page,
+		SieveScript *filter)
+{
+	GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
+	GtkTreeIter iter;
+
+	gtk_list_store_append(list_store, &iter);
+	gtk_list_store_set(list_store, &iter,
+			FILTER_NAME, filter->name,
+			FILTER_ACTIVE, filter->active,
+			-1);
+}
+
+static gchar *filters_list_get_selected_filter(GtkWidget *list_view)
+{
+	GtkTreeSelection *selector;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *res = NULL;
+
+	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+
+	if (!gtk_tree_selection_get_selected(selector, &model, &iter))
+		return NULL;
+
+	gtk_tree_model_get(model, &iter, FILTER_NAME, &res, -1);
+
+	return res;
+}
+
+static void filter_add(GtkWidget *widget, SieveManagerPage *page)
+{
+	SieveSession *session = page->active_session;
+	if (!session)
+		return;
+	gchar *filter_name = input_dialog(_("Add Sieve script"),
+			_("Enter name for a new Sieve filter script."), "");
+	if (!filter_name || !filter_name[0])
+		return;
+
+	sieve_editor_new(session, filter_name);
+	/*
+	sieve_session_add_script(session, filter_name
+			(sieve_session_data_cb_fn)filter_added, (gpointer)page);
+			*/
+}
+
+static void filter_got_data(SieveSession *session, gchar *contents,
+		CommandDataGetScript *cmd_data)
+{
+	SieveManagerPage *page = cmd_data->page;
+	SieveEditorPage *editor;
+
+	if (!contents) {
+		g_free(cmd_data);
+		return;
+	} else if (contents == (void *)-1) {
+		got_session_error(session, _("Unable to get script contents"), page);
+		return;
+	}
+
+	if (cmd_data->first_line) {
+		cmd_data->first_line = FALSE;
+		editor = sieve_editor_new(session, cmd_data->filter_name);
+		cmd_data->editor_page = editor;
+	} else {
+		editor = cmd_data->editor_page;
+		sieve_editor_append_text(editor, "\n", 1);
+	}
+	sieve_editor_append_text(editor, contents, strlen(contents));
+}
+
+static void filter_edit(GtkWidget *widget, SieveManagerPage *page)
+{
+	SieveEditorPage *editor;
+	CommandDataGetScript *cmd_data;
+	SieveSession *session = page->active_session;
+	if (!session)
+		return;
+	gchar *filter_name = filters_list_get_selected_filter(page->filters_list);
+	if (!filter_name)
+		return;
+
+	editor = sieve_editor_get(session, filter_name);
+	if (editor) {
+		sieve_editor_present(editor);
+	} else {
+		cmd_data = g_new0(CommandDataGetScript, 1);
+		cmd_data->first_line = TRUE;
+		cmd_data->filter_name = filter_name;
+		cmd_data->page = page;
+
+		sieve_session_get_script(session, filter_name,
+			(sieve_session_data_cb_fn)filter_got_data, cmd_data);
+	}
+}
+
+static void filter_renamed(SieveSession *session, gboolean success,
+		CommandDataRename *data)
+{
+	SieveManagerPage *page = data->page;
+	GSList *cur;
+
+	if (!success) {
+		got_session_error(session, "Unable to rename script", page);
+		return;
+	}
+
+	manager_sessions_foreach(cur, session, page) {
+		filters_list_rename_filter(page, data->name_old, data->name_new);
+	}
+	g_free(data);
+}
+
+static void filter_rename(GtkWidget *widget, SieveManagerPage *page)
+{
+	CommandDataRename *cmd_data;
+	gchar *name_old, *name_new;
+	SieveSession *session;
+
+	name_old = filters_list_get_selected_filter(page->filters_list);
+	if (!name_old)
+		return;
+
+	session = page->active_session;
+	if (!session)
+		return;
+
+	name_new = input_dialog(_("Add Sieve script"),
+			_("Enter new name for the script."), name_old);
+	if (!name_new)
+		return;
+
+	cmd_data = g_new(CommandDataRename, 1);
+	cmd_data->name_new = name_new;
+	cmd_data->name_old = name_old;
+	cmd_data->page = page;
+	sieve_session_rename_script(session, name_old, name_new,
+			(sieve_session_data_cb_fn)filter_renamed, (gpointer)cmd_data);
+}
+
+static void filter_activated(SieveSession *session, gboolean success,
+		CommandDataName *cmd_data)
+{
+	SieveManagerPage *page = cmd_data->page;
+	GSList *cur;
+
+	if (!success) {
+		got_session_error(session, "Unable to set active script", page);
+		return;
+	}
+
+	manager_sessions_foreach(cur, session, page) {
+		filter_set_active(page, cmd_data->filter_name);
+	}
+	g_free(cmd_data);
+}
+
+static void sieve_set_active_filter(SieveManagerPage *page, gchar *filter_name)
+{
+	SieveSession *session;
+	CommandDataName *cmd_data;
+
+	session = page->active_session;
+	cmd_data = g_new(CommandDataName, 1);
+	cmd_data->filter_name = filter_name;
+	cmd_data->page = page;
+
+	sieve_session_set_active_script(session, filter_name,
+			(sieve_session_data_cb_fn)filter_activated, cmd_data);
+}
+
+/*
+ * activate button clicked
+ */
+static void filter_activate(GtkWidget *widget, SieveManagerPage *page)
+{
+	gchar *filter_name = filters_list_get_selected_filter(page->filters_list);
+	if (!filter_name)
+		return;
+	sieve_set_active_filter(page, filter_name);
+}
+
+static void filter_deleted(SieveSession *session, const gchar *err_msg,
+		CommandDataName *cmd_data)
+{
+	SieveManagerPage *page = cmd_data->page;
+	GSList *cur;
+
+	if (err_msg) {
+		got_session_error(session, err_msg, page);
+		return;
+	}
+
+	manager_sessions_foreach(cur, session, page) {
+		filters_list_delete_filter(page, cmd_data->filter_name);
+	}
+	g_free(cmd_data);
+}
+
+
+static void filter_delete(GtkWidget *widget, SieveManagerPage *page)
+{
+	gchar buf[256];
+	gchar *filter_name;
+	SieveSession *session;
+	CommandDataName *cmd_data;
+
+	filter_name = filters_list_get_selected_filter(page->filters_list);
+	if (filter_name == NULL)
+		return;
+
+	session = page->active_session;
+	if (!session)
+		return;
+
+	g_snprintf(buf, sizeof(buf),
+		   _("Do you really want to delete the filter '%s'?"), filter_name);
+	if (alertpanel_full(_("Delete filter"), buf,
+				GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, FALSE,
+				NULL, ALERT_WARNING, G_ALERTDEFAULT) != G_ALERTALTERNATE)
+		return;
+
+	cmd_data = g_new(CommandDataName, 1);
+	cmd_data->filter_name = filter_name;
+	cmd_data->page = page;
+
+	sieve_session_delete_script(session, filter_name,
+			(sieve_session_data_cb_fn)filter_deleted, cmd_data);
+}
+
+/*
+ * select a filter in the list
+ *
+ * return TRUE is successfully selected, FALSE otherwise
+ */
+
+static gboolean filter_select (GtkWidget *list_view, GtkTreeModel *model,
+		GtkTreeIter *iter)
+{
+	GtkTreeSelection *selection;
+	GtkTreePath* path;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+	gtk_tree_selection_select_iter(selection, iter);
+	path = gtk_tree_model_get_path(model, iter);
+	if (path == NULL) return FALSE;
+	gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
+	gtk_tree_path_free(path);
+	return TRUE;
+}
+
+/*
+ * find matching filter. return FALSE on match
+ */
+static gboolean filter_search_equal_fn (GtkTreeModel *model, gint column,
+		const gchar *key, GtkTreeIter *iter, gpointer search_data)
+{
+	SieveManagerPage *page = (SieveManagerPage *)search_data;
+	gchar *filter_name;
+
+	if (!key) return TRUE;
+
+	gtk_tree_model_get (model, iter, FILTER_NAME, &filter_name, -1);
+
+	if (strncmp (key, filter_name, strlen(key)) != 0) return TRUE;
+	return !filter_select(page->filters_list, model, iter);
+}
+
+/*
+ * search for a filter row by its name. return true if found.
+ */
+gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
+		gchar *filter_name)
+{
+	gchar *name;
+
+	if (!gtk_tree_model_get_iter_first (model, iter))
+		return FALSE;
+
+	do {
+		gtk_tree_model_get (model, iter, FILTER_NAME, &name, -1);
+		if (strcmp(filter_name, name) == 0) {
+			return TRUE;
+		}
+	} while (gtk_tree_model_iter_next (model, iter));
+	return FALSE;
+}
+
+static gboolean filter_set_inactive(GtkTreeModel *model,
+		GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+	gtk_list_store_set(GTK_LIST_STORE(model), iter,
+			FILTER_ACTIVE, FALSE,
+			-1);
+	return FALSE;
+}
+
+/*
+ * Set the active filter in the table.
+ * @param filter_name The filter to make active (may be null)
+ */
+static void filter_set_active(SieveManagerPage *page, gchar *filter_name)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
+
+	/* Deactivate all filters */
+	gtk_tree_model_foreach(model, filter_set_inactive, NULL);
+
+	/* Set active filter */
+	if (filter_name) {
+		if (!filter_find_by_name (model, &iter, filter_name))
+			return;
+
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+				FILTER_ACTIVE, TRUE,
+				-1);
+	}
+}
+
+static void filter_active_toggled(GtkCellRendererToggle *widget,
+				    gchar *path,
+				    SieveManagerPage *page)
+{
+	GtkTreeIter iter;
+	gchar *filter_name;
+	gboolean active;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
+
+	if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
+		return;
+
+	/* get existing value */
+	gtk_tree_model_get(model, &iter,
+			FILTER_NAME, &filter_name,
+			FILTER_ACTIVE, &active,
+			-1);
+
+	sieve_set_active_filter(page, active ? NULL : filter_name);
+}
+
+static void filter_double_clicked(GtkTreeView *list_view,
+				   GtkTreePath *path, GtkTreeViewColumn *column,
+				   SieveManagerPage *page)
+{
+	filter_edit(GTK_WIDGET(list_view), page);
+}
+
+static void filters_create_list_view_columns(SieveManagerPage *page,
+		GtkWidget *list_view)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	/* Name */
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes
+		(_("Name"), renderer,
+		 "text", FILTER_NAME,
+		 NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
+	gtk_tree_view_column_set_expand(column, TRUE);
+
+	/* Active */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_object_set(renderer,
+		     "radio", TRUE,
+		     "activatable", TRUE,
+		      NULL);
+	column = gtk_tree_view_column_new_with_attributes
+		(_("Active"), renderer,
+		 "active", FILTER_ACTIVE,
+		 NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
+	gtk_tree_view_column_set_alignment (column, 0.5);
+	CLAWS_SET_TIP(gtk_tree_view_column_get_widget(column),
+			_("An account can only have one active script at a time."));
+	g_signal_connect(G_OBJECT(renderer), "toggled",
+			 G_CALLBACK(filter_active_toggled), page);
+
+	gtk_tree_view_set_search_column(GTK_TREE_VIEW(list_view), FILTER_NAME);
+	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(list_view),
+			filter_search_equal_fn, page, NULL);
+}
+
+
+static GtkListStore* filters_create_data_store(void)
+{
+	return gtk_list_store_new(N_FILTER_COLUMNS,
+			G_TYPE_STRING,	/* FILTER_NAME */
+			G_TYPE_BOOLEAN,	/* FILTER_ACTIVE */
+			-1);
+}
+
+static GtkWidget *filters_list_view_create(SieveManagerPage *page)
+{
+	GtkTreeView *list_view;
+	GtkTreeSelection *selector;
+	GtkListStore *store = filters_create_data_store();
+
+	list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
+	g_object_unref(G_OBJECT(store));
+
+	selector = gtk_tree_view_get_selection(list_view);
+	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+
+	/* create the columns */
+	filters_create_list_view_columns(page, GTK_WIDGET(list_view));
+
+	/* set a double click listener */
+	g_signal_connect(G_OBJECT(list_view), "row_activated",
+			G_CALLBACK(filter_double_clicked),
+			page);
+
+	return GTK_WIDGET(list_view);
+}
+
+static gboolean manager_key_pressed(GtkWidget *widget, GdkEventKey *event,
+				    gpointer data)
+{
+	SieveManagerPage* page = (SieveManagerPage *) data;
+
+	if (event && event->keyval == GDK_KEY_Escape)
+		sieve_manager_done(page);
+
+	return FALSE;
+}
+
+static void got_session_error(SieveSession *session, const gchar *msg,
+		SieveManagerPage *page)
+{
+	if (page->active_session != session)
+		return;
+	gtk_label_set_text(GTK_LABEL(page->status_text), msg);
+}
+
+static void sieve_manager_on_error(SieveSession *session,
+		const gchar *msg, gpointer user_data)
+{
+	SieveManagerPage *page = (SieveManagerPage *)user_data;
+	got_session_error(session, msg, page);
+}
+
+static void sieve_manager_on_connected(SieveSession *session,
+		gboolean connected, gpointer user_data)
+{
+	SieveManagerPage *page = (SieveManagerPage *)user_data;
+	if (page->active_session != session)
+		return;
+	if (!connected) {
+		gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), FALSE);
+		gtk_label_set_text(GTK_LABEL(page->status_text),
+				_("Unable to connect"));
+	}
+}
+
+static void got_filter_listed(SieveSession *session, SieveScript *script,
+		SieveManagerPage *page)
+{
+	if (!script) {
+		got_session_error(session, "Unable to list scripts", page);
+		return;
+	}
+	if (!script->name) {
+		/* done receiving list */
+		page->got_list = TRUE;
+		gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), TRUE);
+		gtk_label_set_text(GTK_LABEL(page->status_text), "");
+		return;
+	}
+	filters_list_insert_filter(page, script);
+}
+
+/*
+ * An account was selected from the menu. Get its list of scripts.
+ */
+static void account_changed(GtkWidget *widget, SieveManagerPage *page)
+{
+	gint account_id;
+	PrefsAccount *account;
+	SieveSession *session;
+
+	account_id = combobox_get_active_data(GTK_COMBO_BOX(page->accounts_menu));
+	account = account_find_from_id(account_id);
+	if (!account)
+		return;
+	session = page->active_session = sieve_session_get_for_account(account);
+	sieve_session_handle_status(session,
+			sieve_manager_on_error,
+			sieve_manager_on_connected,
+			page);
+	filters_list_clear(page);
+	if (session_is_connected(SESSION(session))) {
+		gtk_label_set_text(GTK_LABEL(page->status_text),
+				_("Listing scripts..."));
+	} else {
+		gtk_label_set_text(GTK_LABEL(page->status_text),
+				_("Connecting..."));
+	}
+	sieve_session_list_scripts(session,
+			(sieve_session_data_cb_fn)got_filter_listed, (gpointer)page);
+}
+
+static SieveManagerPage *sieve_manager_page_new()
+{
+	SieveManagerPage *page;
+	GtkWidget *window;
+	GtkWidget *hbox, *vbox, *vbox_allbuttons, *vbox_buttons;
+	GtkWidget *accounts_menu;
+	GtkWidget *label;
+	GtkWidget *scrolledwin;
+	GtkWidget *list_view;
+	GtkWidget *btn;
+	GtkWidget *status_text;
+	GtkTreeIter iter;
+	GtkListStore *menu;
+	GList *account_list, *cur;
+	PrefsAccount *ap;
+	SieveAccountConfig *config;
+	PrefsAccount *default_account = NULL;
+
+	page = g_new0(SieveManagerPage, 1);
+
+	/* Manage Window */
+
+	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sievemanager");
+	gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+	gtk_window_set_title (GTK_WINDOW (window), _("Manage Sieve Filters"));
+	gtk_widget_set_size_request (window, 480, 296);
+	MANAGE_WINDOW_SIGNALS_CONNECT (window);
+	g_signal_connect (G_OBJECT (window), "key_press_event",
+			G_CALLBACK (manager_key_pressed), page);
+
+	vbox = gtk_vbox_new (FALSE, 10);
+	gtk_container_add (GTK_CONTAINER (window), vbox);
+
+	hbox = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+	/* Accounts list */
+
+	label = gtk_label_new (_("Account"));
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+	accounts_menu = gtkut_sc_combobox_create(NULL, FALSE);
+	menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(accounts_menu)));
+	gtk_box_pack_start (GTK_BOX (hbox), accounts_menu, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT(accounts_menu), "changed",
+			  G_CALLBACK (account_changed), page);
+
+	account_list = account_get_list();
+	for (cur = account_list; cur != NULL; cur = cur->next) {
+		ap = (PrefsAccount *)cur->data;
+		config = sieve_prefs_account_get_config(ap);
+		if (config->enable) {
+			COMBOBOX_ADD (menu, ap->account_name, ap->account_id);
+			if (!default_account || ap->is_default)
+				default_account = ap;
+		}
+	}
+
+	if (!default_account) {
+		gtk_widget_destroy(label);
+		gtk_widget_destroy(accounts_menu);
+	}
+
+	/* status */
+	status_text = gtk_label_new ("");
+	gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
+
+	/* Filters list */
+
+	hbox = gtk_hbox_new (FALSE, 8);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
+
+	/* Table */
+
+	scrolledwin = gtk_scrolled_window_new (NULL, NULL);
+	gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+
+	list_view = filters_list_view_create(page);
+	gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
+
+	/* Buttons */
+
+	vbox_allbuttons = gtk_vbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), vbox_allbuttons, FALSE, FALSE, 0);
+
+	vbox_buttons = gtk_vbox_new (FALSE, 0);
+	gtk_widget_set_sensitive(vbox_buttons, FALSE);
+	gtk_box_pack_start (GTK_BOX (vbox_allbuttons), vbox_buttons, FALSE, FALSE, 0);
+
+	/* new */
+	btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
+	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			  G_CALLBACK (filter_add), page);
+
+	/* edit */
+	btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			G_CALLBACK (filter_edit), page);
+
+	/* delete */
+	btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			G_CALLBACK (filter_delete), page);
+
+	/* rename */
+	btn = gtk_button_new_with_label("Rename");
+	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			G_CALLBACK (filter_rename), page);
+
+
+	/* activate */
+	btn = gtk_button_new_with_label("Activate");
+	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			G_CALLBACK (filter_activate), page);
+
+	/* refresh */
+	btn = gtk_button_new_with_mnemonic("_Refresh");
+	gtk_box_pack_start (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 4);
+	g_signal_connect (G_OBJECT(btn), "clicked",
+			G_CALLBACK (account_changed), page);
+
+	/* bottom area stuff */
+
+	gtkut_stock_button_set_create(&hbox,
+			&btn, GTK_STOCK_CLOSE,
+			NULL, NULL, NULL, NULL);
+
+	/* close */
+	gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_grab_default (btn);
+	g_signal_connect (G_OBJECT (btn), "clicked",
+			  G_CALLBACK (sieve_manager_close), page);
+
+	page->window = window;
+	page->accounts_menu = accounts_menu;
+	page->filters_list = list_view;
+	page->status_text = status_text;
+	page->vbox_buttons = vbox_buttons;
+
+	/* select default (first) account */
+	if (default_account) {
+		combobox_select_by_data(GTK_COMBO_BOX(accounts_menu),
+				default_account->account_id);
+	} else {
+		gtk_label_set_text(GTK_LABEL(status_text),
+				_("To use Sieve, enable it in an account's preferences."));
+	}
+
+	return page;
+}
+
+void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
+{
+	sieve_manager_done(page);
+}
+
+void sieve_manager_done(SieveManagerPage *page)
+{
+	manager_pages = g_slist_remove(manager_pages, page);
+	gtk_widget_destroy(page->window);
+	g_free(page);
+}
+
+void sieve_manager_show()
+{
+	SieveManagerPage *page = sieve_manager_page_new();
+	manager_pages = g_slist_prepend(manager_pages, page);
+	gtk_widget_show_all(page->window);
+}
diff --git a/src/plugins/managesieve/sieve_manager.h b/src/plugins/managesieve/sieve_manager.h
new file mode 100644
index 0000000..9665bb8
--- /dev/null
+++ b/src/plugins/managesieve/sieve_manager.h
@@ -0,0 +1,42 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef SIEVE_MANAGER_H
+#define SIEVE_MANAGER_H
+
+#include "managesieve.h"
+
+typedef struct SieveManagerPage SieveManagerPage;
+
+struct SieveManagerPage
+{
+	GtkWidget*	window;
+	GtkWidget*	accounts_menu;
+	GtkWidget*	status_text;
+	GtkWidget*	filters_list;
+	GtkWidget*	vbox_buttons;
+	SieveSession	*active_session;
+	gboolean	got_list;
+};
+
+void sieve_manager_show(void);
+void sieve_manager_done(SieveManagerPage *page);
+
+#endif /* SIEVE_MANAGER_H */
diff --git a/src/plugins/managesieve/sieve_plugin.c b/src/plugins/managesieve/sieve_plugin.c
new file mode 100644
index 0000000..0ed9114
--- /dev/null
+++ b/src/plugins/managesieve/sieve_plugin.c
@@ -0,0 +1,154 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2015 the Claws Mail Team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "version.h"
+#include "claws.h"
+#include "plugin.h"
+#include "utils.h"
+#include "hooks.h"
+#include "menu.h"
+#include "mainwindow.h"
+#include "log.h"
+#include "sieve_prefs.h"
+#include "sieve_manager.h"
+
+#define PLUGIN_NAME (_("ManageSieve"))
+
+static gint main_menu_id = 0;
+
+static void manage_cb(GtkAction *action, gpointer data) {
+	sieve_manager_show();
+}
+
+static GtkActionEntry sieve_main_menu[] = {{
+	"Tools/ManageSieveFilters",
+	NULL, N_("Manage Sieve Filters..."), NULL, NULL, G_CALLBACK(manage_cb)
+}};
+
+/**
+ * Initialize plugin.
+ *
+ * @param error  For storing the returned error message.
+ *
+ * @return 0 if initialization succeeds, -1 on failure.
+ */
+gint plugin_init(gchar **error)
+{
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
+				VERSION_NUMERIC, PLUGIN_NAME, error))
+		return -1;
+
+	gtk_action_group_add_actions(mainwin->action_group, sieve_main_menu, 1,
+			(gpointer)mainwin);
+	MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager,
+			"/Menu/Tools", "ManageSieveFilters", "Tools/ManageSieveFilters",
+			GTK_UI_MANAGER_MENUITEM, main_menu_id)
+
+	sieve_prefs_init();
+
+	debug_print("ManageSieve plugin loaded\n");
+
+	return 0;
+}
+
+/**
+ * Destructor for the plugin.
+ * Unregister callback functions and free stuff.
+ *
+ * @return Always TRUE.
+ */
+gboolean plugin_done(void)
+{
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+	if (mainwin == NULL)
+		return FALSE;
+
+	MENUITEM_REMUI_MANAGER(mainwin->ui_manager, mainwin->action_group, "Tools/ManageSieveFilters", main_menu_id);
+	main_menu_id = 0;
+
+	sieve_prefs_done();
+	sieve_sessions_close();
+
+	debug_print("ManageSieve plugin unloaded\n");
+	return TRUE;
+}
+
+const gchar *plugin_name(void)
+{
+	return PLUGIN_NAME;
+}
+
+/**
+ * Get the description of the plugin.
+ *
+ * @return The plugin's description, maybe translated.
+ */
+const gchar *plugin_desc(void)
+{
+	return _("Manage sieve filters on a server using the ManageSieve protocol.");
+}
+
+/**
+ * Get the kind of plugin.
+ *
+ * @return The "GTK2" constant.
+ */
+const gchar *plugin_type(void)
+{
+	return "GTK2";
+}
+/**
+ * Get the license acronym the plugin is released under.
+ *
+ * @return The "GPL3+" constant.
+ */
+const gchar *plugin_licence(void)
+{
+	return "GPL3+";
+}
+
+/**
+ * Get the version of the plugin.
+ *
+ * @return The current version string.
+ */
+const gchar *plugin_version(void)
+{
+	return VERSION;
+}
+
+/**
+ * Get the features implemented by the plugin.
+ *
+ * @return A constant PluginFeature structure with the features.
+ */
+struct PluginFeature *plugin_provides(void)
+{
+	static struct PluginFeature features[] =
+		{ {PLUGIN_UTILITY, N_("ManageSieve")},
+		  {PLUGIN_NOTHING, NULL}};
+
+	return features;
+}
diff --git a/src/plugins/managesieve/sieve_prefs.c b/src/plugins/managesieve/sieve_prefs.c
new file mode 100644
index 0000000..69d8aa4
--- /dev/null
+++ b/src/plugins/managesieve/sieve_prefs.c
@@ -0,0 +1,520 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "defs.h"
+#include "gtk/gtkutils.h"
+#include "gtk/combobox.h"
+#include "alertpanel.h"
+#include "passcrypt.h"
+#include "utils.h"
+#include "prefs.h"
+#include "prefs_gtk.h"
+#include "sieve_prefs.h"
+#include "managesieve.h"
+
+#define PACK_HBOX(hbox, vbox) \
+{ \
+	hbox = gtk_hbox_new (FALSE, 5); \
+	gtk_widget_show (hbox); \
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); \
+}
+
+#define RADIO_ADD(radio, group, hbox, vbox, label) \
+{ \
+	PACK_HBOX(hbox, vbox); \
+	gtk_container_set_border_width(GTK_CONTAINER (hbox), 0); \
+	radio = gtk_radio_button_new_with_label(group, label); \
+	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); \
+	gtk_widget_show(radio); \
+	gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0); \
+}
+
+struct SieveAccountPage
+{
+	PrefsPage page;
+
+	GtkWidget *enable_checkbtn;
+	GtkWidget *serv_frame;
+	GtkWidget *auth_frame;
+	GtkWidget *host_checkbtn, *host_entry;
+	GtkWidget *port_checkbtn, *port_spinbtn;
+	GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
+	GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
+	GtkWidget *auth_custom_vbox, *auth_method_hbox;
+	GtkWidget *uid_entry;
+	GtkWidget *pass_entry;
+	GtkWidget *auth_menu;
+
+	PrefsAccount *account;
+};
+
+static struct SieveAccountPage account_page;
+
+static void update_auth_sensitive(struct SieveAccountPage *page)
+{
+	gboolean use_auth, custom;
+
+	custom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom));
+	use_auth = custom || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse));
+
+	gtk_widget_set_sensitive(GTK_WIDGET(page->auth_custom_vbox), custom);
+	gtk_widget_set_sensitive(GTK_WIDGET(page->auth_method_hbox), use_auth);
+}
+
+static void auth_toggled(GtkToggleButton *togglebutton,
+		gpointer user_data)
+{
+	struct SieveAccountPage *page = (struct SieveAccountPage *) user_data;
+	update_auth_sensitive(page);
+}
+
+static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
+						 GtkWindow *window,
+						 gpointer data)
+{
+	struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
+	PrefsAccount *account = (PrefsAccount *) data;
+	SieveAccountConfig *config;
+
+	GtkWidget *page_vbox, *sieve_vbox;
+	GtkWidget *hbox;
+	GtkWidget *hbox_spc;
+
+	GtkWidget *enable_checkbtn;
+	GtkWidget *serv_vbox, *tls_frame;
+	GtkWidget *tls_vbox, *serv_frame;
+	GtkWidget *auth_vbox, *auth_frame;
+	GtkWidget *auth_custom_vbox, *auth_method_hbox;
+	GtkSizeGroup *size_group;
+	GtkWidget *host_checkbtn, *host_entry;
+	GtkWidget *port_checkbtn, *port_spinbtn;
+	GSList *tls_group = NULL;
+	GSList *auth_group = NULL;
+	GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
+	GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
+	GtkWidget *label;
+	GtkWidget *uid_entry;
+	GtkWidget *pass_entry;
+	GtkWidget *auth_menu;
+	GtkListStore *menu;
+	GtkTreeIter iter;
+
+	page_vbox = gtk_vbox_new (FALSE, VSPACING);
+	gtk_widget_show (page_vbox);
+	gtk_container_set_border_width (GTK_CONTAINER (page_vbox), VBOX_BORDER);
+
+	/* Enable/disable */
+	PACK_CHECK_BUTTON (page_vbox, enable_checkbtn,
+			   _("Enable Sieve"));
+
+	sieve_vbox = gtk_vbox_new (FALSE, VSPACING);
+	gtk_widget_show (sieve_vbox);
+	gtk_box_pack_start (GTK_BOX (page_vbox), sieve_vbox, FALSE, FALSE, 0);
+
+	/* Server info */
+	serv_vbox = gtkut_get_options_frame(sieve_vbox, &serv_frame, _("Server information"));
+	gtk_widget_show (serv_vbox);
+	gtk_box_pack_start (GTK_BOX (page_vbox), serv_vbox, FALSE, FALSE, 0);
+
+	SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
+	size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	/* Server name */
+	PACK_HBOX (hbox, serv_vbox);
+	PACK_CHECK_BUTTON (hbox, host_checkbtn, _("Server name"));
+	gtk_size_group_add_widget(size_group, host_checkbtn);
+
+	host_entry = gtk_entry_new();
+	gtk_widget_show (host_entry);
+	gtk_box_pack_start (GTK_BOX (hbox), host_entry, TRUE, TRUE, 0);
+	SET_TOGGLE_SENSITIVITY (host_checkbtn, host_entry);
+	CLAWS_SET_TIP(hbox,
+		_("Connect to this host instead of the host used for receiving mail"));
+
+	/* Port */
+	PACK_HBOX (hbox, serv_vbox);
+	PACK_CHECK_BUTTON (hbox, port_checkbtn, _("Server port"));
+	port_spinbtn = gtk_spin_button_new_with_range(1, 65535, 1);
+	gtk_widget_show (port_spinbtn);
+	gtk_box_pack_start (GTK_BOX (hbox), port_spinbtn, FALSE, FALSE, 0);
+	SET_TOGGLE_SENSITIVITY (port_checkbtn, port_spinbtn);
+	gtk_size_group_add_widget(size_group, port_checkbtn);
+	CLAWS_SET_TIP(hbox,
+		_("Connect to this port instead of the default"));
+
+	/* Encryption */
+
+	tls_vbox = gtkut_get_options_frame(sieve_vbox, &tls_frame, _("Encryption"));
+	gtk_widget_show (tls_vbox);
+	gtk_box_pack_start (GTK_BOX (page_vbox), tls_vbox, FALSE, FALSE, 0);
+
+	RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
+			_("No TLS"));
+	RADIO_ADD(tls_radio_maybe, tls_group, hbox, tls_vbox,
+			_("Use TLS when available"));
+	RADIO_ADD(tls_radio_yes, tls_group, hbox, tls_vbox,
+			_("Require TLS"));
+
+	/* Authentication */
+
+	auth_vbox = gtkut_get_options_frame(sieve_vbox, &auth_frame,
+			_("Authentication"));
+
+	RADIO_ADD(auth_radio_noauth, auth_group, hbox, auth_vbox,
+		_("No authentication"));
+	RADIO_ADD(auth_radio_reuse, auth_group, hbox, auth_vbox,
+		_("Use same authentication as for receiving mail"));
+	RADIO_ADD(auth_radio_custom, auth_group, hbox, auth_vbox,
+		_("Specify authentication"));
+
+	g_signal_connect(G_OBJECT(auth_radio_custom), "toggled",
+			G_CALLBACK(auth_toggled), page);
+	g_signal_connect(G_OBJECT(auth_radio_reuse), "toggled",
+			G_CALLBACK(auth_toggled), page);
+
+	/* Custom Auth Settings */
+
+	hbox = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (hbox);
+	gtk_box_pack_start (GTK_BOX (auth_vbox), hbox, FALSE, FALSE, 0);
+
+	hbox_spc = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (hbox_spc);
+	gtk_box_pack_start (GTK_BOX (hbox), hbox_spc, FALSE, FALSE, 0);
+	gtk_widget_set_size_request (hbox_spc, 12, -1);
+
+	auth_custom_vbox = gtk_vbox_new (FALSE, VSPACING/2);
+	gtk_widget_show (auth_custom_vbox);
+	gtk_container_set_border_width (GTK_CONTAINER (auth_custom_vbox), 0);
+	gtk_box_pack_start (GTK_BOX (hbox), auth_custom_vbox, TRUE, TRUE, 0);
+
+	/* User ID + Password */
+
+	hbox = gtk_hbox_new (FALSE, 8);
+	gtk_widget_show (hbox);
+	gtk_box_pack_start (GTK_BOX (auth_custom_vbox), hbox, FALSE, FALSE, 0);
+
+	/* User ID*/
+	label = gtk_label_new (_("User ID"));
+	gtk_widget_show (label);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+	uid_entry = gtk_entry_new ();
+	gtk_widget_show (uid_entry);
+	gtk_widget_set_size_request (uid_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_box_pack_start (GTK_BOX (hbox), uid_entry, TRUE, TRUE, 0);
+
+	/* Password */
+	label = gtk_label_new (_("Password"));
+	gtk_widget_show (label);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+	pass_entry = gtk_entry_new ();
+	gtk_widget_show (pass_entry);
+	gtk_widget_set_size_request (pass_entry, DEFAULT_ENTRY_WIDTH, -1);
+	gtk_entry_set_visibility (GTK_ENTRY (pass_entry), FALSE);
+	gtk_box_pack_start (GTK_BOX (hbox), pass_entry, TRUE, TRUE, 0);
+
+	/* Authentication method */
+
+	auth_method_hbox = gtk_hbox_new (FALSE, 8);
+	gtk_widget_show (auth_method_hbox);
+	gtk_box_pack_start (GTK_BOX (auth_vbox), auth_method_hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new (_("Authentication method"));
+	gtk_widget_show (label);
+	gtk_box_pack_start (GTK_BOX (auth_method_hbox), label, FALSE, FALSE, 0);
+
+	auth_menu = gtkut_sc_combobox_create(NULL, FALSE);
+	menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(auth_menu)));
+	gtk_widget_show (auth_menu);
+	gtk_box_pack_start (GTK_BOX (auth_method_hbox), auth_menu, FALSE, FALSE, 0);
+
+	COMBOBOX_ADD (menu, _("Automatic"), SIEVEAUTH_AUTO);
+	COMBOBOX_ADD (menu, NULL, 0);
+	COMBOBOX_ADD (menu, "PLAIN", SIEVEAUTH_PLAIN);
+	COMBOBOX_ADD (menu, "LOGIN", SIEVEAUTH_LOGIN);
+	COMBOBOX_ADD (menu, "CRAM-MD5", SIEVEAUTH_CRAM_MD5);
+
+	/* Populate config */
+
+	config = sieve_prefs_account_get_config(account);
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_checkbtn), config->enable);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(host_checkbtn), config->use_host);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(port_checkbtn), config->use_port);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(port_spinbtn), (float) config->port);
+
+	if (config->host != NULL)
+		gtk_entry_set_text(GTK_ENTRY(host_entry), config->host);
+	if (config->userid != NULL)
+		gtk_entry_set_text(GTK_ENTRY(uid_entry), config->userid);
+	if (config->passwd != NULL)
+		gtk_entry_set_text(GTK_ENTRY(pass_entry), config->passwd);
+
+	combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
+
+	/* Add items to page struct */
+	page->account = account;
+	page->enable_checkbtn = enable_checkbtn;
+	page->serv_frame = serv_frame;
+	page->auth_frame = auth_frame;
+	page->auth_custom_vbox = auth_custom_vbox;
+	page->auth_method_hbox = auth_method_hbox;
+	page->host_checkbtn = host_checkbtn;
+	page->host_entry = host_entry;
+	page->port_checkbtn = port_checkbtn;
+	page->port_spinbtn = port_spinbtn;
+	page->auth_radio_noauth = auth_radio_noauth;
+	page->auth_radio_reuse = auth_radio_reuse;
+	page->auth_radio_custom = auth_radio_custom;
+	page->tls_radio_no = tls_radio_no;
+	page->tls_radio_maybe = tls_radio_maybe;
+	page->tls_radio_yes = tls_radio_yes;
+	page->uid_entry = uid_entry;
+	page->pass_entry = pass_entry;
+	page->auth_menu = auth_menu;
+	page->page.widget = page_vbox;
+
+	/* Update things */
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
+				config->tls_type == SIEVE_TLS_NO ? tls_radio_no :
+				config->tls_type == SIEVE_TLS_MAYBE ? tls_radio_maybe :
+				tls_radio_yes), TRUE);
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
+				config->auth == SIEVEAUTH_REUSE ? auth_radio_reuse :
+				config->auth == SIEVEAUTH_CUSTOM ? auth_radio_custom :
+				auth_radio_noauth), TRUE);
+
+	update_auth_sensitive(page);
+
+	/* Free things */
+	g_object_unref(G_OBJECT(size_group));
+}
+
+static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
+{
+}
+
+static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
+{
+	SieveAccountConfig *config;
+
+	config = sieve_prefs_account_get_config(page->account);
+
+	config->enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_checkbtn));
+	config->use_port = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->port_checkbtn));
+	config->use_host = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn));
+	config->port = (gushort)gtk_spin_button_get_value_as_int
+			(GTK_SPIN_BUTTON(page->port_spinbtn));
+
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_noauth)))
+		config->auth = SIEVEAUTH_NONE;
+	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse)))
+		config->auth = SIEVEAUTH_REUSE;
+	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom)))
+		config->auth = SIEVEAUTH_CUSTOM;
+
+	config->tls_type =
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_no)) ?
+			SIEVE_TLS_NO :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_maybe)) ?
+			SIEVE_TLS_MAYBE :
+			SIEVE_TLS_YES;
+
+	config->host = gtk_editable_get_chars(GTK_EDITABLE(page->host_entry), 0, -1);
+	config->userid = gtk_editable_get_chars(GTK_EDITABLE(page->uid_entry), 0, -1);
+	config->passwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
+	config->auth_type = combobox_get_active_data(GTK_COMBO_BOX(page->auth_menu));
+
+	sieve_prefs_account_set_config(page->account, config);
+	sieve_prefs_account_free_config(config);
+	return TRUE;
+}
+
+static gboolean sieve_prefs_account_check(struct SieveAccountPage *page)
+{
+	if (strchr(gtk_entry_get_text(GTK_ENTRY(page->host_entry)), ' ')) {
+		alertpanel_error(_("Sieve server must not contain a space."));
+		return FALSE;
+	}
+
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn)) &&
+			*gtk_entry_get_text(GTK_ENTRY(page->host_entry)) == '\0') {
+		alertpanel_error(_("Sieve server is not entered."));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void sieve_prefs_account_save_func(PrefsPage *_page)
+{
+	struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
+	if (sieve_prefs_account_check(page)) {
+		sieve_prefs_account_apply(page);
+	}
+}
+
+static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
+{
+	struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
+	return sieve_prefs_account_check(page);
+}
+
+void sieve_prefs_init()
+{
+	static gchar *path[3];
+	path[0] = _("Plugins");
+	path[1] = _("Sieve");
+	path[2] = NULL;
+
+	account_page.page.path = path;
+	account_page.page.create_widget = sieve_prefs_account_create_widget_func;
+	account_page.page.destroy_widget = sieve_prefs_account_destroy_widget_func;
+	account_page.page.save_page = sieve_prefs_account_save_func;
+	account_page.page.can_close = sieve_prefs_account_can_close;
+	account_page.page.weight = 30.0;
+	prefs_account_register_page((PrefsPage *) &account_page);
+}
+
+void sieve_prefs_done(void)
+{
+	prefs_account_unregister_page((PrefsPage *) &account_page);
+}
+
+struct SieveAccountConfig *sieve_prefs_account_get_config(
+		PrefsAccount *account)
+{
+	SieveAccountConfig *config;
+	const gchar *confstr;
+	gchar enc_userid[256], enc_passwd[256];
+	gchar enable, use_host, use_port;
+	gsize len;
+
+	config = g_new0(SieveAccountConfig, 1);
+
+	config->enable = FALSE;
+	config->use_host = FALSE;
+	config->host = NULL;
+	config->use_port = FALSE;
+	config->port = 4190;
+	config->tls_type = SIEVE_TLS_YES;
+	config->auth = SIEVEAUTH_REUSE;
+	config->auth_type = SIEVEAUTH_AUTO;
+	config->userid = NULL;
+	config->passwd = NULL;
+
+	confstr = prefs_account_get_privacy_prefs(account, "sieve");
+	if (confstr == NULL)
+		return config;
+
+
+	sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %256s %256s",
+			&enable, &use_host,
+			&config->host,
+			&use_port, &config->port,
+			(char *)&config->tls_type,
+			(char *)&config->auth,
+			(char *)&config->auth_type,
+			enc_userid,
+			enc_passwd);
+
+	config->enable = enable == 'y';
+	config->use_host = use_host == 'y';
+	config->use_port = use_port == 'y';
+
+	if (config->host[0] == '!' && !config->host[1]) {
+		g_free(config->host);
+		config->host = NULL;
+	}
+
+	config->userid = g_base64_decode(enc_userid, &len);
+	config->passwd = g_base64_decode(enc_passwd, &len);
+	passcrypt_decrypt(config->passwd, len);
+
+	return config;
+}
+
+void sieve_prefs_account_set_config(
+		PrefsAccount *account, SieveAccountConfig *config)
+{
+	gchar *confstr = NULL;
+	gchar *enc_userid = NULL;
+	gchar *enc_passwd = NULL;
+	gchar *tmp;
+	gsize len;
+
+	if (config->userid) {
+		len = strlen(config->userid);
+		enc_userid = g_base64_encode(config->userid, len);
+	}
+
+	if (config->passwd) {
+		tmp = g_strdup(config->passwd);
+		len = strlen(tmp);
+		passcrypt_encrypt(tmp, len);
+		enc_passwd = g_base64_encode(tmp, len);
+		g_free(tmp);
+	}
+
+	confstr = g_strdup_printf("%c%c %s %c%hu %hhu %hhu %hhu %s %s",
+			config->enable ? 'y' : 'n',
+			config->use_host ? 'y' : 'n',
+			config->host && config->host[0] ? config->host : "!",
+			config->use_port ? 'y' : 'n',
+			config->port,
+			config->tls_type,
+			config->auth,
+			config->auth_type,
+			enc_userid ? enc_userid : "",
+			enc_passwd ? enc_passwd : "");
+
+	if (enc_userid)
+		g_free(enc_userid);
+	if (enc_passwd)
+		g_free(enc_passwd);
+
+	prefs_account_set_privacy_prefs(account, "sieve", confstr);
+
+	g_free(confstr);
+
+	sieve_account_prefs_updated(account);
+}
+
+void sieve_prefs_account_free_config(SieveAccountConfig *config)
+{
+	g_free(config->host);
+	g_free(config->userid);
+	g_free(config->passwd);
+	g_free(config);
+}
+
diff --git a/src/plugins/managesieve/sieve_prefs.h b/src/plugins/managesieve/sieve_prefs.h
new file mode 100644
index 0000000..c0c2417
--- /dev/null
+++ b/src/plugins/managesieve/sieve_prefs.h
@@ -0,0 +1,51 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004-2015 the Claws Mail team
+ * Copyright (C) 2014-2015 Charles Lehner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef SIEVE_PREFS_H
+#define SIEVE_PREFS_H
+
+typedef struct SieveAccountConfig SieveAccountConfig;
+
+#include "prefs_account.h"
+#include "managesieve.h"
+
+struct SieveAccountConfig
+{
+	gboolean	enable;
+	gboolean	use_host;
+	gchar 		*host;
+	gboolean	use_port;
+	gushort		port;
+	SieveAuth	auth;
+	SieveAuthType	auth_type;
+	SieveTLSType	tls_type;
+	gchar		*userid;
+	gchar		*passwd;
+};
+
+void sieve_prefs_init(void);
+void sieve_prefs_done(void);
+struct SieveAccountConfig *sieve_prefs_account_get_config(
+		PrefsAccount *account);
+void sieve_prefs_account_set_config(
+		PrefsAccount *account, SieveAccountConfig *config);
+void sieve_prefs_account_free_config(SieveAccountConfig *config);
+
+#endif /* SIEVE_PREFS_H */
diff --git a/src/plugins/managesieve/version.rc b/src/plugins/managesieve/version.rc
new file mode 100644
index 0000000..0202262
--- /dev/null
+++ b/src/plugins/managesieve/version.rc
@@ -0,0 +1,36 @@
+1 VERSIONINFO
+ FILEVERSION 0, 0, 0, 0
+ PRODUCTVERSION 0, 0, 0, 0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "FileDescription", "Claws Mail ManageSieve Plugin\0"
+            VALUE "FileVersion", "0.0.0.0\0"
+            VALUE "ProductVersion", "0.0.0.0 Win32\0"
+            VALUE "LegalCopyright", "GPL / © 1999-2014 Hiroyuki Yamamoto & The Claws Mail Team\0"
+            VALUE "CompanyName", "GNU / Free Software Foundation\0"
+            VALUE "ProductName", "Claws Mail\0"
+//            VALUE "Comments", "\0"
+//            VALUE "InternalName", "\0"
+//            VALUE "LegalTrademarks", "\0"
+//            VALUE "OriginalFilename", "\0"
+//            VALUE "PrivateBuild", "\0"
+//            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END

commit 9b928dfc0e70dfd7010becf1801ccbcfd4ab7bfa
Author: Charles Lehner <cel at celehner.com>
Date:   Sun Nov 16 17:14:14 2014 -0500

    Make message_search interface-based
    
    - Factor out compose/messageview checking.
    - Make general so other code can use it

diff --git a/src/message_search.c b/src/message_search.c
index 9866d7c..33965bd 100644
--- a/src/message_search.c
+++ b/src/message_search.c
@@ -54,14 +54,25 @@ static struct MessageSearchWindow {
 	GtkWidget *close_btn;
 	GtkWidget *stop_btn;
 
-	MessageView *messageview;
+	SearchInterface *interface;
+	void *interface_obj;
 
-	Compose *compose;
-	gboolean search_compose;
 	gboolean is_searching;
 	gboolean body_entry_has_focus;
 } search_window;
 
+static SearchInterface compose_interface = {
+	.search_string_backward = (SearchStringFunc) compose_search_string_backward,
+	.set_position = (SetPositionFunc) compose_set_position,
+	.search_string = (SearchStringFunc) compose_search_string,
+};
+
+static SearchInterface messageview_interface = {
+	.set_position = (SetPositionFunc) messageview_set_position,
+	.search_string = (SearchStringFunc) messageview_search_string,
+	.search_string_backward = (SearchStringFunc) messageview_search_string_backward,
+};
+
 static void message_search_create	(void);
 static void message_search_execute	(gboolean	 backward);
 
@@ -103,34 +114,30 @@ static void message_hide_stop_button(void)
 
 void message_search(MessageView *messageview)
 {
-	if (!search_window.window)
-		message_search_create();
-	else
-		gtk_widget_hide(search_window.window);
-
-	search_window.messageview = messageview;
-	search_window.search_compose = FALSE;
-
-	gtk_widget_grab_focus(search_window.next_btn);
-	gtk_widget_grab_focus(search_window.body_entry);
-	gtk_widget_show(search_window.window);
+	message_search_other(&messageview_interface, (void *)messageview);
 }
 
 void message_search_compose(Compose *compose)
 {
+	message_search_other(&compose_interface, (void *)compose);
+}
+
+void message_search_other(SearchInterface *interface, void *obj)
+{
 	if (!search_window.window)
 		message_search_create();
 	else
 		gtk_widget_hide(search_window.window);
 
-	search_window.compose = compose;
-	search_window.search_compose = TRUE;
+	search_window.interface_obj = obj;
+	search_window.interface = interface;
 
 	gtk_widget_grab_focus(search_window.next_btn);
 	gtk_widget_grab_focus(search_window.body_entry);
 	gtk_widget_show(search_window.window);
 }
 
+
 static void message_search_create(void)
 {
 	GtkWidget *window;
@@ -266,8 +273,7 @@ static void message_search_create(void)
 
 static void message_search_execute(gboolean backward)
 {
-	MessageView *messageview = search_window.messageview;
-	Compose *compose = search_window.compose;
+	void *interface_obj = search_window.interface_obj;
 	gboolean case_sens;
 	gboolean all_searched = FALSE;
 	gchar *body_str;
@@ -309,25 +315,13 @@ static void message_search_execute(gboolean backward)
 		AlertValue val;
 
 		if (backward) {
-			if (search_window.search_compose) {
-				if (compose_search_string_backward
-					(compose, body_str, case_sens) == TRUE)
-					break;
-			} else {
-				if (messageview_search_string_backward
-					(messageview, body_str, case_sens) == TRUE)
-					break;
-			}
+			if (search_window.interface->search_string_backward
+				(interface_obj, body_str, case_sens) == TRUE)
+				break;
 		} else {
-			if (search_window.search_compose) {
-				if (compose_search_string
-					(compose, body_str, case_sens) == TRUE)
-					break;
-			} else {
-				if (messageview_search_string
-					(messageview, body_str, case_sens) == TRUE)
-					break;
-			}
+			if (search_window.interface->search_string
+				(interface_obj, body_str, case_sens) == TRUE)
+				break;
 		}
 
 		if (all_searched) {
@@ -352,13 +346,8 @@ static void message_search_execute(gboolean backward)
 		if (G_ALERTALTERNATE == val) {
 			manage_window_focus_in(search_window.window,
 					       NULL, NULL);
-			if (search_window.search_compose) {
-				compose_set_position(compose,
-							 backward ? -1 : 0);
-			} else {
-				messageview_set_position(messageview,
-							 backward ? -1 : 0);
-			}
+			search_window.interface->set_position(interface_obj,
+							backward ? -1 : 0);
 		} else
 			break;
 	}
diff --git a/src/message_search.h b/src/message_search.h
index 625f0b8..e6ab436 100644
--- a/src/message_search.h
+++ b/src/message_search.h
@@ -25,7 +25,18 @@
 #include "messageview.h"
 #include "compose.h"
 
+typedef void (*SetPositionFunc)(void *obj, gint pos);
+typedef gboolean (*SearchStringFunc)(void *obj,
+	const gchar *str, gboolean case_sens);
+
+typedef struct {
+	SetPositionFunc set_position;
+	SearchStringFunc search_string;
+	SearchStringFunc search_string_backward;
+} SearchInterface;
+
 void message_search	(MessageView	*messageview);
 void message_search_compose	(Compose	*compose);
+void message_search_other	(SearchInterface	*source, void *obj);
 
 #endif /* __MESSAGE_SEARCH_H__ */

commit b0978b8f43fa2da616a3171001ba75e7c89f9c34
Author: Charles Lehner <cel at celehner.com>
Date:   Sat Nov 22 20:44:25 2014 -0500

    Add callback for session connection result

diff --git a/src/common/session.c b/src/common/session.c
index 15d4fba..8569148 100644
--- a/src/common/session.c
+++ b/src/common/session.c
@@ -128,6 +128,8 @@ gint session_connect(Session *session, const gchar *server, gushort port)
 	if (session->conn_id < 0) {
 		g_warning("can't connect to server.");
 		session_close(session);
+		if (session->connect_finished)
+			session->connect_finished(session, FALSE);
 		return -1;
 	}
 
@@ -142,6 +144,8 @@ gint session_connect(Session *session, const gchar *server, gushort port)
 	if (sock == NULL) {
 		g_warning("can't connect to server.");
 		session_close(session);
+		if (session->connect_finished)
+			session->connect_finished(session, FALSE);
 		return -1;
 	}
 	sock->is_smtp = session->is_smtp;
@@ -159,6 +163,8 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 	if (!sock) {
 		g_warning("can't connect to server.");
 		session->state = SESSION_ERROR;
+		if (session->connect_finished)
+			session->connect_finished(session, FALSE);
 		return -1;
 	}
 
@@ -176,6 +182,8 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 			g_warning("can't initialize SSL.");
 			log_error(LOG_PROTOCOL, _("SSL handshake failed\n"));
 			session->state = SESSION_ERROR;
+			if (session->connect_finished)
+				session->connect_finished(session, FALSE);
 			return -1;
 		}
 	}
@@ -183,8 +191,11 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 
 	/* we could have gotten a timeout while waiting for user input in 
 	 * an SSL certificate dialog */
-	if (session->state == SESSION_TIMEOUT)
+	if (session->state == SESSION_TIMEOUT) {
+		if (session->connect_finished)
+			session->connect_finished(session, FALSE);
 		return -1;
+	}
 
 	sock_set_nonblocking_mode(sock, session->nonblocking);
 
@@ -195,6 +206,8 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 					 session_read_msg_cb,
 					 session);
 
+	if (session->connect_finished)
+		session->connect_finished(session, TRUE);
 	return 0;
 }
 
diff --git a/src/common/session.h b/src/common/session.h
index 98ae50e..cd4b774 100644
--- a/src/common/session.h
+++ b/src/common/session.h
@@ -130,6 +130,8 @@ struct _Session
 	gint (*recv_msg)		(Session	*session,
 					 const gchar	*msg);
 
+	void (*connect_finished)	(Session	*session,
+					 gboolean	success);
 	gint (*send_data_finished)	(Session	*session,
 					 guint		 len);
 	gint (*recv_data_finished)	(Session	*session,

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list