Python plugin: Add examples
authorHolger Berndt <hb@claws-mail.org>
Sun, 7 Apr 2013 13:04:41 +0000 (15:04 +0200)
committerHolger Berndt <hb@claws-mail.org>
Sun, 7 Apr 2013 13:09:36 +0000 (15:09 +0200)
14 files changed:
.gitignore
configure.ac
src/plugins/python/Makefile.am
src/plugins/python/examples/Makefile.am [new file with mode: 0644]
src/plugins/python/examples/README.examples [new file with mode: 0644]
src/plugins/python/examples/auto/compose_any [new file with mode: 0644]
src/plugins/python/examples/auto/shutdown [new file with mode: 0644]
src/plugins/python/examples/auto/startup [new file with mode: 0644]
src/plugins/python/examples/compose/Macro-Expansion [new file with mode: 0644]
src/plugins/python/examples/main/Create-Tomboy-Note [new file with mode: 0644]
src/plugins/python/examples/main/Mass-mail [new file with mode: 0644]
src/plugins/python/examples/main/Open-Tomboy-Notes [new file with mode: 0644]
src/plugins/python/examples/main/Print-action-names-to-stdout [new file with mode: 0644]
src/plugins/python/examples/main/Recusively-mark-messages-as-read [new file with mode: 0644]

index 228c5859a3da9304a8e8b5bbb973f102acbe7aa8..952c114a9c65ba2e34046dc1fcbc0d24cb405d0f 100644 (file)
 /src/plugins/python/Makefile
 /src/plugins/python/Makefile.in
 /src/plugins/python/*.o
+/src/plugins/python/examples/Makefile
+/src/plugins/python/examples/Makefile.in
 /src/plugins/rssyl/.deps
 /src/plugins/rssyl/*.la
 /src/plugins/rssyl/.libs
index d4892680382c681572dfec091fd185a3f48ac818..12430e9470e62f93fe3bf8f8bf4d2d89541ee8da 100644 (file)
@@ -101,7 +101,7 @@ AC_SYS_LARGEFILE
 
 dnl ******************************
 dnl Checks for host
-dnl Not needed anymore because we 
+dnl Not needed anymore because we
 dnl do AC_CANONICAL_SYSTEM above
 dnl ******************************
 dnl AC_CANONICAL_HOST
@@ -184,7 +184,7 @@ case "$target" in
        CFLAGS="$CFLAGS -std=gnu99 -DSOLARIS"
        ;;
 esac
-  
+
 dnl Checks for iconv
 AM_ICONV
 
@@ -379,7 +379,7 @@ AC_CHECK_HEADERS(fcntl.h sys/file.h unistd.h paths.h \
 AC_CHECK_HEADER([execinfo.h], [AC_DEFINE(HAVE_BACKTRACE,1,[Has backtrace*() needed for retrieving stack traces])])
 AC_SEARCH_LIBS(backtrace_symbols, [execinfo])
 
-dnl alf - Check for apache installation f*ck up. apache may also install an 
+dnl alf - Check for apache installation f*ck up. apache may also install an
 dnl fnmatch, which includes their own regex stuff if USE_HSREGEX is defined
 AC_TRY_COMPILE([#include <stdlib.h>
                #include <fnmatch.h>],
@@ -427,7 +427,7 @@ dnl *****************
 
 dnl check for glib
 PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.6 gmodule-2.0 >= 2.6 gobject-2.0 >= 2.6 gthread-2.0 >= 2.6)
-      
+
 GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
 
@@ -512,7 +512,7 @@ AC_ARG_WITH(config-dir,    [  --with-config-dir=RCDIR      Local configuration d
              ac_cv_with_config_dir="$withval", ac_cv_with_config_dir=".claws-mail")
 if test x"$ac_cv_with_config_dir" = x""; then
        ac_cv_with_config_dir=".claws-mail"
-fi 
+fi
 AC_DEFINE_UNQUOTED(CFG_RC_DIR, "$ac_cv_with_config_dir", Configuration directory)
 
 dnl ************************
@@ -607,7 +607,7 @@ dnl Check for X-Face support
 AC_MSG_CHECKING([whether to use compface])
 if test x"$enable_compface" = xyes; then
        AC_MSG_RESULT(yes)
-       AC_CHECK_LIB(compface, uncompface, 
+       AC_CHECK_LIB(compface, uncompface,
                [AC_DEFINE(HAVE_LIBCOMPFACE, 1, Define if you want compface support.)],
                [enable_compface=no])
        if test x"$enable_compface" = xyes; then
@@ -1895,6 +1895,7 @@ src/plugins/pdf_viewer/Makefile
 src/plugins/perl/Makefile
 src/plugins/perl/tools/Makefile
 src/plugins/python/Makefile
+src/plugins/python/examples/Makefile
 src/plugins/pgpcore/Makefile
 src/plugins/pgpmime/Makefile
 src/plugins/pgpinline/Makefile
index 0ed1d650c86e625e1dbc3fd4e9f782dbb5158047..daef423a73c0ad2eef603f8c7ccdf34d9e23859d 100644 (file)
@@ -1,3 +1,5 @@
+SUBDIRS = examples
+
 plugindir = $(pkglibdir)/plugins
 
 if BUILD_PYTHON_PLUGIN
diff --git a/src/plugins/python/examples/Makefile.am b/src/plugins/python/examples/Makefile.am
new file mode 100644 (file)
index 0000000..d20c063
--- /dev/null
@@ -0,0 +1,10 @@
+EXTRA_DIST = \
+       README.examples \
+       auto/shutdown \
+       auto/startup \
+       compose/Macro-Expansion \
+       main/Create-Tomboy-Note \
+       main/Mass-mail \
+       main/Open-Tomboy-Notes \
+       main/Print-action-names-to-stdout \
+       main/Recusively-mark-messages-as-read
diff --git a/src/plugins/python/examples/README.examples b/src/plugins/python/examples/README.examples
new file mode 100644 (file)
index 0000000..ebe7b86
--- /dev/null
@@ -0,0 +1,58 @@
+This directory tree contains some example scripts. Feel free
+to copy them to the appropriate subdirectories under
+~/.claws-mail/python-scripts and adjust them to your needs. 
+
+Unless otherwise noted in the respective files, all example snippets
+are in the public domain.
+
+Table of contents:
+==================
+
+* auto/startup
+  An example startup script. It demonstrates how to modify the menu of
+  Claws Mail's main window by adding a menu item under the Help menu
+  to generate and browse the API documentation of the plugin.
+  It also adds a menu item to mark a whole thread as read in the
+  Edit menu.
+  Furthermore, it shows how to build a D-Bus bridge to Claws Mail
+  that other processes can use to trigger Claws Mail events.
+  Also see auto/shutdown for cleanup.
+
+* auto/shutdown
+  Demonstrates how to clean up the stuff that has been introduced in
+  the auto/startup example.
+
+* auto/compose_any
+  An example compose script. It demonstrates how to strip reply
+  prefixes that Claws Mail doesn't yet know about from the subject
+  header.
+
+* main/Print-action-names-to-stdout
+  Prints the names of all actions that are currently in the
+  action group of Claws Mail's main window to standard output 
+
+* main/Recursively-mark-messages-as-read
+  Demonstrates how to perform actions to a directory tree under the
+  currently selected folder in the main window.
+
+* main/Mass-mail
+  Demonstrates how to automate composing of mails, and sending them out
+
+* main/Create-Tomboy-Note
+  Create a Tomboy note for each selected message, containing the
+  subject as note title and a Claws Mail link in the body which
+  links back to Claws Mail (requires the Claws Mail addin for Tomboy).
+  Optionally, the user can choose to add a marker string for the
+  Tomboy Reminder addin into the note.
+  To achieve this, this example demonstrates how to talk to other
+  programs via D-Bus, as well as how to query additional information
+  from the user using direct GTK+ programming.
+
+* main/Open-Tomboy-Notes
+  This example opens all Tomboy notes which link to any of the currently
+  selected messages, and thus completes the round trip from the
+  "Create-Tomboy-Note" example.
+
+* compose/Macro-Expansion
+  Demonstrates how to do text expansion in the compose window
+  mail body editor
diff --git a/src/plugins/python/examples/auto/compose_any b/src/plugins/python/examples/auto/compose_any
new file mode 100644 (file)
index 0000000..b15f0f3
--- /dev/null
@@ -0,0 +1,50 @@
+import re
+
+# Strip prefixes in subject
+#
+# When replying to a reply, Claws Mail strips the "Re: " reply
+# marker of the subject line before prefixing with its own.
+# Claws Mail also knows several localized variants from various
+# mailers, such as "Aw: " (German Outlook), "Odp: " (Polish Outlook)
+# and so on.
+#
+# However, it doesn't know all, and as of 3.8.1, adding new ones
+# is not possible via a config option.
+#
+# This function is there to add new markers. It will also strip
+# an already messed up original subject line, provided that all
+# prefixes are defined below.
+# So, for example, replying to a mail with
+#    Subject: R: Re: R: Re: Aw: R: Re: Old topic
+# will result in 
+#    Subject: Re: Old topic
+#
+# This is a slightly adapted version of a script provided
+# by Michael Gmelin and Slavko on Claws Mail's users mailing list.
+def strip_subject_prefixes():
+    # A list of prefixes to strip during reply. Add the ones that are
+    # interesting for you here.
+    prefixes = ["Re", "R", "Odp", "Aw"]
+    
+    # Build up regex to match unwanted prefixes
+    prefix_string = "|".join(prefixes)
+    regex_str = r"^(Re|Fwd|Fw):( (%s):)+" % prefix_string
+    
+    # Get a string with those prefixes stripped
+    new_subject = re.sub(regex_str, r"\1:",    clawsmail.compose_window.get_subject())
+    
+    # Set this string to be the new subject
+    clawsmail.compose_window.set_subject(new_subject)
+    
+    # Normally, when the subject or body is modified, the mail gets marked
+    # as modified, wich results in a popup dialog when the compose window is 
+    # just closed. We don't want to treat the automatic modification of the
+    # subject line from above to trigger such a popup, so we override the
+    # modification marker.
+    # Note that this affects only for the modifications done so far. As
+    # soon as the user starts to modify the mail manually, it will be
+    # set again.
+    clawsmail.compose_window.set_modified(False)
+
+
+strip_subject_prefixes()
\ No newline at end of file
diff --git a/src/plugins/python/examples/auto/shutdown b/src/plugins/python/examples/auto/shutdown
new file mode 100644 (file)
index 0000000..90ec5c5
--- /dev/null
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+# stuff that only needs to be cleaned up if claws mail is not exiting anyways
+if not clawsmail.is_exiting():
+    
+    # cleanup menus and actions that have been added in the startup script
+    try:
+        ui_manager = clawsmail.get_mainwindow_ui_manager()
+        for merge_id in mainwindow_merge_ids:
+            ui_manager.remove_ui(merge_id)
+    except NameError:
+        pass
+    try:
+        group = clawsmail.get_mainwindow_action_group()
+        for action in mainwindow_actions:
+            group.remove_action(action)
+    except NameError:
+        pass
+        
diff --git a/src/plugins/python/examples/auto/startup b/src/plugins/python/examples/auto/startup
new file mode 100644 (file)
index 0000000..8901cf0
--- /dev/null
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+# lists to store information for cleanup in the shutdown script
+mainwindow_merge_ids = []
+mainwindow_actions = []
+
+
+# function definitions
+
+def add_python_documentation_menu_item():
+    # Adds a Help -> Python API documentation menu item
+    def pydoc_cb(action):
+        # callback for "Python API documentation" action
+        import os, tempfile, subprocess, pydoc
+        working_directory = os.getcwd()  # store current working directory
+        os.chdir(tempfile.gettempdir())  # switch to a temporary directory
+        pydoc.writedoc(clawsmail)        # write out API documentation to $TEMP/clawsmail.html
+        subprocess.Popen(["xdg-open", "clawsmail.html"]) # start html viewer in the background
+        os.chdir(working_directory)      # switch back to original working directory
+
+    global mainwindow_merge_ids
+    global mainwindow_actions
+    
+    # create "Python API documentation" menu item
+    group = clawsmail.get_mainwindow_action_group()
+    ui_manager = clawsmail.get_mainwindow_ui_manager()
+    action = gtk.Action("pydoc", "Python API documentation", None, None)
+    action.connect("activate", pydoc_cb)
+    group.add_action(action)
+    merge_id = ui_manager.new_merge_id()
+    ui_manager.add_ui(merge_id, "/Menu/Help", "pydoc", "pydoc", gtk.UI_MANAGER_MENUITEM, True)
+    mainwindow_merge_ids.append(merge_id)
+    mainwindow_actions.append(action)
+
+def add_mark_thread_read_menu_item():
+    # Adds an Edit -> Mark thread as read menu item
+    def thread_read_cb(action):
+        # callback for "Mark thread as read" action
+        selected_messages = clawsmail.get_summaryview_selected_message_list()
+        group = clawsmail.get_mainwindow_action_group()
+        group.get_action("Edit/SelectThread").activate()
+        group.get_action("Message/Mark/MarkRead").activate()
+        clawsmail.summaryview_select_messages(selected_messages)        
+
+    global mainwindow_merge_ids
+    global mainwindow_actions
+    
+    # create "Mark thread read" menu item
+    group = clawsmail.get_mainwindow_action_group()
+    ui_manager = clawsmail.get_mainwindow_ui_manager()
+    action = gtk.Action("ThreadRead", "Mark thread as read", None, None)
+    action.connect("activate", thread_read_cb)
+    group.add_action_with_accel(action, None)
+    merge_id = ui_manager.new_merge_id()
+    ui_manager.add_ui(merge_id, "/Menu/Edit", "ThreadRead", "ThreadRead", gtk.UI_MANAGER_MENUITEM, False)
+    mainwindow_merge_ids.append(merge_id)
+    mainwindow_actions.append(action)
+
+def add_dbus_interface():
+    # exports an interface to Claws Mail on the session D-Bus
+    #
+    # Example invokation to trigger an update of the summary view from the command line:
+    # dbus-send --session --type=method_call --dest=org.ClawsMail.PythonPlugin /org/ClawsMail/PythonPlugin org.ClawsMail.PythonPlugin.MainWindow.TriggerGtkAction string:'View/UpdateSummary'
+    try:
+        import dbus
+        import dbus.service
+        from dbus.mainloop.glib import DBusGMainLoop    
+    except ImportError:
+        print 'Cannot setup D-Bus interface: D-Bus Python bindings not available.'
+        return None
+        
+    class ClawsMailService(dbus.service.Object):
+        @dbus.service.method("org.ClawsMail.PythonPlugin.MainWindow", in_signature='s', out_signature='')
+        def TriggerGtkAction(self, action_path):
+            action = clawsmail.get_mainwindow_action_group().get_action(action_path)
+            if action:
+                action.activate()
+            else:
+                print 'No such action:', action_path
+                
+    loop = DBusGMainLoop(set_as_default=True)
+    session_bus = dbus.SessionBus()
+    name = dbus.service.BusName("org.ClawsMail.PythonPlugin", session_bus)
+    object = ClawsMailService(session_bus, '/org/ClawsMail/PythonPlugin')
+    return name
+
+# call the functions that have been defined above, or comment the functions that you want to omit
+add_python_documentation_menu_item()
+add_mark_thread_read_menu_item()
+dbus_interface = add_dbus_interface()
diff --git a/src/plugins/python/examples/compose/Macro-Expansion b/src/plugins/python/examples/compose/Macro-Expansion
new file mode 100644 (file)
index 0000000..80e9887
--- /dev/null
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+
+# If the cursor in the compose window body is on a word
+# that is listed in this table as a key (element before the colon),
+# this word is replaced with the value (element after the colon).
+# To add key/value pairs, just add more lines.
+replacement_table = {
+    "dsm"   : "Dear Sir/Madam,\n",
+    "th"    : "Thanks,\nHolger",
+    "blake" : "And did those feet in ancient time\nWalk upon England's mountains green?\nAnd was the holy Lamb of God\nOn England's pleasant pastures seen?",
+}
+
+# helper function to get the current word under the cursor
+def get_current_word(buffer):
+    start = buffer.get_iter_at_mark(buffer.get_insert())
+    end = buffer.get_iter_at_mark(buffer.get_insert())
+    if not start.starts_word():
+        start.backward_word_start()
+    if not end.ends_word():
+        end.forward_word_end()
+    return (start.get_text(end), start, end)
+    
+
+buffer = clawsmail.compose_window.text.get_buffer()         # get text buffer of body editor
+(current_word, start, end) = get_current_word(buffer)       # get current word under the cursor
+if current_word in replacement_table:                       # if current word is a key in the replacement table...
+    buffer.delete(start, end)                               # delete the current word
+    buffer.insert(start, replacement_table[current_word])   # and insert the replacement in its place
diff --git a/src/plugins/python/examples/main/Create-Tomboy-Note b/src/plugins/python/examples/main/Create-Tomboy-Note
new file mode 100644 (file)
index 0000000..6002a4f
--- /dev/null
@@ -0,0 +1,130 @@
+# -*- Mode: python -*-
+
+import dbus
+import gtk
+
+def add_note(msg):
+    
+    def get_reminder(desc):
+        get_reminder.reminder = None
+
+        # callback functions for the GUI
+        def no_reminder(button, ww):
+            get_reminder.reminder = ""
+            ww.destroy()
+
+        def date_time_cb(button, ww, cal, cb, hours, minutes):
+            ymd = list(cal.get_date())
+            ymd[1] += 1
+            get_reminder.reminder = "/".join([str(v) for v in ymd])
+            if cb.get_active():
+                get_reminder.reminder += "".join([" at ", "%02d" % hours.get_value_as_int(), ":", "%02d" % minutes.get_value_as_int()])
+            ww.destroy()
+        
+        def day_selected(cal, exp):
+            ymd = list(cal.get_date())
+            ymd[1] += 1
+            exp.set_label("/".join(str(vv) for vv in ymd))
+        
+        def custom(button, ww, entry):
+            get_reminder.reminder = entry.get_text()
+            ww.destroy()
+        
+
+        # Check if the user wants a reminder in a dialog box
+        win = gtk.Window()
+        win.set_title("Reminder")
+        win.connect("destroy", gtk.main_quit)
+        win.set_position(gtk.WIN_POS_CENTER)
+        table = gtk.Table(2,7)
+        win.add(table)
+        table.attach(gtk.Label(desc), 0, 2, 0, 1)
+        # no reminder
+        button = gtk.Button("No reminder")
+        button.connect("clicked", no_reminder, win)
+        table.attach(button, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=0, ypadding=4)
+        table.attach(gtk.HSeparator(), 0, 2, 2, 3)
+        # date / time reminder
+        button = gtk.Button("Date/Time")
+        table.attach(button, 0, 1, 3, 4, xoptions=gtk.FILL, yoptions=gtk.EXPAND | gtk.FILL, ypadding=4)
+        hbox = gtk.HBox()
+        table.attach(hbox, 1, 2, 3, 4)
+        cal = gtk.Calendar()
+        exp = gtk.Expander()
+        day_selected(cal, exp)
+        cal.connect("day-selected", day_selected, exp)
+        exp.add(cal)
+        hbox.pack_start(exp)
+        cb = gtk.CheckButton("at")
+        hbox.pack_start(cb, False, False)
+        hours = gtk.SpinButton(gtk.Adjustment(12.0, 0.0, 24.0, 1.0, 5.0, 0.0))
+        hours.set_numeric(True)
+        hours.set_wrap(True)
+        hbox.pack_start(hours, False, False)
+        hbox.pack_start(gtk.Label(":"), False, False)
+        minutes = gtk.SpinButton(gtk.Adjustment(0.0, 0.0, 59.0, 1.0, 5.0, 0.0))
+        minutes.set_numeric(True)
+        minutes.set_wrap(True)
+        hbox.pack_start(minutes, False, False)
+        button.connect("clicked", date_time_cb, win, cal, cb, hours, minutes)
+        # custom
+        button = gtk.Button("custom")
+        table.attach(button, 0, 1, 4, 5, xoptions=gtk.FILL, yoptions=0, ypadding=4)
+        entry = gtk.Entry()
+        button.connect("clicked", custom, win, entry)
+        table.attach(entry, 1, 2, 4, 5)
+        
+        # "Show note" toggle option
+        table.attach(gtk.HSeparator(), 0, 2, 5, 6)
+        cb = gtk.CheckButton("Show note")
+        table.attach(cb, 0, 2, 6, 7)
+
+        win.show_all()
+        win.present()
+        gtk.main()
+        return (get_reminder.reminder, cb.get_active())
+    
+    title = msg.Subject
+    # set up contents: opening tag
+    content = ["<note-content>"]
+    # title
+    content.append(title)
+    content.append("\n\n")
+    # reminder if wanted
+    (reminder, show_note) = get_reminder("\n".join([msg.From, msg.Subject]))
+    if reminder == None:
+        return
+    if reminder:
+        content.extend(["!", reminder, "\n"])
+    # link back to email
+    msgid = msg.MessageID
+    if msgid[0] != "<":
+        msgid = "<" + msgid
+    if msgid[-1] != ">":
+        msgid += ">" 
+    msgid = msgid.replace("<", "&lt;").replace(">", "&gt;")
+    link = '<link:cm-mail uri="%s/%s">%s</link:cm-mail>' % (clawsmail.get_folderview_selected_folder().get_identifier(), msgid, msg.Subject)
+    content.append(link)
+    #closing tag
+    content.append("</note-content>")
+
+    # create a tomboy note
+    bus = dbus.SessionBus()
+    rc = bus.get_object('org.gnome.Tomboy', '/org/gnome/Tomboy/RemoteControl')
+    rc_iface = dbus.Interface(rc, dbus_interface='org.gnome.Tomboy.RemoteControl')
+    uri = rc_iface.CreateNamedNote(title)
+    rc_iface.SetNoteContentsXml(uri, "".join(content))
+    rc_iface.DisplayNote(uri)
+    if not show_note:
+        rc_iface.HideNote(uri)
+
+
+# iterate over all notes
+for msg in clawsmail.get_summaryview_selected_message_list():
+    add_note(msg)
+    
+
+
+
+
+
diff --git a/src/plugins/python/examples/main/Mass-mail b/src/plugins/python/examples/main/Mass-mail
new file mode 100644 (file)
index 0000000..228e7da
--- /dev/null
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+
+# Send the same mail to a list of people, one at a time.
+# As this is normal Python code, the message contents and 
+# the addresses could also come from an external source 
+# (such as a file, or a database).
+addresses = ["mail1@example.tld", "mail2@example.tld", "mail3@example.tld"]
+
+for address in addresses:
+    # The argument for the constructor is an email address on which
+    # the sending account is selected.
+    # It's also possible to use the default constructor without arguments,
+    # in which case the same rules as on a menu click one "New message"
+    # are applied.
+    cw = clawsmail.ComposeWindow("berndth@gmx.de")
+    
+    # Add a recipient. There are also add_Cc and add_Bcc functions.
+    cw.add_To(address)
+    
+    # Set the subject of the message
+    cw.set_subject("Mass mail")
+    
+    # For the message body, access to the GtkTextView is granted in ComposeWindow.text.
+    buffer = cw.text.get_buffer()
+    buffer.set_text("This is an automatic message")
+    
+    # Access to the GtkUIManager is also provided, look for "send later" action
+    action = None
+    for action_group in cw.ui_manager.get_action_groups():
+        for action in action_group.list_actions():
+            action = action_group.get_action("Message/SendLater")
+            if action:
+                break
+        if action:
+            break;
+    if action:
+        action.activate()
+
+# Finally, the action group of the main window can be used to send the messages out
+# Comment this for now, to not actually send stuff during testing
+#clawsmail.get_mainwindow_action_group().get_action("Message/SendQueue").activate()
diff --git a/src/plugins/python/examples/main/Open-Tomboy-Notes b/src/plugins/python/examples/main/Open-Tomboy-Notes
new file mode 100644 (file)
index 0000000..20da034
--- /dev/null
@@ -0,0 +1,25 @@
+# -*- Mode: python -*-
+
+import re
+
+import dbus
+import gtk
+
+# collect message ids of all selected messages
+msgids = set()
+for msg in clawsmail.get_summaryview_selected_message_list():
+    msgid = msg.MessageID.replace("<", "&lt;").replace(">", "&gt;")
+    msgids.add(msgid)
+
+# setup D-Bus interface object
+bus = dbus.SessionBus()
+rc = bus.get_object('org.gnome.Tomboy', '/org/gnome/Tomboy/RemoteControl')
+rc_iface = dbus.Interface(rc, dbus_interface='org.gnome.Tomboy.RemoteControl')
+
+# iterate over all Tomboy notes
+for uri in rc_iface.ListAllNotes():
+    contents = rc_iface.GetNoteContentsXml(uri)
+    # Check if message id is in a link to claws mail
+    for msgid in msgids:
+        if re.search(r'<link:cm-mail uri=".*?%s.*?">' % msgid, contents) != None:
+            rc_iface.DisplayNote(uri)
diff --git a/src/plugins/python/examples/main/Print-action-names-to-stdout b/src/plugins/python/examples/main/Print-action-names-to-stdout
new file mode 100644 (file)
index 0000000..3420eb6
--- /dev/null
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+action_group = clawsmail.get_mainwindow_action_group()
+for action in action_group.list_actions():
+    print action.get_name()
diff --git a/src/plugins/python/examples/main/Recusively-mark-messages-as-read b/src/plugins/python/examples/main/Recusively-mark-messages-as-read
new file mode 100644 (file)
index 0000000..85c108e
--- /dev/null
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+# Define the function to deal with each folder
+def deal_with_folder(folder):
+    # Get actions for selecting all messages, and marking the selection as read
+    action_group = clawsmail.get_mainwindow_action_group();
+    select_all_action = action_group.get_action("Edit/SelectAll")
+    mark_read_action = action_group.get_action("Message/Mark/MarkRead")
+    
+    # Select given folder
+    clawsmail.folderview_select_folder(folder)
+    
+    # Search for messages with age greater than 28 days
+    clawsmail.quicksearch_search("ag 28", clawsmail.QUICK_SEARCH_EXTENDED)
+    
+    # Mark all messages in the search result as read
+    select_all_action.activate()
+    mark_read_action.activate()
+
+
+# Get selected folder
+root = clawsmail.get_folderview_selected_folder()
+
+# Get a tree of subfolders. The argument could also be a string of a mailbox name,
+# or left out for a list of mailbox trees.
+tree = clawsmail.get_folder_tree(root)
+
+# Call above function for all folders.
+tree.traverse(deal_with_folder)
+
+# Clear the quicksearch widget again
+clawsmail.quicksearch_clear()
+
+# Change back to original folder
+clawsmail.folderview_select_folder(root)